input = ARGF.readlines(chomp: true).map(&:chars) # always tilts left def tilt(platform) platform .map {|row| row.chunk_while { [_1, _2].tally.fetch(?#, 0).even? }} .map {|row| row.flat_map { _1.sort.reverse }} end def load(platform) platform.reverse .each.with_index .sum {|row, i| row.count(?O) * (i+1) } end # part one p load(tilt(input.transpose).transpose) def spin_cycle(platform) return enum_for(__method__, platform) unless block_given? loop do # north platform = tilt(platform.transpose).transpose # west platform = tilt(platform) # south platform = tilt(platform.reverse.transpose).transpose.reverse # east platform = tilt(platform.map(&:reverse)).map(&:reverse) yield platform end end # part two spin = spin_cycle(input) seen = {} (1_000_000_000).times do |i| platform = spin.next if seen.has_key?(platform.hash) start, _ = seen.fetch(platform.hash) i = (1_000_000_000 - start) % (i+1 - start) + start p seen.find {|_,(j,_)| j == i }.fetch(1).fetch(1) exit end seen[platform.hash] = [i+1, load(platform)] end