Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Instant Insanity in Scala
object InstantInsanity extends App {
type Cube = Seq[Char]
val cubes: Seq[Cube] = Seq("BGWGBR", "WGBWRR", "GWRBRR", "BRGGWW").map(_.toSeq)
// Rotate a cube 90 degrees over its Z-axis, leaving up and down in place.
def rot: Cube => Cube = { case Seq(u, f, r, b, l, d) => Seq(u, r, b, l, f, d) }
// Twist a cube around the axis running from the upper-front-right
// corner to the back-left-down corner.
def twist: Cube => Cube = { case Seq(u, f, r, b, l, d) => Seq(f, r, u, l, d, b) }
// Exchange up and down, front and left, back and right.
def flip: Cube => Cube = { case Seq(u, f, r, b, l, d) => Seq(d, l, b, r, f, u) }
// Compute all 24 ways to orient a cube.
def orientations: Cube => Seq[Cube] = { c: Cube =>
for {
c1 <- Seq(c, rot(c), rot(rot(c)), rot(rot(rot(c))))
c2 <- Seq(c1, twist(c1), twist(twist(c1)))
c3 <- Seq(c2, flip(c2))
} yield c3
}
// Compute which faces of a cube are visible when placed in a pile.
def visible: Cube => Seq[Char] = { case Seq(u, f, r, b, l, d) => Seq(f, r, b, l) }
// Two cubes are compatible if they have different colours on every
// visible face.
def compatible: (Cube, Cube) => Boolean = {
case (c1, c2) => visible(c1).zip(visible(c2)).forall { case (v1, v2) => v1 != v2 }
}
// Determine whether a cube can be added to pile of cubes, without
// invalidating the solution.
def allowed: (Cube, Seq[Cube]) => Boolean = {
case (c, cs) => cs.forall(compatible(_, c))
}
// Return a list of all ways of orienting each cube such that no side of
// the pile has two faces the same.
def solutions: Seq[Cube] => Seq[Seq[Cube]] = {
case Nil => Seq(Nil)
case c :: cs => for {
_cs <- solutions(cs)
_c <- orientations(c)
if allowed(_c, _cs)
} yield _c +: _cs
}
solutions(cubes)
.map(_.map(_.mkString("")))
.map(ss => "[" + ss.mkString(", ") + "]")
.foreach(println)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment