diff options
Diffstat (limited to 'aoc-2020-gleam')
-rw-r--r-- | aoc-2020-gleam/src/days/day03.gleam | 12 | ||||
-rw-r--r-- | aoc-2020-gleam/src/days/day11.gleam | 20 | ||||
-rw-r--r-- | aoc-2020-gleam/src/days/day12.gleam | 32 | ||||
-rw-r--r-- | aoc-2020-gleam/src/days/day17.gleam | 88 | ||||
-rw-r--r-- | aoc-2020-gleam/src/util/dir.gleam | 4 | ||||
-rw-r--r-- | aoc-2020-gleam/src/util/pos.gleam | 47 | ||||
-rw-r--r-- | aoc-2020-gleam/src/util/pos2.gleam | 48 | ||||
-rw-r--r-- | aoc-2020-gleam/src/util/pos3.gleam | 30 | ||||
-rw-r--r-- | aoc-2020-gleam/src/util/pos4.gleam | 31 |
9 files changed, 231 insertions, 81 deletions
diff --git a/aoc-2020-gleam/src/days/day03.gleam b/aoc-2020-gleam/src/days/day03.gleam index 5639fd6..33f15eb 100644 --- a/aoc-2020-gleam/src/days/day03.gleam +++ b/aoc-2020-gleam/src/days/day03.gleam @@ -9,7 +9,7 @@ import gleam/set.{Set} import ext/intx import ext/iteratorx as iterx import util/input_util -import util/pos.{Pos} +import util/pos2.{Pos2} const starting_pos = #(0, 0) @@ -18,7 +18,7 @@ const base_slope = #(3, 1) const all_slopes = [#(1, 1), base_slope, #(5, 1), #(7, 1), #(1, 2)] type Area { - Area(trees: Set(Pos), cycle: Int, height: Int) + Area(trees: Set(Pos2), cycle: Int, height: Int) } fn parse_area(from text: String) -> Area { @@ -51,17 +51,17 @@ fn parse_area(from text: String) -> Area { Area(trees, cycle, height) } -fn has_tree(in area: Area, at pos: Pos) -> Bool { +fn has_tree(in area: Area, at pos: Pos2) -> Bool { set.contains(area.trees, #(pos.0 % area.cycle, pos.1)) } -fn is_valid(pos: Pos, in area: Area) -> Bool { +fn is_valid(pos: Pos2, in area: Area) -> Bool { intx.is_between(pos.1, 0, and: area.height - 1) } -fn tree_count(in area: Area, with slope: Pos) -> Int { +fn tree_count(in area: Area, with slope: Pos2) -> Int { starting_pos - |> iter.iterate(with: pos.add(_, slope)) + |> iter.iterate(with: pos2.add(_, slope)) |> iter.take_while(satisfying: is_valid(_, in: area)) |> iterx.count(satisfying: has_tree(in: area, at: _)) } diff --git a/aoc-2020-gleam/src/days/day11.gleam b/aoc-2020-gleam/src/days/day11.gleam index db25317..1fd8f87 100644 --- a/aoc-2020-gleam/src/days/day11.gleam +++ b/aoc-2020-gleam/src/days/day11.gleam @@ -9,7 +9,7 @@ import ext/resultx as resx import ext/genericx as genx import ext/iteratorx as iterx import util/input_util -import util/pos.{Pos} +import util/pos2.{Pos2} type Seat { Empty @@ -17,11 +17,11 @@ type Seat { } type Grid { - Grid(data: Map(Pos, Seat)) + Grid(data: Map(Pos2, Seat)) } type Settings { - Settings(threshold: Int, adjacent_counter: fn(Grid, Pos) -> Int) + Settings(threshold: Int, adjacent_counter: fn(Grid, Pos2) -> Int) } fn build_grid(from input: String) -> Grid { @@ -48,9 +48,9 @@ fn build_grid(from input: String) -> Grid { |> Grid } -fn count_near_adjacent(grid: Grid, from start: Pos) -> Int { +fn count_near_adjacent(grid: Grid, from start: Pos2) -> Int { start - |> pos.neighbours8 + |> pos2.neighbours8 |> setx.count(satisfying: fn(n) { case map.get(grid.data, n) { Ok(seat) -> seat == Occupied @@ -59,12 +59,12 @@ fn count_near_adjacent(grid: Grid, from start: Pos) -> Int { }) } -fn count_far_adjacent(grid: Grid, from start: Pos) -> Int { - pos.directions8 - |> listx.count(satisfying: fn(d) { +fn count_far_adjacent(grid: Grid, from start: Pos2) -> Int { + pos2.directions8() + |> setx.count(satisfying: fn(d) { start - |> pos.add(d) - |> iterx.unfold_infinitely(pos.add(_, d)) + |> pos2.add(d) + |> iterx.unfold_infinitely(pos2.add(_, d)) |> iter.take(up_to: 1000) |> iterx.filter_map(with: map.get(grid.data, _)) |> iter.first diff --git a/aoc-2020-gleam/src/days/day12.gleam b/aoc-2020-gleam/src/days/day12.gleam index 2986c01..3df7ce8 100644 --- a/aoc-2020-gleam/src/days/day12.gleam +++ b/aoc-2020-gleam/src/days/day12.gleam @@ -3,7 +3,7 @@ import gleam/int import gleam/list import gleam/string as str import util/input_util -import util/pos.{Pos} +import util/pos2.{Pos2} import util/dir.{Dir, East, North, South, West} type Instr { @@ -30,19 +30,19 @@ fn process_moves( lines: List(String), initial: a, execute: fn(a, Instr) -> a, - locator: fn(a) -> Pos, + locator: fn(a) -> Pos2, ) -> 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)) } + |> fn(s: a) { pos2.manhattan_dist(from: pos2.zero, to: locator(s)) } } type State1 { - State1(pos: Pos, dir: Dir) + State1(pos: Pos2, dir: Dir) } -const initial_state1 = State1(pos: pos.zero, dir: East) +const initial_state1 = State1(pos: pos2.zero, dir: East) fn execute_instr1(prev: State1, instr: Instr) -> State1 { case instr { @@ -51,8 +51,8 @@ fn execute_instr1(prev: State1, instr: Instr) -> State1 { ..prev, pos: target |> dir.offset - |> pos.mul(by: times) - |> pos.add(prev.pos), + |> pos2.mul(by: times) + |> pos2.add(prev.pos), ) Turn(times) -> State1( @@ -65,8 +65,8 @@ fn execute_instr1(prev: State1, instr: Instr) -> State1 { ..prev, pos: prev.dir |> dir.offset - |> pos.mul(by: times) - |> pos.add(prev.pos), + |> pos2.mul(by: times) + |> pos2.add(prev.pos), ) } } @@ -76,10 +76,10 @@ fn part1(lines: List(String)) -> Int { } type State2 { - State2(ship_pos: Pos, anchor_pos: Pos) + State2(ship_pos: Pos2, anchor_pos: Pos2) } -const initial_state2 = State2(ship_pos: pos.zero, anchor_pos: #(10, 1)) +const initial_state2 = State2(ship_pos: pos2.zero, anchor_pos: #(10, 1)) fn execute_instr2(prev: State2, instr: Instr) -> State2 { case instr { @@ -88,20 +88,20 @@ fn execute_instr2(prev: State2, instr: Instr) -> State2 { ..prev, anchor_pos: target |> dir.offset - |> pos.mul(by: times) - |> pos.add(prev.anchor_pos), + |> pos2.mul(by: times) + |> pos2.add(prev.anchor_pos), ) Turn(times) -> State2( ..prev, - anchor_pos: pos.rotate_around_origin(this: prev.anchor_pos, by: times), + anchor_pos: pos2.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), + |> pos2.mul(by: times) + |> pos2.add(prev.ship_pos), ) } } diff --git a/aoc-2020-gleam/src/days/day17.gleam b/aoc-2020-gleam/src/days/day17.gleam new file mode 100644 index 0000000..78603e0 --- /dev/null +++ b/aoc-2020-gleam/src/days/day17.gleam @@ -0,0 +1,88 @@ +import gleam/io +import gleam/list +import gleam/bool +import gleam/string as str +import gleam/set.{Set} +import util/input_util +import util/pos3 +import util/pos4 + +fn parse_grid(input: String, with constructor: fn(Int, Int) -> a) -> Set(a) { + input + |> str.split(on: "\n") + |> list.index_map(with: fn(y, line) { + line + |> str.to_graphemes + |> list.index_map(with: fn(x, grapheme) { + case grapheme { + "#" -> [constructor(x, y)] + "." -> [] + _ -> panic + } + }) + |> list.flatten + }) + |> list.flatten + |> set.from_list +} + +fn cycle( + grid: Set(a), + with neighbours: fn(a) -> Set(a), + by times: Int, +) -> Set(a) { + use <- bool.guard(when: times == 0, return: grid) + + grid + |> set.fold( + from: set.new(), + with: fn(acc, pos) { + acc + |> set.insert(pos) + |> set.union(neighbours(pos)) + }, + ) + |> set.filter(for: fn(pos) { + let active = set.contains(in: grid, this: pos) + let count = + pos + |> neighbours + |> set.intersection(grid) + |> set.size + + case active, count { + True, 2 -> True + True, 3 -> True + True, _ -> False + False, 3 -> True + False, _ -> False + } + }) + |> cycle(with: neighbours, by: times - 1) +} + +fn part1(input: String) -> Int { + input + |> parse_grid(with: fn(x, y) { #(x, y, 0) }) + |> cycle(with: pos3.neighbours26, by: 6) + |> set.size +} + +fn part2(input: String) -> Int { + input + |> parse_grid(with: fn(x, y) { #(x, y, 0, 0) }) + |> cycle(with: pos4.neighbours80, by: 6) + |> set.size +} + +pub fn main() -> Nil { + let test = input_util.read_text("test17") + let assert 112 = part1(test) + let assert 848 = part2(test) + + let input = input_util.read_text("day17") + io.debug(part1(input)) + io.debug(part2(input)) + + Nil +} diff --git a/aoc-2020-gleam/src/util/dir.gleam b/aoc-2020-gleam/src/util/dir.gleam index 6f637d9..194d712 100644 --- a/aoc-2020-gleam/src/util/dir.gleam +++ b/aoc-2020-gleam/src/util/dir.gleam @@ -2,7 +2,7 @@ import gleam/int import gleam/iterator as iter import ext/resultx as resx import ext/iteratorx as iterx -import util/pos.{Pos} +import util/pos2.{Pos2} pub type Dir { North @@ -11,7 +11,7 @@ pub type Dir { West } -pub fn offset(direction: Dir) -> Pos { +pub fn offset(direction: Dir) -> Pos2 { case direction { North -> #(0, 1) East -> #(1, 0) diff --git a/aoc-2020-gleam/src/util/pos.gleam b/aoc-2020-gleam/src/util/pos.gleam deleted file mode 100644 index dd3d01d..0000000 --- a/aoc-2020-gleam/src/util/pos.gleam +++ /dev/null @@ -1,47 +0,0 @@ -import gleam/int -import gleam/list -import gleam/set.{Set} - -pub type Pos = - #(Int, Int) - -pub const zero = #(0, 0) - -pub const directions8 = [ - #(1, 0), - #(1, 1), - #(0, 1), - #(-1, 1), - #(-1, 0), - #(-1, -1), - #(0, -1), - #(1, -1), -] - -pub fn add(p1: Pos, p2: Pos) -> Pos { - #(p1.0 + p2.0, p1.1 + p2.1) -} - -pub fn sub(p1: Pos, p2: Pos) -> Pos { - #(p1.0 - p2.0, p1.1 - p2.1) -} - -pub fn mul(p: Pos, by scalar: Int) -> Pos { - #(p.0 * scalar, p.1 * scalar) -} - -pub fn neighbours8(p: Pos) -> Set(Pos) { - directions8 - |> list.map(with: add(p, _)) - |> set.from_list -} - -pub fn manhattan_dist(from p1: Pos, to p2: Pos) -> Int { - int.absolute_value(p1.0 - p2.0) + int.absolute_value(p1.1 - p2.1) -} - -pub fn rotate_around_origin(this p: Pos, by times: Int) -> Pos { - let assert Ok(sin) = list.at([0, -1, 0, 1], times) - let assert Ok(cos) = list.at([1, 0, -1, 0], times) - #(p.0 * cos - p.1 * sin, p.0 * sin + p.1 * cos) -} diff --git a/aoc-2020-gleam/src/util/pos2.gleam b/aoc-2020-gleam/src/util/pos2.gleam new file mode 100644 index 0000000..4de2ab9 --- /dev/null +++ b/aoc-2020-gleam/src/util/pos2.gleam @@ -0,0 +1,48 @@ +import gleam/int +import gleam/bool +import gleam/list +import gleam/set.{Set} + +pub type Pos2 = + #(Int, Int) + +pub const zero = #(0, 0) + +pub fn directions8() -> Set(Pos2) { + set.from_list({ + use x <- list.flat_map(over: [-1, 0, 1]) + use y <- list.flat_map(over: [-1, 0, 1]) + let pos = #(x, y) + use <- bool.guard(when: pos == zero, return: []) + [pos] + }) +} + +pub fn add(p1: Pos2, p2: Pos2) -> Pos2 { + #(p1.0 + p2.0, p1.1 + p2.1) +} + +pub fn sub(p1: Pos2, p2: Pos2) -> Pos2 { + #(p1.0 - p2.0, p1.1 - p2.1) +} + +pub fn mul(p: Pos2, by scalar: Int) -> Pos2 { + #(p.0 * scalar, p.1 * scalar) +} + +pub fn neighbours8(p: Pos2) -> Set(Pos2) { + directions8() + |> set.to_list + |> list.map(with: add(p, _)) + |> set.from_list +} + +pub fn manhattan_dist(from p1: Pos2, to p2: Pos2) -> Int { + int.absolute_value(p1.0 - p2.0) + int.absolute_value(p1.1 - p2.1) +} + +pub fn rotate_around_origin(this p: Pos2, by times: Int) -> Pos2 { + let assert Ok(sin) = list.at([0, -1, 0, 1], times) + let assert Ok(cos) = list.at([1, 0, -1, 0], times) + #(p.0 * cos - p.1 * sin, p.0 * sin + p.1 * cos) +} diff --git a/aoc-2020-gleam/src/util/pos3.gleam b/aoc-2020-gleam/src/util/pos3.gleam new file mode 100644 index 0000000..5525607 --- /dev/null +++ b/aoc-2020-gleam/src/util/pos3.gleam @@ -0,0 +1,30 @@ +import gleam/list +import gleam/bool +import gleam/set.{Set} + +pub type Pos3 = + #(Int, Int, Int) + +pub const zero = #(0, 0, 0) + +fn directions26() -> Set(Pos3) { + set.from_list({ + use x <- list.flat_map(over: [-1, 0, 1]) + use y <- list.flat_map(over: [-1, 0, 1]) + use z <- list.flat_map(over: [-1, 0, 1]) + let pos = #(x, y, z) + use <- bool.guard(when: pos == zero, return: []) + [pos] + }) +} + +pub fn add(p1: Pos3, p2: Pos3) -> Pos3 { + #(p1.0 + p2.0, p1.1 + p2.1, p1.2 + p2.2) +} + +pub fn neighbours26(p: Pos3) -> Set(Pos3) { + directions26() + |> set.to_list + |> list.map(with: add(p, _)) + |> set.from_list +} diff --git a/aoc-2020-gleam/src/util/pos4.gleam b/aoc-2020-gleam/src/util/pos4.gleam new file mode 100644 index 0000000..3eda4c5 --- /dev/null +++ b/aoc-2020-gleam/src/util/pos4.gleam @@ -0,0 +1,31 @@ +import gleam/list +import gleam/bool +import gleam/set.{Set} + +pub type Pos4 = + #(Int, Int, Int, Int) + +pub const zero = #(0, 0, 0, 0) + +fn directions80() -> Set(Pos4) { + set.from_list({ + use x <- list.flat_map(over: [-1, 0, 1]) + use y <- list.flat_map(over: [-1, 0, 1]) + use z <- list.flat_map(over: [-1, 0, 1]) + use w <- list.flat_map(over: [-1, 0, 1]) + let pos = #(x, y, z, w) + use <- bool.guard(when: pos == zero, return: []) + [pos] + }) +} + +pub fn add(p1: Pos4, p2: Pos4) -> Pos4 { + #(p1.0 + p2.0, p1.1 + p2.1, p1.2 + p2.2, p1.3 + p2.3) +} + +pub fn neighbours80(p: Pos4) -> Set(Pos4) { + directions80() + |> set.to_list + |> list.map(with: add(p, _)) + |> set.from_list +} |