aboutsummaryrefslogtreecommitdiff
path: root/aoc-2020-gleam/src/days/day12.gleam
diff options
context:
space:
mode:
Diffstat (limited to 'aoc-2020-gleam/src/days/day12.gleam')
-rw-r--r--aoc-2020-gleam/src/days/day12.gleam123
1 files changed, 123 insertions, 0 deletions
diff --git a/aoc-2020-gleam/src/days/day12.gleam b/aoc-2020-gleam/src/days/day12.gleam
new file mode 100644
index 0000000..2986c01
--- /dev/null
+++ b/aoc-2020-gleam/src/days/day12.gleam
@@ -0,0 +1,123 @@
+import gleam/io
+import gleam/int
+import gleam/list
+import gleam/string as str
+import util/input_util
+import util/pos.{Pos}
+import util/dir.{Dir, East, North, South, West}
+
+type Instr {
+ MoveIn(dir: Dir, by: Int)
+ Turn(by: Int)
+ MoveForward(by: Int)
+}
+
+fn parse_instr(line: String) -> Instr {
+ let assert Ok(#(action, value)) = str.pop_grapheme(line)
+ let assert Ok(value) = int.parse(value)
+ case action {
+ "N" -> MoveIn(dir: North, by: value)
+ "E" -> MoveIn(dir: East, by: value)
+ "S" -> MoveIn(dir: South, by: value)
+ "W" -> MoveIn(dir: West, by: value)
+ "L" -> Turn(by: dir.degree_to_turn(-value))
+ "R" -> Turn(by: dir.degree_to_turn(value))
+ "F" -> MoveForward(by: value)
+ }
+}
+
+fn process_moves(
+ lines: List(String),
+ initial: a,
+ execute: fn(a, Instr) -> a,
+ locator: fn(a) -> Pos,
+) -> Int {
+ lines
+ |> list.map(with: parse_instr)
+ |> list.fold(from: initial, with: execute)
+ |> fn(s: a) { pos.manhattan_dist(from: pos.zero, to: locator(s)) }
+}
+
+type State1 {
+ State1(pos: Pos, dir: Dir)
+}
+
+const initial_state1 = State1(pos: pos.zero, dir: East)
+
+fn execute_instr1(prev: State1, instr: Instr) -> State1 {
+ case instr {
+ MoveIn(target, times) ->
+ State1(
+ ..prev,
+ pos: target
+ |> dir.offset
+ |> pos.mul(by: times)
+ |> pos.add(prev.pos),
+ )
+ Turn(times) ->
+ State1(
+ ..prev,
+ dir: prev.dir
+ |> dir.rotate_clockwise(by: times),
+ )
+ MoveForward(times) ->
+ State1(
+ ..prev,
+ pos: prev.dir
+ |> dir.offset
+ |> pos.mul(by: times)
+ |> pos.add(prev.pos),
+ )
+ }
+}
+
+fn part1(lines: List(String)) -> Int {
+ process_moves(lines, initial_state1, execute_instr1, fn(s) { s.pos })
+}
+
+type State2 {
+ State2(ship_pos: Pos, anchor_pos: Pos)
+}
+
+const initial_state2 = State2(ship_pos: pos.zero, anchor_pos: #(10, 1))
+
+fn execute_instr2(prev: State2, instr: Instr) -> State2 {
+ case instr {
+ MoveIn(target, times) ->
+ State2(
+ ..prev,
+ anchor_pos: target
+ |> dir.offset
+ |> pos.mul(by: times)
+ |> pos.add(prev.anchor_pos),
+ )
+ Turn(times) ->
+ State2(
+ ..prev,
+ anchor_pos: pos.rotate_around_origin(this: prev.anchor_pos, by: times),
+ )
+ MoveForward(times) ->
+ State2(
+ ..prev,
+ ship_pos: prev.anchor_pos
+ |> pos.mul(by: times)
+ |> pos.add(prev.ship_pos),
+ )
+ }
+}
+
+fn part2(lines: List(String)) -> Int {
+ process_moves(lines, initial_state2, execute_instr2, fn(s) { s.ship_pos })
+}
+
+pub fn main() -> Nil {
+ let test = input_util.read_lines("test12")
+ let assert 25 = part1(test)
+ let assert 286 = part2(test)
+
+ let input = input_util.read_lines("day12")
+ io.debug(part1(input))
+ io.debug(part2(input))
+
+ Nil
+}