Skip to content

Instantly share code, notes, and snippets.

@JRuumis
Created December 9, 2022 12:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JRuumis/7a998a10bab1a89975972f74d69f7ee5 to your computer and use it in GitHub Desktop.
Save JRuumis/7a998a10bab1a89975972f74d69f7ee5 to your computer and use it in GitHub Desktop.
Day9 Janis
import scala.annotation.tailrec
import scala.math.abs
object Day9RopeBridge extends App {
val ropeStepsInput = scala.io.Source.fromFile("./Sources/Day9RopeBridge.txt").getLines()
case class Move(moveX: Int, moveY: Int)
val moves: List[Move] = ropeStepsInput.map(_.split(" ").toList).map{_ match {
case "U" :: len :: Nil => Move(0, -1*len.toInt)
case "D" :: len :: Nil => Move(0, len.toInt)
case "L" :: len :: Nil => Move(-1*len.toInt, 0)
case "R" :: len :: Nil => Move(len.toInt, 0)
}}.toList
val stepMoves: List[Move] = moves.flatMap {m =>
(0 to abs(m.moveX + m.moveY)-1).map(_ => Move(m.moveX / abs(m.moveX + m.moveY), m.moveY / abs(m.moveX + m.moveY)) )
}
case class Coordinates(x: Int, y: Int) {
def moveCoord(m: Move): Coordinates = Coordinates(x + m.moveX, y + m.moveY)
}
abstract sealed class RopeLink {
val epoch: Int
val currentCoord: Coordinates
}
case class Head(epoch: Int, currentCoord: Coordinates) extends RopeLink {
def go(move: Move): Head = Head(epoch+1, currentCoord.moveCoord(move))
}
case class Tail(epoch: Int, currentCoord: Coordinates) extends RopeLink {
def follow(ropeLinkToFollow: RopeLink): Tail = (ropeLinkToFollow.currentCoord, currentCoord) match {
case (h,t) if (h == t) => Tail(epoch+1, currentCoord) // Head on Tail, don't move
case (h,t) if abs(h.x - t.x) <= 1 && abs(h.y - t.y) <= 1 => Tail(epoch+1, currentCoord) // Next to each other, don't move
case (h,t) if abs(h.y - t.y) > 1 && abs(h.x - t.x) > 1 => { // !!!!!!!!! missed this initially
val move: Move = Move(
h.x - t.x + (if(h.x - t.x >= 0) -1 else 1),
h.y - t.y + (if(h.y - t.y >= 0) -1 else 1)
)
Tail(epoch+1, currentCoord.moveCoord(move))
}
case (h,t) if abs(h.x - t.x) > 1 => {
val move: Move = Move(
h.x - t.x + (if(h.x - t.x >= 0) -1 else 1),
h.y - t.y // if x is big step, y is +/-1 and should align with head
)
Tail(epoch+1, currentCoord.moveCoord(move))
} // move along X axis
case (h,t) if abs(h.y - t.y) > 1 => {
val move: Move = Move(
h.x - t.x, // if y is big step, x is +/-1 and should align with head
h.y - t.y + (if(h.y - t.y >= 0) -1 else 1)
)
Tail(epoch+1, currentCoord.moveCoord(move))
}
}
}
@tailrec
def pullTail(linkToFollow: RopeLink, tail: List[Tail], newTail: List[Tail] = List()): List[Tail] = tail match {
case Nil => newTail.reverse
case curTailLink :: rest => {
val newCurTailLink: Tail = curTailLink.follow(linkToFollow)
pullTail(newCurTailLink, rest, newCurTailLink :: newTail)
}
}
@tailrec
def ropeMover(moves: List[Move], currentHead: Head, currentTailLinks: List[Tail], accuHeads: List[Head], accuTails: List[List[Tail]]): (List[Head], List[List[Tail]]) = moves match {
case Nil => (accuHeads, accuTails)
case currentMove :: rest => {
val newHead: Head = currentHead.go(currentMove)
val newTailLinks: List[Tail] = pullTail(newHead, currentTailLinks)
ropeMover(rest, newHead, newTailLinks, newHead :: accuHeads, newTailLinks :: accuTails)
}
}
val startHead = Head(1, Coordinates(0,0))
def lastTailLinkCoordSize(tails: List[List[Tail]]): Int = tails.map(_.reverse.head.currentCoord).distinct.size
// Part 1
val startTail = List(Tail(1, Coordinates(0,0)))
val (heads, tails) = ropeMover(stepMoves, startHead, startTail, List(startHead), List(startTail))
val tailCoordinateDistinctCount = lastTailLinkCoordSize(tails)
println(s"Tail has visited ${tailCoordinateDistinctCount} coordinates at least once." )
// Part 2
val startTail2 = (1 to 9).toList.map(_ => Tail(1, Coordinates(0,0)))
val (heads2, tails2) = ropeMover(stepMoves, startHead, startTail2, List(startHead), List(startTail2))
val tailCoordinateDistinctCount2 = lastTailLinkCoordSize(tails2)
println(s"Last link of the long tail has visited ${tailCoordinateDistinctCount2} coordinates at least once." )
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment