aboutsummaryrefslogtreecommitdiff
path: root/gleam/aoc2019/src/aoc_2019/day_2.gleam
blob: 8faa0eab804df998b98c56f51fb2d5e68582e174 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import gary.{type ErlangArray}
import gary/array.{type ArrayError}
import gleam/bool
import gleam/int
import gleam/list
import gleam/result
import gleam/string

pub fn parse(input: String) -> ErlangArray(Int) {
  input
  |> string.split(",")
  |> list.map(int.parse)
  |> result.values()
  |> array.from_list(default: -1)
  |> array.make_fixed()
}

pub fn pt_1(input: ErlangArray(Int)) -> Int {
  let assert Ok(result) =
    input
    |> edit_starting_intcodes(12, 2)
    |> run_intcode(0)

  result
}

pub fn pt_2(input: ErlangArray(Int)) -> Int {
  let assert [result] = {
    use noun <- list.flat_map(list.range(0, 99))
    use verb <- list.filter_map(list.range(0, 99))
    let result = input |> edit_starting_intcodes(noun, verb) |> run_intcode(0)
    case result == Ok(19_690_720) {
      True -> Ok(100 * noun + verb)
      False -> Error(Nil)
    }
  }

  result
}

fn run_intcode(
  intcode: ErlangArray(Int),
  pointer: Int,
) -> Result(Int, ArrayError) {
  let assert Ok(op_code) = array.get(intcode, pointer)
  let op = get_op(op_code)

  use <- bool.guard(result.is_error(op), array.get(intcode, 0))
  let assert Ok(position_1) = array.get(intcode, pointer + 1)
  let assert Ok(position_2) = array.get(intcode, pointer + 2)
  let assert Ok(position_3) = array.get(intcode, pointer + 3)

  let assert Ok(value_1) = array.get(intcode, position_1)
  let assert Ok(value_2) = array.get(intcode, position_2)

  let assert Ok(f) = op
  let new_value = f(value_1, value_2)
  let assert Ok(updated_intcode) = array.set(intcode, position_3, new_value)
  run_intcode(updated_intcode, pointer + 4)
}

fn edit_starting_intcodes(
  intcodes: ErlangArray(Int),
  new_code_1: Int,
  new_code_2: Int,
) -> ErlangArray(Int) {
  let assert Ok(updated) =
    intcodes
    |> array.set(at: 1, put: new_code_1)
    |> result.try(array.set(into: _, at: 2, put: new_code_2))
  updated
}

fn get_op(code: Int) -> Result(fn(Int, Int) -> Int, Nil) {
  case code {
    1 -> Ok(int.add)
    2 -> Ok(int.multiply)
    99 -> Error(Nil)
    _ -> panic as "bad opcode"
  }
}