PointerChain provided by Greg Pfeil github.com/sellout

This commit is contained in:
Aly 2020-07-03 21:04:08 -07:00
parent 8b52321920
commit b5efa9c7f5
8 changed files with 258 additions and 124 deletions

View file

@ -38,6 +38,7 @@ lazy val tagless = (project in file("tagless")).settings(
"com.chuusai" %% "shapeless" % "2.3.3",
"org.typelevel" %% "cats-core" % "2.1.1",
"org.typelevel" %% "cats-effect" % "2.1.3",
"org.typelevel" %% "cats-collections-core" % "0.9.0",
"io.chrisdavenport" %% "fuuid" % "0.4.0",
"io.higherkindness" %% "droste-core" % "0.8.0",
"org.scalameta" %% "munit" % "0.7.9" % Test,

View file

@ -9,11 +9,11 @@ import scodec.stream.{StreamDecoder, StreamEncoder}
object Main extends IOApp {
override def run(args: List[String]): IO[ExitCode] = {
(Stream.resource(Blocker[IO]) >>= write[IO]).compile.drain.as(ExitCode.Success)
(Stream.resource(Blocker[IO]) >>= read[IO]).compile.drain.as(ExitCode.Success)
}
def read[F[_] : RaiseThrowable : Sync : ContextShift](blocker: Blocker): Stream[F, Unit] = {
val input = Paths.get("""C:\Users\aprim\Documents\FancadeLevels\MetaWires""")
val input = Paths.get("""C:\Users\aprim\Documents\FancadeLevels\TaglessTest""")
io.file.readAll[F](input, blocker, 1024)
.through(StreamDecoder.once(Codecs.encCartridge).toPipeByte)
.evalMap(c => Sync[F].delay(println(c)))

View file

@ -1,56 +0,0 @@
package tf.bug.fancadetagless
import cats._
import cats.implicits._
import higherkindness.droste._
import polymorphic._
import tf.bug.fancadegraph.PinDefinition
import tf.bug.fancadegraph.Level
import tf.bug.fancadegraph.Block
import tf.bug.fancadegraph.Template
import tf.bug.fancadescodec.Position
sealed trait Fancade[A] {
val template: Exists[Template]
val pins: Vector[PinDefinition]
}
object Fancade {
implicit val fancadeFunctor: Functor[Fancade] = new Functor[Fancade] {
override def map[A, B](fa: Fancade[A])(f: A => B): Fancade[B] =
fa match {
case Capture(template, pins) =>
Capture(template, pins)
case Use(children, template, inputs, pins) =>
Use(children.map(f), template, inputs, pins)
}
}
case class Capture[A](template: Exists[Template], pins: Vector[PinDefinition]) extends Fancade[A]
case class Use[A](children: Vector[A], template: Exists[Template], inputs: Vector[PinDefinition], pins: Vector[PinDefinition]) extends Fancade[A]
def flatten: Algebra[Fancade, PointerChain[Fancade]] = Algebra {
case Capture(template, pins) =>
PointerChain.single(Capture(template, pins))
case Use(children, template, inputs, pins) =>
???
}
val stack: FancadeF => PointerChain[Fancade] = scheme.cata(flatten)
def render(f: FancadeF): Level = {
val pointerChain = stack(f)
val blocks = pointerChain.map {
case (ind, fc) =>
Block(
Position(0, ind, 0),
fc.template
)
}
Level(
blocks.toSet,
???
)
}
}

View file

@ -0,0 +1,85 @@
package tf.bug.fancadetagless
import cats._
import cats.implicits._
import higherkindness.droste.data._
import polymorphic._
import scalax.collection.Graph
import scalax.collection.GraphEdge.DiHyperEdge
import tf.bug.fancadegraph.Block
import tf.bug.fancadegraph.Level
import tf.bug.fancadegraph.Pin
import tf.bug.fancadegraph.PinDefinition
import tf.bug.fancadegraph.Template
import tf.bug.fancadescodec.Position
sealed trait FancadeF[A] {
val template: Exists[Template]
val pins: Vector[PinDefinition]
}
object FancadeF {
implicit val fancadeTraverse: Traverse[FancadeF] = new Traverse[FancadeF] {
override def traverse[G[_]: Applicative, A, B](fa: FancadeF[A])(f: A => G[B]): G[FancadeF[B]] =
fa match {
case Capture(t, p) => Capture[B](t, p).pure[G].widen
case Use(c, t, i, o) =>
c.traverse(f).map { newC => Use(newC, t, i, o) }
}
override def foldLeft[A, B](fa: FancadeF[A], b: B)(f: (B, A) => B): B =
fa match {
case Capture(_, _) => b
case Use(c, _, _, _) => c.foldLeft(b)(f)
}
override def foldRight[A, B](fa: FancadeF[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
fa match {
case Capture(_, _) => lb
case Use(c, _, _, _) => Traverse[Vector].foldRight(c, lb)(f)
}
}
case class Capture[A](template: Exists[Template], pins: Vector[PinDefinition]) extends FancadeF[A]
case class Use[A](children: Vector[A], template: Exists[Template], inputs: Vector[PinDefinition], pins: Vector[PinDefinition]) extends FancadeF[A]
def render(f: Fix[FancadeF]): Level = {
val pc = PointerChain.deduplicate[Id, FancadeF](f)
val pcvi = pc.vertices.zipWithIndex
val blocks: Set[Block] = pcvi.map {
case (block, y) =>
Block(
Position(0, y, 0),
block.template
)
}.toSet
val wires: Graph[Pin, DiHyperEdge] =
pcvi.foldLeft(Graph.empty[Pin, DiHyperEdge]) {
case (graph, (block, y)) =>
block match {
case Capture(_, _) => graph
case Use(children, template, inputs, _) =>
val thisBlock = Block(
Position(0, y, 0),
template
)
val thesePins = inputs.map(Pin(thisBlock, _))
val childrenPins: Vector[Pin] = children.flatMap { child =>
val childInst = pc.vertices(child)
val childBlock = Block(
Position(0, child, 0),
childInst.template
)
childInst.pins.map(Pin(childBlock, _))
}
val newEdges: Vector[DiHyperEdge[Pin]] = childrenPins.zip(thesePins).map {
case (from, to) => DiHyperEdge(from, to)
}
graph ++ newEdges
}
}
Level(blocks, wires)
}
}

View file

@ -55,6 +55,8 @@ trait Fanscript[F[_]] {
def onBoxArt(onBoxArt: F[Unit]): F[Unit]
def onTouch(onTouch: F[Fanscript.Touch] => F[Unit]): F[Unit]
def addNumbers(a: F[Float], b: F[Float]): F[Float]
def screenSizeWidth(screenSize: F[ScreenSize]): F[Float]
def screenSizeHeight(screenSize: F[ScreenSize]): F[Float]
@ -79,30 +81,30 @@ object Fanscript {
def run[F[_]](implicit interp: Fanscript[F]): F[R]
}
implicit object fancade extends Fanscript[FancadeW] {
implicit object fancade extends Fanscript[Fancade] {
override def lift(value: Float): FancadeW[Float] =
Fix(Fancade.Capture(
override def lift(value: Float): Fancade[Float] =
Fix(FancadeF.Capture(
Exists(Template(
BlockDefinition.NumberValue,
value
)),
Vector(BlockDefinition.NumberValue.output)
))
override def lift(value: Vector3): FancadeW[Vector3] = ???
override def lift(value: Rotation): FancadeW[Rotation] = ???
override def lift(value: Boolean): FancadeW[Boolean] = ???
override def lift(value: Vector3): Fancade[Vector3] = ???
override def lift(value: Rotation): Fancade[Rotation] = ???
override def lift(value: Boolean): Fancade[Boolean] = ???
override def win(stop: Boolean): FancadeW[Unit] = ???
override def lose(stop: Boolean): FancadeW[Unit] = ???
override def setScore(score: FancadeW[Float]): FancadeW[Unit] = ???
override def setCamera(position: FancadeW[Vector3], rotation: FancadeW[Rotation], distance: FancadeW[Float]): FancadeW[Unit] = ???
override def setLight(position: FancadeW[Vector3], rotation: FancadeW[Rotation]): FancadeW[Unit] = ???
override def screenSize: FancadeW[ScreenSize] = ???
override def accelerometer: FancadeW[Vector3] = ???
override def win(stop: Boolean): Fancade[Unit] = ???
override def lose(stop: Boolean): Fancade[Unit] = ???
override def setScore(score: Fancade[Float]): Fancade[Unit] = ???
override def setCamera(position: Fancade[Vector3], rotation: Fancade[Rotation], distance: Fancade[Float]): Fancade[Unit] = ???
override def setLight(position: Fancade[Vector3], rotation: Fancade[Rotation]): Fancade[Unit] = ???
override def screenSize: Fancade[ScreenSize] = ???
override def accelerometer: Fancade[Vector3] = ???
override def getPosition(obj: FancadeW[Obj]): FancadeW[Position] =
Fix(Fancade.Use(
override def getPosition(obj: Fancade[Obj]): Fancade[Position] =
Fix(FancadeF.Use(
Vector(obj),
Exists(Template(
BlockDefinition.GetPosition,
@ -111,53 +113,64 @@ object Fanscript {
Vector(BlockDefinition.GetPosition.obj),
Vector(BlockDefinition.GetPosition.position)
))
override def setPosition(obj: FancadeW[Obj], position: FancadeW[Vector3], rotation: FancadeW[Rotation]): FancadeW[Unit] = ???
override def raycast(from: FancadeW[Vector3], to: FancadeW[Vector3]): FancadeW[Raycast] = ???
override def getSize(obj: FancadeW[Obj]): FancadeW[Size] = ???
override def setVisible(obj: FancadeW[Obj], visible: FancadeW[Boolean]): FancadeW[Unit] = ???
override def createObj(original: FancadeW[Obj]): FancadeW[Obj] = ???
override def destroyObj(obj: FancadeW[Obj]): FancadeW[Obj] = ???
override def setPosition(obj: Fancade[Obj], position: Fancade[Vector3], rotation: Fancade[Rotation]): Fancade[Unit] = ???
override def raycast(from: Fancade[Vector3], to: Fancade[Vector3]): Fancade[Raycast] = ???
override def getSize(obj: Fancade[Obj]): Fancade[Size] = ???
override def setVisible(obj: Fancade[Obj], visible: Fancade[Boolean]): Fancade[Unit] = ???
override def createObj(original: Fancade[Obj]): Fancade[Obj] = ???
override def destroyObj(obj: Fancade[Obj]): Fancade[Obj] = ???
override def playSound(loop: Boolean, sound: Sample)(volume: FancadeW[Float], pitch: FancadeW[Float]): FancadeW[Float] = ???
override def stopSound(channel: FancadeW[Float]): FancadeW[Unit] = ???
override def volumePitch(channel: FancadeW[Float], volume: FancadeW[Float], pitch: FancadeW[Float]): FancadeW[Unit] = ???
override def playSound(loop: Boolean, sound: Sample)(volume: Fancade[Float], pitch: Fancade[Float]): Fancade[Float] = ???
override def stopSound(channel: Fancade[Float]): Fancade[Unit] = ???
override def volumePitch(channel: Fancade[Float], volume: Fancade[Float], pitch: Fancade[Float]): Fancade[Unit] = ???
override def addForce(obj: FancadeW[Obj], force: FancadeW[Vector3], applyAt: FancadeW[Vector3], torque: FancadeW[Vector3]): FancadeW[Unit] = ???
override def getVelocity(obj: FancadeW[Obj]): FancadeW[Velocity] = ???
override def setVelocity(obj: FancadeW[Obj], velocity: FancadeW[Vector3], spin: FancadeW[Vector3]): FancadeW[Unit] = ???
override def setLocked(obj: FancadeW[Obj], position: FancadeW[Vector3], rotation: FancadeW[Vector3]): FancadeW[Unit] = ???
override def setMass(obj: FancadeW[Obj], mass: FancadeW[Float]): FancadeW[Unit] = ???
override def setFriction(obj: FancadeW[Obj], friction: FancadeW[Float]): FancadeW[Unit] = ???
override def setBounciness(obj: FancadeW[Obj], bounciness: FancadeW[Float]): FancadeW[Unit] = ???
override def setGravity(gravity: FancadeW[Vector3]): FancadeW[Unit] = ???
override def addConstraint(base: FancadeW[Obj], part: FancadeW[Obj], pivot: FancadeW[Vector3]): FancadeW[Constraint] = ???
override def linearLimits(constraint: FancadeW[Constraint], lower: FancadeW[Vector3], upper: FancadeW[Vector3]): FancadeW[Unit] = ???
override def angularLimits(constraint: FancadeW[Constraint], lower: FancadeW[Vector3], upper: FancadeW[Vector3]): FancadeW[Unit] = ???
override def linearSpring(constraint: FancadeW[Constraint], stiffness: FancadeW[Vector3], damping: FancadeW[Vector3]): FancadeW[Unit] = ???
override def angularSpring(constraint: FancadeW[Constraint], stiffness: FancadeW[Vector3], damping: FancadeW[Vector3]): FancadeW[Unit] = ???
override def linearMotor(constraint: FancadeW[Constraint], speed: FancadeW[Vector3], force: FancadeW[Vector3]): FancadeW[Unit] = ???
override def angularMotor(constraint: FancadeW[Constraint], speed: FancadeW[Vector3], force: FancadeW[Vector3]): FancadeW[Unit] = ???
override def addForce(obj: Fancade[Obj], force: Fancade[Vector3], applyAt: Fancade[Vector3], torque: Fancade[Vector3]): Fancade[Unit] = ???
override def getVelocity(obj: Fancade[Obj]): Fancade[Velocity] = ???
override def setVelocity(obj: Fancade[Obj], velocity: Fancade[Vector3], spin: Fancade[Vector3]): Fancade[Unit] = ???
override def setLocked(obj: Fancade[Obj], position: Fancade[Vector3], rotation: Fancade[Vector3]): Fancade[Unit] = ???
override def setMass(obj: Fancade[Obj], mass: Fancade[Float]): Fancade[Unit] = ???
override def setFriction(obj: Fancade[Obj], friction: Fancade[Float]): Fancade[Unit] = ???
override def setBounciness(obj: Fancade[Obj], bounciness: Fancade[Float]): Fancade[Unit] = ???
override def setGravity(gravity: Fancade[Vector3]): Fancade[Unit] = ???
override def addConstraint(base: Fancade[Obj], part: Fancade[Obj], pivot: Fancade[Vector3]): Fancade[Constraint] = ???
override def linearLimits(constraint: Fancade[Constraint], lower: Fancade[Vector3], upper: Fancade[Vector3]): Fancade[Unit] = ???
override def angularLimits(constraint: Fancade[Constraint], lower: Fancade[Vector3], upper: Fancade[Vector3]): Fancade[Unit] = ???
override def linearSpring(constraint: Fancade[Constraint], stiffness: Fancade[Vector3], damping: Fancade[Vector3]): Fancade[Unit] = ???
override def angularSpring(constraint: Fancade[Constraint], stiffness: Fancade[Vector3], damping: Fancade[Vector3]): Fancade[Unit] = ???
override def linearMotor(constraint: Fancade[Constraint], speed: Fancade[Vector3], force: Fancade[Vector3]): Fancade[Unit] = ???
override def angularMotor(constraint: Fancade[Constraint], speed: Fancade[Vector3], force: Fancade[Vector3]): Fancade[Unit] = ???
override def ifElse(cond: FancadeW[Boolean])(ifTrue: FancadeW[Unit])(ifFalse: FancadeW[Unit]): FancadeW[Unit] = ???
override def onPlay(onPlay: FancadeW[Unit]): FancadeW[Unit] = ???
override def onBoxArt(onBoxArt: FancadeW[Unit]): FancadeW[Unit] = ???
override def onTouch(onTouch: FancadeW[Touch] => FancadeW[Unit]): FancadeW[Unit] = ???
override def ifElse(cond: Fancade[Boolean])(ifTrue: Fancade[Unit])(ifFalse: Fancade[Unit]): Fancade[Unit] = ???
override def onPlay(onPlay: Fancade[Unit]): Fancade[Unit] = ???
override def onBoxArt(onBoxArt: Fancade[Unit]): Fancade[Unit] = ???
override def onTouch(onTouch: Fancade[Touch] => Fancade[Unit]): Fancade[Unit] = ???
override def addNumbers(a: Fancade[Float], b: Fancade[Float]): Fancade[Float] =
Fix(FancadeF.Use(
Vector(a, b),
Exists(Template(
BlockDefinition.AddNumbers,
()
)),
Vector(BlockDefinition.AddNumbers.input1, BlockDefinition.AddNumbers.input2),
Vector(BlockDefinition.AddNumbers.output)
))
override def screenSizeWidth(screenSize: FancadeW[ScreenSize]): FancadeW[Float] = ???
override def screenSizeHeight(screenSize: FancadeW[ScreenSize]): FancadeW[Float] = ???
override def screenSizeWidth(screenSize: Fancade[ScreenSize]): Fancade[Float] = ???
override def screenSizeHeight(screenSize: Fancade[ScreenSize]): Fancade[Float] = ???
override def positionPosition(position: FancadeW[Position]): FancadeW[Vector3] = ???
override def positionRotation(position: FancadeW[Position]): FancadeW[Rotation] = ???
override def positionPosition(position: Fancade[Position]): Fancade[Vector3] = ???
override def positionRotation(position: Fancade[Position]): Fancade[Rotation] = ???
override def raycastHit(raycast: FancadeW[Raycast]): FancadeW[Boolean] = ???
override def raycastPosition(raycast: FancadeW[Raycast]): FancadeW[Vector3] = ???
override def raycastObj(raycast: FancadeW[Raycast]): FancadeW[Obj] = ???
override def raycastHit(raycast: Fancade[Raycast]): Fancade[Boolean] = ???
override def raycastPosition(raycast: Fancade[Raycast]): Fancade[Vector3] = ???
override def raycastObj(raycast: Fancade[Raycast]): Fancade[Obj] = ???
override def sizeMin(size: FancadeW[Size]): FancadeW[Vector3] = ???
override def sizeMax(size: FancadeW[Size]): FancadeW[Vector3] = ???
override def sizeMin(size: Fancade[Size]): Fancade[Vector3] = ???
override def sizeMax(size: Fancade[Size]): Fancade[Vector3] = ???
override def velocityVelocity(velocity: FancadeW[Velocity]): FancadeW[Vector3] = ???
override def velocitySpin(velocity: FancadeW[Velocity]): FancadeW[Vector3] = ???
override def velocityVelocity(velocity: Fancade[Velocity]): Fancade[Vector3] = ???
override def velocitySpin(velocity: Fancade[Velocity]): Fancade[Vector3] = ???
}

View file

@ -0,0 +1,62 @@
package tf.bug.fancadetagless
import cats.effect.{Blocker, ContextShift, ExitCode, IO, IOApp, Sync}
import fs2._
import higherkindness.droste.data._
import java.nio.file.{Paths, StandardOpenOption}
import scodec.stream.StreamEncoder
import tf.bug.fancadegraph.Level
import tf.bug.fancadescodec.Cartridge
import tf.bug.fancadescodec.Codecs
object Main extends IOApp {
override def run(args: List[String]): IO[ExitCode] =
program[IO].compile.drain.as(ExitCode.Success)
def program[F[_] : Sync : ContextShift]: Stream[F, Unit] = {
val program = new Fanscript.Program[Float] {
override def run[G[_]](implicit interp: Fanscript[G]): G[Float] = {
val one = interp.lift(1.0f)
val two = interp.lift(2.0f)
val three = interp.lift(3.0f)
interp.addNumbers(
interp.addNumbers(
one,
interp.addNumbers(
two,
three
)
),
interp.addNumbers(
two,
three
)
)
}
}
val fancade: Fix[FancadeF] = program.run[Fancade]
val level: Level = FancadeF.render(fancade)
val cart: Cartridge = Cartridge(
"Test",
"rayc",
"Test of tagless",
Vector(
Level.encode(level)
)
)
val output = Paths.get("""C:\Users\aprim\Documents\FancadeLevels\TaglessTest""")
(for {
blocker <- Stream.resource(Blocker[F])
result <- Stream.emit[F, Cartridge](cart)
.through(StreamEncoder.once(Codecs.encCartridge).toPipeByte[F])
.through(io.file.writeAll(output, blocker, Seq(StandardOpenOption.TRUNCATE_EXISTING)))
} yield result)
}
}

View file

@ -2,21 +2,51 @@ package tf.bug.fancadetagless
import cats._
import cats.implicits._
import cats.data.State
import higherkindness.droste._
import higherkindness.droste.data._
import higherkindness.droste.scheme
case class PointerChain[F[_]](internal: Map[Int, F[Int]])(implicit functor: Functor[F]) {
case class PointerChain[T[_], E[_]](vertices: Vector[E[Int]], roots: T[Int])
def ++(other: PointerChain[F]): PointerChain[F] = {
???
}
def map[B](f: ((Int, F[Int])) => B): Vector[B] = internal.map(f).toVector
}
case class PointerState[F[_]](seen: Map[F[Int], Int], vertices: Vector[F[Int]], lastIndex: Int)
object PointerChain {
def empty[F[_] : Functor]: PointerChain[F] = PointerChain(Map.empty)
def deduplicate[R[_], F[_]](input: R[Fix[F]])(
implicit rt: Traverse[R],
rf: Traverse[F]
): PointerChain[R, F] = {
val addAll: State[PointerState[F], R[Int]] = input.traverse(scheme.cataM(findOrAddNode[F]))
val result: (PointerState[F], R[Int]) = addAll.run(PointerState.empty[F]).value
val graphed: (Vector[F[Int]], R[Int]) = result.leftMap(_.vertices.reverse)
val chain: PointerChain[R, F] = PointerChain(graphed._1, graphed._2)
chain
}
def single[F[_] : Functor](value: F[Nothing]): PointerChain[F] = PointerChain(Map(0 -> value.widen))
def findOrAddNode[F[_]]: AlgebraM[State[PointerState[F], *], F, Int] = AlgebraM { tree =>
for {
gs <- State.get[PointerState[F]]
seen = gs.seen
result <- seen.get(tree) match {
case Some(index) => State.pure[PointerState[F], Int](index)
case None =>
val index = gs.lastIndex
for {
_ <- State.set(PointerState(
seen + (tree -> index),
tree +: gs.vertices,
index + 1
))
} yield index
}
} yield result
}
}
object PointerState {
def empty[F[_]]: PointerState[F] = PointerState(Map(), Vector(), 0)
}

View file

@ -4,7 +4,6 @@ import higherkindness.droste.data.Fix
package object fancadetagless {
type FancadeF = Fix[Fancade]
type FancadeW[A] = FancadeF
type Fancade[A] = Fix[FancadeF]
}