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