Skip to content

Commit f260e4e

Browse files
committed
that didn't work
1 parent a489167 commit f260e4e

File tree

6 files changed

+282
-3
lines changed

6 files changed

+282
-3
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Advent of Code 2025
22

33
[![Tests](https://github.com/devries/advent_of_code_2025/actions/workflows/test.yml/badge.svg)](https://github.com/devries/advent_of_code_2025/actions/workflows/test.yml)
4-
[![Stars: 17](https://img.shields.io/badge/⭐_Stars-17-yellow)](https://adventofcode.com/2025)
4+
[![Stars: 18](https://img.shields.io/badge/⭐_Stars-18-yellow)](https://adventofcode.com/2025)
55

66
This year will be my second year doing Advent of Code in [Gleam](https://gleam.run).
77
Last year I was still learning the language, and in the past year I have used it
@@ -64,3 +64,9 @@ information.
6464
the corners are inside the figure. It may be that the corners are inside,
6565
but there is a line going through one of the walls. I ran out of time
6666
this morning to work on this and will pick it up later.
67+
68+
- [Day 10](https://adventmfcode.com/2025/day/10): [⭐ solution](src/day010/solution.gleam)
69+
70+
I tried doing part 2 a naive way with some memoization, but it seems like
71+
I still need to work on it. Code was getting very convoluted anyway, not
72+
pretty like the first several days.

gleam.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ glint = ">= 1.2.1 and < 2.0.0"
2222
argv = ">= 1.0.2 and < 2.0.0"
2323
glemplate = ">= 8.1.1 and < 9.0.0"
2424
gleam_yielder = ">= 1.1.0 and < 2.0.0"
25+
gleam_deque = ">= 1.0.0 and < 2.0.0"
2526

2627
[dev-dependencies]
2728
gleeunit = ">= 1.0.0 and < 2.0.0"

inputs

manifest.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ packages = [
66
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
77
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
88
{ name = "gleam_community_colour", version = "2.0.2", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "E34DD2C896AC3792151EDA939DA435FF3B69922F33415ED3C4406C932FBE9634" },
9+
{ name = "gleam_deque", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_deque", source = "hex", outer_checksum = "64D77068931338CF0D0CB5D37522C3E3CCA7CB7D6C5BACB41648B519CC0133C7" },
910
{ name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" },
1011
{ name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" },
1112
{ name = "gleam_otp", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "BA6A294E295E428EC1562DC1C11EA7530DCB981E8359134BEABC8493B7B2258E" },
@@ -25,12 +26,13 @@ packages = [
2526

2627
[requirements]
2728
argv = { version = ">= 1.0.2 and < 2.0.0" }
29+
gleam_deque = { version = ">= 1.0.0 and < 2.0.0" }
2830
gleam_erlang = { version = ">= 1.3.0 and < 2.0.0" }
2931
gleam_otp = { version = ">= 1.2.0 and < 2.0.0" }
3032
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
3133
gleam_time = { version = ">= 1.6.0 and < 2.0.0" }
34+
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
3235
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
3336
glemplate = { version = ">= 8.1.1 and < 9.0.0" }
3437
glint = { version = ">= 1.2.1 and < 2.0.0" }
3538
simplifile = { version = ">= 2.3.1 and < 3.0.0" }
36-
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }

src/day10/solution.gleam

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
import gleam/deque
2+
import gleam/dict
3+
import gleam/erlang/process
4+
import gleam/int
5+
import gleam/io
6+
import gleam/list
7+
import gleam/option
8+
import gleam/result
9+
import gleam/set
10+
import gleam/string
11+
import internal/aoc_utils
12+
import internal/memoize
13+
14+
pub fn main() {
15+
let filename = "inputs/day10.txt"
16+
17+
let lines_result = aoc_utils.read_lines(from: filename)
18+
case lines_result {
19+
Ok(lines) -> {
20+
// If the file was converting into a list of lines
21+
// successfully then run each part of the problem
22+
aoc_utils.run_part_and_print("Part 1", fn() { solve_p1(lines) })
23+
aoc_utils.run_part_and_print("Part 2", fn() { solve_p2(lines) })
24+
}
25+
Error(_) -> io.println("Error reading file")
26+
}
27+
}
28+
29+
// Part 1
30+
pub fn solve_p1(lines: List(String)) -> Result(String, String) {
31+
lines
32+
|> list.map(fn(row) {
33+
let parts = parse(row)
34+
35+
let assert Ok(light_list) = dict.get(parts, "lights")
36+
let assert Ok(light_string) = list.first(light_list)
37+
let lights = parse_lights(light_string)
38+
39+
let assert Ok(button_strings) = dict.get(parts, "buttons")
40+
let buttons = button_strings |> list.map(parse_button)
41+
42+
list.range(1, list.length(buttons))
43+
|> list.fold_until(0, fn(count, pushes) {
44+
let result =
45+
list.combinations(buttons, pushes)
46+
|> list.fold_until(count, fn(c, button_combo) {
47+
case press_buttons(button_combo) == lights {
48+
True -> list.Stop(pushes)
49+
False -> list.Continue(c)
50+
}
51+
})
52+
53+
case result {
54+
0 -> list.Continue(count)
55+
n -> list.Stop(n)
56+
}
57+
})
58+
})
59+
|> int.sum
60+
|> int.to_string
61+
|> Ok
62+
}
63+
64+
// Part 2
65+
pub fn solve_p2(lines: List(String)) -> Result(String, String) {
66+
lines
67+
|> list.map(fn(row) {
68+
let parts = parse(row)
69+
70+
let assert Ok(count_list) = dict.get(parts, "joltages")
71+
let assert Ok(count_string) = list.first(count_list)
72+
let joltages = parse_joltages(count_string)
73+
74+
echo joltages
75+
let assert Ok(button_strings) = dict.get(parts, "buttons")
76+
let buttons =
77+
button_strings
78+
|> list.map(fn(one_button) {
79+
parse_button(one_button) |> button_to_list(list.length(joltages))
80+
})
81+
82+
use cache <- memoize.with_cache()
83+
84+
let queue =
85+
list.fold(buttons, deque.new(), fn(acc, b) {
86+
deque.push_back(acc, #(b, 1))
87+
})
88+
89+
find_p2_solution(cache, queue, buttons, joltages)
90+
|> echo
91+
})
92+
|> int.sum
93+
|> int.to_string
94+
|> Ok
95+
}
96+
97+
type Button {
98+
Button(wires: List(Int))
99+
}
100+
101+
fn parse(line: String) -> dict.Dict(String, List(String)) {
102+
string.split(line, " ")
103+
|> list.group(fn(part) {
104+
case string.first(part) {
105+
Ok("[") -> "lights"
106+
Ok("(") -> "buttons"
107+
Ok("{") -> "joltages"
108+
_ -> "unknown"
109+
}
110+
})
111+
}
112+
113+
fn parse_lights(part: String) -> set.Set(Int) {
114+
part
115+
|> string.drop_start(1)
116+
|> string.drop_end(1)
117+
|> string.to_graphemes
118+
|> list.index_fold([], fn(illuminated, char, i) {
119+
case char {
120+
"." -> illuminated
121+
"#" -> [i, ..illuminated]
122+
_ -> panic as "unexpected character in lights string"
123+
}
124+
})
125+
|> set.from_list
126+
}
127+
128+
fn parse_button(part: String) -> Button {
129+
part
130+
|> string.drop_start(1)
131+
|> string.drop_end(1)
132+
|> string.split(",")
133+
|> list.map(int.parse)
134+
|> result.values
135+
|> Button
136+
}
137+
138+
fn parse_joltages(part: String) -> List(Int) {
139+
part
140+
|> string.drop_start(1)
141+
|> string.drop_end(1)
142+
|> string.split(",")
143+
|> list.map(int.parse)
144+
|> result.values
145+
}
146+
147+
// Press a list of buttons and output which lights are on
148+
fn press_buttons(buttons: List(Button)) -> set.Set(Int) {
149+
buttons
150+
|> list.fold(dict.new(), fn(acc, button) {
151+
list.fold(button.wires, acc, fn(acc_inner, wire) {
152+
dict.upsert(acc_inner, wire, fn(v) {
153+
case v {
154+
option.None -> 1
155+
option.Some(count) -> count + 1
156+
}
157+
})
158+
})
159+
})
160+
|> dict.to_list
161+
|> list.filter_map(fn(tup) {
162+
case tup.1 % 2 {
163+
0 -> Error(Nil)
164+
1 -> Ok(tup.0)
165+
_ -> panic as "remainder has to be 0 or 1"
166+
}
167+
})
168+
|> set.from_list
169+
}
170+
171+
fn button_to_list(button: Button, length: Int) -> List(Int) {
172+
let wires = set.from_list(button.wires)
173+
174+
list.range(0, length - 1)
175+
|> list.fold([], fn(acc, v) {
176+
case set.contains(wires, v) {
177+
True -> [1, ..acc]
178+
False -> [0, ..acc]
179+
}
180+
})
181+
|> list.reverse
182+
}
183+
184+
fn list_add(left: List(Int), right: List(Int)) -> List(Int) {
185+
let assert Ok(pairs) = list.strict_zip(left, right)
186+
list.map(pairs, fn(tup) { tup.0 + tup.1 })
187+
}
188+
189+
fn list_subtract(left: List(Int), right: List(Int)) -> List(Int) {
190+
let assert Ok(pairs) = list.strict_zip(left, right)
191+
list.map(pairs, fn(tup) { tup.0 - tup.1 })
192+
}
193+
194+
fn find_p2_solution(
195+
cache: memoize.Cache(List(Int), Int),
196+
queue: deque.Deque(#(List(Int), Int)),
197+
buttons: List(List(Int)),
198+
joltages: List(Int),
199+
) -> Int {
200+
case deque.pop_front(queue) {
201+
Error(Nil) -> panic as "no solution found"
202+
Ok(#(#(current, pushes), new_deque)) -> {
203+
let new_sums =
204+
buttons
205+
|> list.map(list_add(_, current))
206+
207+
let remains =
208+
list.map(new_sums, list_subtract(joltages, _))
209+
// remove negatives
210+
|> list.filter(fn(l) {
211+
list.fold_until(l, True, fn(_, element) {
212+
case element < 0 {
213+
True -> list.Stop(False)
214+
False -> list.Continue(True)
215+
}
216+
})
217+
})
218+
219+
// check if you found it
220+
case list.contains(remains, list.repeat(0, list.length(joltages))) {
221+
True -> pushes + 1
222+
False -> {
223+
// check if the cache has a way to complete this value
224+
let cache_result =
225+
remains
226+
|> list.map(fn(k) { process.call(cache, 100, memoize.Get(_, k)) })
227+
|> list.fold_until(0, fn(_, cache_value) {
228+
case cache_value {
229+
Ok(v) -> list.Stop(v + pushes + 1)
230+
Error(Nil) -> list.Continue(0)
231+
}
232+
})
233+
234+
case cache_result {
235+
0 -> {
236+
// add results to cache, queue, and keep going
237+
list.each(new_sums, fn(sum) {
238+
process.send(cache, memoize.Put(sum, pushes + 1))
239+
})
240+
241+
let new_deque =
242+
list.fold(new_sums, new_deque, fn(acc, sum) {
243+
deque.push_back(acc, #(sum, pushes + 1))
244+
})
245+
246+
find_p2_solution(cache, new_deque, buttons, joltages)
247+
}
248+
v -> v
249+
}
250+
}
251+
}
252+
}
253+
}
254+
}

test/day10_test.gleam

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import day10/solution
2+
import gleam/string
3+
4+
const testinput = "[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}
5+
[...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2}
6+
[.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5}"
7+
8+
pub fn part1_test() {
9+
let lines = string.split(testinput, "\n")
10+
assert solution.solve_p1(lines) == Ok("7")
11+
}
12+
13+
pub fn part2_test() {
14+
let lines = string.split(testinput, "\n")
15+
assert solution.solve_p2(lines) == Ok("33")
16+
}

0 commit comments

Comments
 (0)