aboutsummaryrefslogtreecommitdiff
path: root/day14/part2
blob: 3b575a38ecfb248eae2060d46b4bad2cfdcb605e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/usr/bin/env ruby

class KnotHash
  def initialize(text)
    @list = (0...256).to_a
    @skip = 0
    @ptr = 0
    @input = text.chars.map(&:ord) + [17,31,73,47,23]
  end

  def run(rounds = 64)
    rounds.times do
      @input.each do |len|
        reverse_sublist!(len)
      end
    end
    return self
  end

  def compress
    p = 0
    out = []

    16.times do
      out << @list[p...p+16].inject(:^)
      p += 16
    end

    return out
  end

  def hexdigest
    dense = self.compress
    hex = dense.map { |i| "%02x" % i }
    return hex.join
  end

  def bindigest
    dense = self.compress
    hex = dense.map { |i| "%08b" % i }
    return hex.join
  end

  def to_a
    return @list
  end

  def to_s
    l = @list.dup
    l[@ptr] = "[#{l[@ptr]}]"
    return "#{l.join(' ')} skip = #{@skip}"
  end

  private

  def reverse_sublist!(len)
    if @ptr + len > @list.length then
      reverse_wrapping_sublist!(len)
    else
      reverse_contained_sublist!(len)
    end

    inc_ptr!(len)
  end

  def reverse_wrapping_sublist!(len)
    dbl = @list.dup + @list.dup
    sublist = dbl[@ptr...@ptr+len].reverse

    (@ptr...@ptr+len).each do |i|
      @list[i % @list.length] = sublist[i-@ptr]
    end
  end

  def reverse_contained_sublist!(len)
    sublist = @list[@ptr...@ptr+len].reverse

    (@ptr...@ptr+len).each do |i|
      @list[i] = sublist[i-@ptr]
    end
  end

  def inc_ptr!(len)
    @ptr += len
    @ptr += @skip
    @ptr = @ptr % @list.length
    @skip += 1
  end
end

input = gets.chomp
grid = []

(0..127).each do |r|
  hash = KnotHash.new("#{input}-#{r}").run
  grid << hash.bindigest.chars.map{|c|c == '1'}
end

def find_first_used(grid)
  (0..127).each do |r|
    (0..127).each do |c|
      return [r,c] if grid[r][c]
    end
  end
  return nil
end

def mark_off_region(grid, start)
  coords = [start]
  loop do
    break if coords.empty?
    row, col = coords.shift
    next unless grid[row][col]
    grid[row][col] = false
    coords << [row-1, col] if row > 0
    coords << [row+1, col] if row < 127
    coords << [row, col-1] if col > 0
    coords << [row, col+1] if col < 127
  end
end

regions = 0

loop do
  f = find_first_used(grid)
  break if f.nil?
  regions += 1
  mark_off_region(grid, f)
end

puts regions