Skip to content

Commit

Permalink
day 25 article
Browse files Browse the repository at this point in the history
  • Loading branch information
merlinorg committed Dec 25, 2024
1 parent a9689c6 commit b867d91
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 0 deletions.
74 changes: 74 additions & 0 deletions docs/2024/puzzles/day25.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,84 @@ import Solver from "../../../../../website/src/components/Solver.js"

# Day 25: Code Chronicle

by [@merlinorg](https://github.com/merlinorg)

## Puzzle description

https://adventofcode.com/2024/day/25

## Solution summary

1. Parse and partition the locks and keys.
2. Find all lock and key combinations that could fit.
3. Return the count of potential matches.

## Parsing

It's the last day of Advent of Code so we'll keep it simple. The input consists
of a sequence of grids, separated by blank lines. Each grid is a sequence of lines
consisting of the `#` and `.` characters. Locks have `#` characters in the first
row, where keys have `.` characters. To parse this we'll just use simple string
splitting.

First, we split the input into grids by matching on the blank lines. This gives us
an array of strings, each grid represented by a single string. Then we partition
this into two arrays; one the keys, and the other locks. For this, we use the
`partition` method that takes a predicate; every grid that matches this predicate
will be placed in the first array of the resulting tuple, the rest in the second.

```scala 3
val (locks, keys) = input.split("\n\n").partition(_.startsWith("#"))
```

In general, arrays are not the most ergonomic data structures to use, but for
this final puzzle they are more than sufficient.

## Matching

To find all potential matches we will use a for comprehension to loop through
all the locks, and then for each lock, through all the keys. For each pair of
a lock and key, we want to determine whether there is any overlap that would
prevent the key fitting the lock.
We can perform this test by simply zipping the key and the lock strings; this
gives us a collection of every corresponding character from each string. The
key can fit the lock if there is no location containing a `#` character in
both grids.

```scala 3
val matches = for
lock <- locks
key <- keys
if lock.zip(key).forall: (lockChar, keyChar) =>
lockChar != '#' || keyChar != '#'
yield lock -> key
```

This returns all of the matching lock and key combinations; the solution to
the puzzle is the size of this array.

## Final code

```scala 3
def part1(input: String): Int =
val (locks, keys) = input.split("\n\n").partition(_.startsWith("#"))

val matches = for
lock <- locks
key <- keys
if lock.zip(key).forall: (lockChar, keyChar) =>
lockChar != '#' || keyChar != '#'
yield lock -> key

matches.length
```

### Run it in the browser

#### Part 1

<Solver puzzle="day25-part1" year="2024"/>

## Solutions from the community

Share your solution to the Scala community by editing this page.
Expand Down
1 change: 1 addition & 0 deletions solver/src/main/scala/adventofcode/Solver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ object Solver:
"day21-part2" -> day21.part2,
"day22-part1" -> day22.part1,
"day22-part2" -> day22.part2,
"day25-part1" -> day25.part1,
)

private val solutions2023: Map[String, String => Any] =
Expand Down

0 comments on commit b867d91

Please sign in to comment.