diff options
author | Tomasz Chojnacki <tomaszchojnacki2001@gmail.com> | 2023-02-19 20:42:51 +0100 |
---|---|---|
committer | Tomasz Chojnacki <tomaszchojnacki2001@gmail.com> | 2023-02-19 20:42:51 +0100 |
commit | c4372e5b3d64d1b08cf9b00d0845141bbee753f6 (patch) | |
tree | 43c410dedf2088730b41079adc9e1b299844c619 /aoc-2020-gleam/src/days | |
parent | c74bb3862190e866a8764bf0781f60b248b64876 (diff) | |
download | gleam_aoc2020-c4372e5b3d64d1b08cf9b00d0845141bbee753f6.tar.gz gleam_aoc2020-c4372e5b3d64d1b08cf9b00d0845141bbee753f6.zip |
Finish day 3
Diffstat (limited to 'aoc-2020-gleam/src/days')
-rw-r--r-- | aoc-2020-gleam/src/days/day03.gleam | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/aoc-2020-gleam/src/days/day03.gleam b/aoc-2020-gleam/src/days/day03.gleam new file mode 100644 index 0000000..da67658 --- /dev/null +++ b/aoc-2020-gleam/src/days/day03.gleam @@ -0,0 +1,99 @@ +import gleam/string +import gleam/list +import gleam/function +import gleam/io +import gleam/iterator as iter +import gleam/int +import gleam/set.{Set} +import ext/resultx +import ext/iteratorx as iterx +import util/input_util + +type Pos = + #(Int, Int) + +const starting_pos = #(0, 0) + +const base_slope = #(3, 1) + +const all_slopes = [#(1, 1), base_slope, #(5, 1), #(7, 1), #(1, 2)] + +fn add(p1: Pos, p2: Pos) -> Pos { + #(p1.0 + p2.0, p1.1 + p2.1) +} + +type Area { + Area(trees: Set(Pos), cycle: Int, height: Int) +} + +fn parse_area(from text: String) -> Area { + let lines = string.split(text, on: "\n") + + let trees = + list.index_fold( + over: lines, + from: set.new(), + with: fn(prev, line, y) { + line + |> string.to_graphemes + |> list.index_map(with: fn(x, grapheme) { + case grapheme { + "#" -> Ok(#(x, y)) + _ -> Error(Nil) + } + }) + |> list.filter_map(with: function.identity) + |> set.from_list + |> set.union(prev) + }, + ) + let cycle = + lines + |> list.first + |> resultx.force_unwrap + |> string.length + let height = list.length(lines) + + Area(trees, cycle, height) +} + +fn has_tree(in area: Area, at pos: Pos) -> Bool { + set.contains(area.trees, #(pos.0 % area.cycle, pos.1)) +} + +fn is_valid(pos: Pos, in area: Area) -> Bool { + 0 <= pos.1 && pos.1 < area.height +} + +fn tree_count(in area: Area, with slope: Pos) -> Int { + starting_pos + |> iter.iterate(with: add(_, slope)) + |> iter.take_while(satisfying: is_valid(_, in: area)) + |> iterx.count(satisfying: has_tree(in: area, at: _)) +} + +fn part1(text: String) -> Int { + text + |> parse_area + |> tree_count(with: base_slope) +} + +fn part2(text: String) -> Int { + let area = parse_area(from: text) + + all_slopes + |> list.map(with: tree_count(in: area, with: _)) + |> int.product +} + +pub fn run() -> Nil { + let test = input_util.read_text("test03") + assert 7 = part1(test) + assert 336 = part2(test) + + let input = input_util.read_text("day03") + io.debug(part1(input)) + io.debug(part2(input)) + + Nil +} |