Mercurial > repos > other > adventofcode2023
changeset 31:47dc75915e91
Implement falling/destroying blocks
Implemented part 1 with supports/supported by logic.
Implemented part 2 with cascades and summing counts. Code has
caching so it is quick _but_ it gives an answer that's too low.
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Wed, 03 Jan 2024 17:00:56 +0000 |
parents | 6de4f4d5404d |
children | a1b748f2c416 |
files | day22.rb day22.txt |
diffstat | 2 files changed, 113 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/day22.rb Wed Jan 03 17:00:56 2024 +0000 @@ -0,0 +1,96 @@ +#! /usr/bin/env ruby + +require 'set' + +if ARGV.length != 1 + abort("Incorrect arguments - needs input file") +elsif not File.exist? (ARGV[0]) +abort("File #{ARGV[0]} did not exist") +end + +file = ARGV[0] + +Block = Struct.new(:id, :x, :y, :z) +SupportedBy = Struct.new(:blocks, :z) +supports = Hash.new +supported_by = Hash.new + +blocks = File.open(file, "r").each_line(chomp: true).with_index.map do |line, id| + block_start, block_end = line.split("~") + start_x, start_y, start_z = block_start.split(",") + end_x, end_y, end_z = block_end.split(",") + supports[id] = [] + Block.new(id, start_x.to_i..end_x.to_i, start_y.to_i..end_y.to_i, start_z.to_i..end_z.to_i) +end + +def height_sort(a,b) + if a.z.first == b.z.first + # Make it a stable sort + a.y.first == b.y.first ? a.x.first <=> b.x.first : a.y.first <=> b.y.first + else + a.z.first <=> b.z.first + end +end + +blocks.sort! {|a,b| height_sort(a, b)} + +def overlap?(range_1, range_2) + range_1.include?(range_2.first) || range_1.include?(range_2.last) || range_2.include?(range_1.first) || range_2.include?(range_1.last) +end + +blocks.reduce([]) do |lower_blocks, block| + support_blocks = lower_blocks.reduce(SupportedBy.new([], 0)) do |candidate_supports, lower_block| + if overlap?(block.x, lower_block.x) && overlap?(block.y, lower_block.y) + if lower_block.z.last > candidate_supports.z + SupportedBy.new([lower_block], lower_block.z.last) + elsif lower_block.z.last == candidate_supports.z + candidate_supports.blocks << lower_block + candidate_supports + else + candidate_supports + end + else + candidate_supports + end + end + drop = block.z.first - support_blocks.z - 1 + block.z = (support_blocks.z+1)..(support_blocks.z+block.z.size) + support_blocks.blocks.each {|support| supports[support.id] << block} + supported_by[block.id] = support_blocks.blocks + lower_blocks << block + lower_blocks +end + +disintegratable = supports.filter {|block_id, supports_list| supports_list.all? {|supported| supported_by[supported.id].length > 1} } + +puts "#{disintegratable.length} disintegratable blocks" + +def find_droppers(id, supports, supported_by, dropping, cache) + new_drops = supports[id].filter do |block| + (Set.new(supported_by[block.id].map(&:id)) - dropping).length == 0 + end + dropping = dropping + new_drops.map(&:id) + new_drops.each do |supported_block| + cache_key = [supported_block.id, Set.new(supported_by[supported_block.id].map(&:id)) & dropping] + if cache.include?(cache_key) + dropping += cache[cache_key] + #puts "Got #{cache[cache_key]} for #{cache_key}" + else + supported_droppers = find_droppers(supported_block.id, supports, supported_by, dropping, cache) + cache[cache_key] = supported_droppers + #puts "Caching #{supported_droppers} for #{cache_key} while dropping #{dropping}" + dropping += supported_droppers + end + end + dropping - [id] +end + +cascade = Hash.new +cache = Hash.new + +blocks.reverse.each do |block| + id = block.id + cascade[id] = find_droppers(id, supports, supported_by, Set.new([id]), cache) +end + +puts "Dropping a total of #{cascade.values.map{|val| val.length}.sum} blocks" \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/day22.txt Wed Jan 03 17:00:56 2024 +0000 @@ -0,0 +1,17 @@ +--- Day 22: Sand Slabs --- + +Blocks are represented by the x/y/z coordiantes of their two ends. e.g. + +1,0,1~1,2,1 +0,0,2~2,0,2 +0,2,3~2,2,3 +0,0,4~0,2,4 +2,0,5~2,2,5 +0,1,6~2,1,6 +1,1,8~1,1,9 + +Work out where the blocks fall to if they're not on something else, and work out how many blocks do not support other blocks. + +--- Part 2 --- + +What if we could cause a cascade? Knock out each block and sum the number of _other_ blocks that would fall \ No newline at end of file