|
| 1 | +# --- Day 8: Two-Factor Authentication --- |
| 2 | +# |
| 3 | +# You come across a door implementing what you can only assume is an implementation of two-factor |
| 4 | +# authentication after a long game of requirements telephone. |
| 5 | +# |
| 6 | +# To get past the door, you first swipe a keycard (no problem; there was one on a nearby |
| 7 | +# desk). Then, it displays a code on a little screen, and you type that code on a keypad. Then, |
| 8 | +# presumably, the door unlocks. |
| 9 | +# |
| 10 | +# Unfortunately, the screen has been smashed. After a few minutes, you've taken everything apart |
| 11 | +# and figured out how it works. Now you just have to work out what the screen would have |
| 12 | +# displayed. |
| 13 | +# |
| 14 | +# The magnetic strip on the card you swiped encodes a series of instructions for the screen; these |
| 15 | +# instructions are your puzzle input. The screen is 50 pixels wide and 6 pixels tall, all of which |
| 16 | +# start off, and is capable of three somewhat peculiar operations: |
| 17 | +# |
| 18 | +# |
| 19 | +# rect AxB turns on all of the pixels in a rectangle at the top-left of the screen which is A wide |
| 20 | +# and B tall. |
| 21 | +# |
| 22 | +# rotate row y=A by B shifts all of the pixels in row A (0 is the top row) right by B |
| 23 | +# pixels. Pixels that would fall off the right end appear at the left end of the row. |
| 24 | +# |
| 25 | +# rotate column x=A by B shifts all of the pixels in column A (0 is the left column) down by B |
| 26 | +# pixels. Pixels that would fall off the bottom appear at the top of the column. |
| 27 | +# |
| 28 | +# For example, here is a simple sequence on a smaller screen: |
| 29 | +# |
| 30 | +# rect 3x2 creates a small rectangle in the top-left corner: |
| 31 | +# ###.... |
| 32 | +# ###.... |
| 33 | +# ....... |
| 34 | +# |
| 35 | +# rotate column x=1 by 1 rotates the second column down by one pixel: |
| 36 | +# #.#.... |
| 37 | +# ###.... |
| 38 | +# .#..... |
| 39 | +# |
| 40 | +# rotate row y=0 by 4 rotates the top row right by four pixels: |
| 41 | +# ....#.# |
| 42 | +# ###.... |
| 43 | +# .#..... |
| 44 | +# |
| 45 | +# rotate column x=1 by 1 again rotates the second column down by one pixel, causing the bottom pixel |
| 46 | +# to wrap back to the top: |
| 47 | +# .#..#.# |
| 48 | +# #.#.... |
| 49 | +# .#..... |
| 50 | +# |
| 51 | +# As you can see, this display technology is extremely powerful, and will soon dominate the |
| 52 | +# tiny-code-displaying-screen market. That's what the advertisement on the back of the display |
| 53 | +# tries to convince you, anyway. |
| 54 | +# |
| 55 | +# There seems to be an intermediate check of the voltage used by the display: after you swipe your |
| 56 | +# card, if the screen did work, how many pixels should be lit? |
| 57 | +# |
| 58 | +# Your puzzle answer was 116. |
| 59 | +# |
| 60 | +# --- Part Two --- |
| 61 | +# |
| 62 | +# You notice that the screen is only capable of displaying capital letters; in the font it uses, |
| 63 | +# each letter is 5 pixels wide and 6 tall. |
| 64 | +# |
| 65 | +# After you swipe your card, what code is the screen trying to display? |
| 66 | +# |
| 67 | +# Your puzzle answer was UPOJFLBCEZ. |
| 68 | + |
| 69 | +require_relative 'input' |
| 70 | + |
| 71 | +day = __FILE__[/\d+/].to_i(10) |
| 72 | +input = Input.for_day(day) |
| 73 | + |
| 74 | +# puts "solving day #{day} from input\n#{input.inspect}" |
| 75 | + |
| 76 | +class Display |
| 77 | + def initialize(cols=50, rows=6) |
| 78 | + @display = Array.new(rows) { Array.new(cols, '.') } |
| 79 | + end |
| 80 | + |
| 81 | + # rect AxB |
| 82 | + # turns on all of the pixels in a rectangle at the top-left |
| 83 | + # of the screen which is A wide and B tall. |
| 84 | + def rect(wide, tall) |
| 85 | + tall.times do |row| |
| 86 | + wide.times do |col| |
| 87 | + @display[row][col] = '#' |
| 88 | + end |
| 89 | + end |
| 90 | + self |
| 91 | + end |
| 92 | + |
| 93 | + # rotate row y=A by B |
| 94 | + # shifts all of the pixels in row A (0 is the top row) right by B pixels. |
| 95 | + # Pixels that would fall off the right end appear at the left end of the row. |
| 96 | + def row(row, by) |
| 97 | + by.times { @display[row].unshift @display[row].pop } |
| 98 | + self |
| 99 | + end |
| 100 | + |
| 101 | + # rotate column x=A by B |
| 102 | + # shifts all of the pixels in column A (0 is the left column) down by B pixels. |
| 103 | + # Pixels that would fall off the bottom appear at the top of the column. |
| 104 | + def column(col, by) |
| 105 | + tmp = @display.map {|row| row[col] }.join |
| 106 | + by.times { tmp[0,0]= tmp[-1]; tmp.chop! } |
| 107 | + tmp.each_char.with_index {|c,i| @display[i][col] = c } |
| 108 | + self |
| 109 | + end |
| 110 | + |
| 111 | + def to_s |
| 112 | + @display.map {|row| row.join }.join("\n") |
| 113 | + end |
| 114 | + |
| 115 | + def count |
| 116 | + @display.map {|row| row.count('#') }.reduce(:+) |
| 117 | + end |
| 118 | +end |
| 119 | + |
| 120 | +# display = Display.new(7,3) |
| 121 | +# input = <<-EOL |
| 122 | +# rect 3x2 |
| 123 | +# rotate column x=1 by 1 |
| 124 | +# rotate row y=0 by 4 |
| 125 | +# rotate column x=1 by 1 |
| 126 | +# EOL |
| 127 | + |
| 128 | +display = Display.new(50,6) |
| 129 | + |
| 130 | +input.each_line do |line| |
| 131 | + case line |
| 132 | + when /^rect (\d+)x(\d+)$/ |
| 133 | + display.rect($1.to_i,$2.to_i) |
| 134 | + when /^rotate column x=(\d+) by (\d+)$/ |
| 135 | + display.column($1.to_i,$2.to_i) |
| 136 | + when /^rotate row y=(\d+) by (\d+)$/ |
| 137 | + display.row($1.to_i,$2.to_i) |
| 138 | + else |
| 139 | + fail "Bad Command? #{line}" |
| 140 | + end |
| 141 | + |
| 142 | + # puts display, nil |
| 143 | +end |
| 144 | + |
| 145 | +puts display, display.count |
0 commit comments