From 10e7706062c64cc0da55587bfb1a85c988ae950c Mon Sep 17 00:00:00 2001 From: "H.J" Date: Wed, 5 Jun 2024 14:08:47 -0400 Subject: gleam 2017 day 8 --- aoc2017-gleam/src/aoc_2017/day_8.gleam | 131 +++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 aoc2017-gleam/src/aoc_2017/day_8.gleam diff --git a/aoc2017-gleam/src/aoc_2017/day_8.gleam b/aoc2017-gleam/src/aoc_2017/day_8.gleam new file mode 100644 index 0000000..2f9d0dc --- /dev/null +++ b/aoc2017-gleam/src/aoc_2017/day_8.gleam @@ -0,0 +1,131 @@ +import gleam/dict +import gleam/int +import gleam/list +import gleam/option.{None, Some} +import gleam/string + +const max_register = "__MAX" + +pub type Instruction { + Instruction(register: String, op: Operation, condition: Condition) +} + +pub type Operation { + Inc(by: Int) + Dec(by: Int) +} + +pub type Condition { + Equal(register: String, value: Int) + NotEqual(register: String, value: Int) + LessThan(register: String, value: Int) + GreaterThan(register: String, value: Int) + LessThanOrEq(register: String, value: Int) + GreaterThanOrEq(register: String, value: Int) +} + +type Registers = + dict.Dict(String, Int) + +pub fn parse(input: String) { + input + |> string.split("\n") + |> list.map(parse_instruction) +} + +fn parse_instruction(str: String) -> Instruction { + case string.split(str, " ") { + [name, op, by, "if", cond_name, cond_type, cond_by] -> + Instruction(name, to_op(op, by), to_cond(cond_name, cond_type, cond_by)) + _ -> panic as { "couldn't parse: " <> str } + } +} + +pub fn pt_1(input: List(Instruction)) { + let registers = dict.new() |> dict.insert(max_register, 0) + + input + |> list.fold(registers, next_instruction) + |> dict.delete(max_register) + |> dict.values() + |> list.reduce(int.max) +} + +fn next_instruction(regs: Registers, inst: Instruction) { + case to_compare_fn(inst.condition)(fetch(inst.condition.register, regs)) { + True -> { + let updated_regs = dict.update(regs, inst.register, to_update_fn(inst.op)) + let assert Ok(max) = updated_regs |> dict.values |> list.reduce(int.max) + dict.insert(updated_regs, max_register, max) + } + False -> regs + } +} + +pub fn pt_2(input: List(Instruction)) { + let registers = dict.new() |> dict.insert(max_register, 0) + + input + |> list.fold(registers, next_instruction) + |> dict.get(max_register) +} + +fn int(str: String) -> Int { + let assert Ok(n) = int.parse(str) + n +} + +fn to_op(raw_op: String, raw_by: String) -> Operation { + case raw_op { + "inc" -> Inc(int(raw_by)) + "dec" -> Dec(int(raw_by)) + _ -> panic as { "bad op: " <> raw_op } + } +} + +fn to_cond(name: String, raw_type: String, raw_by: String) -> Condition { + case raw_type { + "==" -> Equal(name, int(raw_by)) + "!=" -> NotEqual(name, int(raw_by)) + ">" -> GreaterThan(name, int(raw_by)) + "<" -> LessThan(name, int(raw_by)) + ">=" -> GreaterThanOrEq(name, int(raw_by)) + "<=" -> LessThanOrEq(name, int(raw_by)) + _ -> panic as { "bad condition: " <> raw_type } + } +} + +fn to_compare_fn(condition: Condition) -> fn(Int) -> Bool { + case condition { + Equal(value: v, ..) -> fn(a) { a == v } + NotEqual(value: v, ..) -> fn(a) { a != v } + GreaterThan(value: v, ..) -> fn(a) { a > v } + LessThan(value: v, ..) -> fn(a) { a < v } + GreaterThanOrEq(value: v, ..) -> fn(a) { a >= v } + LessThanOrEq(value: v, ..) -> fn(a) { a <= v } + } +} + +fn to_update_fn(op: Operation) { + case op { + Inc(n) -> fn(x) { + case x { + Some(i) -> i + n + None -> n + } + } + Dec(n) -> fn(x) { + case x { + Some(i) -> i - n + None -> -n + } + } + } +} + +fn fetch(name: String, registers: Registers) -> Int { + case dict.get(registers, name) { + Ok(n) -> n + Error(_) -> 0 + } +} -- cgit v1.2.3