Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f2e2abd

Browse files
committed
Solve 2024 day 21 part 1
1 parent 1c3f21f commit f2e2abd

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
593A
2+
508A
3+
386A
4+
459A
5+
246A
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package eu.sim642.adventofcode2024
2+
3+
import eu.sim642.adventofcodelib.Grid
4+
import eu.sim642.adventofcodelib.graph.{BFS, GraphSearch, Heuristic, UnitNeighbors}
5+
import eu.sim642.adventofcodelib.pos.Pos
6+
import eu.sim642.adventofcodelib.GridImplicits.*
7+
8+
object Day21 {
9+
10+
type Code = String
11+
12+
private val numericKeypad: Grid[Char] = Vector(
13+
Vector('7', '8', '9'),
14+
Vector('4', '5', '6'),
15+
Vector('1', '2', '3'),
16+
Vector(' ', '0', 'A'),
17+
)
18+
19+
private val directionalKeypad: Grid[Char] = Vector(
20+
Vector(' ', '^', 'A'),
21+
Vector('<', 'v', '>'),
22+
)
23+
24+
private val directionalOffsets = Map(
25+
'^' -> Pos(0, -1),
26+
'>' -> Pos(1, 0),
27+
'v' -> Pos(0, 1),
28+
'<' -> Pos(-1, 0),
29+
)
30+
31+
case class State(directionalPoss: List[Pos], numericPos: Pos, input: Code) {
32+
33+
def numericPress(button: Char): Option[State] = button match {
34+
case 'A' =>
35+
val newButton = numericKeypad(numericPos)
36+
Some(copy(input = input + newButton))
37+
case _ =>
38+
val offset = directionalOffsets(button)
39+
val newNumericPos = numericPos + offset
40+
if (numericKeypad.containsPos(newNumericPos) && numericKeypad(newNumericPos) != ' ')
41+
Some(copy(numericPos = newNumericPos))
42+
else
43+
None // out of keypad
44+
}
45+
46+
def directionalPress(button: Char): Option[State] = directionalPoss match {
47+
case Nil => numericPress(button)
48+
case directionalPos :: newDirectionalPoss =>
49+
button match {
50+
case 'A' =>
51+
val newButton = directionalKeypad(directionalPos)
52+
copy(directionalPoss = newDirectionalPoss).directionalPress(newButton).map(newState =>
53+
newState.copy(directionalPoss = directionalPos :: newState.directionalPoss)
54+
)
55+
case _ =>
56+
val offset = directionalOffsets(button)
57+
val newDirectionalPos = directionalPos + offset
58+
if (directionalKeypad.containsPos(newDirectionalPos) && directionalKeypad(newDirectionalPos) != ' ')
59+
Some(copy(directionalPoss = newDirectionalPos :: newDirectionalPoss))
60+
else
61+
None // out of keypad
62+
}
63+
}
64+
65+
def userPress(button: Char): Option[State] = directionalPress(button)
66+
}
67+
68+
def shortestSequenceLength(code: Code): Int = {
69+
70+
val graphSearch = new GraphSearch[State] with UnitNeighbors[State] {
71+
override val startNode: State = State(List.fill(2)(directionalKeypad.posOf('A')), numericKeypad.posOf('A'), "")
72+
73+
override def unitNeighbors(state: State): IterableOnce[State] = "<v>^A".iterator.flatten(state.userPress).filter(s => code.startsWith(s.input))
74+
75+
override def isTargetNode(state: State, dist: Int): Boolean = state.input == code
76+
}
77+
78+
BFS.search(graphSearch).target.get._2
79+
}
80+
81+
def codeComplexity(code: Code): Int = {
82+
val numericPart = code.dropRight(1).toInt
83+
shortestSequenceLength(code) * numericPart
84+
}
85+
86+
def sumCodeComplexity(codes: Seq[Code]): Int = codes.map(codeComplexity).sum
87+
88+
def parseCodes(input: String): Seq[Code] = input.linesIterator.toSeq
89+
90+
lazy val input: String = scala.io.Source.fromInputStream(getClass.getResourceAsStream("day21.txt")).mkString.trim
91+
92+
def main(args: Array[String]): Unit = {
93+
println(sumCodeComplexity(parseCodes(input)))
94+
}
95+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package eu.sim642.adventofcode2024
2+
3+
import Day21._
4+
import org.scalatest.funsuite.AnyFunSuite
5+
6+
class Day21Test extends AnyFunSuite {
7+
8+
val exampleInput =
9+
"""029A
10+
|980A
11+
|179A
12+
|456A
13+
|379A""".stripMargin
14+
15+
test("Part 1 examples") {
16+
assert(sumCodeComplexity(parseCodes(exampleInput)) == 126384)
17+
}
18+
19+
test("Part 1 input") {
20+
assert(sumCodeComplexity(parseCodes(input)) == 157892)
21+
}
22+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /