Skip to content

Commit eedd1fe

Browse files
committed
Solve 2024 day 20 part 2
1 parent 44acb72 commit eedd1fe

File tree

2 files changed

+108
-28
lines changed

2 files changed

+108
-28
lines changed

src/main/scala/eu/sim642/adventofcode2024/Day20.scala

+84-26
Original file line numberDiff line numberDiff line change
@@ -25,39 +25,97 @@ object Day20 {
2525
}
2626
}
2727

28-
def findCheats(grid: Grid[Char]): Set[Cheat] = {
29-
val forwardSearch = gridGraphSearch(grid, 'S', 'E')
30-
val forwardResult = BFS.search(forwardSearch)
31-
val backwardSearch = gridGraphSearch(grid, 'E', 'S')
32-
val backwardResult = BFS.search(backwardSearch)
33-
34-
val noCheatDistance = forwardResult.target.get._2
35-
36-
(for {
37-
(row, y) <- grid.view.zipWithIndex
38-
(cell, x) <- row.view.zipWithIndex
39-
if cell == '#'
40-
pos = Pos(x, y)
41-
startOffset <- Pos.axisOffsets
42-
start = pos + startOffset
43-
if grid.containsPos(start) && grid(start) != '#'
44-
endOffset <- Pos.axisOffsets
45-
if startOffset != endOffset
46-
end = pos + endOffset
47-
if grid.containsPos(end) && grid(end) != '#'
48-
cheatDistance = forwardResult.distances(start) + 2 + backwardResult.distances(end)
49-
//if cheatDistance <= noCheatDistance
50-
save = noCheatDistance - cheatDistance
51-
} yield Cheat(start, end, save)).toSet
28+
trait Part {
29+
def findCheats(grid: Grid[Char]): Set[Cheat]
30+
31+
def countGoodCheats(grid: Grid[Char]): Int = findCheats(grid).count(_.save >= 100)
32+
}
33+
34+
object Part1 extends Part {
35+
override def findCheats(grid: Grid[Char]): Set[Cheat] = {
36+
val forwardSearch = gridGraphSearch(grid, 'S', 'E')
37+
val forwardResult = BFS.search(forwardSearch)
38+
val backwardSearch = gridGraphSearch(grid, 'E', 'S')
39+
val backwardResult = BFS.search(backwardSearch)
40+
41+
val noCheatDistance = forwardResult.target.get._2
42+
43+
(for {
44+
(row, y) <- grid.view.zipWithIndex
45+
(cell, x) <- row.view.zipWithIndex
46+
if cell == '#'
47+
pos = Pos(x, y)
48+
startOffset <- Pos.axisOffsets
49+
start = pos + startOffset
50+
if grid.containsPos(start) && grid(start) != '#'
51+
endOffset <- Pos.axisOffsets
52+
if startOffset != endOffset
53+
end = pos + endOffset
54+
if grid.containsPos(end) && grid(end) != '#'
55+
cheatDistance = forwardResult.distances(start) + 2 + backwardResult.distances(end)
56+
//if cheatDistance <= noCheatDistance
57+
save = noCheatDistance - cheatDistance
58+
} yield Cheat(start, end, save)).toSet
59+
}
5260
}
5361

54-
def countGoodCheats(grid: Grid[Char]): Int = findCheats(grid).count(_.save >= 100)
62+
object Part2 extends Part {
63+
override def findCheats(grid: Grid[Char]): Set[Cheat] = {
64+
val forwardSearch = gridGraphSearch(grid, 'S', 'E')
65+
val forwardResult = BFS.search(forwardSearch)
66+
val backwardSearch = gridGraphSearch(grid, 'E', 'S')
67+
val backwardResult = BFS.search(backwardSearch)
68+
69+
val noCheatDistance = forwardResult.target.get._2
70+
71+
// TODO: optimize
72+
73+
/*(for {
74+
(row, y) <- grid.view.zipWithIndex
75+
(cell, x) <- row.view.zipWithIndex
76+
if cell == '.'
77+
start = Pos(x, y)
78+
startOffset <- Pos.axisOffsets
79+
startCheat <- 0 to 20
80+
pos = start + startCheat *: startOffset
81+
if grid.containsPos(pos)
82+
endOffset <- Pos.axisOffsets
83+
if startOffset != endOffset && startOffset != -endOffset
84+
endCheat <- 0 to (20 - startCheat)
85+
end = pos + endCheat *: endOffset
86+
if grid.containsPos(end) && grid(end) != '#'
87+
cheatDistance = forwardResult.distances(start) + (startCheat + endCheat) + backwardResult.distances(end)
88+
//if cheatDistance <= noCheatDistance
89+
save = noCheatDistance - cheatDistance
90+
} yield Cheat(start, end, save)).toSet*/
91+
92+
(for {
93+
(row, y) <- grid.view.zipWithIndex
94+
(cell, x) <- row.view.zipWithIndex
95+
if cell != '#'
96+
start = Pos(x, y)
97+
xOffset <- -20 to 20
98+
pos = start + Pos(xOffset, 0)
99+
if grid.containsPos(pos)
100+
startCheat = xOffset.abs
101+
maxEndCheat = 20 - startCheat
102+
yOffset <- (-maxEndCheat) to maxEndCheat
103+
end = pos + Pos(0, yOffset)
104+
if grid.containsPos(end) && grid(end) != '#'
105+
endCheat = yOffset.abs
106+
cheatDistance = forwardResult.distances(start) + (startCheat + endCheat) + backwardResult.distances(end)
107+
//if cheatDistance <= noCheatDistance
108+
save = noCheatDistance - cheatDistance
109+
} yield Cheat(start, end, save)).toSet
110+
}
111+
}
55112

56113
def parseGrid(input: String): Grid[Char] = input.linesIterator.map(_.toVector).toVector
57114

58115
lazy val input: String = scala.io.Source.fromInputStream(getClass.getResourceAsStream("day20.txt")).mkString.trim
59116

60117
def main(args: Array[String]): Unit = {
61-
println(countGoodCheats(parseGrid(input)))
118+
println(Part1.countGoodCheats(parseGrid(input)))
119+
println(Part2.countGoodCheats(parseGrid(input)))
62120
}
63121
}

src/test/scala/eu/sim642/adventofcode2024/Day20Test.scala

+24-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class Day20Test extends AnyFunSuite {
2424
|###############""".stripMargin
2525

2626
test("Part 1 examples") {
27-
val cheats = findCheats(parseGrid(exampleInput)).groupCount(_.save)
27+
val cheats = Part1.findCheats(parseGrid(exampleInput)).groupCount(_.save)
2828
assert(cheats(2) == 14)
2929
assert(cheats(4) == 14)
3030
assert(cheats(6) == 2)
@@ -39,6 +39,28 @@ class Day20Test extends AnyFunSuite {
3939
}
4040

4141
test("Part 1 input answer") {
42-
assert(countGoodCheats(parseGrid(input)) == 1490)
42+
assert(Part1.countGoodCheats(parseGrid(input)) == 1490)
43+
}
44+
45+
test("Part 2 examples") {
46+
val cheats = Part2.findCheats(parseGrid(exampleInput)).groupCount(_.save)
47+
assert(cheats(50) == 32)
48+
assert(cheats(52) == 31)
49+
assert(cheats(54) == 29)
50+
assert(cheats(56) == 39)
51+
assert(cheats(58) == 25)
52+
assert(cheats(60) == 23)
53+
assert(cheats(62) == 20)
54+
assert(cheats(64) == 19)
55+
assert(cheats(66) == 12)
56+
assert(cheats(68) == 14)
57+
assert(cheats(70) == 12)
58+
assert(cheats(72) == 22)
59+
assert(cheats(74) == 4)
60+
assert(cheats(76) == 3)
61+
}
62+
63+
ignore("Part 2 input answer") { // TODO: optimize (~4.3s)
64+
assert(Part2.countGoodCheats(parseGrid(input)) == 1011325)
4365
}
4466
}

0 commit comments

Comments
 (0)