diff options
Diffstat (limited to 'aoc2023')
78 files changed, 0 insertions, 4610 deletions
diff --git a/aoc2023/.DS_Store b/aoc2023/.DS_Store Binary files differdeleted file mode 100644 index 5172429..0000000 --- a/aoc2023/.DS_Store +++ /dev/null diff --git a/aoc2023/.github/workflows/test.yml b/aoc2023/.github/workflows/test.yml deleted file mode 100644 index cf2096e..0000000 --- a/aoc2023/.github/workflows/test.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: test - -on: - push: - branches: - - master - - main - pull_request: - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: erlef/setup-beam@v1 - with: - otp-version: "26.0.2" - gleam-version: "0.32.4" - rebar3-version: "3" - # elixir-version: "1.15.4" - - run: gleam deps download - - run: gleam test - - run: gleam format --check src test diff --git a/aoc2023/.gitignore b/aoc2023/.gitignore deleted file mode 100644 index 8248306..0000000 --- a/aoc2023/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -*.beam -*.ez -build -erl_crash.dump - -aoc.toml
\ No newline at end of file diff --git a/aoc2023/README.md b/aoc2023/README.md deleted file mode 100644 index 3f534e8..0000000 --- a/aoc2023/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# aoc2023 - -[](https://hex.pm/packages/aoc2023) -[](https://hexdocs.pm/aoc2023/) - -## Quick start - -```sh -gleam run # Run the project -gleam test # Run the tests -gleam shell # Run an Erlang shell -``` - -## Installation - -If available on Hex this package can be added to your Gleam project: - -```sh -gleam add aoc2023 -``` - -and its documentation can be found at <https://hexdocs.pm/aoc2023>. - -## Use - -* Set up a solution: `gleam run -m adglent/day <n>` -* Check against examples: `gleam test -- --modules=day<n>/day<n>_test` -* Get final answer: `gleam run -m day<n>/solve <p>`
\ No newline at end of file diff --git a/aoc2023/gleam.toml b/aoc2023/gleam.toml deleted file mode 100644 index 8190aef..0000000 --- a/aoc2023/gleam.toml +++ /dev/null @@ -1,22 +0,0 @@ -name = "aoc2023" -version = "0.1.0" -gleam = ">= 0.33.0" - -# Fill out these fields if you intend to generate HTML documentation or publish -# your project to the Hex package manager. -# -# description = "" -# licences = ["Apache-2.0"] -# repository = { type = "github", user = "username", repo = "project" } -# links = [{ title = "Website", href = "https://gleam.run" }] - -[dependencies] -gleam_stdlib = "~> 0.33" -simplifile = "~> 1.0" -gleam_erlang = "~> 0.23" -gleam_community_maths = "~> 1.0" -gleam_otp = "~> 0.8" -pqueue = "~> 2.0" - -[dev-dependencies] -adglent = "~> 1.2" diff --git a/aoc2023/manifest.toml b/aoc2023/manifest.toml deleted file mode 100644 index 900b5c0..0000000 --- a/aoc2023/manifest.toml +++ /dev/null @@ -1,29 +0,0 @@ -# This file was generated by Gleam -# You typically do not need to edit this file - -packages = [ - { name = "adglent", version = "1.2.0", build_tools = ["gleam"], requirements = ["glint", "gleam_http", "gleam_stdlib", "simplifile", "gleam_erlang", "gap", "gleam_httpc", "snag", "gleam_community_ansi", "tom", "gleam_otp"], otp_app = "adglent", source = "hex", outer_checksum = "A20D35001061F8AD602E3B92FB3AC0E1E4EEC642AD2AAE0ACEAD3A85F37DA7F0" }, - { name = "gap", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "5E369751DB547BFBDA7735878DC04DA31FCA3112193D61D5D7566010C7C8BA98" }, - { name = "gleam_community_ansi", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8B5A9677BC5A2738712BBAF2BA289B1D8195FDF962BBC769569976AD5E9794E1" }, - { name = "gleam_community_colour", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "036C206886AFB9F153C552700A7A0B4D2864E3BC96A20C77E5F34A013C051BE3" }, - { name = "gleam_community_maths", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_community_maths", source = "hex", outer_checksum = "1B9DB313E94A0E4674CA84C5D29F45ECFE211BFB38ABBD8B23737395F47D08B3" }, - { name = "gleam_erlang", version = "0.23.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "C21CFB816C114784E669FFF4BBF433535EEA9960FA2F216209B8691E87156B96" }, - { name = "gleam_http", version = "3.5.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "AECDA43AFD523D07A8F09068598A6E271C505278A0CB6F9C7A2E4365EAE8D11E" }, - { name = "gleam_httpc", version = "2.1.1", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "06AC1CA52C9BAA66C9D5C0303B2BF34E39AA1546BB96AEE496E4B06D513AB8C7" }, - { name = "gleam_otp", version = "0.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_erlang"], otp_app = "gleam_otp", source = "hex", outer_checksum = "18EF8242A5E54BA92F717C7222F03B3228AEE00D1F286D4C56C3E8C18AA2588E" }, - { name = "gleam_stdlib", version = "0.33.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "539E37A2AA5EBE8E75F4B74755E4CC604BD957C3000AC8D705A2024886A2738B" }, - { name = "glint", version = "0.13.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_community_ansi", "gleam_community_colour", "snag"], otp_app = "glint", source = "hex", outer_checksum = "46E56049CD370D61F720D319D0AB970408C9336EEB918F08B5DCB1DCE9845FA3" }, - { name = "pqueue", version = "2.0.7", build_tools = ["rebar3"], requirements = [], otp_app = "pqueue", source = "hex", outer_checksum = "8B0204BB202335890E4E7F9B99A8EC0B84DDB8513EE298EB180EE9B3BCB4C859" }, - { name = "simplifile", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0BD6F0E7DA1A7E11D18B8AD48453225CAFCA4C8CFB4513D217B372D2866C501C" }, - { name = "snag", version = "0.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "8FD70D8FB3728E08AC425283BB509BB0F012BE1AE218424A597CDE001B0EE589" }, - { name = "tom", version = "0.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "5C5A9B8586C547F1F39542B1A3BBD9FEE17AFEAB51CE53B32B13D0D46B421249" }, -] - -[requirements] -adglent = { version = "~> 1.2" } -gleam_community_maths = { version = "~> 1.0" } -gleam_erlang = { version = "~> 0.23" } -gleam_otp = { version = "~> 0.8" } -gleam_stdlib = { version = "~> 0.33" } -pqueue = { version = "~> 2.0" } -simplifile = { version = "~> 1.0" } diff --git a/aoc2023/src/.gitignore b/aoc2023/src/.gitignore deleted file mode 100644 index bc13a69..0000000 --- a/aoc2023/src/.gitignore +++ /dev/null @@ -1 +0,0 @@ -aoc2023.gleam
\ No newline at end of file diff --git a/aoc2023/src/aoc2023.gleam b/aoc2023/src/aoc2023.gleam deleted file mode 100644 index aab904d..0000000 --- a/aoc2023/src/aoc2023.gleam +++ /dev/null @@ -1,12 +0,0 @@ -import gleam/io -import gleam/bit_array - -const str = "abcdefgh -abcdefgh" - -pub fn main() { - let trim = 8 - let assert <<_:bytes-size(trim), "\n":utf8, rest:bytes>> = - bit_array.from_string(str) - io.debug(rest) -} diff --git a/aoc2023/src/day1/.gitignore b/aoc2023/src/day1/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day1/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day1/solve.gleam b/aoc2023/src/day1/solve.gleam deleted file mode 100644 index 37a19d2..0000000 --- a/aoc2023/src/day1/solve.gleam +++ /dev/null @@ -1,57 +0,0 @@ -import adglent.{First, Second} -import gleam/io -import gleam/list -import gleam/string -import gleam/regex.{type Match, Match} -import gleam/int - -pub fn part1(input: String) { - let assert Ok(re) = regex.from_string("[1-9]") - - input - |> string.split("\n") - |> list.fold(0, fn(acc, s) { - let matches = regex.scan(s, with: re) - - let assert Ok(Match(content: first, ..)) = list.first(matches) - let assert Ok(Match(content: last, ..)) = list.last(matches) - let assert Ok(i) = int.parse(first <> last) - acc + i - }) - |> string.inspect -} - -const substitutions = [ - #("one", "o1e"), - #("two", "t2o"), - #("three", "t3e"), - #("four", "4"), - #("five", "5e"), - #("six", "6"), - #("seven", "7n"), - #("eight", "e8t"), - #("nine", "n9e"), -] - -pub fn part2(input: String) { - list.fold(over: substitutions, from: input, with: fn(acc, sub) { - let #(from, to) = sub - string.replace(in: acc, each: from, with: to) - }) - |> part1 -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("1") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day10/.gitignore b/aoc2023/src/day10/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day10/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day10/solve.gleam b/aoc2023/src/day10/solve.gleam deleted file mode 100644 index c33634d..0000000 --- a/aoc2023/src/day10/solve.gleam +++ /dev/null @@ -1,177 +0,0 @@ -import adglent.{First, Second} -import gleam/bool -import gleam/dict.{type Dict} -import gleam/list -import gleam/int -import gleam/io -import gleam/set.{type Set} -import gleam/string - -type Posn { - Posn(row: Int, col: Int) -} - -fn add_posns(p1: Posn, p2: Posn) -> Posn { - Posn(p1.row + p2.row, p1.col + p2.col) -} - -type PipeGrid = - Dict(Posn, String) - -const north = Posn(-1, 0) - -const south = Posn(1, 0) - -const east = Posn(0, 1) - -const west = Posn(0, -1) - -const initial_directions = [ - #(north, ["|", "7", "F"]), - #(south, ["|", "J", "L"]), - #(east, ["-", "J", "7"]), - #(west, ["-", "F", "L"]), -] - -fn pipe_neighbors(pipe: String) -> List(Posn) { - case pipe { - "|" -> [north, south] - "-" -> [east, west] - "L" -> [north, east] - "F" -> [south, east] - "7" -> [south, west] - "J" -> [north, west] - _ -> panic as "bad pipe" - } -} - -fn make_grid(input: String) -> PipeGrid { - { - use r, row <- list.index_map(string.split(input, "\n")) - use c, col <- list.index_map(string.to_graphemes(row)) - #(Posn(r, c), col) - } - |> list.flatten - |> dict.from_list -} - -fn valid_start_direction(grid: PipeGrid, s: Posn) { - let assert [dir, ..] = { - use d <- list.filter_map(initial_directions) - let #(delta, valids) = d - let neighbor = add_posns(s, delta) - case dict.get(grid, neighbor) { - Ok(pipe) -> - case list.contains(valids, pipe) { - True -> Ok(neighbor) - False -> Error(Nil) - } - Error(_) -> Error(Nil) - } - } - dir -} - -fn to_next_pipe(current: Posn, grid: PipeGrid, acc: List(Posn)) { - let assert [prev, ..] = acc - let assert Ok(pipe) = dict.get(grid, current) - use <- bool.guard(pipe == "S", [current, ..acc]) - let assert [next] = { - pipe - |> pipe_neighbors - |> list.filter_map(fn(p) { - case add_posns(p, current) { - neighbor if neighbor == prev -> Error(Nil) - neighbor -> Ok(neighbor) - } - }) - } - to_next_pipe(next, grid, [current, ..acc]) -} - -pub fn part1(input: String) { - let grid = - input - |> make_grid - - let assert Ok(s) = - grid - |> dict.filter(fn(_, v) { v == "S" }) - |> dict.keys - |> list.first - - grid - |> valid_start_direction(s) - |> to_next_pipe(grid, [s]) - |> list.length - |> fn(i) { { { i - 1 } / 2 } } - |> string.inspect -} - -fn trace_ray(p: Posn, loop: Set(Posn), grid: PipeGrid) -> Bool { - use <- bool.guard(set.contains(loop, p), False) - int.is_odd(count_crossings(p, loop, grid, 0, "")) -} - -fn count_crossings( - p: Posn, - loop: Set(Posn), - grid: PipeGrid, - acc: Int, - corner: String, -) { - let maybe_cell = dict.get(grid, p) - use <- bool.guard(maybe_cell == Error(Nil), acc) - let assert Ok(cell) = maybe_cell - let next = add_posns(p, east) - case set.contains(loop, p) { - False -> count_crossings(next, loop, grid, acc, corner) - True -> - case corner, cell { - _, "|" -> count_crossings(next, loop, grid, acc + 1, corner) - _, "F" | _, "L" -> count_crossings(next, loop, grid, acc, cell) - "F", "J" | "L", "7" -> count_crossings(next, loop, grid, acc + 1, "") - "F", "7" | "L", "J" -> count_crossings(next, loop, grid, acc, "") - _, _ -> count_crossings(next, loop, grid, acc, corner) - } - } -} - -pub fn part2(input: String) { - let grid = - input - |> make_grid - - let assert Ok(s) = - grid - |> dict.filter(fn(_, v) { v == "S" }) - |> dict.keys - |> list.first - - let loop_pipes = - grid - |> valid_start_direction(s) - |> to_next_pipe(grid, [s]) - |> set.from_list - - grid - |> dict.keys - |> list.filter(trace_ray(_, loop_pipes, grid)) - |> list.length() - |> string.inspect -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("10") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day11/.gitignore b/aoc2023/src/day11/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day11/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day11/solve.gleam b/aoc2023/src/day11/solve.gleam deleted file mode 100644 index 35464a1..0000000 --- a/aoc2023/src/day11/solve.gleam +++ /dev/null @@ -1,84 +0,0 @@ -import adglent.{First, Second} -import gleam/io -import gleam/int -import gleam/string -import gleam/list - -type Posn { - Posn(x: Int, y: Int) -} - -fn find_empty(grid: List(List(String))) { - use acc, row, r <- list.index_fold(grid, []) - case list.unique(row) { - ["."] -> [r, ..acc] - _ -> acc - } -} - -fn count_prior_empty_ranks(rank: Int, empty_ranks: List(Int)) -> Int { - empty_ranks - |> list.drop_while(fn(r_empty) { r_empty > rank }) - |> list.length -} - -fn parse_with_expansion(input: String, expansion: Int) -> List(Posn) { - let add = expansion - 1 - let grid = - input - |> string.split("\n") - |> list.map(string.to_graphemes) - - let empty_row_list = find_empty(grid) - let empty_col_list = find_empty(list.transpose(grid)) - - { - use r, row <- list.index_map(grid) - use acc, cell, c <- list.index_fold(over: row, from: []) - - let p = Posn(r, c) - let empty_r = count_prior_empty_ranks(r, empty_row_list) - let empty_c = count_prior_empty_ranks(c, empty_col_list) - case cell { - "#" -> [Posn(p.x + empty_r * add, p.y + empty_c * add), ..acc] - _empty -> acc - } - } - |> list.flatten() -} - -fn all_distances(stars: List(Posn)) -> Int { - use acc, pair <- list.fold(list.combination_pairs(stars), 0) - let #(s1, s2) = pair - acc + int.absolute_value(s1.x - s2.x) + int.absolute_value(s1.y - s2.y) -} - -fn find_distances(input: String, expand_by: Int) -> String { - input - |> parse_with_expansion(expand_by) - |> all_distances - |> string.inspect -} - -pub fn part1(input: String) { - find_distances(input, 2) -} - -pub fn part2(input: String) { - find_distances(input, 1_000_000) -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("11") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day12/.gitignore b/aoc2023/src/day12/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day12/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day12/solve.gleam b/aoc2023/src/day12/solve.gleam deleted file mode 100644 index 893b83c..0000000 --- a/aoc2023/src/day12/solve.gleam +++ /dev/null @@ -1,90 +0,0 @@ -import adglent.{First, Second} -import gleam/io -import gleam/string -import gleam/list -import gleam/int -import gleam/result -import utilities/memo.{type Cache} - -type ParserState = - #(String, List(Int), Int, Bool) - -fn parse_folds(input: String, folds: Int) { - let records = string.split(input, "\n") - use record <- list.map(records) - let assert Ok(#(template, sets_str)) = string.split_once(record, " ") - - let template = - template - |> list.repeat(folds) - |> list.intersperse("?") - |> string.concat - let sets = - sets_str - |> string.split(",") - |> list.map(int.parse) - |> result.values - |> list.repeat(folds) - |> list.flatten() - - #(template, sets) -} - -fn do_count( - template: String, - groups: List(Int), - left: Int, - gap: Bool, - cache: Cache(ParserState, Int), -) -> Int { - use <- memo.memoize(cache, #(template, groups, left, gap)) - case template, groups, left, gap { - "", [], 0, _ -> 1 - "?" <> t_rest, [g, ..g_rest], 0, False -> - do_count(t_rest, g_rest, g - 1, g == 1, cache) - + do_count(t_rest, groups, 0, False, cache) - "?" <> t_rest, [], 0, False - | "?" <> t_rest, _, 0, True - | "." <> t_rest, _, 0, _ -> do_count(t_rest, groups, 0, False, cache) - "#" <> t_rest, [g, ..g_rest], 0, False -> - do_count(t_rest, g_rest, g - 1, g == 1, cache) - "?" <> t_rest, gs, l, False | "#" <> t_rest, gs, l, False -> - do_count(t_rest, gs, l - 1, l == 1, cache) - _, _, _, _ -> 0 - } -} - -fn count_solutions(acc: Int, condition: #(String, List(Int))) -> Int { - use cache: Cache(ParserState, Int) <- memo.create() - let #(template, groups) = condition - acc + do_count(template, groups, 0, False, cache) -} - -pub fn part1(input: String) { - input - |> parse_folds(1) - |> list.fold(0, count_solutions) - |> string.inspect -} - -pub fn part2(input: String) { - input - |> parse_folds(5) - |> list.fold(0, count_solutions) - |> string.inspect -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("12") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day13/.gitignore b/aoc2023/src/day13/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day13/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day13/solve.gleam b/aoc2023/src/day13/solve.gleam deleted file mode 100644 index 6f9b9a0..0000000 --- a/aoc2023/src/day13/solve.gleam +++ /dev/null @@ -1,87 +0,0 @@ -import adglent.{First, Second} -import gleam/io -import gleam/list -import gleam/string -import gleam/bool - -type SymmetryType { - Horizontal(Int) - Vertical(Int) -} - -fn is_symmetric(xss: List(List(a)), errs: Int) { - let assert [left, ..right] = xss - do_is_symmetric([left], right, errs) -} - -fn do_is_symmetric( - left: List(List(a)), - right: List(List(a)), - errors: Int, -) -> Result(Int, Nil) { - use <- bool.guard(list.is_empty(right), Error(Nil)) - let assert [h, ..t] = right - let found_errors = - list.zip(list.flatten(left), list.flatten(right)) - |> list.filter(fn(tup) { tup.1 != tup.0 }) - |> list.length - case found_errors == errors { - True -> Ok(list.length(left)) - False -> do_is_symmetric([h, ..left], t, errors) - } -} - -fn get_symmetry_type(xss: List(List(String)), errors: Int) { - case is_symmetric(xss, errors) { - Ok(n) -> Horizontal(n) - _ -> { - let assert Ok(n) = is_symmetric(list.transpose(xss), errors) - Vertical(n) - } - } -} - -fn summarize_notes(symmetries: List(SymmetryType)) { - use acc, note <- list.fold(symmetries, 0) - acc - + case note { - Horizontal(n) -> 100 * n - Vertical(n) -> n - } -} - -fn solve(input: String, errors: Int) { - input - |> string.split("\n\n") - |> list.map(fn(strs) { - strs - |> string.split("\n") - |> list.map(string.to_graphemes) - |> get_symmetry_type(errors) - }) - |> summarize_notes - |> string.inspect -} - -pub fn part1(input: String) { - solve(input, 0) -} - -pub fn part2(input: String) { - solve(input, 1) -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("13") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day14/.gitignore b/aoc2023/src/day14/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day14/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day14/solve.gleam b/aoc2023/src/day14/solve.gleam deleted file mode 100644 index ecc5361..0000000 --- a/aoc2023/src/day14/solve.gleam +++ /dev/null @@ -1,94 +0,0 @@ -import adglent.{First, Second} -import gleam/dict -import gleam/int -import gleam/io -import gleam/list -import gleam/order -import gleam/string - -fn parse(input) { - input - |> string.split("\n") - |> list.map(string.to_graphemes) - |> list.transpose() -} - -fn roll_boulders(strs: List(String)) { - { - use chunks <- list.map(list.chunk(strs, fn(c) { c == "O" || c == "." })) - list.sort(chunks, order.reverse(string.compare)) - } - |> list.flatten -} - -fn score(matrix) { - use acc, col <- list.fold(matrix, 0) - acc - + { - use col_acc, char, n <- list.index_fold(list.reverse(col), 0) - case char { - "O" -> col_acc + n + 1 - _ -> col_acc - } - } -} - -pub fn part1(input: String) { - input - |> parse - |> list.map(roll_boulders) - |> score() - |> string.inspect -} - -fn rotate(matrix) { - matrix - |> list.map(list.reverse) - |> list.transpose -} - -fn spin(matrix) { - use acc, _ <- list.fold(list.range(1, 4), matrix) - acc - |> list.map(roll_boulders) - |> rotate -} - -fn spin_cycle(matrix) { - let cache = dict.new() - check_if_seen(matrix, cache, 1_000_000_000) -} - -fn check_if_seen(matrix, cache, count) { - case dict.get(cache, matrix) { - Error(Nil) -> - check_if_seen(spin(matrix), dict.insert(cache, matrix, count), count - 1) - Ok(n) -> { - let assert Ok(extra) = int.modulo(count, n - count) - list.fold(list.range(1, extra), matrix, fn(acc, _) { spin(acc) }) - |> score - } - } -} - -pub fn part2(input: String) { - input - |> parse - |> spin_cycle - |> string.inspect -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("14") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day15/.gitignore b/aoc2023/src/day15/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day15/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day15/solve.gleam b/aoc2023/src/day15/solve.gleam deleted file mode 100644 index a7d250c..0000000 --- a/aoc2023/src/day15/solve.gleam +++ /dev/null @@ -1,104 +0,0 @@ -import adglent.{First, Second} -import gleam/io -import gleam/string -import gleam/list -import gleam/int -import gleam/dict.{type Dict} -import gleam/option.{None, Some} - -fn split(input: String) -> List(String) { - input - |> string.split(",") -} - -fn hash_algorithm(str: String) -> Int { - let codepoints = - str - |> string.to_utf_codepoints() - |> list.map(string.utf_codepoint_to_int) - use acc, c <- list.fold(codepoints, 0) - let assert Ok(acc) = int.modulo({ acc + c } * 17, 256) - acc -} - -pub fn part1(input: String) -> String { - input - |> split - |> list.fold(0, fn(acc, str) { acc + hash_algorithm(str) }) - |> string.inspect -} - -type Instruction { - Remove(label: String) - Insert(label: String, focal: Int) -} - -fn read_instruction(str: String) -> Instruction { - case string.split(str, "=") { - [label, focal_str] -> { - let assert Ok(focal) = int.parse(focal_str) - Insert(label, focal) - } - _ -> Remove(string.drop_right(str, 1)) - } -} - -fn parse_instructions(insts: List(String)) -> Dict(Int, List(#(String, Int))) { - use acc, inst <- list.fold(insts, dict.new()) - case read_instruction(inst) { - Remove(label) -> remove_lens(acc, label) - Insert(label, focal) -> insert_lens(acc, label, focal) - } -} - -fn remove_lens(boxes, label) { - use v <- dict.update(boxes, hash_algorithm(label)) - case v { - Some(lenses) -> - case list.key_pop(lenses, label) { - Ok(#(_, updated)) -> updated - Error(Nil) -> lenses - } - None -> [] - } -} - -fn insert_lens(boxes, label, focal) { - use v <- dict.update(boxes, hash_algorithm(label)) - case v { - Some(lenses) -> list.key_set(lenses, label, focal) - None -> [#(label, focal)] - } -} - -fn focusing_power(boxes: Dict(Int, List(#(String, Int)))) -> Int { - use acc, k, v <- dict.fold(boxes, 0) - let box_acc = { - use acc, lens, i <- list.index_fold(v, 0) - acc + lens.1 * { i + 1 } - } - acc + { k + 1 } * box_acc -} - -pub fn part2(input: String) -> String { - input - |> split - |> parse_instructions - |> focusing_power - |> string.inspect -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("15") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day16/.gitignore b/aoc2023/src/day16/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day16/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day16/solve.gleam b/aoc2023/src/day16/solve.gleam deleted file mode 100644 index 65ce36b..0000000 --- a/aoc2023/src/day16/solve.gleam +++ /dev/null @@ -1,119 +0,0 @@ -import adglent.{First, Second} -import gleam/bool -import gleam/dict.{type Dict} -import gleam/io -import gleam/list -import gleam/result -import gleam/set.{type Set} -import utilities/array2d.{type Posn, Posn} - -type Direction { - Up - Right - Down - Left -} - -type Light { - Light(posn: Posn, dir: Direction) -} - -fn move(l: Light) -> Light { - let Light(p, dir) = l - case dir { - Up -> Light(..l, posn: Posn(..p, r: p.r - 1)) - Down -> Light(..l, posn: Posn(..p, r: p.r + 1)) - Left -> Light(..l, posn: Posn(..p, c: p.c - 1)) - Right -> Light(..l, posn: Posn(..p, c: p.c + 1)) - } -} - -fn transform(l: Light, cell: Result(String, Nil)) -> List(Light) { - use <- bool.guard(result.is_error(cell), []) - let assert Ok(c) = cell - let Light(p, dir) = l - case dir, c { - // no change - _, "." | Up, "|" | Down, "|" | Left, "-" | Right, "-" -> [l] - // diagonal mirrors - Left, "/" -> [Light(p, Down)] - Down, "/" -> [Light(p, Left)] - Right, "/" -> [Light(p, Up)] - Up, "/" -> [Light(p, Right)] - Left, "\\" -> [Light(p, Up)] - Up, "\\" -> [Light(p, Left)] - Right, "\\" -> [Light(p, Down)] - Down, "\\" -> [Light(p, Right)] - // splitters - Left, "|" | Right, "|" -> [Light(p, Up), Light(p, Down)] - Up, "-" | Down, "-" -> [Light(p, Left), Light(p, Right)] - _, _ -> panic as "unrecognized cell type" - } -} - -fn energize(lights: List(Light), visited: Set(Light), grid: Dict(Posn, String)) { - let next_positions = - lights - |> list.flat_map(fn(l) { - let next = move(l) - transform(next, dict.get(grid, next.posn)) - }) - |> list.filter(fn(l) { !set.contains(visited, l) }) - let all_visited = set.union(set.from_list(next_positions), visited) - case visited == all_visited { - True -> - set.fold(visited, set.new(), fn(acc, l) { set.insert(acc, l.posn) }) - |> set.to_list - |> list.length - False -> energize(next_positions, all_visited, grid) - } -} - -pub fn part1(input: String) { - let grid = array2d.parse_grid(input) - - [Light(Posn(0, -1), Right)] - |> energize(set.new(), grid) -} - -pub fn part2(input: String) { - let grid = array2d.parse_grid(input) - - let Posn(rows, cols) = { - use acc, p <- list.fold(dict.keys(grid), Posn(0, 0)) - case acc.r + acc.c > p.r + p.c { - True -> acc - False -> p - } - } - - let all_starts = - list.concat([ - list.map(list.range(0, rows), fn(r) { Light(Posn(r, -1), Right) }), - list.map(list.range(0, rows), fn(r) { Light(Posn(r, cols + 1), Left) }), - list.map(list.range(0, cols), fn(c) { Light(Posn(-1, c), Down) }), - list.map(list.range(0, cols), fn(c) { Light(Posn(rows + 1, c), Up) }), - ]) - - use acc, p <- list.fold(all_starts, 0) - let energized = energize([p], set.new(), grid) - case acc > energized { - True -> acc - False -> energized - } -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("16") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day17/.gitignore b/aoc2023/src/day17/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day17/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day17/solve.gleam b/aoc2023/src/day17/solve.gleam deleted file mode 100644 index 7a01c4d..0000000 --- a/aoc2023/src/day17/solve.gleam +++ /dev/null @@ -1,143 +0,0 @@ -import adglent.{First, Second} -import gleam/bool -import gleam/dict.{type Dict} -import gleam/io -import gleam/list -import gleam/result -import gleam/string -import gleam/set.{type Set} -import utilities/array2d.{type Posn, Posn} -import utilities/prioqueue.{type PriorityQueue} - -type State { - State(posn: Posn, heatloss: Int, previous: Posn, history: List(Posn)) -} - -const deltas = [Posn(-1, 0), Posn(1, 0), Posn(0, -1), Posn(0, 1)] - -fn make_key(s: State) { - #(s.posn, same_dir(s)) -} - -fn same_dir(s: State) { - case s.history { - [] -> [] - [first, ..] as deltas -> - list.take_while(deltas, fn(d) { d == first }) - |> list.take(10) - } -} - -fn is_goal(s: State, min_run: Int, goal: Posn) { - goal == s.posn && list.length(same_dir(s)) >= min_run -} - -fn find_good_neighbors(max: Int, min: Int, s: State, grid) { - deltas - |> list.filter(eliminate_bad_neighbors(_, s, max, min, grid)) - |> list.map(make_state(_, s, grid)) -} - -fn eliminate_bad_neighbors(d: Posn, s: State, max, min, grid) { - let neighbor = array2d.add_posns(d, s.posn) - - use <- bool.guard( - neighbor == s.previous || !dict.has_key(grid, neighbor), - False, - ) - case same_dir(s), list.length(same_dir(s)) { - [prev, ..], l if l == max -> d != prev - _, 0 -> True - [prev, ..], l if l < min -> d == prev - _, _ -> True - } -} - -fn make_state(d: Posn, s: State, grid) { - let neighbor = array2d.add_posns(d, s.posn) - let assert Ok(heat_lost) = dict.get(grid, neighbor) - State( - posn: neighbor, - heatloss: s.heatloss + heat_lost, - previous: s.posn, - history: [d, ..s.history], - ) -} - -fn find_path( - grid: Dict(Posn, Int), - queue: PriorityQueue(State), - seen: Set(#(Posn, List(Posn))), - get_neighbors: fn(State) -> List(State), - is_goal: fn(State) -> Bool, -) { - let assert Ok(#(state, rest)) = prioqueue.pop(queue) - let key = - make_key( - state - |> io.debug, - ) - case set.contains(seen, key) { - True -> find_path(grid, rest, seen, get_neighbors, is_goal) - False -> { - let now_seen = set.insert(seen, key) - let neighbors = get_neighbors(state) - case list.find(neighbors, is_goal) { - Ok(final) -> final.heatloss - _err -> { - let now_queue = - list.fold(neighbors, rest, fn(acc, n) { - prioqueue.insert(acc, n, n.heatloss) - }) - find_path(grid, now_queue, now_seen, get_neighbors, is_goal) - } - } - } - } -} - -pub fn part1(input: String) { - let raw_grid = - input - |> array2d.to_list_of_lists - - let grid = array2d.to_2d_intarray(raw_grid) - - let rmax = list.length(raw_grid) - let assert Ok(cmax) = - raw_grid - |> list.first - |> result.map(list.length) - - let start = State(Posn(0, 0), 0, Posn(0, 0), []) - let goal = Posn(rmax, cmax) - - find_path( - grid, - prioqueue.insert(prioqueue.new(), start, 0), - set.new(), - find_good_neighbors(0, 3, _, grid), - is_goal(_, 1, goal), - ) - |> string.inspect -} - -pub fn part2(input: String) { - input - |> string.inspect -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("17") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day18/.gitignore b/aoc2023/src/day18/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day18/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day18/solve.gleam b/aoc2023/src/day18/solve.gleam deleted file mode 100644 index 2c000f9..0000000 --- a/aoc2023/src/day18/solve.gleam +++ /dev/null @@ -1,113 +0,0 @@ -import adglent.{First, Second} -import gleam/io -import gleam/int -import gleam/list -import gleam/option.{Some} -import gleam/regex.{type Match, Match} -import gleam/string - -type Coord { - Coord(x: Int, y: Int) -} - -type Direction { - Up - Right - Down - Left -} - -type Dig { - Dig(dir: Direction, dist: Int) -} - -fn to_direction(c: String) { - case c { - "R" | "0" -> Right - "D" | "1" -> Down - "L" | "2" -> Left - "U" | "3" -> Up - _ -> panic - } -} - -fn parse_front(line: String) { - let assert Ok(re) = regex.from_string("(.) (.*) \\(.*\\)") - let assert [Match(submatches: [Some(dir), Some(dist)], ..)] = - regex.scan(with: re, content: line) - let assert Ok(n) = int.parse(dist) - Dig(to_direction(dir), n) -} - -fn parse_hex(line: String) { - let assert Ok(re) = regex.from_string("\\(#(.....)(.)\\)") - let assert [Match(submatches: [Some(dist), Some(dir)], ..)] = - regex.scan(with: re, content: line) - let assert Ok(n) = int.base_parse(dist, 16) - Dig(to_direction(dir), n) -} - -fn go(current: Coord, dig: Dig) { - case dig { - Dig(Up, n) -> Coord(current.x, current.y + n) - Dig(Right, n) -> Coord(current.x + n, current.y) - Dig(Down, n) -> Coord(current.x, current.y - n) - Dig(Left, n) -> Coord(current.x - n, current.y) - } -} - -fn double_triangle(c1: Coord, c2: Coord) { - { c1.x * c2.y } - { c2.x * c1.y } -} - -fn start_dig(digs: List(Dig)) { - do_next_dig(digs, Coord(0, 0), 0, 0) -} - -fn do_next_dig( - digs: List(Dig), - current: Coord, - area: Int, - perimeter: Int, -) -> Int { - case digs { - [] -> int.absolute_value(area) / 2 + { perimeter / 2 } + 1 - [dig, ..rest] -> { - let next = go(current, dig) - let area = area + double_triangle(current, next) - let perimeter = perimeter + dig.dist - do_next_dig(rest, next, area, perimeter) - } - } -} - -fn solve_with(input, f) { - input - |> string.split("\n") - |> list.map(f) - |> start_dig - |> string.inspect -} - -pub fn part1(input: String) { - solve_with(input, parse_front) -} - -pub fn part2(input: String) { - solve_with(input, parse_hex) -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("18") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day19/.gitignore b/aoc2023/src/day19/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day19/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day19/solve.gleam b/aoc2023/src/day19/solve.gleam deleted file mode 100644 index 186e783..0000000 --- a/aoc2023/src/day19/solve.gleam +++ /dev/null @@ -1,255 +0,0 @@ -import adglent.{First, Second} -import gleam/io -import gleam/string -import gleam/dict.{type Dict} -import gleam/order.{type Order, Gt, Lt} -import gleam/regex.{type Match, Match} -import gleam/list -import gleam/option.{Some} -import gleam/int - -type Rating { - XtremelyCool - Musical - Aerodynamic - Shiny -} - -type Part { - Part(x: Int, m: Int, a: Int, s: Int) -} - -type Action { - Accept - Reject - SendTo(String) -} - -type Rule { - If(rating: Rating, comparison: Order, threshold: Int, do: Action) - Just(do: Action) -} - -type Workflow = - Dict(String, List(Rule)) - -type Interval { - Interval(min: Int, max: Int) -} - -type PartRange { - PartRange(x: Interval, m: Interval, a: Interval, s: Interval) -} - -fn parse_workflow(input: String) -> Workflow { - let assert Ok(re) = regex.from_string("(.*){(.*)}") - - use acc, line <- list.fold(string.split(input, "\n"), dict.new()) - let assert [Match(submatches: [Some(name), Some(all_rules)], ..)] = - regex.scan(re, line) - let rules = - string.split(all_rules, ",") - |> parse_rules - dict.insert(acc, name, rules) -} - -fn parse_rules(rules: List(String)) -> List(Rule) { - let assert Ok(re_rule) = regex.from_string("(.*)(>|<)(.*):(.*)") - use rule <- list.map(rules) - case regex.scan(re_rule, rule) { - [Match(submatches: [Some(r), Some(c), Some(t), Some(i)], ..)] -> - If(to_rating(r), to_comp(c), to_val(t), to_instruction(i)) - _nomatch -> Just(to_instruction(rule)) - } -} - -fn to_instruction(rule: String) { - case rule { - "A" -> Accept - "R" -> Reject - name -> SendTo(name) - } -} - -fn to_rating(rating: String) { - case rating { - "x" -> XtremelyCool - "m" -> Musical - "a" -> Aerodynamic - _s -> Shiny - } -} - -fn get_rating(part: Part, rating: Rating) -> Int { - case rating { - XtremelyCool -> part.x - Musical -> part.m - Aerodynamic -> part.a - Shiny -> part.s - } -} - -fn to_comp(comp: String) { - case comp { - "<" -> Lt - _gt -> Gt - } -} - -fn to_val(val: String) { - let assert Ok(n) = int.parse(val) - n -} - -fn parse_parts(input: String) -> List(Part) { - let assert Ok(re) = regex.from_string("{x=(.*),m=(.*),a=(.*),s=(.*)}") - - use part <- list.map(string.split(input, "\n")) - let assert [Match(submatches: [Some(x), Some(m), Some(a), Some(s)], ..)] = - regex.scan(re, part) - Part(to_val(x), to_val(m), to_val(a), to_val(s)) -} - -fn start_evaluating_workflow(part: Part, workflow: Workflow) -> Int { - evaluate_workflow(part, "in", workflow) -} - -fn evaluate_workflow(part: Part, name: String, workflow: Workflow) -> Int { - let assert Ok(rules) = dict.get(workflow, name) - case evaluate_rules(part, rules) { - Accept -> part.x + part.m + part.a + part.s - Reject -> 0 - SendTo(name) -> evaluate_workflow(part, name, workflow) - } -} - -fn evaluate_rules(part: Part, rules: List(Rule)) -> Action { - case rules { - [] -> panic - [Just(do), ..] -> do - [If(rating, comparison, threshold, do), ..rest] -> - case int.compare(get_rating(part, rating), threshold) == comparison { - True -> do - False -> evaluate_rules(part, rest) - } - } -} - -pub fn part1(input: String) { - let assert Ok(#(workflows_str, parts_str)) = string.split_once(input, "\n\n") - - let workflows = parse_workflow(workflows_str) - let parts = parse_parts(parts_str) - - list.map(parts, start_evaluating_workflow(_, workflows)) - |> int.sum - |> string.inspect -} - -fn size(interval: Interval) { - interval.max - interval.min + 1 -} - -fn all_in_range(pr: PartRange) { - size(pr.x) * size(pr.m) * size(pr.a) * size(pr.s) -} - -fn get_partrange(pr: PartRange, rating: Rating) -> Interval { - case rating { - XtremelyCool -> pr.x - Musical -> pr.m - Aerodynamic -> pr.a - Shiny -> pr.s - } -} - -fn update_partrange(pr: PartRange, rating: Rating, i: Interval) -> PartRange { - case rating { - XtremelyCool -> PartRange(..pr, x: i) - Musical -> PartRange(..pr, m: i) - Aerodynamic -> PartRange(..pr, a: i) - Shiny -> PartRange(..pr, s: i) - } -} - -pub fn part2(input: String) { - let assert Ok(#(workflows_str, _)) = string.split_once(input, "\n\n") - - let workflow = parse_workflow(workflows_str) - let start = Interval(1, 4000) - - PartRange(start, start, start, start) - |> evaluate_workflow_on_range("in", workflow) - |> string.inspect -} - -fn evaluate_workflow_on_range( - pr: PartRange, - name: String, - workflow: Workflow, -) -> Int { - let assert Ok(rules) = dict.get(workflow, name) - evaluate_rules_on_range(pr, rules, workflow) -} - -fn evaluate_rules_on_range( - pr: PartRange, - rules: List(Rule), - workflow: Workflow, -) -> Int { - case rules { - [Just(Accept), ..] -> all_in_range(pr) - [Just(Reject), ..] -> 0 - [Just(SendTo(name)), ..] -> evaluate_workflow_on_range(pr, name, workflow) - [If(rating, comparison, t, action), ..rest] -> { - let mod_i = get_partrange(pr, rating) - case comparison { - Lt -> - split_range( - keep: update_partrange(pr, rating, Interval(mod_i.min, t - 1)), - and_do: action, - pass: update_partrange(pr, rating, Interval(t, mod_i.max)), - and_eval: rest, - with: workflow, - ) - _gt -> - split_range( - keep: update_partrange(pr, rating, Interval(t + 1, mod_i.max)), - and_do: action, - pass: update_partrange(pr, rating, Interval(mod_i.min, t)), - and_eval: rest, - with: workflow, - ) - } - } - [] -> panic - } -} - -fn split_range( - keep keep: PartRange, - and_do action: Action, - pass pass: PartRange, - and_eval rest: List(Rule), - with workflow: Workflow, -) -> Int { - int.add( - evaluate_rules_on_range(keep, [Just(action)], workflow), - evaluate_rules_on_range(pass, rest, workflow), - ) -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("19") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day2/.gitignore b/aoc2023/src/day2/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day2/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day2/solve.gleam b/aoc2023/src/day2/solve.gleam deleted file mode 100644 index 608955f..0000000 --- a/aoc2023/src/day2/solve.gleam +++ /dev/null @@ -1,66 +0,0 @@ -import adglent.{First, Second} -import gleam/io -import gleam/int -import gleam/string -import gleam/list - -pub type Game { - Game(red: Int, blue: Int, green: Int) -} - -fn parse(input: String) -> List(List(Game)) { - use line <- list.map(string.split(input, "\n")) - let assert [_, rounds] = string.split(line, on: ": ") - use match <- list.map(string.split(rounds, on: "; ")) - use acc, draw <- list.fold( - over: string.split(match, on: ", "), - from: Game(0, 0, 0), - ) - let assert Ok(#(n_str, color)) = string.split_once(draw, " ") - let assert Ok(n) = int.parse(n_str) - case color { - "red" -> Game(..acc, red: n) - "blue" -> Game(..acc, blue: n) - "green" -> Game(..acc, green: n) - _ -> panic as "unrecognized color" - } -} - -pub fn part1(input: String) { - use acc, game, i <- list.index_fold(parse(input), 0) - case list.any(game, fn(m) { m.red > 12 || m.green > 13 || m.blue > 14 }) { - False -> acc + i + 1 - True -> acc - } -} - -pub fn part2(input: String) { - { - use game <- list.map(parse(input)) - use acc, match <- list.fold(game, Game(0, 0, 0)) - let Game(red: red, green: green, blue: blue) = match - Game( - red: int.max(red, acc.red), - blue: int.max(blue, acc.blue), - green: int.max(green, acc.green), - ) - } - |> list.fold(from: 0, with: fn(acc, g: Game) { - acc + g.red * g.blue * g.green - }) -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("2") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day20/.gitignore b/aoc2023/src/day20/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day20/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day20/solve.gleam b/aoc2023/src/day20/solve.gleam deleted file mode 100644 index 9192dac..0000000 --- a/aoc2023/src/day20/solve.gleam +++ /dev/null @@ -1,251 +0,0 @@ -import adglent.{First, Second} -import gleam/bool -import gleam/dict.{type Dict} -import gleam/io -import gleam/iterator.{type Iterator, type Step, Next} -import gleam/list -import gleam/queue.{type Queue} -import gleam/set -import gleam/string - -type Node { - Broadcaster(children: List(String)) - Flipflop(children: List(String), state: Power) - Conjunction(children: List(String), state: Dict(String, TonePitch)) - Ground -} - -type Tone { - Tone(from: String, to: String, pitch: TonePitch) -} - -type Power { - On - Off -} - -type TonePitch { - Low - High -} - -type State { - State( - nodes: Dict(String, Node), - low: Int, - high: Int, - cycle: Int, - sentry_nodes: Dict(String, Int), - ) -} - -fn flip_power(p: Power) -> Power { - case p { - On -> Off - Off -> On - } -} - -fn flip_flop_pitch(p: Power) -> TonePitch { - case p { - Off -> High - On -> Low - } -} - -fn combinator_pitch(state) { - case list.unique(dict.values(state)) { - [High] -> Low - _ -> High - } -} - -fn get_children(node) { - case node { - Flipflop(children: cs, ..) -> cs - Conjunction(children: cs, ..) -> cs - Broadcaster(children: cs) -> cs - Ground -> [] - } -} - -fn parse_node(input: String) -> #(String, Node) { - let assert [full_name, children_str] = string.split(input, on: " -> ") - let children = string.split(children_str, on: ", ") - - case full_name { - "%" <> name -> #(name, Flipflop(children: children, state: Off)) - "&" <> name -> #(name, Conjunction(children: children, state: dict.new())) - "broadcaster" -> #("broadcaster", Broadcaster(children: children)) - name -> #(name, Ground) - } -} - -fn to_initial_state(nodes: List(#(String, Node))) -> Dict(String, Node) { - let node_dict = dict.from_list(nodes) - let node_names = dict.keys(node_dict) - - let node_dict = - node_dict - |> dict.values - |> list.map(get_children) - |> list.concat - |> set.from_list - |> set.drop(dict.keys(node_dict)) - |> set.to_list - |> list.fold(node_dict, fn(acc, n) { dict.insert(acc, n, Ground) }) - - use name, node <- dict.map_values(node_dict) - case node { - Conjunction(state: _, children: chs) -> - node_names - |> list.filter(fn(n) { - let assert Ok(node) = dict.get(node_dict, n) - list.contains(get_children(node), any: name) - }) - |> list.map(fn(n) { #(n, Low) }) - |> dict.from_list() - |> fn(dict) { Conjunction(state: dict, children: chs) } - other -> other - } -} - -fn add_to_queue(from, children, pitch, queue) { - use acc, c <- list.fold(children, queue) - queue.push_back(acc, Tone(from: from, to: c, pitch: pitch)) -} - -fn add_tones(state: State, nodes, pitch, n) { - case pitch { - Low -> - State(..state, nodes: nodes, low: state.low + n, cycle: state.cycle + 1) - High -> - State(..state, nodes: nodes, high: state.high + n, cycle: state.cycle + 1) - } -} - -fn press_button_once(initial: State, queue: Queue(Tone)) { - let State(nodes: nodes, ..) = initial - - use <- bool.guard(queue.is_empty(queue), initial) - let assert Ok(#(Tone(from_name, to_name, pitch), rest)) = - queue.pop_front(queue) - - let assert Ok(to_node) = dict.get(nodes, to_name) - case to_node { - Broadcaster(children) -> { - let new_state = - add_tones(initial, nodes, pitch, list.length(children) + 1) - - let new_queue = add_to_queue(to_name, children, pitch, rest) - press_button_once(new_state, new_queue) - } - - Conjunction(state: state, children: children) -> { - let new_state = - state - |> dict.insert(from_name, pitch) - - let updated_nodes = - Conjunction(state: new_state, children: children) - |> dict.insert(nodes, to_name, _) - - let pitch_out = combinator_pitch(new_state) - - let new_state = - add_tones(initial, updated_nodes, pitch_out, list.length(children)) - |> check_for_interesting_node(from_name, pitch_out) - - add_to_queue(to_name, children, pitch_out, rest) - |> press_button_once(new_state, _) - } - - Flipflop(..) if pitch == High -> - press_button_once(State(..initial, cycle: initial.cycle + 1), rest) - - Flipflop(state: state, children: children) -> { - let updated_nodes = - Flipflop(state: flip_power(state), children: children) - |> dict.insert(nodes, to_name, _) - - let pitch_out = flip_flop_pitch(state) - let new_state = - add_tones(initial, updated_nodes, pitch_out, list.length(children)) - - add_to_queue(to_name, children, flip_flop_pitch(state), rest) - |> press_button_once(new_state, _) - } - - Ground(..) -> - press_button_once(State(..initial, cycle: initial.cycle + 1), rest) - } -} - -pub fn part1(input: String) { - let initial_state = - input - |> string.split(on: "\n") - |> list.map(parse_node) - |> to_initial_state() - - iterator.iterate( - from: State(initial_state, 0, 0, 1, dict.new()), - with: press_button_once(_, queue.from_list([ - Tone("button", "broadcaster", Low), - ])), - ) - |> iterator.at(1000) - |> fn(s) { - let assert Ok(State(high: high, low: low, ..)) = s - high * low - } - |> string.inspect -} - -fn check_for_interesting_node(state, name, pitch_out) { - case name, pitch_out { - "rk", High | "cd", High | "zf", High | "qx", High -> - State( - ..state, - sentry_nodes: dict.insert(state.sentry_nodes, name, state.cycle), - ) - _, _ -> state - } -} - -pub fn part2(input: String) { - let initial_state = - input - |> string.split(on: "\n") - |> list.map(parse_node) - |> to_initial_state() - - iterator.iterate( - from: State(initial_state, 0, 0, 1, dict.new()), - with: press_button_once(_, queue.from_list([ - Tone("button", "broadcaster", Low), - ])), - ) - |> iterator.drop_while(fn(s) { dict.size(s.sentry_nodes) < 4 }) - |> iterator.step - |> fn(s: Step(State, Iterator(State))) { - let assert Next(goal, _rest) = s - goal.sentry_nodes - } - |> string.inspect -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("20") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day22/.gitignore b/aoc2023/src/day22/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day22/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day22/solve.gleam b/aoc2023/src/day22/solve.gleam deleted file mode 100644 index 7bf2fb4..0000000 --- a/aoc2023/src/day22/solve.gleam +++ /dev/null @@ -1,199 +0,0 @@ -import adglent.{First, Second} -import gleam/bool -import gleam/dict.{type Dict} -import gleam/int -import gleam/io -import gleam/list -import gleam/option.{None, Some} -import gleam/regex -import gleam/result -import gleam/set.{type Set} -import gleam/string - -type Point { - Point(x: Int, y: Int, z: Int) -} - -fn down_one(p: Point) -> Point { - Point(..p, z: p.z - 1) -} - -type Block { - Block(index: Int, from: Point, to: Point) -} - -fn compare_blocks(b1: Block, b2: Block) { - int.compare(b1.to.z, b2.to.z) -} - -type Space = - Dict(Point, Block) - -type AllBlocks = - Dict(Block, List(Point)) - -type BlockTree = - Dict(Int, Set(Int)) - -fn parse_block(index: Int, input: String) -> Block { - let assert Ok(re) = regex.from_string("(.*),(.*),(.*)~(.*),(.*),(.*)") - - let assert [scan] = regex.scan(with: re, content: input) - - let assert [x1, y1, z1, x2, y2, z2] = - scan.submatches - |> option.all - |> option.unwrap([]) - |> list.map(int.parse) - |> result.values - Block(index: index, from: Point(x1, y1, z1), to: Point(x2, y2, z2)) -} - -fn cross_section_at_level(b: Block, z: Int) -> List(Point) { - use x <- list.flat_map(list.range(b.from.x, b.to.x)) - use y <- list.map(list.range(b.from.y, b.to.y)) - Point(x, y, z) -} - -fn place_block(space: Space, b: Block, z: Int) -> Space { - let now_occupied = { - use x <- list.flat_map(list.range(b.from.x, b.to.x)) - use y <- list.flat_map(list.range(b.from.y, b.to.y)) - use z <- list.map(list.range(z, z + b.to.z - b.from.z)) - #(Point(x, y, z), b) - } - - dict.merge(space, dict.from_list(now_occupied)) -} - -fn find_lowest_level(space: Space, b: Block) -> Space { - do_find_lowest(space, b, b.from.z) -} - -fn do_find_lowest(space: Space, b: Block, z: Int) -> Space { - let is_intersecting = - list.any(cross_section_at_level(b, z), dict.has_key(space, _)) - - case z, is_intersecting { - 0, _ -> place_block(space, b, 1) - _, True -> place_block(space, b, z + 1) - _, False -> do_find_lowest(space, b, z - 1) - } -} - -fn to_block_positions(space: Space) -> AllBlocks { - use acc, point, index <- dict.fold(space, dict.new()) - use points <- dict.update(acc, index) - case points { - Some(ps) -> [point, ..ps] - None -> [point] - } -} - -fn above_blocks(blocks: AllBlocks) -> BlockTree { - use acc, block, points <- dict.fold(blocks, dict.new()) - use _ <- dict.update(acc, block.index) - { - use above_block, above_points <- dict.filter(blocks) - above_block.index != block.index - && list.any(above_points, fn(p) { list.contains(points, down_one(p)) }) - } - |> dict.keys - |> list.map(fn(b) { b.index }) - |> set.from_list -} - -fn below_blocks(blocktree: BlockTree) -> BlockTree { - use acc, block, _ <- dict.fold(blocktree, dict.new()) - use _ <- dict.update(acc, block) - { - use _, aboves <- dict.filter(blocktree) - set.contains(aboves, block) - } - |> dict.keys - |> set.from_list -} - -fn vulnerable_blocks(below_tree: BlockTree) -> List(Int) { - use block <- list.filter(dict.keys(below_tree)) - use bs <- list.any(dict.values(below_tree)) - !{ set.size(bs) == 0 } && { set.size(set.delete(bs, block)) == 0 } -} - -pub fn part1(input: String) { - let settled_blocks = - input - |> string.split("\n") - |> list.index_map(parse_block) - |> list.sort(compare_blocks) - |> list.fold(dict.new(), find_lowest_level) - - let block_positions = to_block_positions(settled_blocks) - let above_blocks = above_blocks(block_positions) - let below_blocks = below_blocks(above_blocks) - - let vulnerable_blocks = vulnerable_blocks(below_blocks) - - list.length(dict.keys(block_positions)) - list.length(vulnerable_blocks) -} - -fn all_falling_blocks(n: Int, above: BlockTree, below: BlockTree) { - let starting_set = set.insert(set.new(), n) - do_falling_blocks(starting_set, starting_set, above, below) -} - -fn do_falling_blocks( - fallen: Set(Int), - blocks: Set(Int), - above: BlockTree, - below: BlockTree, -) -> Int { - use <- bool.guard(set.size(blocks) == 0, set.size(fallen) - 1) - - let blocks_above = - { - use block <- list.flat_map(set.to_list(blocks)) - let assert Ok(supports) = dict.get(above, block) - use support <- list.filter(set.to_list(supports)) - let assert Ok(supportings) = dict.get(below, support) - use supporting <- list.all(set.to_list(supportings)) - set.contains(fallen, supporting) - } - |> set.from_list() - - set.union(fallen, blocks_above) - |> do_falling_blocks(blocks_above, above, below) -} - -pub fn part2(input: String) { - let settled_blocks = - input - |> string.split("\n") - |> list.index_map(parse_block) - |> list.sort(compare_blocks) - |> list.fold(dict.new(), find_lowest_level) - - let block_positions = to_block_positions(settled_blocks) - let above_blocks = above_blocks(block_positions) - let below_blocks = below_blocks(above_blocks) - - let vulnerable_blocks = vulnerable_blocks(below_blocks) - - use acc, b <- list.fold(vulnerable_blocks, 0) - acc + all_falling_blocks(b, above_blocks, below_blocks) -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("22") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day23/.gitignore b/aoc2023/src/day23/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day23/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day23/solve.gleam b/aoc2023/src/day23/solve.gleam deleted file mode 100644 index e1fe638..0000000 --- a/aoc2023/src/day23/solve.gleam +++ /dev/null @@ -1,194 +0,0 @@ -import adglent.{First, Second} -import gleam/int -import gleam/io -import gleam/dict.{type Dict} -import gleam/list -import gleam/option.{type Option, None, Some} -import gleam/string -import gleam/set.{type Set} -import gleam/bool -import utilities/array2d.{type Array2D, type Posn, Posn} - -type Path { - Unknown - Straight - Junction -} - -type Route { - Route(to: Posn, distance: Int) -} - -fn append_to_key(v: Option(List(a)), new: a) -> List(a) { - case v { - None -> [new] - Some(xs) -> [new, ..xs] - } -} - -fn first_parse_path(c: String) -> Result(Path, Nil) { - case c { - "#" -> Error(Nil) - _ -> Ok(Unknown) - } -} - -fn junction_neighbors(p: Posn) -> List(Posn) { - [Posn(..p, r: p.r + 1), Posn(..p, c: p.c + 1)] -} - -fn mark_junctions(trails: Array2D(Path)) -> Array2D(Path) { - use trail, _ <- dict.map_values(trails) - - let valid_neighbors = - trail - |> array2d.ortho_neighbors - |> list.filter(dict.has_key(trails, _)) - - case list.length(valid_neighbors) { - 2 -> Straight - _ -> Junction - } -} - -fn start_walking_to_next_junction( - start: Posn, - next: Posn, - trails: Array2D(Path), -) { - let seen = - set.new() - |> set.insert(start) - |> set.insert(next) - walk_to_next_junction(start, next, 1, seen, trails) -} - -fn walk_to_next_junction( - start: Posn, - current: Posn, - length: Int, - seen: Set(Posn), - trails: Array2D(Path), -) -> #(Posn, Route) { - let assert [next] = - current - |> array2d.ortho_neighbors - |> list.filter(fn(n) { dict.has_key(trails, n) && !set.contains(seen, n) }) - - case dict.get(trails, next) { - Ok(Junction) -> #(start, Route(to: next, distance: length + 1)) - _ -> { - let seen = set.insert(seen, current) - walk_to_next_junction(start, next, { length + 1 }, seen, trails) - } - } -} - -fn find_routes(junctions, trails) { - use junction <- list.flat_map(junctions) - use neighbor <- list.filter_map(junction_neighbors(junction)) - case dict.has_key(trails, neighbor) { - True -> Ok(start_walking_to_next_junction(junction, neighbor, trails)) - False -> Error(Nil) - } -} - -fn generate_routes( - junctions: List(Posn), - trails: Array2D(Path), -) -> Dict(Posn, List(Route)) { - use acc, #(from, route) <- list.fold( - find_routes(junctions, trails), - dict.new(), - ) - dict.update(acc, from, append_to_key(_, route)) -} - -fn generate_2way_routes( - junctions: List(Posn), - trails: Array2D(Path), -) -> Dict(Posn, List(Route)) { - use acc, #(from, route) <- list.fold( - find_routes(junctions, trails), - dict.new(), - ) - acc - |> dict.update(from, append_to_key(_, route)) - |> dict.update(route.to, append_to_key(_, Route(from, route.distance))) -} - -fn dfs(routes, from, to) { - let seen = set.insert(set.new(), from) - do_dfs(routes, from, to, 0, seen) -} - -fn do_dfs( - routes: Dict(Posn, List(Route)), - from: Posn, - to: Posn, - acc: Int, - seen: Set(Posn), -) -> Int { - use <- bool.guard(to == from, acc) - - let assert Ok(all_routes) = dict.get(routes, from) - let neighbors = list.filter(all_routes, fn(r) { !set.contains(seen, r.to) }) - - case neighbors { - [] -> 0 - neighbors -> - list.fold(neighbors, acc, fn(inner_acc, n) { - let score = - do_dfs(routes, n.to, to, acc + n.distance, set.insert(seen, n.to)) - int.max(score, inner_acc) - }) - } -} - -fn solve_using( - input: String, - using: fn(List(Posn), Dict(Posn, Path)) -> Dict(Posn, List(Route)), -) -> Int { - let min_row = 0 - let max_row = list.length(string.split(input, "\n")) - 1 - - let trails = - input - |> array2d.parse_grid_using(first_parse_path) - |> mark_junctions - - let junctions = - trails - |> dict.filter(fn(_, v) { v == Junction }) - |> dict.keys - - let assert Ok(start) = list.find(junctions, fn(j) { j.r == min_row }) - let assert Ok(end) = list.find(junctions, fn(j) { j.r == max_row }) - - let routes = using(junctions, trails) - - dfs(routes, start, end) -} - -pub fn part1(input: String) { - solve_using(input, generate_routes) -} - -pub fn part2(input: String) { - solve_using(input, generate_2way_routes) -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("23") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day3/.gitignore b/aoc2023/src/day3/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day3/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day3/solve.gleam b/aoc2023/src/day3/solve.gleam deleted file mode 100644 index ad975aa..0000000 --- a/aoc2023/src/day3/solve.gleam +++ /dev/null @@ -1,180 +0,0 @@ -import adglent.{First, Second} -import gleam/io -import gleam/dict.{type Dict} -import gleam/string -import gleam/list -import gleam/int -import gleam/order.{type Order, Eq} - -type Coord { - Coord(x: Int, y: Int) -} - -type SymbolKind { - Gear - SomethingElse -} - -type Symbol { - Number(Int) - Symbol(SymbolKind) - Empty -} - -type Board = - Dict(Coord, Symbol) - -type Cell { - Cell(coord: Coord, symbol: Symbol) -} - -type Part { - Part(coords: List(Coord), part_number: Int) -} - -fn to_symbol(c: String) -> Symbol { - case int.parse(c), c { - Ok(n), _ -> Number(n) - _, "." -> Empty - _, "*" -> Symbol(Gear) - _, _ -> Symbol(SomethingElse) - } -} - -fn to_board(input: String) -> Board { - { - use y, r <- list.index_map(string.split(input, "\n")) - use x, c <- list.index_map(string.to_graphemes(r)) - #(Coord(x, y), to_symbol(c)) - } - |> list.flatten() - |> dict.from_list() -} - -fn cell_compare(a: Cell, b: Cell) -> Order { - case int.compare(a.coord.y, b.coord.y) { - Eq -> int.compare(a.coord.x, b.coord.x) - other -> other - } -} - -fn find_all_part_digits(b: Board) -> List(Cell) { - b - |> dict.filter(fn(_, v) { - case v { - Number(_) -> True - _ -> False - } - }) - |> dict.to_list() - |> list.map(fn(tup) { Cell(tup.0, tup.1) }) - |> list.sort(cell_compare) -} - -fn to_parts(cells: List(Cell)) -> List(Part) { - do_parts(cells, []) -} - -fn do_parts(cells: List(Cell), parts: List(Part)) -> List(Part) { - case cells { - [] -> parts - [Cell(next, Number(n)), ..t] -> { - case parts { - [] -> do_parts(t, [Part([next], n), ..parts]) - [Part([prev, ..] as coords, n0), ..rest_parts] -> - case { next.x - prev.x }, { next.y - prev.y } { - 1, 0 -> - do_parts(t, [Part([next, ..coords], n0 * 10 + n), ..rest_parts]) - _, _ -> do_parts(t, [Part([next], n), ..parts]) - } - _ -> panic - } - } - _ -> panic - } -} - -fn all_neighbors(c: Coord) -> List(Coord) { - use dx <- list.flat_map([-1, 0, 1]) - use dy <- list.filter_map([-1, 0, 1]) - case dx, dy { - 0, 0 -> Error(Nil) - _, _ -> Ok(Coord(c.x + dx, c.y + dy)) - } -} - -fn sum_valid_parts(acc: Int, part: Part, board: Board) -> Int { - let neighbors = - part.coords - |> list.flat_map(all_neighbors) - |> list.unique() - - let sym = [Ok(Symbol(Gear)), Ok(Symbol(SomethingElse))] - case list.any(neighbors, fn(c) { list.contains(sym, dict.get(board, c)) }) { - True -> acc + part.part_number - False -> acc - } -} - -pub fn part1(input: String) -> Int { - let board = to_board(input) - - board - |> find_all_part_digits - |> to_parts - |> list.fold(0, fn(acc, p) { sum_valid_parts(acc, p, board) }) -} - -fn to_part_with_neighbors(part: Part) -> Part { - part.coords - |> list.flat_map(all_neighbors) - |> list.unique - |> Part(part.part_number) -} - -fn find_part_numbers_near_gear(gear: Coord, parts: List(Part)) -> List(Int) { - use part <- list.filter_map(parts) - case list.contains(part.coords, gear) { - True -> Ok(part.part_number) - False -> Error(Nil) - } -} - -fn to_sum_of_gear_ratios(adjacent_parts: List(List(Int))) -> Int { - use acc, ps <- list.fold(adjacent_parts, 0) - case ps { - [p1, p2] -> acc + p1 * p2 - _ -> acc - } -} - -pub fn part2(input: String) -> Int { - let board = to_board(input) - - let parts = - board - |> find_all_part_digits - |> to_parts - |> list.map(to_part_with_neighbors) - - board - |> dict.filter(fn(_, v) { v == Symbol(Gear) }) - |> dict.keys - |> list.map(find_part_numbers_near_gear(_, parts)) - |> to_sum_of_gear_ratios -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("3") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day4/.gitignore b/aoc2023/src/day4/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day4/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day4/solve.gleam b/aoc2023/src/day4/solve.gleam deleted file mode 100644 index 34d6098..0000000 --- a/aoc2023/src/day4/solve.gleam +++ /dev/null @@ -1,98 +0,0 @@ -import adglent.{First, Second} -import gleam/bool -import gleam/dict.{type Dict} -import gleam/int -import gleam/io -import gleam/list -import gleam/option.{None, Some} -import gleam/result -import gleam/set.{type Set} -import gleam/string - -type Card { - Card(number: Int, winners: Int) -} - -fn numbers_to_set(str: String) -> Set(Int) { - str - |> string.split(" ") - |> list.map(int.parse) - |> result.values() - |> set.from_list() -} - -fn parse_card(card: String) -> Card { - 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) = int.parse(string.trim(n_str)) - - let winning = numbers_to_set(winning_str) - let has = numbers_to_set(has_str) - let winners = set.size(set.intersection(winning, has)) - - Card(number: n, winners: winners) -} - -fn win_points(n: Int) { - bool.guard(n < 2, n, fn() { 2 * win_points(n - 1) }) -} - -pub fn part1(input: String) { - use acc, c <- list.fold(string.split(input, "\n"), 0) - c - |> parse_card - |> fn(c: Card) { win_points(c.winners) } - |> int.add(acc) -} - -fn win_more_cards(cards: List(String), count: Dict(Int, Int)) { - case cards { - [] -> - count - |> dict.values - |> int.sum - [raw_card, ..rest] -> { - let card = parse_card(raw_card) - case card.winners { - 0 -> win_more_cards(rest, count) - n -> win_more_cards(rest, update_counts(n, card, count)) - } - } - } -} - -fn update_counts(n: Int, card: Card, count: Dict(Int, Int)) -> Dict(Int, Int) { - let assert Ok(bonus) = dict.get(count, card.number) - use acc, n <- list.fold(list.range(card.number + 1, card.number + n), 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" - } -} - -pub fn part2(input: String) { - let cards = string.split(input, "\n") - - let count = - list.range(1, list.length(cards)) - |> list.map(fn(n) { #(n, 1) }) - |> dict.from_list() - - win_more_cards(cards, count) -} - -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/src/day5/.gitignore b/aoc2023/src/day5/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day5/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day5/solve.gleam b/aoc2023/src/day5/solve.gleam deleted file mode 100644 index 7c05310..0000000 --- a/aoc2023/src/day5/solve.gleam +++ /dev/null @@ -1,162 +0,0 @@ -import adglent.{First, Second} -import gleam/io -import gleam/string -import gleam/result -import gleam/list.{Continue, Stop} -import gleam/int -import gleam/function - -// Types ------------------------------------------------------------------------------------------- - -pub type Almanac { - Almanac(seeds: List(Int), mappers: List(Mapper)) -} - -pub type MappingRange { - MRange(start: Int, end: Int, offset: Int) -} - -pub type SeedRange { - SRange(start: Int, end: Int) -} - -type Mapper = - List(MappingRange) - -// Parsing ----------------------------------------------------------------------------------------- - -fn parse_input(input: String) { - let assert ["seeds: " <> raw_seeds, ..raw_mappers] = - string.split(input, on: "\n\n") - - let seeds = string_to_int_list(raw_seeds) - let mappers = - list.map( - raw_mappers, - function.compose(string.split(_, on: "\n"), parse_mapper), - ) - Almanac(seeds, mappers) -} - -fn string_to_int_list(str: String) { - str - |> string.split(on: " ") - |> list.map(int.parse) - |> result.values -} - -fn parse_mapper(strs: List(String)) -> Mapper { - let assert [_, ..raw_ranges] = strs - list.map(raw_ranges, parse_mrange) - |> list.sort(fn(a, b) { int.compare(a.start, b.start) }) -} - -fn parse_mrange(str: String) -> MappingRange { - let assert [destination, source, range_width] = string_to_int_list(str) - MRange(source, source + range_width - 1, destination - source) -} - -// Part 1 ------------------------------------------------------------------------------------------ - -pub fn part1(input: String) { - let Almanac(seeds, mappers) = parse_input(input) - - list.map(seeds, list.fold(over: mappers, from: _, with: correspond)) - |> list.reduce(int.min) - |> result.unwrap(0) - |> string.inspect -} - -fn correspond(n: Int, mapper: Mapper) { - use acc, mrange <- list.fold_until(over: mapper, from: n) - case mrange.start <= acc && acc <= mrange.end { - True -> Stop(acc + mrange.offset) - False -> Continue(acc) - } -} - -// Part 2 ------------------------------------------------------------------------------------------ - -pub fn part2(input: String) { - let Almanac(seeds, mappers) = parse_input(input) - - let assert [SRange(answer, _), ..] = - seeds - |> list.sized_chunk(into: 2) - |> list.map(fn(chunk) { - let assert [start, length] = chunk - [SRange(start, start + length - 1)] - |> remap_all_seed_ranges(mappers) - }) - |> list.flatten() - |> list.sort(fn(a, b) { int.compare(a.start, b.start) }) - - string.inspect(answer) -} - -fn remap_all_seed_ranges(srs: List(SeedRange), mappers: List(Mapper)) { - case mappers { - [] -> srs - [mapper, ..rest] -> - list.flat_map(srs, remap_range(_, mapper)) - |> remap_all_seed_ranges(rest) - } -} - -fn remap_range(r: SeedRange, mapper: Mapper) -> List(SeedRange) { - do_remap_range(r, mapper, []) -} - -fn transform_range(r: SeedRange, mapper: MappingRange) -> SeedRange { - SRange(r.start + mapper.offset, r.end + mapper.offset) -} - -fn do_remap_range(r: SeedRange, mapper: Mapper, acc: List(SeedRange)) { - case mapper { - // no more mappings -> no mapping covers this range - [] -> [r, ..acc] - // range is to the left of current mapping -> no mapping covers this range - [m, ..] if r.end < m.start -> [r, ..acc] - // range is to the right of current mapping -> move to next mapping - [m, ..ms] if r.start > m.end -> do_remap_range(r, ms, acc) - // range is fully inside mapping -> range is transformed - [m, ..] if r.start >= m.start && r.end <= m.end -> [ - transform_range(r, m), - ..acc - ] - // range overlaps start but not end -> left side not transformed, right side transformed - [m, ..] if r.start < m.start && r.end <= m.end -> [ - SRange(r.start, m.start - 1), - transform_range(SRange(m.start, r.end), m), - ..acc - ] - // range overlaps end but not start -> left side transformed, right side moves to next mapping - [m, ..ms] if r.start >= m.start && r.end > m.end -> - do_remap_range(SRange(m.end + 1, r.end), ms, [ - transform_range(SRange(r.start, m.end), m), - ..acc - ]) - // mapping is fully inside range -> left not transformed, middle transformed, right to next - [m, ..ms] -> - do_remap_range(SRange(m.end + 1, r.end), ms, [ - SRange(r.start, m.start - 1), - transform_range(SRange(m.start, m.end), m), - ..acc - ]) - } -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("5") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day6/.gitignore b/aoc2023/src/day6/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day6/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day6/solve.gleam b/aoc2023/src/day6/solve.gleam deleted file mode 100644 index 88044c4..0000000 --- a/aoc2023/src/day6/solve.gleam +++ /dev/null @@ -1,85 +0,0 @@ -import adglent.{First, Second} -import gleam/io -import gleam/string -import gleam/int -import gleam/list -import gleam/result - -type Race { - Race(time: Int, distance: Int) -} - -fn parse_with_bad_kerning(input: String) { - input - |> string.split("\n") - |> list.map(fn(str) { - str - |> string.split(" ") - |> list.map(int.parse) - |> result.values - }) - |> list.transpose - |> list.map(fn(ns) { - let assert [t, d] = ns - Race(t, d) - }) -} - -fn find_bound(race: Race, button_time: Int, step: Int) { - let travel_time = race.time - button_time - case button_time * travel_time > race.distance { - True -> button_time - False -> find_bound(race, button_time + step, step) - } -} - -fn lower_bound(race: Race) { - find_bound(race, 1, 1) -} - -fn upper_bound(race: Race) { - find_bound(race, race.time, -1) -} - -pub fn part1(input: String) { - { - use acc, race <- list.fold(parse_with_bad_kerning(input), 1) - acc * { upper_bound(race) - lower_bound(race) + 1 } - } - |> string.inspect -} - -fn parse_properly(input: String) { - input - |> string.replace(" ", "") - |> string.split("\n") - |> list.flat_map(string.split(_, ":")) - |> list.map(int.parse) - |> result.values -} - -pub fn part2(input: String) { - let assert [time, distance] = - input - |> parse_properly - - let race = Race(time, distance) - - upper_bound(race) - lower_bound(race) + 1 - |> string.inspect -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("6") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day7/.gitignore b/aoc2023/src/day7/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day7/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day7/solve.gleam b/aoc2023/src/day7/solve.gleam deleted file mode 100644 index 4454883..0000000 --- a/aoc2023/src/day7/solve.gleam +++ /dev/null @@ -1,140 +0,0 @@ -import adglent.{First, Second} -import gleam/bool -import gleam/function -import gleam/int -import gleam/io -import gleam/list -import gleam/order.{type Order, Eq, Lt} -import gleam/string - -// Types ------------------------------------------------------------------------------------------- - -type Hand { - Hand(cards: List(Int), wager: Int) -} - -// Common functions -------------------------------------------------------------------------------- - -fn parse_hand(str: String) -> Hand { - let assert [cards, wager] = string.split(str, " ") - let cards = - string.to_graphemes(cards) - |> list.map(card_rank) - let assert Ok(wager) = int.parse(wager) - - Hand(cards, wager) -} - -fn classify_hand(hand: Hand) -> Int { - case list.length(list.unique(hand.cards)), card_counts(hand) { - 1, _ -> 8 - 2, [1, 4] -> 7 - 2, [2, 3] -> 6 - 3, [1, 1, 3] -> 5 - 3, [1, 2, 2] -> 4 - 4, _ -> 3 - 5, _ -> 2 - _, _ -> 1 - } -} - -fn card_counts(hand: Hand) { - hand.cards - |> list.sort(int.compare) - |> list.chunk(function.identity) - |> list.map(list.length) - |> list.sort(int.compare) -} - -fn card_rank(card: String) -> Int { - case int.parse(card), card { - Ok(n), _ -> n - _, "A" -> 14 - _, "K" -> 13 - _, "Q" -> 12 - _, "J" -> 11 - _, "T" -> 10 - _, _ -> 1 - } -} - -fn compare_hands(hand1: Hand, hand2: Hand, using: fn(Hand) -> Int) -> Order { - case int.compare(using(hand1), using(hand2)) { - Eq -> compare_top_card(hand1.cards, hand2.cards) - other -> other - } -} - -fn compare_top_card(cards1: List(Int), cards2: List(Int)) -> Order { - use <- bool.guard(cards1 == [] || cards2 == [], Eq) - let assert [c1, ..rest1] = cards1 - let assert [c2, ..rest2] = cards2 - case int.compare(c1, c2) { - Eq -> compare_top_card(rest1, rest2) - other -> other - } -} - -fn part(input: String, comparator: fn(Hand, Hand) -> Order) { - input - |> string.split("\n") - |> list.map(parse_hand) - |> list.sort(comparator) - |> list.index_map(fn(i, h) { { i + 1 } * h.wager }) - |> int.sum - |> string.inspect -} - -// Part 1 ------------------------------------------------------------------------------------------ - -pub fn part1(input: String) { - part(input, compare_without_wilds) -} - -fn compare_without_wilds(hand1: Hand, hand2: Hand) { - compare_hands(hand1, hand2, classify_hand) -} - -// Part 2 ------------------------------------------------------------------------------------------ - -pub fn part2(input: String) { - part(string.replace(input, "J", "*"), compare_hands_considering_jokers) -} - -fn find_best_joker_substitution(hand: Hand) { - use acc, card <- list.fold(list.range(2, 14), Hand([], 0)) - let subbed_cards = { - use c <- list.map(hand.cards) - case c { - 1 -> card - other -> other - } - } - let subbed_hand = Hand(..hand, cards: subbed_cards) - case compare_hands(acc, subbed_hand, classify_hand) { - Lt -> subbed_hand - _ -> acc - } -} - -fn compare_hands_considering_jokers(hand1: Hand, hand2: Hand) -> Order { - use hand <- compare_hands(hand1, hand2) - hand - |> find_best_joker_substitution - |> classify_hand -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("7") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day8/.gitignore b/aoc2023/src/day8/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day8/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day8/solve.gleam b/aoc2023/src/day8/solve.gleam deleted file mode 100644 index 6b36e2d..0000000 --- a/aoc2023/src/day8/solve.gleam +++ /dev/null @@ -1,91 +0,0 @@ -import adglent.{First, Second} -import gleam/bool -import gleam/dict.{type Dict} -import gleam/io -import gleam/iterator.{type Iterator, Next} -import gleam/list -import gleam/option.{Some} -import gleam/string -import gleam/regex.{type Match, Match} -import gleam_community/maths/arithmetics - -type Paths { - Paths(to_left: String, to_right: String) -} - -type Maze = - Dict(String, Paths) - -fn parse(input: String) -> #(Iterator(String), Dict(String, Paths)) { - let assert [directions_str, maze_str] = string.split(input, "\n\n") - - let directions = - directions_str - |> string.to_graphemes() - |> iterator.from_list - |> iterator.cycle - - let assert Ok(re) = regex.from_string("(...) = \\((...), (...)\\)") - let maze = - maze_str - |> string.split("\n") - |> list.map(fn(str) { - let assert [Match(submatches: [Some(name), Some(left), Some(right)], ..)] = - regex.scan(re, str) - #(name, Paths(left, right)) - }) - |> dict.from_list - - #(directions, maze) -} - -fn to_next_step( - current: String, - stop_at: String, - count: Int, - directions: Iterator(String), - maze: Maze, -) -> Int { - use <- bool.guard(string.ends_with(current, stop_at), count) - let assert Next(next_direction, rest_directions) = iterator.step(directions) - let assert Ok(paths) = dict.get(maze, current) - case next_direction { - "L" -> paths.to_left - "R" -> paths.to_right - _ -> panic as "bad direction" - } - |> to_next_step(stop_at, count + 1, rest_directions, maze) -} - -pub fn part1(input: String) -> Int { - let #(directions, maze) = parse(input) - - to_next_step("AAA", "ZZZ", 0, directions, maze) -} - -pub fn part2(input: String) -> Int { - let #(directions, maze) = parse(input) - - use acc, name <- list.fold(dict.keys(maze), 1) - case string.ends_with(name, "A") { - False -> acc - True -> - to_next_step(name, "Z", 0, directions, maze) - |> arithmetics.lcm(acc) - } -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("8") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/day9/.gitignore b/aoc2023/src/day9/.gitignore deleted file mode 100644 index ae40cea..0000000 --- a/aoc2023/src/day9/.gitignore +++ /dev/null @@ -1 +0,0 @@ -input.txt
\ No newline at end of file diff --git a/aoc2023/src/day9/solve.gleam b/aoc2023/src/day9/solve.gleam deleted file mode 100644 index a2cc7ae..0000000 --- a/aoc2023/src/day9/solve.gleam +++ /dev/null @@ -1,70 +0,0 @@ -import adglent.{First, Second} -import gleam/io -import gleam/list -import gleam/string -import gleam/int - -fn parse(input: String, backwards backwards: Bool) -> List(List(Int)) { - use line <- list.map(string.split(input, "\n")) - use n_str <- list.map(maybe_backwards(string.split(line, " "), backwards)) - let assert Ok(n) = int.parse(n_str) - n -} - -fn maybe_backwards(xs: List(a), backwards: Bool) -> List(a) { - case backwards { - False -> list.reverse(xs) - True -> xs - } -} - -fn is_constant(ns: List(Int)) -> Bool { - case list.unique(ns) { - [_] -> True - _ -> False - } -} - -fn take_derivative(ns: List(Int)) -> List(Int) { - ns - |> list.window_by_2 - |> list.map(fn(tup) { tup.0 - tup.1 }) -} - -fn extrapolate(ns: List(Int)) { - case is_constant(ns), ns { - True, [n, ..] -> n - False, [n, ..] -> n + extrapolate(take_derivative(ns)) - _, _ -> panic as "list empty when it shouldn't be" - } -} - -fn part(input: String, backwards backwards: Bool) { - input - |> parse(backwards: backwards) - |> list.fold(0, fn(acc, ns) { extrapolate(ns) + acc }) - |> string.inspect -} - -pub fn part1(input: String) { - part(input, backwards: False) -} - -pub fn part2(input: String) { - part(input, backwards: True) -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("9") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} diff --git a/aoc2023/src/utilities/array2d.gleam b/aoc2023/src/utilities/array2d.gleam deleted file mode 100644 index 8538129..0000000 --- a/aoc2023/src/utilities/array2d.gleam +++ /dev/null @@ -1,74 +0,0 @@ -import gleam/list -import gleam/dict.{type Dict} -import gleam/string -import gleam/int -import gleam/result - -pub type Posn { - Posn(r: Int, c: Int) -} - -pub type Array2D(a) = - Dict(Posn, a) - -pub fn add_posns(p1: Posn, p2: Posn) -> Posn { - case p1, p2 { - Posn(r1, c1), Posn(r2, c2) -> Posn(r1 + r2, c1 + c2) - } -} - -pub fn ortho_neighbors(p: Posn) -> List(Posn) { - let Posn(r, c) = p - [Posn(r + 1, c), Posn(r - 1, c), Posn(r, c + 1), Posn(r, c - 1)] -} - -pub fn to_2d_array(xss: List(List(a))) -> Array2D(a) { - to_2d_array_using(xss, fn(x) { Ok(x) }) -} - -pub fn to_2d_array_using( - xss: List(List(a)), - f: fn(a) -> Result(b, Nil), -) -> Array2D(b) { - { - use r, row <- list.index_map(xss) - use c, cell <- list.index_map(row) - case f(cell) { - Ok(contents) -> Ok(#(Posn(r, c), contents)) - Error(Nil) -> Error(Nil) - } - } - |> list.flatten - |> result.values - |> dict.from_list -} - -pub fn to_2d_intarray(xss: List(List(String))) -> Array2D(Int) { - { - use r, row <- list.index_map(xss) - use c, cell <- list.index_map(row) - let assert Ok(n) = int.parse(cell) - #(Posn(r, c), n) - } - |> list.flatten - |> dict.from_list -} - -pub fn to_list_of_lists(str: String) -> List(List(String)) { - str - |> string.split("\n") - |> list.map(string.to_graphemes) -} - -pub fn parse_grid(str: String) -> Array2D(String) { - parse_grid_using(str, fn(x) { Ok(x) }) -} - -pub fn parse_grid_using( - str: String, - f: fn(String) -> Result(a, Nil), -) -> Array2D(a) { - str - |> to_list_of_lists - |> to_2d_array_using(f) -} diff --git a/aoc2023/src/utilities/memo.gleam b/aoc2023/src/utilities/memo.gleam deleted file mode 100644 index b06d8fd..0000000 --- a/aoc2023/src/utilities/memo.gleam +++ /dev/null @@ -1,57 +0,0 @@ -import gleam/dict.{type Dict} -import gleam/otp/actor.{type Next, Continue, Stop} -import gleam/erlang/process.{type Subject, Normal} -import gleam/option.{None} - -const timeout = 1000 - -type Message(k, v) { - Shutdown - Get(key: k, client: Subject(Result(v, Nil))) - Set(key: k, value: v) -} - -type Server(k, v) = - Subject(Message(k, v)) - -pub opaque type Cache(k, v) { - Cache(server: Server(k, v)) -} - -fn handle_message( - message: Message(k, v), - dict: Dict(k, v), -) -> Next(Message(k, v), Dict(k, v)) { - case message { - Shutdown -> Stop(Normal) - Get(key, client) -> { - process.send(client, dict.get(dict, key)) - Continue(dict, None) - } - Set(key, value) -> Continue(dict.insert(dict, key, value), None) - } -} - -pub fn create(apply fun: fn(Cache(k, v)) -> t) -> t { - let assert Ok(server) = actor.start(dict.new(), handle_message) - let result = fun(Cache(server)) - process.send(server, Shutdown) - result -} - -pub fn set(in cache: Cache(k, v), for key: k, insert value: v) -> Nil { - process.send(cache.server, Set(key, value)) -} - -pub fn get(from cache: Cache(k, v), fetch key: k) -> Result(v, Nil) { - process.call(cache.server, fn(c) { Get(key, c) }, timeout) -} - -pub fn memoize(with cache: Cache(k, v), this key: k, apply fun: fn() -> v) -> v { - let result = case get(from: cache, fetch: key) { - Ok(value) -> value - Error(Nil) -> fun() - } - set(in: cache, for: key, insert: result) - result -} diff --git a/aoc2023/src/utilities/prioqueue.gleam b/aoc2023/src/utilities/prioqueue.gleam deleted file mode 100644 index abf21b9..0000000 --- a/aoc2023/src/utilities/prioqueue.gleam +++ /dev/null @@ -1,64 +0,0 @@ -//adapted from https://github.com/byronanderson/adventofcode2021/blob/main/gleam_advent/src/priority_queue.gleam - -import gleam/dict.{type Dict} - -type Ref - -@external(erlang, "erlang", "make_ref") -fn make_ref() -> Ref - -type PQueue(a) - -pub opaque type PriorityQueue(a) { - PriorityQueue(queue: PQueue(#(a, Ref)), refs: Dict(a, Ref)) -} - -type OutResult(a) { - Empty - Value(a, Int) -} - -@external(erlang, "pqueue2", "new") -fn new_() -> PQueue(a) - -@external(erlang, "pqueue2", "in") -fn insert_(item: a, prio: Int, queue: PQueue(a)) -> PQueue(a) - -@external(erlang, "pqueue2", "pout") -fn pop_(queue: PQueue(a)) -> #(OutResult(a), PQueue(a)) - -pub fn new() -> PriorityQueue(a) { - PriorityQueue(queue: new_(), refs: dict.new()) -} - -pub fn insert( - queue: PriorityQueue(a), - value: a, - priority: Int, -) -> PriorityQueue(a) { - let ref = make_ref() - - let refs = - queue.refs - |> dict.insert(value, ref) - - PriorityQueue( - refs: refs, - queue: insert_(#(value, ref), priority, queue.queue), - ) -} - -pub fn pop(queue: PriorityQueue(a)) -> Result(#(a, PriorityQueue(a)), Nil) { - case pop_(queue.queue) { - #(Value(#(value, ref), _priority), pqueue) -> { - let assert Ok(recently_enqueued_ref) = dict.get(queue.refs, value) - case recently_enqueued_ref == ref { - True -> Ok(#(value, PriorityQueue(refs: queue.refs, queue: pqueue))) - False -> pop(PriorityQueue(refs: queue.refs, queue: pqueue)) - } - } - #(Empty, _pqueue) -> { - Error(Nil) - } - } -} diff --git a/aoc2023/test/aoc2023_test.gleam b/aoc2023/test/aoc2023_test.gleam deleted file mode 100644 index 2b696a4..0000000 --- a/aoc2023/test/aoc2023_test.gleam +++ /dev/null @@ -1,5 +0,0 @@ -import showtime - -pub fn main() { - showtime.main() -} diff --git a/aoc2023/test/day1/day1_test.gleam b/aoc2023/test/day1/day1_test.gleam deleted file mode 100644 index 374653c..0000000 --- a/aoc2023/test/day1/day1_test.gleam +++ /dev/null @@ -1,57 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day1/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( - "1abc2 -pqr3stu8vwx -a1b2c3d4e5f -treb7uchet", - "142", - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "two1nine -eightwothree -abcone2threexyz -xtwone3four -4nineeightseven2 -zoneight234 -7pqrstsixteen", - "281", - ), -] - -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) -} diff --git a/aoc2023/test/day10/day10_test.gleam b/aoc2023/test/day10/day10_test.gleam deleted file mode 100644 index be9d82e..0000000 --- a/aoc2023/test/day10/day10_test.gleam +++ /dev/null @@ -1,60 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day10/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( - "7-F7- -.FJ|7 -SJLL7 -|F--J -LJ.LJ", - "8", - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "........... -.S-------7. -.|F-----7|. -.||OOOOO||. -.||OOOOO||. -.|L-7OF-J|. -.|II|O|II|. -.L--JOL--J. -.....O.....", - "4", - ), -] - -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) -} diff --git a/aoc2023/test/day11/day11_test.gleam b/aoc2023/test/day11/day11_test.gleam deleted file mode 100644 index 8bb8c06..0000000 --- a/aoc2023/test/day11/day11_test.gleam +++ /dev/null @@ -1,66 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day11/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( - "...#...... -.......#.. -#......... -.......... -......#... -.#........ -.........# -.......... -.......#.. -#...#.....", - "374", - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "...#...... -.......#.. -#......... -.......... -......#... -.#........ -.........# -.......... -.......#.. -#...#.....", - "8410", - ), -] - -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) -} diff --git a/aoc2023/test/day12/day12_test.gleam b/aoc2023/test/day12/day12_test.gleam deleted file mode 100644 index 3daf0e9..0000000 --- a/aoc2023/test/day12/day12_test.gleam +++ /dev/null @@ -1,48 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day12/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( - "???.### 1,1,3 -.??..??...?##. 1,1,3 -?#?#?#?#?#?#?#? 1,3,1,6 -????.#...#... 4,1,1 -????.######..#####. 1,6,5 -?###???????? 3,2,1", - "21", - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [] - -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) -} diff --git a/aoc2023/test/day13/day13_test.gleam b/aoc2023/test/day13/day13_test.gleam deleted file mode 100644 index 7c65bed..0000000 --- a/aoc2023/test/day13/day13_test.gleam +++ /dev/null @@ -1,76 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day13/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( - "#.##..##. -..#.##.#. -##......# -##......# -..#.##.#. -..##..##. -#.#.##.#. - -#...##..# -#....#..# -..##..### -#####.##. -#####.##. -..##..### -#....#..#", - "405", - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "#.##..##. -..#.##.#. -##......# -##......# -..#.##.#. -..##..##. -#.#.##.#. - -#...##..# -#....#..# -..##..### -#####.##. -#####.##. -..##..### -#....#..#", - "400", - ), -] - -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) -} diff --git a/aoc2023/test/day14/day14_test.gleam b/aoc2023/test/day14/day14_test.gleam deleted file mode 100644 index 8efa74e..0000000 --- a/aoc2023/test/day14/day14_test.gleam +++ /dev/null @@ -1,66 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day14/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( - "O....#.... -O.OO#....# -.....##... -OO.#O....O -.O.....O#. -O.#..O.#.# -..O..#O..O -.......O.. -#....###.. -#OO..#....", - "136", - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "O....#.... -O.OO#....# -.....##... -OO.#O....O -.O.....O#. -O.#..O.#.# -..O..#O..O -.......O.. -#....###.. -#OO..#....", - "64", - ), -] - -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) -} diff --git a/aoc2023/test/day15/day15_test.gleam b/aoc2023/test/day15/day15_test.gleam deleted file mode 100644 index 0ecaecc..0000000 --- a/aoc2023/test/day15/day15_test.gleam +++ /dev/null @@ -1,42 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day15/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("rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7", "1320"), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example("rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7", "145"), -] - -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) -} diff --git a/aoc2023/test/day16/day16_test.gleam b/aoc2023/test/day16/day16_test.gleam deleted file mode 100644 index 036504e..0000000 --- a/aoc2023/test/day16/day16_test.gleam +++ /dev/null @@ -1,66 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day16/solve - -type Problem1AnswerType = - Int - -type Problem2AnswerType = - Int - -/// Add examples for part 1 here: -/// ```gleam -///const part1_examples: List(Example(Problem1AnswerType)) = [Example("some input", "")] -/// ``` -const part1_examples: List(Example(Problem1AnswerType)) = [ - Example( - ".|...\\.... -|.-.\\..... -.....|-... -........|. -.......... -.........\\ -..../.\\\\.. -.-.-/..|.. -.|....-|.\\ -..//.|....", - 46, - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - ".|...\\.... -|.-.\\..... -.....|-... -........|. -.......... -.........\\ -..../.\\\\.. -.-.-/..|.. -.|....-|.\\ -..//.|....", - 51, - ), -] - -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) -} diff --git a/aoc2023/test/day17/day17_test.gleam b/aoc2023/test/day17/day17_test.gleam deleted file mode 100644 index 2ce48e2..0000000 --- a/aoc2023/test/day17/day17_test.gleam +++ /dev/null @@ -1,54 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day17/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( - "2413432311323 -3215453535623 -3255245654254 -3446585845452 -4546657867536 -1438598798454 -4457876987766 -3637877979653 -4654967986887 -4564679986453 -1224686865563 -2546548887735 -4322674655533", - "102", - ), -] - -// /// ``` -// const part2_examples: List(Example(Problem2AnswerType)) = [] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -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) -// } diff --git a/aoc2023/test/day18/day18_test.gleam b/aoc2023/test/day18/day18_test.gleam deleted file mode 100644 index 7b510c8..0000000 --- a/aoc2023/test/day18/day18_test.gleam +++ /dev/null @@ -1,74 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day18/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( - "R 6 (#70c710) -D 5 (#0dc571) -L 2 (#5713f0) -D 2 (#d2c081) -R 2 (#59c680) -D 2 (#411b91) -L 5 (#8ceee2) -U 2 (#caa173) -L 1 (#1b58a2) -U 2 (#caa171) -R 2 (#7807d2) -U 3 (#a77fa3) -L 2 (#015232) -U 2 (#7a21e3)", - "62", - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "R 6 (#70c710) -D 5 (#0dc571) -L 2 (#5713f0) -D 2 (#d2c081) -R 2 (#59c680) -D 2 (#411b91) -L 5 (#8ceee2) -U 2 (#caa173) -L 1 (#1b58a2) -U 2 (#caa171) -R 2 (#7807d2) -U 3 (#a77fa3) -L 2 (#015232) -U 2 (#7a21e3)", - "952408144115", - ), -] - -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) -} diff --git a/aoc2023/test/day19/day19_test.gleam b/aoc2023/test/day19/day19_test.gleam deleted file mode 100644 index c911de5..0000000 --- a/aoc2023/test/day19/day19_test.gleam +++ /dev/null @@ -1,80 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day19/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( - "px{a<2006:qkq,m>2090:A,rfg} -pv{a>1716:R,A} -lnx{m>1548:A,A} -rfg{s<537:gd,x>2440:R,A} -qs{s>3448:A,lnx} -qkq{x<1416:A,crn} -crn{x>2662:A,R} -in{s<1351:px,qqz} -qqz{s>2770:qs,m<1801:hdj,R} -gd{a>3333:R,R} -hdj{m>838:A,pv} - -{x=787,m=2655,a=1222,s=2876} -{x=1679,m=44,a=2067,s=496} -{x=2036,m=264,a=79,s=2244} -{x=2461,m=1339,a=466,s=291} -{x=2127,m=1623,a=2188,s=1013}", - "19114", - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "px{a<2006:qkq,m>2090:A,rfg} -pv{a>1716:R,A} -lnx{m>1548:A,A} -rfg{s<537:gd,x>2440:R,A} -qs{s>3448:A,lnx} -qkq{x<1416:A,crn} -crn{x>2662:A,R} -in{s<1351:px,qqz} -qqz{s>2770:qs,m<1801:hdj,R} -gd{a>3333:R,R} -hdj{m>838:A,pv} - -{x=787,m=2655,a=1222,s=2876} -{x=1679,m=44,a=2067,s=496} -{x=2036,m=264,a=79,s=2244} -{x=2461,m=1339,a=466,s=291} -{x=2127,m=1623,a=2188,s=1013}", - "167409079868000", - ), -] - -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) -} diff --git a/aoc2023/test/day2/day2_test.gleam b/aoc2023/test/day2/day2_test.gleam deleted file mode 100644 index 28a65da..0000000 --- a/aoc2023/test/day2/day2_test.gleam +++ /dev/null @@ -1,57 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day2/solve - -type Problem1AnswerType = - Int - -type Problem2AnswerType = - Int - -/// Add examples for part 1 here: -/// ```gleam -///const part1_examples: List(Example(Problem1AnswerType)) = [Example("some input", "")] -/// ``` -const part1_examples: List(Example(Problem1AnswerType)) = [ - Example( - "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green -Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue -Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red -Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red -Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green", - 8, - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green -Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue -Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red -Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red -Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green", - 2286, - ), - Example("Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green", 48), -] - -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) -} diff --git a/aoc2023/test/day20/day20_test.gleam b/aoc2023/test/day20/day20_test.gleam deleted file mode 100644 index 9b79b05..0000000 --- a/aoc2023/test/day20/day20_test.gleam +++ /dev/null @@ -1,55 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day20/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( - "broadcaster -> a, b, c -%a -> b -%b -> c -%c -> inv -&inv -> a", - "32000000", - ), - Example( - "broadcaster -> a -%a -> inv, con -&inv -> b -%b -> con -&con -> output -output -> ", - "11687500", - ), -] - -// const part2_examples: List(Example(Problem2AnswerType)) = [] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -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) -// } diff --git a/aoc2023/test/day22/day22_test.gleam b/aoc2023/test/day22/day22_test.gleam deleted file mode 100644 index 3f8c0ca..0000000 --- a/aoc2023/test/day22/day22_test.gleam +++ /dev/null @@ -1,60 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day22/solve - -type Problem1AnswerType = - Int - -type Problem2AnswerType = - Int - -/// Add examples for part 1 here: -/// ```gleam -///const part1_examples: List(Example(Problem1AnswerType)) = [Example("some input", "")] -/// ``` -const part1_examples: List(Example(Problem1AnswerType)) = [ - Example( - "1,0,1~1,2,1 -0,0,2~2,0,2 -0,2,3~2,2,3 -0,0,4~0,2,4 -2,0,5~2,2,5 -0,1,6~2,1,6 -1,1,8~1,1,9", - 5, - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "1,0,1~1,2,1 -0,0,2~2,0,2 -0,2,3~2,2,3 -0,0,4~0,2,4 -2,0,5~2,2,5 -0,1,6~2,1,6 -1,1,8~1,1,9", - 7, - ), -] - -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) -} diff --git a/aoc2023/test/day23/day23_test.gleam b/aoc2023/test/day23/day23_test.gleam deleted file mode 100644 index 206571c..0000000 --- a/aoc2023/test/day23/day23_test.gleam +++ /dev/null @@ -1,92 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day23/solve - -type Problem1AnswerType = - Int - -type Problem2AnswerType = - Int - -/// Add examples for part 1 here: -/// ```gleam -///const part1_examples: List(Example(Problem1AnswerType)) = [Example("some input", "")] -/// ``` -const part1_examples: List(Example(Problem1AnswerType)) = [ - Example( - "#.##################### -#.......#########...### -#######.#########.#.### -###.....#.>.>.###.#.### -###v#####.#v#.###.#.### -###.>...#.#.#.....#...# -###v###.#.#.#########.# -###...#.#.#.......#...# -#####.#.#.#######.#.### -#.....#.#.#.......#...# -#.#####.#.#.#########v# -#.#...#...#...###...>.# -#.#.#v#######v###.###v# -#...#.>.#...>.>.#.###.# -#####v#.#.###v#.#.###.# -#.....#...#...#.#.#...# -#.#########.###.#.#.### -#...###...#...#...#.### -###.###.#.###v#####v### -#...#...#.#.>.>.#.>.### -#.###.###.#.###.#.#v### -#.....###...###...#...# -#####################.#", - 94, - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "#.##################### -#.......#########...### -#######.#########.#.### -###.....#.>.>.###.#.### -###v#####.#v#.###.#.### -###.>...#.#.#.....#...# -###v###.#.#.#########.# -###...#.#.#.......#...# -#####.#.#.#######.#.### -#.....#.#.#.......#...# -#.#####.#.#.#########v# -#.#...#...#...###...>.# -#.#.#v#######v###.###v# -#...#.>.#...>.>.#.###.# -#####v#.#.###v#.#.###.# -#.....#...#...#.#.#...# -#.#########.###.#.#.### -#...###...#...#...#.### -###.###.#.###v#####v### -#...#...#.#.>.>.#.>.### -#.###.###.#.###.#.#v### -#.....###...###...#...# -#####################.#", - 154, - ), -] - -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) -} diff --git a/aoc2023/test/day3/day3_test.gleam b/aoc2023/test/day3/day3_test.gleam deleted file mode 100644 index 30e17a9..0000000 --- a/aoc2023/test/day3/day3_test.gleam +++ /dev/null @@ -1,66 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day3/solve - -type Problem1AnswerType = - Int - -type Problem2AnswerType = - Int - -/// Add examples for part 1 here: -/// ```gleam -///const part1_examples: List(Example(Problem1AnswerType)) = [Example("some input", "")] -/// ``` -const part1_examples: List(Example(Problem1AnswerType)) = [ - Example( - "467..114.. -...*...... -..35..633. -......#... -617*...... -.....+.58. -..592..... -......755. -...$.*.... -.664.598..", - 4361, - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "467..114.. -...*...... -..35..633. -......#... -617*...... -.....+.58. -..592..... -......755. -...$.*.... -.664.598..", - 467_835, - ), -] - -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) -} diff --git a/aoc2023/test/day4/day4_test.gleam b/aoc2023/test/day4/day4_test.gleam deleted file mode 100644 index 324fe36..0000000 --- a/aoc2023/test/day4/day4_test.gleam +++ /dev/null @@ -1,58 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day4/solve - -type Problem1AnswerType = - Int - -type Problem2AnswerType = - Int - -/// 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) -} diff --git a/aoc2023/test/day5/day5_test.gleam b/aoc2023/test/day5/day5_test.gleam deleted file mode 100644 index 86a8692..0000000 --- a/aoc2023/test/day5/day5_test.gleam +++ /dev/null @@ -1,112 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day5/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( - "seeds: 79 14 55 13 - -seed-to-soil map: -50 98 2 -52 50 48 - -soil-to-fertilizer map: -0 15 37 -37 52 2 -39 0 15 - -fertilizer-to-water map: -49 53 8 -0 11 42 -42 0 7 -57 7 4 - -water-to-light map: -88 18 7 -18 25 70 - -light-to-temperature map: -45 77 23 -81 45 19 -68 64 13 - -temperature-to-humidity map: -0 69 1 -1 0 69 - -humidity-to-location map: -60 56 37 -56 93 4", - "35", - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "seeds: 79 14 55 13 - -seed-to-soil map: -50 98 2 -52 50 48 - -soil-to-fertilizer map: -0 15 37 -37 52 2 -39 0 15 - -fertilizer-to-water map: -49 53 8 -0 11 42 -42 0 7 -57 7 4 - -water-to-light map: -88 18 7 -18 25 70 - -light-to-temperature map: -45 77 23 -81 45 19 -68 64 13 - -temperature-to-humidity map: -0 69 1 -1 0 69 - -humidity-to-location map: -60 56 37 -56 93 4", - "46", - ), -] - -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) -} diff --git a/aoc2023/test/day6/day6_test.gleam b/aoc2023/test/day6/day6_test.gleam deleted file mode 100644 index c551993..0000000 --- a/aoc2023/test/day6/day6_test.gleam +++ /dev/null @@ -1,50 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day6/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( - "Time: 7 15 30 -Distance: 9 40 200", - "288", - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "Time: 7 15 30 -Distance: 9 40 200", - "71503", - ), -] - -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) -} diff --git a/aoc2023/test/day7/day7_test.gleam b/aoc2023/test/day7/day7_test.gleam deleted file mode 100644 index f7f8454..0000000 --- a/aoc2023/test/day7/day7_test.gleam +++ /dev/null @@ -1,56 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day7/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( - "32T3K 765 -T55J5 684 -KK677 28 -KTJJT 220 -QQQJA 483", - "6440", - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "32T3K 765 -T55J5 684 -KK677 28 -KTJJT 220 -QQQJA 483", - "5905", - ), -] - -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) -} diff --git a/aoc2023/test/day8/day8_test.gleam b/aoc2023/test/day8/day8_test.gleam deleted file mode 100644 index 2cd499a..0000000 --- a/aoc2023/test/day8/day8_test.gleam +++ /dev/null @@ -1,61 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day8/solve - -type Problem1AnswerType = - Int - -type Problem2AnswerType = - Int - -/// Add examples for part 1 here: -/// ```gleam -///const part1_examples: List(Example(Problem1AnswerType)) = [Example("some input", "")] -/// ``` -const part1_examples: List(Example(Problem1AnswerType)) = [ - Example( - "LLR - -AAA = (BBB, BBB) -BBB = (AAA, ZZZ) -ZZZ = (ZZZ, ZZZ)", - 6, - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "LR - -11A = (11B, XXX) -11B = (XXX, 11Z) -11Z = (11B, XXX) -22A = (22B, XXX) -22B = (22C, 22C) -22C = (22Z, 22Z) -22Z = (22B, 22B) -XXX = (XXX, XXX)", - 6, - ), -] - -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) -} diff --git a/aoc2023/test/day9/day9_test.gleam b/aoc2023/test/day9/day9_test.gleam deleted file mode 100644 index 84fd3ba..0000000 --- a/aoc2023/test/day9/day9_test.gleam +++ /dev/null @@ -1,52 +0,0 @@ -import gleam/list -import showtime/tests/should -import adglent.{type Example, Example} -import day9/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( - "0 3 6 9 12 15 -1 3 6 10 15 21 -10 13 16 21 30 45", - "114", - ), -] - -/// Add examples for part 2 here: -/// ```gleam -///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] -/// ``` -const part2_examples: List(Example(Problem2AnswerType)) = [ - Example( - "0 3 6 9 12 15 -1 3 6 10 15 21 -10 13 16 21 30 45", - "2", - ), -] - -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) -} |