changeset 24:19481b061461

Implement tilting and cycling for Day 14 part 2 Lots of false starts trying to iterate. Eventually looked for "back in same position" to spot a loop. Then took longer to spot that "same position" isn't necessarily "start position" and loop can be offset!
author IBBoard <dev@ibboard.co.uk>
date Sat, 16 Dec 2023 20:39:02 +0000
parents f34254b67082
children 79dc2ba41df2
files day14b.rb
diffstat 1 files changed, 82 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/day14b.rb	Sat Dec 16 20:39:02 2023 +0000
@@ -0,0 +1,82 @@
+#! /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]
+
+platform = File.open(file, "r").each_line(chomp: true).map {|row| row.each_char.to_a}.to_a.transpose()
+
+COL_SIZE = platform[0].length
+puts "Column size: #{COL_SIZE}"
+
+def cycle(platform)
+	[:north, :west, :south, :east].reduce(platform) do |platform, iter|
+#		puts "Push #{iter}"
+		result = platform.map {|col| col.chunk_while {|i, j| i != "#"}.to_a}.map do |col|
+			col.flat_map do |chunk|
+				num_movable_objects = chunk.count("O")
+				new_chunk = Array.new(num_movable_objects, "O")
+				new_chunk.concat(Array.new(chunk.length - num_movable_objects, "."))
+				new_chunk[-1] = "#" if chunk[-1] == "#"
+				new_chunk
+			end
+		end
+		case iter
+		when :north
+			# Pushed it North, now we need to go West
+#			puts "#{result.transpose.map{|col| col.join('')}.join("\n")}\n\n"
+			result.transpose
+		when :west
+			# Pushed it West, now we need to go South
+#			puts "#{result.map{|col| col.join('')}.join("\n")}\n\n"
+			result.transpose.map(&:reverse)
+		when :south
+			# Pushed it South, now we need to go East
+#			puts "#{result.map(&:reverse).transpose.map{|col| col.join('')}.join("\n")}\n\n"
+			result.transpose.map(&:reverse)
+		when :east
+			# Pushed it East, now we need to get back to North alignment
+#			puts "#{result.map(&:reverse).transpose.map(&:reverse).transpose.map{|col| col.join('')}.join("\n")}\n\n"
+			result.map(&:reverse).transpose.map(&:reverse)
+		end
+	end
+end
+
+previous_states = []
+max_cycle_length = 1000000000
+cycle_start = nil
+cycle_length = max_cycle_length
+(1..max_cycle_length).each do |iter|
+#	puts "Cycle #{iter}"
+	platform = cycle(platform)
+	if iter % 1000 == 0
+		puts iter
+	end
+	cycle_start = previous_states.index platform
+	if !cycle_start.nil?
+		cycle_start += 1  # Compensate for zero-indexing in array
+		cycle_length = iter - cycle_start
+#		puts "#{iter} - #{cycle_start} + 1 = #{cycle_length}"
+		break
+	end
+	previous_states << platform
+	puts "\n\n"
+end
+# Already did the first cycle of the loop, so skip it
+#puts "#{(max_cycle_length - cycle_start)} % #{cycle_length} = #{((max_cycle_length - cycle_start) % cycle_length)} extras"
+((max_cycle_length - cycle_start) % cycle_length).times {|n| platform = cycle(platform)}
+total_load = platform.reduce(0) do |weight, col|
+	col_weight = col.each_with_index.reduce(0) do |accum, cell|
+		cell_contents, cell_pos = cell
+		accum + (cell_contents == "O" ? (COL_SIZE - cell_pos) : 0)
+	end
+#	puts "#{col} = #{col_weight}"
+	weight + col_weight
+end
+puts total_load