diff options
Diffstat (limited to 'aoc-2020-gleam/src/days/day20.gleam')
-rw-r--r-- | aoc-2020-gleam/src/days/day20.gleam | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/aoc-2020-gleam/src/days/day20.gleam b/aoc-2020-gleam/src/days/day20.gleam new file mode 100644 index 0000000..12f1964 --- /dev/null +++ b/aoc-2020-gleam/src/days/day20.gleam @@ -0,0 +1,107 @@ +import gleam/io +import gleam/int +import gleam/list +import gleam/dict +import gleam/set.{type Set} +import ext/intx +import ext/listx +import ext/resultx as resx +import ext/genericx as genx +import util/grid +import util/input_util +import util/pos2.{type Pos2} +import util/parser as p + +const tile_size = 10 + +type Tile { + Tile(id: Int, filled: Set(Pos2)) +} + +fn edge_ids(tile: Tile) -> List(Int) { + let extract = fn(filter, map) { + tile.filled + |> set.to_list + |> list.filter(keeping: filter) + |> list.map(with: fn(pos) { int.bitwise_shift_left(1, map(pos)) }) + |> int.sum + } + + let dedup = fn(edge_id) { + int.min( + edge_id, + edge_id + |> intx.reverse_bits(tile_size), + ) + } + + [ + extract(fn(b) { pos2.y(b) == 0 }, pos2.x), + extract(fn(b) { pos2.x(b) == 9 }, pos2.y), + extract(fn(b) { pos2.y(b) == 9 }, pos2.x), + extract(fn(b) { pos2.x(b) == 0 }, pos2.y), + ] + |> list.map(with: dedup) +} + +fn parse_tiles(input: String) -> List(Tile) { + let tile_parser = + p.literal("Tile ") + |> p.proceed(with: p.int()) + |> p.skip(p.literal(":\n")) + |> p.then(p.any_str_of_len(tile_size * tile_size + { tile_size - 1 })) + |> p.map2(fn(id, content) { + Tile( + id, + content + |> grid.parse_grid(with: fn(x, y) { #(x, y) }), + ) + }) + + let assert Ok(tiles) = + input + |> p.parse_entire( + with: tile_parser + |> p.sep1(by: p.nlnl()) + |> p.skip_ws, + ) + tiles +} + +fn part1(input: String) -> Int { + let tiles = parse_tiles(input) + + let counts = + tiles + |> list.flat_map(with: edge_ids) + |> listx.counts + + tiles + |> list.filter(keeping: fn(tile) { + tile + |> edge_ids + |> list.map(with: fn(edge_id) { + counts + |> dict.get(edge_id) + |> resx.assert_unwrap + }) + |> listx.count(satisfying: genx.equals(_, 1)) + |> genx.equals(2) + }) + |> list.map(with: fn(tile) { tile.id }) + |> int.product +} + +fn part2() -> Nil { + todo +} + +pub fn main() -> Nil { + let testing = input_util.read_text("test20") + let assert 20_899_048_083_289 = part1(testing) + + let input = input_util.read_text("day20") + io.debug(part1(input)) + + Nil +} |