|
| 1 | +# --- Day 9: Explosives in Cyberspace --- |
| 2 | +# |
| 3 | +# Wandering around a secure area, you come across a datalink port to a new part of the |
| 4 | +# network. After briefly scanning it for interesting files, you find one file in particular that |
| 5 | +# catches your attention. It's compressed with an experimental format, but fortunately, the |
| 6 | +# documentation for the format is nearby. |
| 7 | +# |
| 8 | +# The format compresses a sequence of characters. Whitespace is ignored. To indicate that some |
| 9 | +# sequence should be repeated, a marker is added to the file, like (10x2). To decompress this |
| 10 | +# marker, take the subsequent 10 characters and repeat them 2 times. Then, continue reading the |
| 11 | +# file after the repeated data. The marker itself is not included in the decompressed output. |
| 12 | +# |
| 13 | +# If parentheses or other characters appear within the data referenced by a marker, that's okay - |
| 14 | +# treat it like normal data, not a marker, and then resume looking for markers after the |
| 15 | +# decompressed section. |
| 16 | +# |
| 17 | +# For example: |
| 18 | +# |
| 19 | +# |
| 20 | +# ADVENT contains no markers and decompresses to itself with no changes, resulting in a |
| 21 | +# decompressed length of 6. |
| 22 | +# |
| 23 | +# A(1x5)BC repeats only the B a total of 5 times, becoming ABBBBBC for a decompressed length of 7. |
| 24 | +# |
| 25 | +# (3x3)XYZ becomes XYZXYZXYZ for a decompressed length of 9. |
| 26 | +# |
| 27 | +# A(2x2)BCD(2x2)EFG doubles the BC and EF, becoming ABCBCDEFEFG for a decompressed length of 11. |
| 28 | +# |
| 29 | +# (6x1)(1x3)A simply becomes (1x3)A - the (1x3) looks like a marker, but because it's within a |
| 30 | +# data section of another marker, it not treated any differently from the A that comes after |
| 31 | +# it. It has a decompressed length of 6. |
| 32 | +# |
| 33 | +# X(8x2)(3x3)ABCY becomes X(3x3)ABC(3x3)ABCY (for a decompressed length of 18), because the |
| 34 | +# decompressed data from the (8x2) marker (the (3x3)ABC) is skipped and not processed further. |
| 35 | +# |
| 36 | +# What is the decompressed length of the file (your puzzle input)? Don't count whitespace. |
| 37 | +# |
| 38 | +# --- Part Two --- |
| 39 | +# |
| 40 | +# Apparently, the file actually uses version two of the format. |
| 41 | +# |
| 42 | +# In version two, the only difference is that markers within decompressed data are |
| 43 | +# decompressed. This, the documentation explains, provides much more substantial compression |
| 44 | +# capabilities, allowing many-gigabyte files to be stored in only a few kilobytes. |
| 45 | +# |
| 46 | +# For example: |
| 47 | +# |
| 48 | +# (3x3)XYZ still becomes XYZXYZXYZ, as the decompressed section contains no markers. |
| 49 | +# |
| 50 | +# X(8x2)(3x3)ABCY becomes XABCABCABCABCABCABCY, because the decompressed data from the (8x2) |
| 51 | +# marker is then further decompressed, thus triggering the (3x3) marker twice for a total of six |
| 52 | +# ABC sequences. |
| 53 | +# |
| 54 | +# (27x12)(20x12)(13x14)(7x10)(1x12)A decompresses into a string of A repeated 241920 times. |
| 55 | +# |
| 56 | +# (25x3)(3x3)ABC(2x3)XY(5x2)PQRSTX(18x9)(3x2)TWO(5x7)SEVEN becomes 445 characters long. |
| 57 | +# |
| 58 | +# Unfortunately, the computer you brought probably doesn't have enough memory to actually |
| 59 | +# decompress the file; you'll have to come up with another way to get its decompressed length. |
| 60 | +# |
| 61 | +# What is the decompressed length of the file using this improved format? |
| 62 | + |
| 63 | +require_relative 'input' |
| 64 | + |
| 65 | +day = __FILE__[/\d+/].to_i(10) |
| 66 | +input = Input.for_day(day) |
| 67 | + |
| 68 | +# puts "solving day #{day} from input\n#{input.inspect}" |
| 69 | + |
| 70 | +def decompressed_size(string) |
| 71 | + inpos = 0 |
| 72 | + limit = string.size |
| 73 | + size = 0 |
| 74 | + |
| 75 | + marker = /\((\d+)x(\d+)\)/ |
| 76 | + |
| 77 | + piece = '' |
| 78 | + while inpos < limit |
| 79 | + if (char = string[inpos]) == '(' # marker? |
| 80 | + until char == ')' |
| 81 | + piece << char |
| 82 | + inpos += 1 |
| 83 | + char = string[inpos] |
| 84 | + end |
| 85 | + piece << char |
| 86 | + len, rep = marker.match(piece).captures.map(&:to_i) |
| 87 | + inpos += len |
| 88 | + piece = '' |
| 89 | + size += len * rep |
| 90 | + else |
| 91 | + size += 1 unless /\s/.match char |
| 92 | + end |
| 93 | + inpos += 1 |
| 94 | + end |
| 95 | + |
| 96 | + size |
| 97 | +end |
| 98 | + |
| 99 | +# puts "#{decompressed_size('ADVENT')} should be 6" |
| 100 | +# puts "#{decompressed_size('A(1x5)BC')} should be 7" |
| 101 | +# puts "#{decompressed_size('(3x3)XYZ')} should be 9" |
| 102 | +# puts "#{decompressed_size('A(2x2)BCD(2x2)EFG')} should be 11" |
| 103 | +# puts "#{decompressed_size('(6x1)(1x3)A')} should be 6" |
| 104 | +# puts "#{decompressed_size('X(8x2)(3x3)ABCY')} should be 18" |
| 105 | + |
| 106 | +puts "V1: #{decompressed_size(input)}" |
| 107 | + |
| 108 | +# -------------------------------------------------------------------------------- |
| 109 | +def decompressed_size_v2(string) |
| 110 | + inpos = 0 |
| 111 | + limit = string.size |
| 112 | + size = 0 |
| 113 | + |
| 114 | + marker = /\((\d+)x(\d+)\)/ |
| 115 | + |
| 116 | + piece = '' |
| 117 | + while inpos < limit |
| 118 | + if (char = string[inpos]) == '(' # marker? |
| 119 | + until char == ')' |
| 120 | + piece << char |
| 121 | + inpos += 1 |
| 122 | + char = string[inpos] |
| 123 | + end |
| 124 | + piece << char |
| 125 | + len, rep = marker.match(piece).captures.map(&:to_i) |
| 126 | + inpos += 1 |
| 127 | + delta = decompressed_size_v2(string[inpos,len]) |
| 128 | + inpos += len |
| 129 | + size += delta * rep |
| 130 | + piece = '' |
| 131 | + else |
| 132 | + inpos += 1 |
| 133 | + size += 1 unless /\s/.match char |
| 134 | + end |
| 135 | + end |
| 136 | + |
| 137 | + size |
| 138 | +end |
| 139 | + |
| 140 | +# puts "#{decompressed_size_v2('(3x3)XYZ')} should be 9" |
| 141 | +# puts "#{decompressed_size_v2('X(8x2)(3x3)ABCY')} should be #{'XABCABCABCABCABCABCY'.length}" |
| 142 | +# puts "#{decompressed_size_v2('(27x12)(20x12)(13x14)(7x10)(1x12)A')} should be 241920" |
| 143 | +# puts "#{decompressed_size_v2('(25x3)(3x3)ABC(2x3)XY(5x2)PQRSTX(18x9)(3x2)TWO(5x7)SEVEN')} should be 445" |
| 144 | + |
| 145 | +puts "V2: #{decompressed_size_v2(input)}" |
0 commit comments