Problem:
Problem E: Driving an Icosahedral Rover

After decades of fruitless efforts, one of the expedition teams of ITO (Intersolar Tourism Organization) finally found a planet that would surely provide one of the best tourist attractions
within a ten light-year radius from our solar system. The most attractive feature of the planet,
besides its comfortable gravity and calm weather, is the area called Mare Triangularis. Despite
the name, the area is not covered with water but is a great plane. Its unique feature is that it is
divided into equilateral triangular sections of the same size, called trigons. The trigons provide
a unique impressive landscape, a must for tourism. It is no wonder the board of ITO decided
to invest a vast amount on the planet.

Despite the expected secrecy of the staff, the Society of Astrogeology caught this information
in no time, as always. They immediately sent their president's letter to the Institute of Science
and Education of the Commonwealth Galactica claiming that authoritative academic inspections
were to be completed before any commercial exploitation might damage the nature.

Fortunately, astrogeologists do not plan to practice all the possible inspections on all of the
trigons; there are far too many of them. Inspections are planned only on some characteristic
trigons and, for each of them, in one of twenty different scientific aspects.

To accelerate building this new tourist resort, ITO's construction machinery team has already succeeded in putting their brand-new
invention in practical use. It is a rover vehicle of the shape of an icosahedron, a regular polyhedron with twenty faces of equilateral triangles.
The machine is customized
so that each of the twenty faces exactly fits each of the trigons.
Controlling the high-tech gyromotor installed inside its body, the rover can roll onto one of the three trigons neighboring the one its bottom is
on.

Figure E.1: The Rover on Mare Triangularis

Each of the twenty faces has its own function. The set of equipments installed on the bottom
face touching the ground can be applied to the trigon it is on. Of course, the rover was meant to accelerate construction of the luxury hotels to host rich interstellar travelers, but, changing
the installed equipment sets, it can also be used to accelerate academic inspections.

You are the driver of this rover and are asked to move the vehicle onto the trigon specified by
the leader of the scientific commission with the smallest possible steps. What makes your task
more difficult is that the designated face installed with the appropriate set of equipments has to
be the bottom. The direction of the rover does not matter.

Figure E.2:The Coordinate System

Figure E.3: Face Numbering

The trigons of Mare Triangularis are given two-dimensional coordinates as shown in Figure E.2.
Like maps used for the Earth, the x axis is from the west to the east, and the y axis is from the
south to the north. Note that all the trigons with its coordinates (x , y) has neighboring trigons
with coordinates (x - 1 , y) and (x + 1 , y). In addition to these, when x + y is even, it has a
neighbor (x , y + 1); otherwise, that is, when x + y is odd, it has a neighbor (x , y - 1).

Figure E.3 shows a development of the skin of the rover. The top face of the development
makes the exterior. That is, if the numbers on faces of the development were actually marked
on the faces of the rover, they should been readable from its outside. These numbers are used
to identify the faces.

When you start the rover, it is on the trigon (0,0) and the face 0 is touching the ground. The
rover is placed so that rolling towards north onto the trigon (0,1) makes the face numbered 5
to be at the bottom.

As your first step, you can choose one of the three adjacent trigons, namely those with coordinates (-1,0), (1,0),
and (0,1), to visit. The bottom will be the face numbered 4, 1, and 5,
respectively. If you choose to go to (1,0) in the first rolling step, the second step can bring
the rover to either of (0,0), (2,0), or (1,-1). The bottom face will be either of 0, 6, or 2,
correspondingly. The rover may visit any of the trigons twice or more, including the start and the goal trigons, when appropriate.

The theoretical design section of ITO showed that the rover can reach any goal trigon on the
specified bottom face within a finite number of steps.

Input

The input consists of a number of datasets. The number of datasets does not exceed 50.

Each of the datasets has three integers x, y, and n in one line, separated by a space. Here, (x,y)
specifies the coordinates of the trigon to which you have to move the rover, and n specifies the
face that should be at the bottom.

The end of the input is indicated by a line containing three zeros.

Output

The output for each dataset should be a line containing a single integer that gives the minimum
number of steps required to set the rover on the specified trigon with the specified face touching
the ground. No other characters should appear in the output.

You can assume that the maximum number of required steps does not exceed 100. Mare Triangularis
is broad enough so that any of its edges cannot be reached within that number of
steps.

Sample Input

0 0 1
3 5 2
-4 1 3
13 -13 2
-32 15 9
-50 50 0
0 0 0

Output for the Sample Input

6
10
9
30
47
100

Solution in Scala (judge verdict: Memory Limit Exceeded)

import scala.annotation.tailrec

object Main extends App {

  override def main(args: Array[String]): Unit = {
    val answerMap = Solver.solveAll
    import scala.io.{StdIn => in}
    Iterator.continually(in.readLine()).takeWhile(str => !(str startsWith "0 0 0")).map(_.split(" ")).map(arr => new Solver(arr(0).toInt, arr(1).toInt, arr(2).toInt))
      .map(solver => solver.solve(answerMap)).foreach(println)
  }

}


sealed trait Coordination {
  val x: Int
  val y: Int
}

object Coordination {
  def apply(x: Int, y: Int): Coordination =
    if (((x + y) & 1) == 1) OddCoordination(x, y)
    else EvenCoordination(x, y)

}

case class OddCoordination(x: Int, y: Int) extends Coordination {}

case class EvenCoordination(x: Int, y: Int) extends Coordination {}

case class Face(bottom: Int, southOrNorth: Int)

sealed trait CoordinationAndFace {
  val coordination: Coordination
  val face: Face

  def next: Seq[CoordinationAndFace]

  val toKeySring: String = List(coordination.x, coordination.y, face.bottom, face.southOrNorth).mkString(",")
}

object CoordinationAndFace {
  def apply(coordination: Coordination, face: Face): CoordinationAndFace = {
    coordination match {
      case e: EvenCoordination => EvenCoordinationAndFace(e, face)
      case o: OddCoordination => OddCoordinationAndFace(o, face)
    }
  }
}

case class EvenCoordinationAndFace(coordination: EvenCoordination, face: Face) extends CoordinationAndFace {
  override def next = Seq(toNorth, toSouthEast, toSouthWest)

  val now = IcosahedronFaces(face.bottom)(face.southOrNorth)

  def toNorth: CoordinationAndFace = {
    val newCoordination = Coordination(coordination.x, coordination.y + 1)
    val nextFace = IcosahedronFaces(now.top)(now.n)
    val newFace = Face(nextFace.n, nextFace.top)
    CoordinationAndFace(newCoordination, newFace)
  }

  def toSouthWest: CoordinationAndFace = {
    val newCoordination = Coordination(coordination.x - 1, coordination.y)
    val nextFace = IcosahedronFaces(now.right)(now.n)
    val newFace = Face(nextFace.n, nextFace.left)
    CoordinationAndFace(newCoordination, newFace)
  }

  def toSouthEast: CoordinationAndFace = {
    val newCoordination = Coordination(coordination.x + 1, coordination.y)
    val nextFace = IcosahedronFaces(now.left)(now.n)
    val newFace = Face(nextFace.n, nextFace.right)
    CoordinationAndFace(newCoordination, newFace)
  }
}

case class OddCoordinationAndFace(coordination: OddCoordination, face: Face) extends CoordinationAndFace {
  override def next = Seq(toSouth, toNorthEast, toNorthWest)

  val now = IcosahedronFaces(face.bottom)(face.southOrNorth)

  def toSouth: CoordinationAndFace = {
    val newCoordination = Coordination(coordination.x, coordination.y - 1)
    val nextFace = IcosahedronFaces(now.top)(now.n)
    val newFace = Face(nextFace.n, nextFace.top)
    CoordinationAndFace(newCoordination, newFace)
  }

  def toNorthWest: CoordinationAndFace = {
    val newCoordination = Coordination(coordination.x - 1, coordination.y)
    val nextFace = IcosahedronFaces(now.left)(now.n)
    val newFace = Face(nextFace.n, nextFace.right)
    CoordinationAndFace(newCoordination, newFace)
  }

  def toNorthEast: CoordinationAndFace = {
    val newCoordination = Coordination(coordination.x + 1, coordination.y)
    val nextFace = IcosahedronFaces(now.right)(now.n)
    val newFace = Face(nextFace.n, nextFace.left)
    CoordinationAndFace(newCoordination, newFace)
  }

}

sealed case class IcosahedronFace(n: Int, top: Int, left: Int, right: Int) {
  def apply(asTop: Int): IcosahedronFace = {
    asTop match {
      case `top` => this
      case `left` => IcosahedronFace(n, left, right, top)
      case `right` => IcosahedronFace(n, right, top, left)
    }
  }
}

object IcosahedronFaces {
  private val list = List(
    IcosahedronFace(0, 5, 1, 4),
    IcosahedronFace(1, 6, 2, 0),
    IcosahedronFace(2, 7, 3, 1),
    IcosahedronFace(3, 8, 4, 2),
    IcosahedronFace(4, 9, 0, 3),
    IcosahedronFace(5, 0, 10, 11),
    IcosahedronFace(6, 1, 11, 12),
    IcosahedronFace(7, 2, 12, 13),
    IcosahedronFace(8, 3, 13, 14),
    IcosahedronFace(9, 4, 14, 10),
    IcosahedronFace(10, 15, 5, 9),
    IcosahedronFace(11, 16, 6, 5),
    IcosahedronFace(12, 17, 7, 6),
    IcosahedronFace(13, 18, 8, 7),
    IcosahedronFace(14, 19, 9, 8),
    IcosahedronFace(15, 10, 19, 16),
    IcosahedronFace(16, 11, 15, 17),
    IcosahedronFace(17, 12, 16, 18),
    IcosahedronFace(18, 13, 17, 19),
    IcosahedronFace(19, 14, 18, 15)
  )

  def apply(n: Int): IcosahedronFace = n match {
    case n: Int if ((0 to 19).contains(n)) => list(n)
  }
}


class Solver(x: Int, y: Int, n: Int) {

  import Solver._

  def solve(answerMap: Array[Int]): Int = {
    if (-100 > x || -100 > y || x >= 100 || y >= 100) {
      val coordination = Coordination(x, y)
      val missing = coordination match {
        case e: EvenCoordination => 100
        case o: OddCoordination => 99
      }
      return missing
    }

    val coordination = Coordination(x, y)
    val missing = coordination match {
      case e: EvenCoordination => 100
      case o: OddCoordination => 99
    }

    val iface = IcosahedronFaces(n)

    val keys = List(
      CoordinationAndFace(coordination, Face(n, iface.top)),
      CoordinationAndFace(coordination, Face(n, iface.left)),
      CoordinationAndFace(coordination, Face(n, iface.right))
    )

    keys.map(cf => answerMap(coordinationAndFaceToInt(cf))).map(v => if (v == 0) missing else v).min
  }

}

object Solver {

  def solveAll: Array[Int] = {
    val init: CoordinationAndFace = CoordinationAndFace(Coordination(0, 0), Face(0, 5))

    import scala.collection.mutable.{Queue => MQueue}

    def solveInner(map: Array[Int], queue: MQueue[(Int, Int)]): Boolean = {
      val head = queue.dequeue()
      if (head._2 < 98) {
        val candidate = intToCoordinationAndFace(head._1).next
        val nextCost = head._2 + 1
        candidate.filter(cf => map(coordinationAndFaceToInt(cf)) == 0).foreach {
          next =>
            map(coordinationAndFaceToInt(next)) = nextCost
            queue.enqueue((coordinationAndFaceToInt( next), nextCost))
        }
        true
      }
      else false
    }

    val map = Array.ofDim[Int](xWidth * xPosition)
    val queue = MQueue(coordinationAndFaceToInt(init) -> 0)
    while(solveInner(map, queue)){}
    map
  }

  val xOffset = 100
  val yOffset = 100
  val xWidth = 200
  val yWidth = 200
  val bottomWidth = 20
  val southOrNorthWidth = 20

  val southOrNorthPosition = 1
  val bottom = southOrNorthWidth * southOrNorthPosition
  val yPosition = bottomWidth * bottom
  val xPosition = yWidth * yPosition

  def toInt(x: Int, y: Int, buttom: Int, southOrNorth: Int): Int = {
    (x + xOffset) * xPosition + (y + yOffset) * yPosition + (buttom) * bottom + (southOrNorth) * southOrNorthPosition
  }

  def fromInt(int: Int): (Int, Int, Int, Int) = {
    ((int / xPosition) - xOffset, (int / yPosition) % yWidth - yOffset, (int / bottom) % bottomWidth, (int / southOrNorthPosition) % southOrNorthWidth)
  }

  def coordinationAndFaceToInt(coordinationAndFace: CoordinationAndFace): Int = {
    val x = coordinationAndFace.coordination.x
    val y = coordinationAndFace.coordination.y
    val bottom = coordinationAndFace.face.bottom
    val southOrNorth = coordinationAndFace.face.southOrNorth
    toInt(x, y, bottom, southOrNorth)
  }

  def intToCoordinationAndFace(int: Int): CoordinationAndFace = {
    val (x, y, bottom, southOrNorth) = fromInt(int)
    CoordinationAndFace(Coordination(x, y), Face(bottom, southOrNorth))
  }

}