day 6
This commit is contained in:
parent
fc530ec5f8
commit
68d39d8896
5 changed files with 324 additions and 0 deletions
|
@ -5,6 +5,7 @@ version = "1.0.0"
|
|||
gleam_stdlib = ">= 0.34.0 and < 2.0.0"
|
||||
stdin = ">= 1.1.4 and < 2.0.0"
|
||||
gleam_yielder = ">= 1.1.0 and < 2.0.0"
|
||||
parallel_map = ">= 2.1.0 and < 3.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
gleeunit = ">= 1.0.0 and < 2.0.0"
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
# You typically do not need to edit this file
|
||||
|
||||
packages = [
|
||||
{ name = "gleam_erlang", version = "0.33.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "A1D26B80F01901B59AABEE3475DD4C18D27D58FA5C897D922FCB9B099749C064" },
|
||||
{ name = "gleam_otp", version = "0.14.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "5A8CE8DBD01C29403390A7BD5C0A63D26F865C83173CF9708E6E827E53159C65" },
|
||||
{ name = "gleam_stdlib", version = "0.45.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "206FCE1A76974AECFC55AEBCD0217D59EDE4E408C016E2CFCCC8FF51278F186E" },
|
||||
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
|
||||
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
|
||||
{ name = "parallel_map", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "parallel_map", source = "hex", outer_checksum = "DE2BA9878728EF9EE34BE83FEDC7A18A1ABE4B2AC1E79C710E3E5D95F5E73404" },
|
||||
{ name = "stdin", version = "1.1.4", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "stdin", source = "hex", outer_checksum = "04C04035F2A4CEEFB023837249649CD25F9A9CF5A45F9947C4D0462428A4677D" },
|
||||
]
|
||||
|
||||
|
@ -12,4 +15,5 @@ packages = [
|
|||
gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" }
|
||||
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
|
||||
parallel_map = { version = ">= 2.1.0 and < 3.0.0" }
|
||||
stdin = { version = ">= 1.1.4 and < 2.0.0" }
|
||||
|
|
10
sample/day6-sample.txt
Normal file
10
sample/day6-sample.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
....#.....
|
||||
.........#
|
||||
..........
|
||||
..#.......
|
||||
.......#..
|
||||
..........
|
||||
.#..^.....
|
||||
........#.
|
||||
#.........
|
||||
......#...
|
137
src/day6_p1.gleam
Normal file
137
src/day6_p1.gleam
Normal file
|
@ -0,0 +1,137 @@
|
|||
import gleam/io
|
||||
import gleam/iterator
|
||||
import gleam/list.{filter, map}
|
||||
import gleam/pair
|
||||
import gleam/result
|
||||
import gleam/string
|
||||
import stdin.{stdin}
|
||||
|
||||
pub fn main() {
|
||||
stdin()
|
||||
|> read_input
|
||||
|> traverse
|
||||
|> io.debug
|
||||
}
|
||||
|
||||
fn traverse(params: #(Map, #(Int, Int))) -> Int {
|
||||
let #(map, guard) = params
|
||||
|
||||
traverse_loop([], map, guard, Up)
|
||||
|> list.unique
|
||||
|> list.length
|
||||
}
|
||||
|
||||
fn traverse_loop(
|
||||
visited: List(#(Int, Int)),
|
||||
map: Map,
|
||||
position: #(Int, Int),
|
||||
direction: Direction,
|
||||
) -> List(#(Int, Int)) {
|
||||
case position {
|
||||
#(x, _) if x < 0 -> visited
|
||||
#(x, _) if x >= map.width -> visited
|
||||
#(_, y) if y < 0 -> visited
|
||||
#(_, y) if y >= map.height -> visited
|
||||
_ -> {
|
||||
let next = walk(position, direction)
|
||||
case
|
||||
map.obstacles
|
||||
|> list.find(fn(x) { x == next })
|
||||
{
|
||||
Ok(_) -> traverse_loop(visited, map, position, turn(direction))
|
||||
_ -> traverse_loop([position, ..visited], map, next, direction)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Direction {
|
||||
Up
|
||||
Left
|
||||
Right
|
||||
Down
|
||||
}
|
||||
|
||||
fn walk(pos: #(Int, Int), dir: Direction) -> #(Int, Int) {
|
||||
let #(x, y) = pos
|
||||
case dir {
|
||||
Up -> #(x, y - 1)
|
||||
Down -> #(x, y + 1)
|
||||
Left -> #(x - 1, y)
|
||||
Right -> #(x + 1, y)
|
||||
}
|
||||
}
|
||||
|
||||
fn turn(dir: Direction) -> Direction {
|
||||
case dir {
|
||||
Up -> Right
|
||||
Right -> Down
|
||||
Down -> Left
|
||||
Left -> Up
|
||||
}
|
||||
}
|
||||
|
||||
type Map {
|
||||
Map(width: Int, height: Int, obstacles: List(#(Int, Int)))
|
||||
}
|
||||
|
||||
fn read_input(it: iterator.Iterator(String)) -> #(Map, #(Int, Int)) {
|
||||
let maptxt =
|
||||
it
|
||||
|> iterator.to_list
|
||||
|> map(string.trim)
|
||||
|> filter(not(string.is_empty))
|
||||
|
||||
let assert Ok(width) = list.first(maptxt) |> result.map(string.length)
|
||||
let height = list.length(maptxt)
|
||||
let obstacles = maptxt |> list.index_fold([], find_obstacles)
|
||||
|
||||
let assert Ok(guard) =
|
||||
maptxt
|
||||
|> find_index(fn(line, y) {
|
||||
use x <- result.try(
|
||||
line
|
||||
|> string.to_graphemes
|
||||
|> find_index(fn(chr, x) {
|
||||
case chr {
|
||||
"^" -> Ok(x)
|
||||
_ -> Error(Nil)
|
||||
}
|
||||
}),
|
||||
)
|
||||
Ok(#(x, y))
|
||||
})
|
||||
|
||||
#(Map(width, height, obstacles), guard)
|
||||
}
|
||||
|
||||
fn find_obstacles(
|
||||
acc: List(#(Int, Int)),
|
||||
line: String,
|
||||
y: Int,
|
||||
) -> List(#(Int, Int)) {
|
||||
line
|
||||
|> string.to_graphemes
|
||||
|> list.index_fold(acc, fn(cur, chr, x) {
|
||||
case chr {
|
||||
"#" -> [#(x, y), ..cur]
|
||||
_ -> cur
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn find_index(
|
||||
lst: List(a),
|
||||
apply: fn(a, Int) -> Result(b, Nil),
|
||||
) -> Result(b, Nil) {
|
||||
lst
|
||||
|> list.index_map(pair.new)
|
||||
|> list.find_map(fn(tup) {
|
||||
let #(elem, index) = tup
|
||||
apply(elem, index)
|
||||
})
|
||||
}
|
||||
|
||||
fn not(a: fn(a) -> Bool) {
|
||||
fn(param: a) -> Bool { !a(param) }
|
||||
}
|
172
src/day6_p2.gleam
Normal file
172
src/day6_p2.gleam
Normal file
|
@ -0,0 +1,172 @@
|
|||
import gleam/dict.{type Dict}
|
||||
import gleam/int
|
||||
import gleam/io
|
||||
import gleam/iterator
|
||||
import gleam/list.{filter, map}
|
||||
import gleam/pair
|
||||
import gleam/result
|
||||
import gleam/string
|
||||
import parallel_map
|
||||
import stdin.{stdin}
|
||||
|
||||
pub fn main() {
|
||||
stdin()
|
||||
|> read_input
|
||||
|> obstruct
|
||||
|> io.debug
|
||||
}
|
||||
|
||||
fn obstruct(params: #(Map, #(Int, Int))) -> Int {
|
||||
let #(map, guard) = params
|
||||
|
||||
// Skip first step (guard starting spot)
|
||||
let assert Finite([_, ..steps]) =
|
||||
traverse_loop_check(dict.new(), map, guard, Up)
|
||||
|
||||
// Beware, this one takes a while...
|
||||
steps
|
||||
|> parallel_map.list_pmap(
|
||||
fn(obstruction) {
|
||||
let new_map = Map(map.width, map.height, [obstruction, ..map.obstacles])
|
||||
traverse_loop_check(dict.new(), new_map, guard, Up)
|
||||
},
|
||||
parallel_map.MatchSchedulersOnline,
|
||||
5000,
|
||||
)
|
||||
|> list.count(fn(x) { x == Ok(Loop) })
|
||||
}
|
||||
|
||||
type Patrol {
|
||||
Finite(visited: List(#(Int, Int)))
|
||||
Loop
|
||||
}
|
||||
|
||||
fn traverse_loop_check(
|
||||
visited: Dict(#(#(Int, Int), Direction), Int),
|
||||
map: Map,
|
||||
position: #(Int, Int),
|
||||
direction: Direction,
|
||||
) -> Patrol {
|
||||
case dict.has_key(visited, #(position, direction)) {
|
||||
True -> Loop
|
||||
False ->
|
||||
case position {
|
||||
#(x, _) if x < 0 -> Finite(visited |> to_steps)
|
||||
#(x, _) if x >= map.width -> Finite(visited |> to_steps)
|
||||
#(_, y) if y < 0 -> Finite(visited |> to_steps)
|
||||
#(_, y) if y >= map.height -> Finite(visited |> to_steps)
|
||||
_ -> {
|
||||
let next = walk(position, direction)
|
||||
case
|
||||
map.obstacles
|
||||
|> list.find(fn(x) { x == next })
|
||||
{
|
||||
Ok(_) ->
|
||||
traverse_loop_check(visited, map, position, turn(direction))
|
||||
_ ->
|
||||
traverse_loop_check(
|
||||
visited |> dict.insert(#(position, direction), 1),
|
||||
map,
|
||||
next,
|
||||
direction,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_steps(visited: Dict(#(a, _), _)) -> List(a) {
|
||||
visited |> dict.keys |> list.map(pair.first) |> list.unique
|
||||
}
|
||||
|
||||
type Direction {
|
||||
Up
|
||||
Left
|
||||
Right
|
||||
Down
|
||||
}
|
||||
|
||||
fn walk(pos: #(Int, Int), dir: Direction) -> #(Int, Int) {
|
||||
let #(x, y) = pos
|
||||
case dir {
|
||||
Up -> #(x, y - 1)
|
||||
Down -> #(x, y + 1)
|
||||
Left -> #(x - 1, y)
|
||||
Right -> #(x + 1, y)
|
||||
}
|
||||
}
|
||||
|
||||
fn turn(dir: Direction) -> Direction {
|
||||
case dir {
|
||||
Up -> Right
|
||||
Right -> Down
|
||||
Down -> Left
|
||||
Left -> Up
|
||||
}
|
||||
}
|
||||
|
||||
type Map {
|
||||
Map(width: Int, height: Int, obstacles: List(#(Int, Int)))
|
||||
}
|
||||
|
||||
fn read_input(it: iterator.Iterator(String)) -> #(Map, #(Int, Int)) {
|
||||
let maptxt =
|
||||
it
|
||||
|> iterator.to_list
|
||||
|> map(string.trim)
|
||||
|> filter(not(string.is_empty))
|
||||
|
||||
let assert Ok(width) = list.first(maptxt) |> result.map(string.length)
|
||||
let height = list.length(maptxt)
|
||||
let obstacles = maptxt |> list.index_fold([], find_obstacles)
|
||||
|
||||
let assert Ok(guard) =
|
||||
maptxt
|
||||
|> find_index(fn(line, y) {
|
||||
use x <- result.try(
|
||||
line
|
||||
|> string.to_graphemes
|
||||
|> find_index(fn(chr, x) {
|
||||
case chr {
|
||||
"^" -> Ok(x)
|
||||
_ -> Error(Nil)
|
||||
}
|
||||
}),
|
||||
)
|
||||
Ok(#(x, y))
|
||||
})
|
||||
|
||||
#(Map(width, height, obstacles), guard)
|
||||
}
|
||||
|
||||
fn find_obstacles(
|
||||
acc: List(#(Int, Int)),
|
||||
line: String,
|
||||
y: Int,
|
||||
) -> List(#(Int, Int)) {
|
||||
line
|
||||
|> string.to_graphemes
|
||||
|> list.index_fold(acc, fn(cur, chr, x) {
|
||||
case chr {
|
||||
"#" -> [#(x, y), ..cur]
|
||||
_ -> cur
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn find_index(
|
||||
lst: List(a),
|
||||
apply: fn(a, Int) -> Result(b, Nil),
|
||||
) -> Result(b, Nil) {
|
||||
lst
|
||||
|> list.index_map(pair.new)
|
||||
|> list.find_map(fn(tup) {
|
||||
let #(elem, index) = tup
|
||||
apply(elem, index)
|
||||
})
|
||||
}
|
||||
|
||||
fn not(a: fn(a) -> Bool) {
|
||||
fn(param: a) -> Bool { !a(param) }
|
||||
}
|
Loading…
Reference in a new issue