|
1 |
| -# Store rows in blocks of this size. |
2 |
| -# 1 = trap, 0 = safe. |
3 |
| -# Within each block, characters on the left are the most significant bits. |
4 |
| -BLOCK = 10 |
5 |
| - |
6 |
| -# We'll pre-compute every single block of 12 -> 10, |
7 |
| -# since 4096 entries in a table is easy. |
8 |
| -RULE = (0...(1 << BLOCK + 2)).map { |i| |
9 |
| - (0...BLOCK).select { |j| |
10 |
| - (i >> j) & 1 != (i >> j + 2) & 1 |
11 |
| - }.map { |j| 1 << j }.reduce(0, :|) |
12 |
| -}.freeze |
13 |
| - |
14 |
| -SAFE_COUNT = (0...(1 << BLOCK)).map { |i| BLOCK - i.to_s(2).count(?1) }.freeze |
15 |
| - |
16 | 1 | rows = begin
|
17 | 2 | arg = ARGV.find { |x| x.start_with?('-n') }
|
18 | 3 | arg && Integer(ARGV.delete(arg)[2..-1])
|
|
21 | 6 | input = (!ARGV.empty? && !File.exist?(ARGV.first) ? ARGV.first : ARGF.read).freeze
|
22 | 7 |
|
23 | 8 | bit = {?^ => 1, ?. => 0}.freeze
|
24 |
| -prev_row = input.each_char.each_slice(BLOCK).map { |slice| |
25 |
| - slice.reduce(0) { |i, c| i << 1 | bit.fetch(c) } |
26 |
| -} |
27 |
| - |
28 |
| -safe = prev_row.sum { |block| SAFE_COUNT[block] } |
| 9 | +row = input.each_char.reduce(0) { |i, c| i << 1 | bit.fetch(c) } |
| 10 | +mask = 2 ** input.size - 1 |
29 | 11 |
|
30 |
| -current_row = Array.new(prev_row.size) |
| 12 | +total = input.size |
| 13 | +traps = row.to_s(2).count(?1) |
31 | 14 |
|
32 | 15 | (rows ? [rows - 1] : [39, 399960]).each { |n|
|
33 | 16 | n.times {
|
34 |
| - window = 0 |
35 |
| - current_row.size.times { |i| |
36 |
| - window = (window << BLOCK | prev_row[i] << 1 | (prev_row[i + 1] || 0) >> BLOCK - 1) & (1 << BLOCK + 2) - 1 |
37 |
| - current_row[i] = RULE[window] |
38 |
| - safe += SAFE_COUNT[current_row[i]] |
39 |
| - } |
40 |
| - prev_row, current_row = [current_row, prev_row] |
| 17 | + row = ((row << 1) ^ (row >> 1)) & mask |
| 18 | + traps += row.to_s(2).count(?1) |
41 | 19 | }
|
42 |
| - puts safe |
| 20 | + total += n * input.size |
| 21 | + puts total - traps |
43 | 22 | }
|
0 commit comments