From ec2d8c531d142f36fe4e55aaf91828a18cb2f173 Mon Sep 17 00:00:00 2001 From: HJ Date: Wed, 20 Dec 2023 23:51:50 -0500 Subject: day 20 gleam in progress --- aoc2023/src/day20/solve.gleam | 125 +++++++++++++++++++++++++++++++++++- aoc2023/test/day20/day20_test.gleam | 6 +- 2 files changed, 127 insertions(+), 4 deletions(-) diff --git a/aoc2023/src/day20/solve.gleam b/aoc2023/src/day20/solve.gleam index e589379..449cdeb 100644 --- a/aoc2023/src/day20/solve.gleam +++ b/aoc2023/src/day20/solve.gleam @@ -1,8 +1,131 @@ import adglent.{First, Second} import gleam/io +import gleam/dict.{type Dict} +import gleam/queue.{type Queue} +import gleam/string +import gleam/list +import gleam/bool + +type Node { + Broadcaster(children: List(String)) + Flipflop(children: List(String), state: Power) + Conjunction(children: List(String), state: Dict(String, TonePitch)) + Ground(children: List(String)) +} + +type Tone { + Tone(from: String, to: String, pitch: TonePitch) +} + +type Power { + On + Off +} + +type TonePitch { + Low + High +} + +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 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) + + 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(node.children, any: name) + }) + |> list.map(fn(n) { #(n, Low) }) + |> dict.from_list() + |> fn(dict) { Conjunction(state: dict, children: chs) } + other -> other + } +} + +fn press_button_once( + initial: #(Dict(String, Node), Int, Int), + queue: Queue(Tone), +) { + let #(nodes, high, low) = initial + use <- bool.guard(queue.is_empty(queue), initial) + let assert Ok(#(Tone(from_name, to_name, pitch) as tone, rest)) = + queue.pop_front(queue) + io.debug(tone) + let assert Ok(to_node) = dict.get(nodes, to_name) + case to_node { + Broadcaster(children) -> + list.fold(children, rest, fn(acc, c) { + queue.push_back(acc, Tone(from: to_name, to: c, pitch: pitch)) + }) + |> press_button_once(initial, _) + + Conjunction(state: state, children: children) -> todo + + Flipflop(..) if pitch == High -> press_button_once(initial, rest) + Flipflop(state: state, children: children) -> { + let updated_nodes = + dict.insert( + nodes, + to_name, + Flipflop(state: flip_power(state), children: children), + ) + let updated_queue = + list.fold(children, rest, fn(acc, c) { + queue.push_back( + acc, + Tone(from: to_name, to: c, pitch: flip_flop_pitch(state)), + ) + }) + press_button_once(#(updated_nodes, 0, 0), updated_queue) + } + Ground(..) -> press_button_once(initial, rest) + } +} pub fn part1(input: String) { - todo as "Implement solution to part 1" + let initial_state = + input + |> string.split(on: "\n") + |> list.map(parse_node) + |> to_initial_state() + + press_button_once( + #(initial_state, 0, 1), + [Tone("button", "broadcaster", Low)] + |> queue.from_list, + ) + + "1" } pub fn part2(input: String) { diff --git a/aoc2023/test/day20/day20_test.gleam b/aoc2023/test/day20/day20_test.gleam index 2cbf670..92e8afb 100644 --- a/aoc2023/test/day20/day20_test.gleam +++ b/aoc2023/test/day20/day20_test.gleam @@ -19,8 +19,7 @@ const part1_examples: List(Example(Problem1AnswerType)) = [ %a -> b %b -> c %c -> inv -&inv -> a -", +&inv -> a", "32000000", ), Example( @@ -28,7 +27,8 @@ const part1_examples: List(Example(Problem1AnswerType)) = [ %a -> inv, con &inv -> b %b -> con -&con -> output", +&con -> output +output -> ", "11687500", ), ] -- cgit v1.2.3