aboutsummaryrefslogtreecommitdiff
path: root/aoc2023/src/day22/solve.gleam
diff options
context:
space:
mode:
authorHunky Jimpjorps <thechairman@thechairman.info>2024-02-02 17:05:12 -0500
committerHunky Jimpjorps <thechairman@thechairman.info>2024-02-02 17:05:12 -0500
commit48e35ad3b0b0c62f936784e4aca70b17c3b0e3f9 (patch)
treef59a13e0b5e80ab925220b4488c6e36b1bec660a /aoc2023/src/day22/solve.gleam
parent87e9ab25ff70e215b537939a4bc23ab101f41dbe (diff)
downloadgleam_aoc-48e35ad3b0b0c62f936784e4aca70b17c3b0e3f9.tar.gz
gleam_aoc-48e35ad3b0b0c62f936784e4aca70b17c3b0e3f9.zip
renaming
Diffstat (limited to 'aoc2023/src/day22/solve.gleam')
-rw-r--r--aoc2023/src/day22/solve.gleam199
1 files changed, 0 insertions, 199 deletions
diff --git a/aoc2023/src/day22/solve.gleam b/aoc2023/src/day22/solve.gleam
deleted file mode 100644
index 7bf2fb4..0000000
--- a/aoc2023/src/day22/solve.gleam
+++ /dev/null
@@ -1,199 +0,0 @@
-import adglent.{First, Second}
-import gleam/bool
-import gleam/dict.{type Dict}
-import gleam/int
-import gleam/io
-import gleam/list
-import gleam/option.{None, Some}
-import gleam/regex
-import gleam/result
-import gleam/set.{type Set}
-import gleam/string
-
-type Point {
- Point(x: Int, y: Int, z: Int)
-}
-
-fn down_one(p: Point) -> Point {
- Point(..p, z: p.z - 1)
-}
-
-type Block {
- Block(index: Int, from: Point, to: Point)
-}
-
-fn compare_blocks(b1: Block, b2: Block) {
- int.compare(b1.to.z, b2.to.z)
-}
-
-type Space =
- Dict(Point, Block)
-
-type AllBlocks =
- Dict(Block, List(Point))
-
-type BlockTree =
- Dict(Int, Set(Int))
-
-fn parse_block(index: Int, input: String) -> Block {
- let assert Ok(re) = regex.from_string("(.*),(.*),(.*)~(.*),(.*),(.*)")
-
- let assert [scan] = regex.scan(with: re, content: input)
-
- let assert [x1, y1, z1, x2, y2, z2] =
- scan.submatches
- |> option.all
- |> option.unwrap([])
- |> list.map(int.parse)
- |> result.values
- Block(index: index, from: Point(x1, y1, z1), to: Point(x2, y2, z2))
-}
-
-fn cross_section_at_level(b: Block, z: Int) -> List(Point) {
- use x <- list.flat_map(list.range(b.from.x, b.to.x))
- use y <- list.map(list.range(b.from.y, b.to.y))
- Point(x, y, z)
-}
-
-fn place_block(space: Space, b: Block, z: Int) -> Space {
- let now_occupied = {
- use x <- list.flat_map(list.range(b.from.x, b.to.x))
- use y <- list.flat_map(list.range(b.from.y, b.to.y))
- use z <- list.map(list.range(z, z + b.to.z - b.from.z))
- #(Point(x, y, z), b)
- }
-
- dict.merge(space, dict.from_list(now_occupied))
-}
-
-fn find_lowest_level(space: Space, b: Block) -> Space {
- do_find_lowest(space, b, b.from.z)
-}
-
-fn do_find_lowest(space: Space, b: Block, z: Int) -> Space {
- let is_intersecting =
- list.any(cross_section_at_level(b, z), dict.has_key(space, _))
-
- case z, is_intersecting {
- 0, _ -> place_block(space, b, 1)
- _, True -> place_block(space, b, z + 1)
- _, False -> do_find_lowest(space, b, z - 1)
- }
-}
-
-fn to_block_positions(space: Space) -> AllBlocks {
- use acc, point, index <- dict.fold(space, dict.new())
- use points <- dict.update(acc, index)
- case points {
- Some(ps) -> [point, ..ps]
- None -> [point]
- }
-}
-
-fn above_blocks(blocks: AllBlocks) -> BlockTree {
- use acc, block, points <- dict.fold(blocks, dict.new())
- use _ <- dict.update(acc, block.index)
- {
- use above_block, above_points <- dict.filter(blocks)
- above_block.index != block.index
- && list.any(above_points, fn(p) { list.contains(points, down_one(p)) })
- }
- |> dict.keys
- |> list.map(fn(b) { b.index })
- |> set.from_list
-}
-
-fn below_blocks(blocktree: BlockTree) -> BlockTree {
- use acc, block, _ <- dict.fold(blocktree, dict.new())
- use _ <- dict.update(acc, block)
- {
- use _, aboves <- dict.filter(blocktree)
- set.contains(aboves, block)
- }
- |> dict.keys
- |> set.from_list
-}
-
-fn vulnerable_blocks(below_tree: BlockTree) -> List(Int) {
- use block <- list.filter(dict.keys(below_tree))
- use bs <- list.any(dict.values(below_tree))
- !{ set.size(bs) == 0 } && { set.size(set.delete(bs, block)) == 0 }
-}
-
-pub fn part1(input: String) {
- let settled_blocks =
- input
- |> string.split("\n")
- |> list.index_map(parse_block)
- |> list.sort(compare_blocks)
- |> list.fold(dict.new(), find_lowest_level)
-
- let block_positions = to_block_positions(settled_blocks)
- let above_blocks = above_blocks(block_positions)
- let below_blocks = below_blocks(above_blocks)
-
- let vulnerable_blocks = vulnerable_blocks(below_blocks)
-
- list.length(dict.keys(block_positions)) - list.length(vulnerable_blocks)
-}
-
-fn all_falling_blocks(n: Int, above: BlockTree, below: BlockTree) {
- let starting_set = set.insert(set.new(), n)
- do_falling_blocks(starting_set, starting_set, above, below)
-}
-
-fn do_falling_blocks(
- fallen: Set(Int),
- blocks: Set(Int),
- above: BlockTree,
- below: BlockTree,
-) -> Int {
- use <- bool.guard(set.size(blocks) == 0, set.size(fallen) - 1)
-
- let blocks_above =
- {
- use block <- list.flat_map(set.to_list(blocks))
- let assert Ok(supports) = dict.get(above, block)
- use support <- list.filter(set.to_list(supports))
- let assert Ok(supportings) = dict.get(below, support)
- use supporting <- list.all(set.to_list(supportings))
- set.contains(fallen, supporting)
- }
- |> set.from_list()
-
- set.union(fallen, blocks_above)
- |> do_falling_blocks(blocks_above, above, below)
-}
-
-pub fn part2(input: String) {
- let settled_blocks =
- input
- |> string.split("\n")
- |> list.index_map(parse_block)
- |> list.sort(compare_blocks)
- |> list.fold(dict.new(), find_lowest_level)
-
- let block_positions = to_block_positions(settled_blocks)
- let above_blocks = above_blocks(block_positions)
- let below_blocks = below_blocks(above_blocks)
-
- let vulnerable_blocks = vulnerable_blocks(below_blocks)
-
- use acc, b <- list.fold(vulnerable_blocks, 0)
- acc + all_falling_blocks(b, above_blocks, below_blocks)
-}
-
-pub fn main() {
- let assert Ok(part) = adglent.get_part()
- let assert Ok(input) = adglent.get_input("22")
- case part {
- First ->
- part1(input)
- |> adglent.inspect
- |> io.println
- Second ->
- part2(input)
- |> adglent.inspect
- |> io.println
- }
-}