day 12
This commit is contained in:
parent
401a086a71
commit
f17388b5ec
7 changed files with 259 additions and 0 deletions
4
sample/day12-sample.txt
Normal file
4
sample/day12-sample.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
AAAA
|
||||||
|
BBCD
|
||||||
|
BBCC
|
||||||
|
EEEC
|
5
sample/day12-sample2.txt
Normal file
5
sample/day12-sample2.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
OOOOO
|
||||||
|
OXOXO
|
||||||
|
OOOOO
|
||||||
|
OXOXO
|
||||||
|
OOOOO
|
10
sample/day12-sample3.txt
Normal file
10
sample/day12-sample3.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
RRRRIICCFF
|
||||||
|
RRRRIICCCF
|
||||||
|
VVRRRCCFFF
|
||||||
|
VVRCCCJFFF
|
||||||
|
VVVVCJJCFE
|
||||||
|
VVIVCCJJEE
|
||||||
|
VVIIICJJEE
|
||||||
|
MIIIIIJJEE
|
||||||
|
MIIISIJEEE
|
||||||
|
MMMISSJEEE
|
5
sample/day12-sample4.txt
Normal file
5
sample/day12-sample4.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
EEEEE
|
||||||
|
EXXXX
|
||||||
|
EEEEE
|
||||||
|
EXXXX
|
||||||
|
EEEEE
|
6
sample/day12-sample5.txt
Normal file
6
sample/day12-sample5.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
AAAAAA
|
||||||
|
AAABBA
|
||||||
|
AAABBA
|
||||||
|
ABBAAA
|
||||||
|
ABBAAA
|
||||||
|
AAAAAA
|
97
src/day12_p1.gleam
Normal file
97
src/day12_p1.gleam
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
import gleam/bool
|
||||||
|
import gleam/dict.{type Dict}
|
||||||
|
import gleam/int
|
||||||
|
import gleam/io
|
||||||
|
import gleam/iterator
|
||||||
|
import gleam/list.{contains, count, filter, fold, map, reverse}
|
||||||
|
import gleam/pair
|
||||||
|
import gleam/string
|
||||||
|
import stdin.{stdin}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
stdin()
|
||||||
|
|> read_input
|
||||||
|
|> detect_regions
|
||||||
|
|> map(calculate_price)
|
||||||
|
|> fold(0, int.add)
|
||||||
|
|> io.debug
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_price(areas: List(#(Int, Int))) {
|
||||||
|
let area = areas |> list.length
|
||||||
|
|
||||||
|
let perimeter =
|
||||||
|
areas
|
||||||
|
|> fold(0, fn(acc, area) {
|
||||||
|
let #(x, y) = area
|
||||||
|
let bounds =
|
||||||
|
[#(x + 1, y), #(x - 1, y), #(x, y + 1), #(x, y - 1)]
|
||||||
|
|> count(fn(point) { areas |> contains(point) |> bool.negate })
|
||||||
|
acc + bounds
|
||||||
|
})
|
||||||
|
|
||||||
|
area * perimeter
|
||||||
|
}
|
||||||
|
|
||||||
|
fn detect_regions(textmap: Dict(#(Int, Int), String)) -> List(List(#(Int, Int))) {
|
||||||
|
textmap
|
||||||
|
|> dict.keys
|
||||||
|
|> fold(#(textmap, []), fn(acc, x) {
|
||||||
|
let #(searchspace, lists) = acc
|
||||||
|
// Make sure we haven't already included this key in another region
|
||||||
|
case lists |> list.find(fn(lst) { lst |> contains(x) }) {
|
||||||
|
Ok(_) -> acc
|
||||||
|
_ -> {
|
||||||
|
let assert Ok(plant) = dict.get(textmap, x)
|
||||||
|
find_region(searchspace, x, plant, [])
|
||||||
|
|> pair.map_second(fn(lst) { [lst |> list.unique, ..lists] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|> pair.second
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_region(
|
||||||
|
textmap: Dict(#(Int, Int), String),
|
||||||
|
start: #(Int, Int),
|
||||||
|
plant: String,
|
||||||
|
processed: List(#(Int, Int)),
|
||||||
|
) -> #(Dict(#(Int, Int), String), List(#(Int, Int))) {
|
||||||
|
let #(x, y) = start
|
||||||
|
let searchspace = dict.delete(textmap, start)
|
||||||
|
|
||||||
|
[#(x - 1, y), #(x + 1, y), #(x, y - 1), #(x, y + 1)]
|
||||||
|
|> filter(fn(x) { is_same(textmap, x, plant) })
|
||||||
|
|> fold(#(searchspace, [start, ..processed]), fn(acc, x) {
|
||||||
|
let #(partialmap, current) = acc
|
||||||
|
find_region(partialmap, x, plant, current)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_same(
|
||||||
|
textmap: Dict(#(Int, Int), String),
|
||||||
|
point: #(Int, Int),
|
||||||
|
plant: String,
|
||||||
|
) -> Bool {
|
||||||
|
case dict.get(textmap, point) {
|
||||||
|
Ok(s) -> s == plant
|
||||||
|
_ -> False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_input(it: iterator.Iterator(String)) -> Dict(#(Int, Int), String) {
|
||||||
|
it
|
||||||
|
|> iterator.fold([], fn(acc, line) {
|
||||||
|
case string.trim(line) {
|
||||||
|
"" -> acc
|
||||||
|
str -> {
|
||||||
|
[str |> string.to_graphemes, ..acc]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|> reverse
|
||||||
|
|> list.index_fold(dict.new(), fn(acc, line, y) {
|
||||||
|
line
|
||||||
|
|> list.index_fold(acc, fn(dic, num, x) { dict.insert(dic, #(x, y), num) })
|
||||||
|
})
|
||||||
|
}
|
132
src/day12_p2.gleam
Normal file
132
src/day12_p2.gleam
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
import gleam/bool
|
||||||
|
import gleam/dict.{type Dict}
|
||||||
|
import gleam/int
|
||||||
|
import gleam/io
|
||||||
|
import gleam/iterator
|
||||||
|
import gleam/list.{contains, filter, fold, map, reverse}
|
||||||
|
import gleam/pair
|
||||||
|
import gleam/string
|
||||||
|
import stdin.{stdin}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
stdin()
|
||||||
|
|> read_input
|
||||||
|
|> detect_regions
|
||||||
|
|> map(calculate_price)
|
||||||
|
|> fold(0, int.add)
|
||||||
|
|> io.debug
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_price(areas: List(#(Int, Int))) {
|
||||||
|
let area = areas |> list.length
|
||||||
|
|
||||||
|
let perimeter =
|
||||||
|
areas
|
||||||
|
|> fold([], fn(acc, area) {
|
||||||
|
let bounds = find_bounds(areas, area)
|
||||||
|
list.append(acc, bounds)
|
||||||
|
})
|
||||||
|
|> count_contiguous
|
||||||
|
|
||||||
|
area * perimeter
|
||||||
|
}
|
||||||
|
|
||||||
|
type Bound {
|
||||||
|
Left
|
||||||
|
Right
|
||||||
|
Top
|
||||||
|
Bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_bounds(
|
||||||
|
areas: List(#(Int, Int)),
|
||||||
|
area: #(Int, Int),
|
||||||
|
) -> List(#(Bound, #(Int, Int))) {
|
||||||
|
let #(x, y) = area
|
||||||
|
[
|
||||||
|
#(Right, #(x + 1, y)),
|
||||||
|
#(Left, #(x - 1, y)),
|
||||||
|
#(Bottom, #(x, y + 1)),
|
||||||
|
#(Top, #(x, y - 1)),
|
||||||
|
]
|
||||||
|
|> filter(fn(p) {
|
||||||
|
let #(_, point) = p
|
||||||
|
areas |> contains(point) |> bool.negate
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_contiguous(bounds: List(#(Bound, #(Int, Int)))) -> Int {
|
||||||
|
bounds
|
||||||
|
|> list.count(fn(b) {
|
||||||
|
case b {
|
||||||
|
#(Top, #(x, y)) -> bounds |> contains(#(Top, #(x - 1, y)))
|
||||||
|
#(Bottom, #(x, y)) -> bounds |> contains(#(Bottom, #(x - 1, y)))
|
||||||
|
#(Left, #(x, y)) -> bounds |> contains(#(Left, #(x, y - 1)))
|
||||||
|
#(Right, #(x, y)) -> bounds |> contains(#(Right, #(x, y - 1)))
|
||||||
|
}
|
||||||
|
|> bool.negate
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn detect_regions(textmap: Dict(#(Int, Int), String)) -> List(List(#(Int, Int))) {
|
||||||
|
textmap
|
||||||
|
|> dict.keys
|
||||||
|
|> fold(#(textmap, []), fn(acc, x) {
|
||||||
|
let #(searchspace, lists) = acc
|
||||||
|
// Make sure we haven't already included this key in another region
|
||||||
|
case lists |> list.find(fn(lst) { lst |> contains(x) }) {
|
||||||
|
Ok(_) -> acc
|
||||||
|
_ -> {
|
||||||
|
let assert Ok(plant) = dict.get(textmap, x)
|
||||||
|
find_region(searchspace, x, plant, [])
|
||||||
|
|> pair.map_second(fn(lst) { [lst |> list.unique, ..lists] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|> pair.second
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_region(
|
||||||
|
textmap: Dict(#(Int, Int), String),
|
||||||
|
start: #(Int, Int),
|
||||||
|
plant: String,
|
||||||
|
processed: List(#(Int, Int)),
|
||||||
|
) -> #(Dict(#(Int, Int), String), List(#(Int, Int))) {
|
||||||
|
let #(x, y) = start
|
||||||
|
let searchspace = dict.delete(textmap, start)
|
||||||
|
|
||||||
|
[#(x - 1, y), #(x + 1, y), #(x, y - 1), #(x, y + 1)]
|
||||||
|
|> filter(fn(x) { is_same(textmap, x, plant) })
|
||||||
|
|> fold(#(searchspace, [start, ..processed]), fn(acc, x) {
|
||||||
|
let #(partialmap, current) = acc
|
||||||
|
find_region(partialmap, x, plant, current)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_same(
|
||||||
|
textmap: Dict(#(Int, Int), String),
|
||||||
|
point: #(Int, Int),
|
||||||
|
plant: String,
|
||||||
|
) -> Bool {
|
||||||
|
case dict.get(textmap, point) {
|
||||||
|
Ok(s) -> s == plant
|
||||||
|
_ -> False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_input(it: iterator.Iterator(String)) -> Dict(#(Int, Int), String) {
|
||||||
|
it
|
||||||
|
|> iterator.fold([], fn(acc, line) {
|
||||||
|
case string.trim(line) {
|
||||||
|
"" -> acc
|
||||||
|
str -> {
|
||||||
|
[str |> string.to_graphemes, ..acc]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|> reverse
|
||||||
|
|> list.index_fold(dict.new(), fn(acc, line, y) {
|
||||||
|
line
|
||||||
|
|> list.index_fold(acc, fn(dic, num, x) { dict.insert(dic, #(x, y), num) })
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in a new issue