aboutsummaryrefslogtreecommitdiff
path: root/aoc-2020-gleam/src
diff options
context:
space:
mode:
authorTomasz Chojnacki <tomaszchojnacki2001@gmail.com>2023-04-06 11:47:33 +0200
committerTomasz Chojnacki <tomaszchojnacki2001@gmail.com>2023-04-06 11:47:33 +0200
commitbcd24674ec0a594882b276fd48fe70c6e3d7ec86 (patch)
treeb89a268e3a11267a34e3cd1a2d42f6ed432c97fd /aoc-2020-gleam/src
parentfeb51c3a6e7eb8a7ac3fa22ac5d12d20e84eb65f (diff)
downloadgleam_aoc2020-bcd24674ec0a594882b276fd48fe70c6e3d7ec86.tar.gz
gleam_aoc2020-bcd24674ec0a594882b276fd48fe70c6e3d7ec86.zip
Finish day 11
Diffstat (limited to 'aoc-2020-gleam/src')
-rw-r--r--aoc-2020-gleam/src/days/day03.gleam10
-rw-r--r--aoc-2020-gleam/src/days/day11.gleam140
-rw-r--r--aoc-2020-gleam/src/ext/mapx.gleam16
-rw-r--r--aoc-2020-gleam/src/ext/setx.gleam10
-rw-r--r--aoc-2020-gleam/src/util/pos.gleam26
5 files changed, 194 insertions, 8 deletions
diff --git a/aoc-2020-gleam/src/days/day03.gleam b/aoc-2020-gleam/src/days/day03.gleam
index 3a62419..0778eea 100644
--- a/aoc-2020-gleam/src/days/day03.gleam
+++ b/aoc-2020-gleam/src/days/day03.gleam
@@ -9,9 +9,7 @@ import ext/intx
import ext/resultx as resx
import ext/iteratorx as iterx
import util/input_util
-
-type Pos =
- #(Int, Int)
+import util/pos.{Pos}
const starting_pos = #(0, 0)
@@ -19,10 +17,6 @@ const base_slope = #(3, 1)
const all_slopes = [#(1, 1), base_slope, #(5, 1), #(7, 1), #(1, 2)]
-fn add(p1: Pos, p2: Pos) -> Pos {
- #(p1.0 + p2.0, p1.1 + p2.1)
-}
-
type Area {
Area(trees: Set(Pos), cycle: Int, height: Int)
}
@@ -68,7 +62,7 @@ fn is_valid(pos: Pos, in area: Area) -> Bool {
fn tree_count(in area: Area, with slope: Pos) -> Int {
starting_pos
- |> iter.iterate(with: add(_, slope))
+ |> iter.iterate(with: pos.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
new file mode 100644
index 0000000..1f0344a
--- /dev/null
+++ b/aoc-2020-gleam/src/days/day11.gleam
@@ -0,0 +1,140 @@
+import gleam/io
+import gleam/string as str
+import gleam/iterator.{Next} as iter
+import gleam/map.{Map}
+import ext/mapx
+import ext/setx
+import ext/listx
+import ext/resultx as resx
+import ext/genericx as genx
+import ext/iteratorx as iterx
+import util/input_util
+import util/pos.{Pos}
+
+type Seat {
+ Empty
+ Occupied
+}
+
+type Grid {
+ Grid(data: Map(Pos, Seat))
+}
+
+type Settings {
+ Settings(threshold: Int, adjacent_counter: fn(Grid, Pos) -> Int)
+}
+
+fn build_grid(from input: String) -> Grid {
+ input
+ |> str.split(on: "\n")
+ |> iter.from_list
+ |> iter.map(with: str.trim)
+ |> iter.index
+ |> iter.flat_map(with: fn(line) {
+ let #(row_index, row) = line
+ row
+ |> str.to_graphemes
+ |> iter.from_list
+ |> iter.index
+ |> iter.flat_map(with: fn(elem) {
+ let #(col_index, grapheme) = elem
+ case grapheme == "L" {
+ True -> iter.single(#(#(col_index, row_index), Empty))
+ False -> iter.empty()
+ }
+ })
+ })
+ |> mapx.from_iter
+ |> Grid
+}
+
+fn count_near_adjacent(grid: Grid, pos: Pos) -> Int {
+ pos
+ |> pos.neighbours8
+ |> setx.count(satisfying: fn(n) {
+ case map.get(grid.data, n) {
+ Ok(seat) -> seat == Occupied
+ Error(Nil) -> False
+ }
+ })
+}
+
+fn count_far_adjacent(grid: Grid, pos: Pos) -> Int {
+ pos.directions8
+ |> listx.count(satisfying: fn(d) {
+ iter.unfold(
+ from: pos.add(pos, d),
+ with: fn(p) { Next(element: p, accumulator: pos.add(p, d)) },
+ )
+ // Bigger than the largest map size
+ |> iter.take(up_to: 1000)
+ |> iterx.filter_map(with: map.get(grid.data, _))
+ |> iter.first
+ |> genx.equals(Ok(Occupied))
+ })
+}
+
+fn count_occupied(grid: Grid) -> Int {
+ grid.data
+ |> map.values
+ |> listx.count(satisfying: genx.equals(_, Occupied))
+}
+
+fn step_grid(prev: Grid, settings: Settings) -> Grid {
+ let Settings(threshold, adjacent_counter) = settings
+ prev.data
+ |> map.map_values(with: fn(pos, seat) {
+ let adjacent = adjacent_counter(prev, pos)
+ case seat {
+ Empty if adjacent == 0 -> Occupied
+ Occupied if adjacent >= threshold -> Empty
+ other -> other
+ }
+ })
+ |> Grid
+}
+
+fn is_stable(grid: Grid, settings: Settings) -> Bool {
+ let Settings(threshold, adjacent_counter) = settings
+ grid.data
+ |> mapx.to_iter
+ |> iter.all(satisfying: fn(entry) {
+ let #(pos, seat) = entry
+ let adjacent = adjacent_counter(grid, pos)
+ case seat {
+ Empty -> adjacent > 0
+ Occupied -> adjacent < threshold
+ }
+ })
+}
+
+fn stabilized_occupied(input: String, settings: Settings) -> Int {
+ input
+ |> build_grid
+ |> iter.unfold(with: fn(g) {
+ Next(element: g, accumulator: step_grid(g, settings))
+ })
+ |> iter.find(one_that: is_stable(_, settings))
+ |> resx.assert_unwrap
+ |> count_occupied
+}
+
+fn part1(input: String) -> Int {
+ stabilized_occupied(input, Settings(4, count_near_adjacent))
+}
+
+fn part2(input: String) -> Int {
+ stabilized_occupied(input, Settings(5, count_far_adjacent))
+}
+
+pub fn main() -> Nil {
+ let test = input_util.read_text("test11")
+ let assert 37 = part1(test)
+ let assert 26 = part2(test)
+
+ let input = input_util.read_text("day11")
+ io.debug(part1(input))
+ io.debug(part2(input))
+
+ Nil
+}
diff --git a/aoc-2020-gleam/src/ext/mapx.gleam b/aoc-2020-gleam/src/ext/mapx.gleam
new file mode 100644
index 0000000..244c1ac
--- /dev/null
+++ b/aoc-2020-gleam/src/ext/mapx.gleam
@@ -0,0 +1,16 @@
+import gleam/map.{Map}
+import gleam/iterator.{Iterator} as iter
+
+pub fn from_iter(iterator: Iterator(#(k, v))) -> Map(k, v) {
+ iter.fold(
+ over: iterator,
+ from: map.new(),
+ with: fn(acc, cur) { map.insert(acc, cur.0, cur.1) },
+ )
+}
+
+pub fn to_iter(map: Map(k, v)) -> Iterator(#(k, v)) {
+ map
+ |> map.to_list
+ |> iter.from_list
+}
diff --git a/aoc-2020-gleam/src/ext/setx.gleam b/aoc-2020-gleam/src/ext/setx.gleam
new file mode 100644
index 0000000..57e368e
--- /dev/null
+++ b/aoc-2020-gleam/src/ext/setx.gleam
@@ -0,0 +1,10 @@
+import gleam/set.{Set}
+import gleam/iterator as iter
+import ext/iteratorx as iterx
+
+pub fn count(set: Set(a), satisfying predicate: fn(a) -> Bool) -> Int {
+ set
+ |> set.to_list
+ |> iter.from_list
+ |> iterx.count(satisfying: predicate)
+}
diff --git a/aoc-2020-gleam/src/util/pos.gleam b/aoc-2020-gleam/src/util/pos.gleam
new file mode 100644
index 0000000..a060440
--- /dev/null
+++ b/aoc-2020-gleam/src/util/pos.gleam
@@ -0,0 +1,26 @@
+import gleam/list
+import gleam/set.{Set}
+
+pub type Pos =
+ #(Int, Int)
+
+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 neighbours8(pos: Pos) -> Set(Pos) {
+ directions8
+ |> list.map(with: add(pos, _))
+ |> set.from_list
+}