Day 7: Bridge Repair
by @philippus
Puzzle description
https://adventofcode.com/2024/day/7
Solution Summary
- Parse the input split the lines into the test value and the numbers on which we will operate
- Find the equations that can be made valid with the different operators (
*
,+
and/or||
). - Sum the test values of the equations that are possibly true
Parsing
Each line of the input contains a test value, followed by a colon and a space (:
) and a list of numbers seperated by
a space. Our parser iterates over the lines, extracts the test values and a list of numbers from each line.
Since we will be summing potentially a lot of numbers, we use a Long
and not an Int
.
def parse(input: String): Seq[(Long, List[Long])] =
input
.linesIterator
.map:
case s"$testValue: $numbers" => (testValue.toLong, numbers.split(" ").map(_.toLong).toList)
.toSeq
Part 1
To find the equations that could possibly be true we iterate over the equations and check each of them using a recursive
checkEquation
function. Its input is the test value and the list of numbers and its return value is a boolean.
In each iteration we have two choices, either we use the *
operator, or we use the +
operator.
We apply the operator on the first two numbers in the list, and then we call checkEquation
again with the result of the
operation concatenated with the remaining numbers. So, the first number in the list serves as the accumulator.
If there is only one number left in the list we compare the value with the test value and if it is equal the equation could be true.
Finally, we sum up the test values of all the equations that could be true.
def checkEquation(testValue: Long, numbers: List[Long]): Boolean =
numbers match {
case fst :: Nil =>
fst == testValue
case fst :: snd :: rest =>
checkEquation(testValue, (fst * snd) :: rest) || checkEquation(testValue, (fst + snd) :: rest)
}
def part1(input: String): Long =
val equations = parse(input)
equations.map:
case (testValue, numbers) =>
if checkEquation(testValue, numbers) then testValue else 0L
.sum
end part1
Part 2
In this part a new concatenation operator ||
is added that combines the digits from its left and right inputs into a
single number, for this we expand the checkEquation
function with a case that does exactly that. We use toString
on
the two numbers, concatenate them using ++
and then apply toLong
, concatenate with the remaining numbers and call
the checkEquation
function.
We add a withConcat
parameter to the checkEquation
function, so that we can use the same function for both parts 1
and 2.
def checkEquation(testValue: Long, numbers: List[Long], withConcat: Boolean = false): Boolean =
numbers match {
case fst :: Nil =>
fst == testValue
case fst :: snd :: rest =>
checkEquation(testValue, (fst * snd) :: rest, withConcat) || checkEquation(testValue, (fst + snd) :: rest, withConcat) ||
(withConcat && checkEquation(testValue, (fst.toString ++ snd.toString).toLong :: rest, withConcat))
}
def part2(input: String): Long =
val equations = parse(input)
equations.map:
case (testValue, numbers) =>
if checkEquation(testValue, numbers, withConcat = true) then testValue else 0L
.sum
end part2
Solutions from the community
- Solution by Artem Nikiforov
- Solution by YannMoisan
- Solution by Spamegg
- Solution by Philippus Baalman
- Solution by Roland Tritsch
- Solution by Antoine Amiguet
- Solution by Guillaume Vandecasteele
- Solution by scarf
- Solution by jnclt
- Solution by Raphaël Marbeck
- Solution of Jan Boerman
- Solution by Maciej Gorywoda
- Solution by nichobi
- Solution by Georgi Krastev
- Solution by Joshua Portway
- Solution by Bulby
- Solution by itsjoeoui
Share your solution to the Scala community by editing this page. You can even write the whole article! See here for the expected format