comparison day14b.rb @ 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
children
comparison
equal deleted inserted replaced
23:f34254b67082 24:19481b061461
1 #! /usr/bin/env ruby
2
3 require 'set'
4
5 if ARGV.length != 1
6 abort("Incorrect arguments - needs input file")
7 elsif not File.exist? (ARGV[0])
8 abort("File #{ARGV[0]} did not exist")
9 end
10
11 file = ARGV[0]
12
13 platform = File.open(file, "r").each_line(chomp: true).map {|row| row.each_char.to_a}.to_a.transpose()
14
15 COL_SIZE = platform[0].length
16 puts "Column size: #{COL_SIZE}"
17
18 def cycle(platform)
19 [:north, :west, :south, :east].reduce(platform) do |platform, iter|
20 # puts "Push #{iter}"
21 result = platform.map {|col| col.chunk_while {|i, j| i != "#"}.to_a}.map do |col|
22 col.flat_map do |chunk|
23 num_movable_objects = chunk.count("O")
24 new_chunk = Array.new(num_movable_objects, "O")
25 new_chunk.concat(Array.new(chunk.length - num_movable_objects, "."))
26 new_chunk[-1] = "#" if chunk[-1] == "#"
27 new_chunk
28 end
29 end
30 case iter
31 when :north
32 # Pushed it North, now we need to go West
33 # puts "#{result.transpose.map{|col| col.join('')}.join("\n")}\n\n"
34 result.transpose
35 when :west
36 # Pushed it West, now we need to go South
37 # puts "#{result.map{|col| col.join('')}.join("\n")}\n\n"
38 result.transpose.map(&:reverse)
39 when :south
40 # Pushed it South, now we need to go East
41 # puts "#{result.map(&:reverse).transpose.map{|col| col.join('')}.join("\n")}\n\n"
42 result.transpose.map(&:reverse)
43 when :east
44 # Pushed it East, now we need to get back to North alignment
45 # puts "#{result.map(&:reverse).transpose.map(&:reverse).transpose.map{|col| col.join('')}.join("\n")}\n\n"
46 result.map(&:reverse).transpose.map(&:reverse)
47 end
48 end
49 end
50
51 previous_states = []
52 max_cycle_length = 1000000000
53 cycle_start = nil
54 cycle_length = max_cycle_length
55 (1..max_cycle_length).each do |iter|
56 # puts "Cycle #{iter}"
57 platform = cycle(platform)
58 if iter % 1000 == 0
59 puts iter
60 end
61 cycle_start = previous_states.index platform
62 if !cycle_start.nil?
63 cycle_start += 1 # Compensate for zero-indexing in array
64 cycle_length = iter - cycle_start
65 # puts "#{iter} - #{cycle_start} + 1 = #{cycle_length}"
66 break
67 end
68 previous_states << platform
69 puts "\n\n"
70 end
71 # Already did the first cycle of the loop, so skip it
72 #puts "#{(max_cycle_length - cycle_start)} % #{cycle_length} = #{((max_cycle_length - cycle_start) % cycle_length)} extras"
73 ((max_cycle_length - cycle_start) % cycle_length).times {|n| platform = cycle(platform)}
74 total_load = platform.reduce(0) do |weight, col|
75 col_weight = col.each_with_index.reduce(0) do |accum, cell|
76 cell_contents, cell_pos = cell
77 accum + (cell_contents == "O" ? (COL_SIZE - cell_pos) : 0)
78 end
79 # puts "#{col} = #{col_weight}"
80 weight + col_weight
81 end
82 puts total_load