Day 2 Part 1

This commit is contained in:
April Eaton 2025-12-02 15:37:19 +01:00
parent 32e35cd824
commit ccee86dc80
9 changed files with 279 additions and 0 deletions

23
day_2/.github/workflows/test.yml vendored Normal file
View file

@ -0,0 +1,23 @@
name: test
on:
push:
branches:
- master
- main
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: erlef/setup-beam@v1
with:
otp-version: "28"
gleam-version: "1.13.0"
rebar3-version: "3"
# elixir-version: "1"
- run: gleam deps download
- run: gleam test
- run: gleam format --check src test

4
day_2/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
*.beam
*.ez
/build
erl_crash.dump

24
day_2/README.md Normal file
View file

@ -0,0 +1,24 @@
# day_2
[![Package Version](https://img.shields.io/hexpm/v/day_2)](https://hex.pm/packages/day_2)
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/day_2/)
```sh
gleam add day_2@1
```
```gleam
import day_2
pub fn main() -> Nil {
// TODO: An example of the project in use
}
```
Further documentation can be found at <https://hexdocs.pm/day_2>.
## Development
```sh
gleam run # Run the project
gleam test # Run the tests
```

20
day_2/gleam.toml Normal file
View file

@ -0,0 +1,20 @@
name = "day_2"
version = "1.0.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 = "", repo = "" }
# links = [{ title = "Website", href = "" }]
#
# For a full reference of all the available options, you can have a look at
# https://gleam.run/writing-gleam/gleam-toml/.
[dependencies]
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
simplifile = ">= 2.3.1 and < 3.0.0"
[dev-dependencies]
gleeunit = ">= 1.0.0 and < 2.0.0"

1
day_2/input.txt Normal file
View file

@ -0,0 +1 @@
24-46,124420-259708,584447-720297,51051-105889,6868562486-6868811237,55-116,895924-1049139,307156-347325,372342678-372437056,1791-5048,3172595555-3172666604,866800081-866923262,5446793-5524858,6077-10442,419-818,57540345-57638189,2143479-2274980,683602048-683810921,966-1697,56537997-56591017,1084127-1135835,1-14,2318887654-2318959425,1919154462-1919225485,351261-558210,769193-807148,4355566991-4355749498,809094-894510,11116-39985,9898980197-9898998927,99828221-99856128,9706624-9874989,119-335

14
day_2/manifest.toml Normal file
View file

@ -0,0 +1,14 @@
# This file was generated by Gleam
# You typically do not need to edit this file
packages = [
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
{ name = "gleam_stdlib", version = "0.67.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "6368313DB35963DC02F677A513BB0D95D58A34ED0A9436C8116820BF94BE3511" },
{ name = "gleeunit", version = "1.9.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "DA9553CE58B67924B3C631F96FE3370C49EB6D6DC6B384EC4862CC4AAA718F3C" },
{ name = "simplifile", version = "2.3.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "957E0E5B75927659F1D2A1B7B75D7B9BA96FAA8D0C53EA71C4AD9CD0C6B848F6" },
]
[requirements]
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
simplifile = { version = ">= 2.3.1 and < 3.0.0" }

77
day_2/src/day_2.gleam Normal file
View file

@ -0,0 +1,77 @@
import gleam/int
import gleam/io
import gleam/list
import gleam/result
import gleam/string
import simplifile
pub fn digits(x: Int, base: Int) -> Result(List(Int), Nil) {
case base < 2 {
True -> Error(Nil)
False -> Ok(digits_loop(x, base, []))
}
}
fn digits_loop(x: Int, base: Int, acc: List(Int)) -> List(Int) {
case int.absolute_value(x) < base {
True -> [x, ..acc]
False -> digits_loop(x / base, base, [x % base, ..acc])
}
}
pub fn int_to_half_length_pair(i: Int) -> Result(#(List(Int), List(Int)), Nil) {
digits(i, 10)
|> result.map(fn(l) { list.split(list: l, at: list.length(l) / 2) })
}
pub fn int_is_doubled_string(i: Int) -> Result(Bool, Nil) {
int_to_half_length_pair(i)
|> result.map(fn(p) {
let #(start, end) = p
start == end
})
}
pub fn filter_for_bad_ids(ids: List(Int)) -> List(Int) {
list.filter(ids, fn(id) { int_is_doubled_string(id) |> result.unwrap(False) })
}
pub fn ranges_to_list_of_ids(ids: List(#(Int, Int))) -> List(Int) {
list.map(ids, fn(id_pair) {
let #(first, last) = id_pair
list.range(first, last)
})
|> list.flatten
}
pub fn ranges_to_bad_ids(ids: List(#(Int, Int))) -> List(Int) {
ranges_to_list_of_ids(ids) |> filter_for_bad_ids
}
pub fn sum_of_bad_ids(ids: List(#(Int, Int))) -> Int {
ranges_to_bad_ids(ids) |> list.fold(0, int.add)
}
pub fn range_string_to_int_pair(s: String) -> #(Int, Int) {
let assert [a, b] =
string.split(s, on: "-")
|> list.map(int.parse)
|> list.map(result.unwrap(_, 0))
#(a, b)
}
pub fn list_of_ranges_to_int_pairs(s: String) -> List(#(Int, Int)) {
string.split(s, on: ",") |> list.map(range_string_to_int_pair)
}
pub fn file_to_sum_of_bad_ids(f: String) -> Int {
simplifile.read(f)
|> result.unwrap("")
|> string.trim
|> list_of_ranges_to_int_pairs
|> sum_of_bad_ids
}
pub fn main() -> Nil {
file_to_sum_of_bad_ids("input.txt") |> int.to_string |> io.println
}

View file

@ -0,0 +1 @@
11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124

115
day_2/test/day_2_test.gleam Normal file
View file

@ -0,0 +1,115 @@
import day_2
import gleeunit
pub fn main() -> Nil {
gleeunit.main()
}
pub fn trivial_digits_test() {
assert day_2.int_to_half_length_pair(1) == Ok(#([], [1]))
}
pub fn two_digit_number_test() {
assert day_2.int_to_half_length_pair(12) == Ok(#([1], [2]))
}
pub fn ten_digit_number_test() {
assert day_2.int_to_half_length_pair(1_234_567_890)
== Ok(#([1, 2, 3, 4, 5], [6, 7, 8, 9, 0]))
}
pub fn eleven_digit_number_test() {
assert day_2.int_to_half_length_pair(12_345_678_901)
== Ok(#([1, 2, 3, 4, 5], [6, 7, 8, 9, 0, 1]))
}
pub fn bad_number_test() {
assert day_2.int_is_doubled_string(123_123) == Ok(True)
}
pub fn good_number_test() {
assert day_2.int_is_doubled_string(123_456) == Ok(False)
}
pub fn list_of_ranges_test() {
assert day_2.ranges_to_list_of_ids([#(10, 20), #(30, 40)])
== [
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
]
}
pub fn ranges_with_bad_ids_test() {
assert day_2.ranges_to_bad_ids([
#(11, 22),
#(95, 115),
#(998, 1012),
#(1_188_511_880, 1_188_511_890),
#(222_220, 222_224),
#(1_698_522, 1_698_528),
#(446_443, 446_449),
#(38_593_856, 38_593_862),
])
== [11, 22, 99, 1010, 1_188_511_885, 222_222, 446_446, 38_593_859]
}
pub fn sum_of_bad_ids_test() {
assert day_2.sum_of_bad_ids([
#(11, 22),
#(95, 115),
#(998, 1012),
#(1_188_511_880, 1_188_511_890),
#(222_220, 222_224),
#(1_698_522, 1_698_528),
#(446_443, 446_449),
#(38_593_856, 38_593_862),
])
== 1_227_775_554
}
pub fn range_parse_test() {
assert day_2.range_string_to_int_pair("111-333") == #(111, 333)
}
pub fn ranges_parse_test() {
let ranges =
"11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124"
assert day_2.list_of_ranges_to_int_pairs(ranges)
== [
#(11, 22),
#(95, 115),
#(998, 1012),
#(1_188_511_880, 1_188_511_890),
#(222_220, 222_224),
#(1_698_522, 1_698_528),
#(446_443, 446_449),
#(38_593_856, 38_593_862),
#(565_653, 565_659),
#(824_824_821, 824_824_827),
#(2_121_212_118, 2_121_212_124),
]
}
pub fn calibrate() {
assert day_2.file_to_sum_of_bad_ids("test/calibration.txt") == 1_227_775_554
}