From 24bae29e6e060672f825362267d2f716e7e4703a Mon Sep 17 00:00:00 2001 From: Hamcha Date: Sat, 7 Dec 2024 18:56:32 +0100 Subject: [PATCH] day 7 --- sample/day7-sample.txt | 9 +++++ src/day7_p1.gleam | 68 +++++++++++++++++++++++++++++++++++ src/day7_p2.gleam | 82 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 sample/day7-sample.txt create mode 100644 src/day7_p1.gleam create mode 100644 src/day7_p2.gleam diff --git a/sample/day7-sample.txt b/sample/day7-sample.txt new file mode 100644 index 0000000..fc6e099 --- /dev/null +++ b/sample/day7-sample.txt @@ -0,0 +1,9 @@ +190: 10 19 +3267: 81 40 27 +83: 17 5 +156: 15 6 +7290: 6 8 6 15 +161011: 16 10 13 +192: 17 8 14 +21037: 9 7 18 13 +292: 11 6 16 20 diff --git a/src/day7_p1.gleam b/src/day7_p1.gleam new file mode 100644 index 0000000..97fb4c6 --- /dev/null +++ b/src/day7_p1.gleam @@ -0,0 +1,68 @@ +import gleam/int +import gleam/io +import gleam/iterator +import gleam/list.{Continue, Stop, count, filter, fold, map} +import gleam/pair +import gleam/result +import gleam/string +import stdin.{stdin} + +pub fn main() { + stdin() + |> read_input + |> filter(is_valid) + |> map(pair.first) + |> fold(0, int.add) + |> io.debug +} + +fn is_valid(equation: #(Int, List(Int))) -> Bool { + let assert #(total, [base, ..operands]) = equation + let op_size = list.length(operands) + let limit = int.bitwise_shift_left(1, op_size) + + list.range(0, limit) + |> list.any(fn(index) { + let operations = + index + |> int.to_base2 + |> string.pad_start(to: op_size, with: "0") + |> string.to_graphemes + + list.zip(operands, operations) + |> list.fold(base, fn(acc, op) { + let #(num, operation) = op + case operation { + "0" -> acc + num + "1" -> acc * num + _ -> panic as "unreachable" + } + }) + |> fn(x) { x == total } + }) +} + +fn read_input(it: iterator.Iterator(String)) -> List(#(Int, List(Int))) { + it + |> iterator.to_list + |> map(string.trim) + |> filter(not(string.is_empty)) + |> map(parse_line) +} + +fn parse_line(line: String) -> #(Int, List(Int)) { + let assert Ok(#(total_str, ops_str)) = line |> string.split_once(":") + let assert Ok(total) = total_str |> int.parse + let assert Ok(ops) = + ops_str + |> string.trim + |> string.split(" ") + |> map(int.parse) + |> result.all + + #(total, ops) +} + +fn not(a: fn(a) -> Bool) { + fn(param: a) -> Bool { !a(param) } +} diff --git a/src/day7_p2.gleam b/src/day7_p2.gleam new file mode 100644 index 0000000..6133d89 --- /dev/null +++ b/src/day7_p2.gleam @@ -0,0 +1,82 @@ +import gleam/float +import gleam/int +import gleam/io +import gleam/iterator +import gleam/list.{Continue, Stop, count, filter, fold, map} +import gleam/pair +import gleam/result +import gleam/string +import stdin.{stdin} + +pub fn main() { + stdin() + |> read_input + |> filter(is_valid) + |> map(pair.first) + |> fold(0, int.add) + |> io.debug +} + +fn is_valid(equation: #(Int, List(Int))) -> Bool { + let assert #(total, [base, ..operands]) = equation + let op_size = list.length(operands) + let assert Ok(limit) = + int.power(3, of: op_size |> int.to_float) |> result.map(float.round) + + list.range(0, limit) + |> list.any(fn(index) { + let assert Ok(operation_string) = + index + |> int.to_base_string(3) + + let operations = + operation_string + |> string.pad_start(to: op_size, with: "0") + |> string.to_graphemes + + list.zip(operands, operations) + |> list.fold(base, fn(acc, op) { + let #(num, operation) = op + case operation { + "0" -> acc + num + "1" -> acc * num + "2" -> concat(acc, num) + _ -> panic as "unreachable" + } + }) + |> fn(x) { x == total } + }) +} + +fn concat(x: Int, y: Int) -> Int { + let assert Ok(x_digits) = int.digits(x, 10) + let assert Ok(y_digits) = int.digits(y, 10) + + let assert Ok(num) = [x_digits, y_digits] |> list.flatten |> int.undigits(10) + num +} + +fn read_input(it: iterator.Iterator(String)) -> List(#(Int, List(Int))) { + it + |> iterator.to_list + |> map(string.trim) + |> filter(not(string.is_empty)) + |> map(parse_line) +} + +fn parse_line(line: String) -> #(Int, List(Int)) { + let assert Ok(#(total_str, ops_str)) = line |> string.split_once(":") + let assert Ok(total) = total_str |> int.parse + let assert Ok(ops) = + ops_str + |> string.trim + |> string.split(" ") + |> map(int.parse) + |> result.all + + #(total, ops) +} + +fn not(a: fn(a) -> Bool) { + fn(param: a) -> Bool { !a(param) } +}