diff options
author | J.J <thechairman@thechairman.info> | 2023-12-04 00:56:43 -0500 |
---|---|---|
committer | J.J <thechairman@thechairman.info> | 2023-12-04 00:56:43 -0500 |
commit | aa4626c6d3feb825f43ae53f0bed09da249f873b (patch) | |
tree | 88140717cee083ab9afa0e6fdd3cdef1385d1e56 /aoc2023 | |
parent | cd893a2756ffcc73df737a154ea7b3e2119329fe (diff) | |
download | gleam_aoc-aa4626c6d3feb825f43ae53f0bed09da249f873b.tar.gz gleam_aoc-aa4626c6d3feb825f43ae53f0bed09da249f873b.zip |
day 4 complete
Diffstat (limited to 'aoc2023')
-rw-r--r-- | aoc2023/src/aoc2023.gleam | 8 | ||||
-rw-r--r-- | aoc2023/src/day4/.gitignore | 1 | ||||
-rw-r--r-- | aoc2023/src/day4/solve.gleam | 129 | ||||
-rw-r--r-- | aoc2023/test/day4/day4_test.gleam | 48 |
4 files changed, 185 insertions, 1 deletions
diff --git a/aoc2023/src/aoc2023.gleam b/aoc2023/src/aoc2023.gleam index ea5c211..30335ee 100644 --- a/aoc2023/src/aoc2023.gleam +++ b/aoc2023/src/aoc2023.gleam @@ -1,5 +1,11 @@ import gleam/io +import gleam/bit_array + +const str = "abcdefgh +abcdefgh" pub fn main() { - io.println("Hello from aoc2023!") + let trim = 8 + let <<_:bytes-size(trim), "\n":utf8, rest:bytes>> = bit_array.from_string(str) + io.debug(rest) } diff --git a/aoc2023/src/day4/.gitignore b/aoc2023/src/day4/.gitignore new file mode 100644 index 0000000..ae40cea --- /dev/null +++ b/aoc2023/src/day4/.gitignore @@ -0,0 +1 @@ +input.txt
\ No newline at end of file diff --git a/aoc2023/src/day4/solve.gleam b/aoc2023/src/day4/solve.gleam new file mode 100644 index 0000000..426922c --- /dev/null +++ b/aoc2023/src/day4/solve.gleam @@ -0,0 +1,129 @@ +import adglent.{First, Second} +import gleam/io +import gleam/string +import gleam/int +import gleam/list +import gleam/dict +import gleam/result +import gleam/option.{None, Some} + +type Card { + Card(number: Int, winning: List(Int), has: List(Int)) +} + +fn numbers_to_list(str: String) -> List(Int) { + str + |> string.split(" ") + |> list.map(int.parse) + |> result.values() +} + +fn parse_card(card: String) { + let assert Ok(#("Card" <> n_str, rest)) = string.split_once(card, ": ") + let assert Ok(#(winning_str, has_str)) = string.split_once(rest, " | ") + let assert Ok(n) = + n_str + |> string.trim + |> int.parse + + let winning = numbers_to_list(winning_str) + let has = numbers_to_list(has_str) + + Card(number: n, winning: winning, has: has) +} + +fn double_up(n) { + case n { + 0 -> 0 + 1 -> 1 + n -> 2 * double_up(n - 1) + } +} + +fn count_wins(card: Card) { + list.fold( + card.has, + 0, + fn(acc, c) { + case list.contains(card.winning, c) { + True -> acc + 1 + False -> acc + } + }, + ) +} + +pub fn part1(input: String) { + input + |> string.split("\n") + |> list.fold( + 0, + fn(acc, c) { + c + |> parse_card + |> count_wins + |> double_up + |> int.add(acc) + }, + ) + |> string.inspect +} + +fn win_more_cards(cards: List(Card), card_count: dict.Dict(Int, Int)) { + case cards { + [] -> + card_count + |> dict.values + |> int.sum + [card, ..rest] -> { + let wins = count_wins(card) + case wins { + 0 -> win_more_cards(rest, card_count) + n -> { + let assert Ok(bonus) = dict.get(card_count, card.number) + let won_cards = list.range(card.number + 1, card.number + n) + { + use acc, n <- list.fold(won_cards, card_count) + use c <- dict.update(acc, n) + case c { + Some(i) -> i + bonus + None -> panic as "won a card that doesn't exist in the card pile" + } + } + |> win_more_cards(rest, _) + } + } + } + } +} + +pub fn part2(input: String) { + let raw_cards = + input + |> string.split("\n") + + let card_count = + list.range(1, list.length(raw_cards)) + |> list.map(fn(n) { #(n, 1) }) + |> dict.from_list() + + raw_cards + |> list.map(parse_card) + |> win_more_cards(card_count) + |> string.inspect +} + +pub fn main() { + let assert Ok(part) = adglent.get_part() + let assert Ok(input) = adglent.get_input("4") + case part { + First -> + part1(input) + |> adglent.inspect + |> io.println + Second -> + part2(input) + |> adglent.inspect + |> io.println + } +} diff --git a/aoc2023/test/day4/day4_test.gleam b/aoc2023/test/day4/day4_test.gleam new file mode 100644 index 0000000..7ca20fa --- /dev/null +++ b/aoc2023/test/day4/day4_test.gleam @@ -0,0 +1,48 @@ +import gleam/list +import showtime/tests/should +import adglent.{type Example, Example} +import day4/solve + +type Problem1AnswerType = + String + +type Problem2AnswerType = + String + +/// Add examples for part 1 here: +/// ```gleam +///const part1_examples: List(Example(Problem1AnswerType)) = [Example("some input", "")] +/// ``` +const part1_examples: List(Example(Problem1AnswerType)) = [Example("Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 +Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 +Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 +Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 +Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 +Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11", "13")] + +/// Add examples for part 2 here: +/// ```gleam +///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] +/// ``` +const part2_examples: List(Example(Problem2AnswerType)) = [Example("Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 +Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 +Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 +Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 +Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 +Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11", "30")] + +pub fn part1_test() { + part1_examples + |> should.not_equal([]) + use example <- list.map(part1_examples) + solve.part1(example.input) + |> should.equal(example.answer) +} + +pub fn part2_test() { + part2_examples + |> should.not_equal([]) + use example <- list.map(part2_examples) + solve.part2(example.input) + |> should.equal(example.answer) +} |