aboutsummaryrefslogtreecommitdiff
path: root/aoc-2020-gleam
diff options
context:
space:
mode:
Diffstat (limited to 'aoc-2020-gleam')
-rw-r--r--aoc-2020-gleam/src/days/day03.gleam12
-rw-r--r--aoc-2020-gleam/src/days/day11.gleam20
-rw-r--r--aoc-2020-gleam/src/days/day12.gleam32
-rw-r--r--aoc-2020-gleam/src/days/day17.gleam88
-rw-r--r--aoc-2020-gleam/src/util/dir.gleam4
-rw-r--r--aoc-2020-gleam/src/util/pos.gleam47
-rw-r--r--aoc-2020-gleam/src/util/pos2.gleam48
-rw-r--r--aoc-2020-gleam/src/util/pos3.gleam30
-rw-r--r--aoc-2020-gleam/src/util/pos4.gleam31
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
+}