Skip to content

Instantly share code, notes, and snippets.

@ShahOdin
Last active August 30, 2020 17:40
Show Gist options
  • Save ShahOdin/0ea19868e8fa77aa07bb244d04aa1f5d to your computer and use it in GitHub Desktop.
Save ShahOdin/0ea19868e8fa77aa07bb244d04aa1f5d to your computer and use it in GitHub Desktop.
snail kata
import cats.data.NonEmptyList
object Snail {
case class Coordinate(i: Int, j: Int)
case class Navigation(visitedSofar: NonEmptyList[Coordinate])
sealed trait Direction
object Direction {
case object Up extends Direction
case object Right extends Direction
case object Down extends Direction
case object Left extends Direction
def rightHandedRotate(currentDir: Direction): Direction = currentDir match {
case Direction.Right =>
Direction.Down
case Direction.Left =>
Direction.Up
case Direction.Up =>
Direction.Right
case Direction.Down =>
Direction.Left
}
}
def coordinateAhead(coordinate: Coordinate, currentDirection: Direction): Coordinate = {
val iValue = coordinate.i
val jValue = coordinate.j
currentDirection match {
case Direction.Up =>
coordinate.copy(j = jValue - 1)
case Direction.Right =>
coordinate.copy(i = iValue + 1)
case Direction.Down =>
coordinate.copy(j = jValue + 1)
case Direction.Left =>
coordinate.copy(i = iValue - 1)
}
}
def maybeCoordinateAhead(navigation: Navigation, currentDirection: Direction, squareSide: Int): Option[Coordinate] = {
val ahead = coordinateAhead(navigation.visitedSofar.head, currentDirection)
Option.when(
!navigation.visitedSofar.toList.contains(ahead) &&
ahead.i <= squareSide &&
ahead.j <= squareSide &&
0 < ahead.i &&
0 < ahead.j
)(ahead)
}
def getNumberAt(xs: List[List[Int]])(coordinate: Coordinate): Int = xs(coordinate.j - 1)(coordinate.i - 1)
def snail(xs: List[List[Int]]): List[Int] = {
def update(currentDirection: Direction, navigation: Navigation): Navigation =
if (navigation.visitedSofar.size == xs.size * xs.size)
navigation
else
maybeCoordinateAhead(navigation, currentDirection, xs.size) match {
case Some(nextCoordinate) =>
update(currentDirection, Navigation(nextCoordinate :: navigation.visitedSofar))
case None =>
update(Direction.rightHandedRotate(currentDirection), navigation)
}
xs match {
case _ if xs.flatten.isEmpty =>
Nil
case _ =>
val start = Coordinate(1, 1)
update(Direction.Right, Navigation(NonEmptyList.one(start)))
.visitedSofar
.reverse
.map(getNumberAt(xs))
.toList
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment