Skip to content

Instantly share code, notes, and snippets.

@Rodel30
Last active December 17, 2017 06:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Rodel30/d256c0170a6899c81aab42db905fc428 to your computer and use it in GitHub Desktop.
Save Rodel30/d256c0170a6899c81aab42db905fc428 to your computer and use it in GitHub Desktop.
AoC 2017
inp = '57276274387944537823652626177853384411146325384494935924454336611953119173638191671326254832624841593421667683474349154668177743437745965461678636631863541462893547616877914914662358836365421198516263335926544716331814125295712581158399321372683742773423626286669759415959391374744214595682795818615532673877868424196926497731144319736445141728123322962547288572434564178492753681842244888368542423832228211172842456231275738182764232265933625119312598161192193214898949267765417468348935134618964683127194391796165368145548814473129857697989322621368744725685183346825333247866734735894493395218781464346951777873929898961358796274889826894529599645442657423438562423853247543621565468819799931598754753467593832328147439341586125262733737128386961596394728159719292787597426898945198788211417854662948358422729471312456437778978749753927251431677533575752312447488337156956217451965643454445329758327129966657189332824969141448538681979632611199385896965946849725421978137753366252459914913637858783146735469758716752765718189175583956476935185985918536318424248425426398158278111751711911227818826766177996223718837428972784328925743869885232266127727865267881592395643836999244218345184474613129823933659422223685422732186536199153988717455568523781673393698356967355875123554797755491181791593156433735591529495984256519631187849654633243225118132152549712643273819314433877592644693826861523243946998615722951182474773173215527598949553185313259992227879964482121769617218685394776778423378182462422788277997523913176326468957342296368178321958626168785578977414537368686438348124283789748775163821457641135163495649331144436157836647912852483177542224864952271874645274572426458614384917923623627532487625396914111582754953944965462576624728896917137599778828769958626788685374749661741223741834844643725486925886933118382649581481351844943368484853956759877215252766294896496444835264357169642341291412768946589781812493421379575569593678354241223363739129813633236996588711791919421574583924743119867622229659211793468744163297478952475933163259769578345894367855534294493613767564497137369969315192443795512585'
# Part 1
inp.chars.map(&:to_i).instance_eval{ select.with_index{|n,i| n == self[i-1]} }.reduce(&:+)
#1031
# Part 2
inp.chars.map(&:to_i).instance_eval{ select.with_index{|n,i| n == self[i-(self.count/2)]} }.reduce(&:+)
#1080
inp = '414 382 1515 319 83 1327 116 391 101 749 1388 1046 1427 105 1341 1590
960 930 192 147 932 621 1139 198 865 820 597 165 232 417 19 183
3379 987 190 3844 1245 1503 3151 3349 2844 4033 175 3625 3565 179 3938 184
116 51 32 155 102 92 65 42 48 91 74 69 52 89 20 143
221 781 819 121 821 839 95 117 626 127 559 803 779 543 44 369
199 2556 93 1101 122 124 2714 625 2432 1839 2700 2636 118 2306 1616 2799
56 804 52 881 1409 47 246 1368 1371 583 49 1352 976 400 1276 1240
1189 73 148 1089 93 76 3205 3440 3627 92 853 95 3314 3551 2929 3626
702 169 492 167 712 488 357 414 187 278 87 150 19 818 178 686
140 2220 1961 1014 2204 2173 1513 2225 443 123 148 580 833 1473 137 245
662 213 1234 199 1353 1358 1408 235 917 1395 1347 194 565 179 768 650
119 137 1908 1324 1085 661 1557 1661 1828 1865 432 110 658 821 1740 145
1594 222 4140 963 209 2782 180 2591 4390 244 4328 3748 4535 192 157 3817
334 275 395 128 347 118 353 281 430 156 312 386 160 194 63 141
146 1116 153 815 2212 2070 599 3018 2640 47 125 2292 165 2348 2694 184
1704 2194 1753 146 2063 1668 1280 615 163 190 2269 1856 150 158 2250 2459'
# Part 1
def checksum(inp)
data = inp.split("\n").map{|r| r.split(/\s+/).map(&:to_i) }
data.map(&:max).reduce(&:+) - data.map(&:min).reduce(&:+)
end
# Part 2
def checksum(inp)
data = inp.split("\n").map{|r| r.split(/\s+/).map(&:to_i) }
validpairs = data.map{|r| r.combination(2).to_a.map(&:sort).select{|p| p[1] % p[0] == 0 } }
# Sanity Check
raise 'Expected one pair per row' if validpairs.any?{|p| p.count != 1 }
validpairs.map{|r| r[0][1] / r[0][0] }.reduce(&:+)
end
# Part 1
def calcdistance(n)
godd = -1
loop do
godd += 2
break if godd**2 >= n
end
ncirc = godd / 2 # In Ruby only returns Int value
((n - ((godd-2)**2 + ncirc + ((godd-1) * ((n - (godd-2)**2 - 1) / (godd-1))))).abs % (godd-1)) + ncirc
end
# Part 2
def firstlargervalue(n)
values = [1, 1, 2, 4, 5, 10, 11]
cellIndices = [0,5]
numberOfSetsOfFour = 0
loop do
numberOfSetsOfFour += 1
2.times do
cellIndices = cellIndices.reduce([]){|ar, i| ar << i; ar << i+1 }
if numberOfSetsOfFour > 1
values << calcvalue(values, cellIndices)
break if values[-1] > n
cellIndices[2] = cellIndices[1] + 1
cellIndices[3] = cellIndices[3] + 1
(numberOfSetsOfFour -2).times do
values << calcvalue(values, cellIndices)
break if values[-1] > n
cellIndices = cellIndices.map{|i| i+1 }
end
break if values[-1] > n
end
values << calcvalue(values, cellIndices)
break if values[-1] > n
# Done with sets of four, time to break down
if cellIndices[0] < 2
cellIndices = cellIndices[0..1] << cellIndices[-1] + 1
else
cellIndices = cellIndices[1..-2] << cellIndices[-1] + 1
end
values << calcvalue(values, cellIndices)
break if values[-1] > n
# Down to two next
cellIndices = cellIndices[1..1] << cellIndices[-1] + 1
values << calcvalue(values, cellIndices)
break if values[-1] > n
end
break if values[-1] > n
end
puts values[-5..-1]
values[-1]
end
def calcvalue(values, inx)
inx.reduce(0){|s, i| s += values[i] }
end
def numvalid(inp)
passes = inp.split("\n")
passes.select{|s| passisvalid?(s) }.count
end
# Part 1
def passisvalid?(pass)
parts = pass.split(' ')
parts.count == parts.uniq.count
end
# Part 2
def passisvalid?(pass)
parts = pass.split(' ')
parts.count == parts.map{|p| p.chars.sort.join }.uniq.count
end
#Part 1
def jumpstoexit(instructions)
inst = instructions.split("\n").map(&:to_i)
jumps = 0
i = 0
loop do
jumps += 1
newi = i + inst[i]
inst[i] += 1
i = newi
break if i < 0 || i >= inst.count
end
jumps
end
#Part 2
def jumpstoexit(instructions)
inst = instructions.split("\n").map(&:to_i)
jumps = 0
i = 0
loop do
jumps += 1
newi = i + inst[i]
inst[i] += inst[i] > 2 ? -1 : 1
i = newi
break if i < 0 || i >= inst.count
end
jumps
end
#Part 1
require 'set'
def numdistributions(inp)
blocks = inp.split(/\s+/).map(&:to_i)
paststates = [blocks.join(':')].to_set
loop do
maxval = blocks.max
idx = blocks.find_index(maxval)
blocks[idx] = 0
maxval.times do
idx = (idx + 1) % blocks.count
blocks[idx] += 1
end
break if paststates.include?(blocks.join(':'))
paststates << blocks.join(':')
end
paststates.count
end
#Part 2
def numdistributionsinloop(inp)
blocks = inp.split(/\s+/).map(&:to_i)
paststates = { blocks.join(':') => 0 }
passes = 0
loop do
maxval = blocks.max
idx = blocks.find_index(maxval)
blocks[idx] = 0
maxval.times do
idx = (idx + 1) % blocks.count
blocks[idx] += 1
end
break if paststates.key?(blocks.join(':'))
passes += 1
paststates[blocks.join(':')] = passes
end
paststates.count - paststates[blocks.join(':')]
end
# Part 1
def baseprogram(inp)
lines = inp.split("\n").grep(/->/)
poss = lines.map{|l| l.split(' ').first }
stacked = lines.reduce([]){|a, l| a += l.split(' -> ').last.split(', ') }
poss.select{|p| !stacked.include?(p) }.first
end
# Part 2
def getcorrectweight(inp)
lines = inp.split("\n")
bp = baseprogram(inp)
tree = parseline(lines, bp)
wgtcache = {}
branch = tree
prevbranch = nil
answer = nil
loop do
wgts = branch[:children].group_by{|c| effectiveweight(wgtcache, c) }
if wgts.count == 1
comparetoidx = prevbranch[:children].find_index(branch) - 1
comparetowgt = effectiveweight(wgtcache, prevbranch[:children][comparetoidx])
wrongwgt = effectiveweight(wgtcache, branch)
diff = comparetowgt - wrongwgt
answer = branch[:weight] + diff
break
else
prevbranch = branch
branch = wgts.select{|k,v| v.count == 1 }.to_a.first[1].first
end
end
answer
end
def parseline(lines, key, parent = nil)
line = lines.grep(/^#{key} /).first
parts = line.split('->')
data = { parent: parent, prog: parts[0].split(' ').first, weight: parts[0].scan(/\((\d+)\)/).first.first.to_i }
if parts[1]
childkeys = parts[1].strip.split(', ')
data[:children] = childkeys.map{|ck| parseline(lines, ck, key) }
end
data
end
def effectiveweight(wgtcache, prg)
wgtcache[prg] ||= begin
wgt = prg[:weight]
if prg.key?(:children)
prg[:children].each{|c|
wgt += effectiveweight(wgtcache, c)
}
end
wgt
end
end
# kd dec -37 if gm <= 9
# 0 1 2 3 4 5 6
# Part 1
def getlargestreg(inp)
lines = inp.split("\n")
reg = Hash.new(0) #Default vaues FTW
lines.each do |l|
pts = l.split(' ')
if reg[pts[4]].public_send(pts[5].to_s, pts[6].to_i)
reg[pts[0]] = reg[pts[0]].public_send( (pts[1] == 'inc' ? :+ : :-), pts[2].to_i)
end
end
reg.values.max
end
# Part 2
def getlargestreg(inp)
lines = inp.split("\n")
reg = Hash.new(0) #Default vaues FTW
maxval = 0
lines.each do |l|
pts = l.split(' ')
if reg[pts[4]].public_send(pts[5].to_s, pts[6].to_i)
reg[pts[0]] = reg[pts[0]].public_send( (pts[1] == 'inc' ? :+ : :-), pts[2].to_i)
maxval = [maxval, reg[pts[0]]].max
end
end
maxval
end
# Part 1
def removegarbage(stream)
stream.gsub(/!./, '').gsub(/<[^>]*>/,'').gsub(/[^{}]/,'')
end
def scoregroups(stream)
clean = removegarbage(stream).chars
lvl = 0
clean.reduce(0) do |score, c|
if c == '{'
lvl += 1
score + lvl
else
lvl -= 1
score
end
end
end
# Part 2
def getgarbagecount(stream)
uncanceledstream = stream.gsub(/!./, '')
startsize = uncanceledstream.length
garbagemissing = uncanceledstream.gsub(/<[^>]*>/,'<>')
startsize - garbagemissing.length
end
#Part 2 alt
def getgarbagecount(stream)
stream.gsub(/!./, '').scan(/<([^>]*)>/).flatten.join.length
end
#Part 1
def multiplyfirsttwo(lngths)
vals = applyshifts(lngths)
vals[0] * vals[1]
end
def applyshifts(lngths)
vals = (0..255).to_a
skip = 0
position = 0
lngths.split(',').map(&:to_i).each do |l|
vals[0,l] = vals[0,l].reverse
shift = skip + l
vals.rotate!(shift)
position += shift
skip += 1
end
vals.rotate(-1 * (position % 256) )
end
#Part 2
def knothash(str)
lngths = str.chars.map(&:ord) + '17,31,73,47,23'.split(',').map(&:to_i)
vals = applyshifts(lngths)
(0..15).to_a.map{|i| "%02X" % vals[(i*16), 16].reduce(0, &:^) }.join.downcase
end
def applyshifts(lngths)
skip = 0
position = 0
vals = (0..255).to_a
64.times do
lngths.each do |l|
vals[0,l] = vals[0,l].reverse
shift = skip + l
vals.rotate!(shift)
position += shift
skip += 1
end
end
vals.rotate(-1 * (position % 256) )
end
# Part 1
def gethexdistance(path)
x = 0
y = 0
path.split(',').each do |d|
case d
when 's'
y -= 1
when 'n'
y += 1
when 'ne'
y += 1
x += 1
when 'se'
x += 1
when 'nw'
x -= 1
when 'sw'
y -= 1
x -= 1
else
raise 'Where you goin?'
end
end
(y*x) < 0 ? (x.abs + y.abs) : [x.abs, y.abs].max
end
# Part 2
def getmaxhexdistance(path)
x = 0
y = 0
maxd = 0
path.split(',').each do |d|
case d
when 's'
y -= 1
when 'n'
y += 1
when 'ne'
y += 1
x += 1
when 'se'
x += 1
when 'nw'
x -= 1
when 'sw'
y -= 1
x -= 1
else
raise 'Where you goin?'
end
dist = (y*x) < 0 ? (x.abs + y.abs) : [x.abs, y.abs].max
maxd = [maxd, dist].max
end
maxd
end
require 'set'
def getcontacts(pipes, n, contacts)
pipes[n].each do |p|
if !contacts.include?(p)
contacts << p
contacts += getcontacts(pipes, p, contacts)
end
end
contacts
end
# Part 1
def countzerocontact(inp)
pipes = inp.split("\n").map{|p| p.split('<->')[1].strip.split(',').map(&:to_i) }
contactable = getcontacts(pipes, 0, [0].to_set)
contactable.count
end
# Part 2
def countgroups(inp)
pipes = inp.split("\n").map{|p| p.split('<->')[1].strip.split(',').map(&:to_i) }
unreached = (0..(pipes.count-1)).to_a
groups = []
loop do
break if unreached.count == 0
contacts = getcontacts(pipes, unreached.first, [unreached.first].to_set)
groups << contacts
unreached -= contacts.to_a
end
groups.count
end
#Part 1
def getseverity(inp)
firewall = inp.split("\n").reduce([]){|a,l|
p = l.split(':').map(&:to_i)
a[p[0]] = p[1]
a
}
firewall.each_with_index.reduce(0){|s,(r,d)|
!r.nil? && d%((r-1)*2) == 0 ? s + (r*d) : s
}
end
#Part 1 alt
inps.split("\n").reduce(0){|s,l|
d,r = l.split(':').map(&:to_i)
d%((r-1)*2) == 0 ? s + (r*d): s
}
#Part 2
def getdelay(inp)
lines = inp.split("\n")
delay = 0
loop do
break unless lines.any?{|l|
d,r = l.split(':').map(&:to_i)
(d+delay)%((r-1)*2) == 0
}
delay += 1
end
delay
end
# From Day 10 Part 2
def knothash(str)
lngths = str.chars.map(&:ord) + '17,31,73,47,23'.split(',').map(&:to_i)
vals = applyshifts(lngths)
(0..15).to_a.map{|i| "%02X" % vals[(i*16), 16].reduce(0, &:^) }.join.downcase
end
def applyshifts(lngths)
skip = 0
position = 0
vals = (0..255).to_a
64.times do
lngths.each do |l|
vals[0,l] = vals[0,l].reverse
shift = skip + l
vals.rotate!(shift)
position += shift
skip += 1
end
end
vals.rotate(-1 * (position % 256) )
end
# End from Day 10 Part 2
def hashtobinary(hsh)
hsh.split('').map{|c| "%04b" % c.to_i(16) }.join
end
#Part 1
def countused(inp)
(0..127).reduce(0) do |n,l|
hsh = knothash("#{inp}-#{l}")
bnry = hashtobinary(hsh)
n += bnry.split('').count{|c| c == '1' }
end
end
#Part 2
def countregions(inp)
grid = (0..127).reduce([]) do |n,l|
hsh = knothash("#{inp}-#{l}")
bnry = hashtobinary(hsh)
n << bnry.split('')
end
checked = [].to_set
ngroups = 0
row = 0
col = 0
loop do
if !checked.include?("#{row}-#{col}")
checked << "#{row}-#{col}"
if grid[row][col] == '1'
ngroups += 1
#Find all cells in region
markfriends(checked, grid, row, col)
end
end
# Next cell
if col < 127
col += 1
elsif row < 127
col = 0
row += 1
else
break
end
end
ngroups
end
def markfriends(cache, grid, row, col)
possiblefriends(row,col).each do |f|
r,c = f
next if cache.include?("#{r}-#{c}")
cache << "#{r}-#{c}"
if grid[r][c] == '1'
markfriends(cache, grid, r, c)
end
end
end
def possiblefriends(row,col)
pf = []
pf << [row-1, col] if row > 0
pf << [row+1, col] if row < 127
pf << [row, col-1] if col > 0
pf << [row, col+1] if col < 127
pf
end
def nextvalue(v,m)
(v * m) % 2147483647
end
def valsmatch(a,b)
a.to_s(2)[-16..-1] == b.to_s(2)[-16..-1]
end
# Part 1
def getnmatches(startA,startB)
matches = 0
valA = startA
valB = startB
4e7.to_i.times do
valA = nextvalue(valA, 16807)
valB = nextvalue(valB, 48271)
matches += 1 if valsmatch(valA, valB)
end
matches
end
# Part 2
def getnmatches(startA,startB)
matches = 0
valA = startA
valB = startB
5e6.to_i.times do
loop do
valA = nextvalue(valA, 16807)
break if valA % 4 == 0
end
loop do
valB = nextvalue(valB, 48271)
break if valB % 8 == 0
end
matches += 1 if valsmatch(valA, valB)
end
matches
end
# Part 1
def performdance(inp)
moves = inp.split(',')
pgs = ('a'..'p').to_a
moves.each do |m|
case m[0]
when 's'
pgs.rotate!(-1 * m[1..-1].to_i)
when 'x'
a, b = m[1..-1].split('/').map(&:to_i)
pgs[a], pgs[b] = pgs[b], pgs[a]
when 'p'
chrs = m[1] + m[3]
pgs = pgs.join.tr(chrs, chrs.reverse).chars
end
end
pgs.join
end
# Part 2
def performdance(inp)
# "Parsing" the moves once provides a small speed boost. .36s instead of .63s
moves = inp.split(',').map{|m|
case m[0]
when 's'
{ key: :s, val: -1 * m[1..-1].to_i }
when 'x'
a, b = m[1..-1].split('/').map(&:to_i)
{ key: :x, a: a, b: b }
when 'p'
chrs = m[1] + m[3]
{ key: :p, c: chrs, cr: chrs.reverse }
end
}
pgs = ('a'..'p').to_a
states = {}
1e9.to_i.times do |i|
moves.each do |m|
case m[:key]
when :s
pgs.rotate!(m[:val])
when :x
pgs[m[:a]], pgs[m[:b]] = pgs[m[:b]], pgs[m[:a]]
when :p
pgs = pgs.join.tr(m[:c], m[:cr]).chars
end
end
hsh = pgs.join
if states.key?(hsh)
loopsize = i - states[hsh]
partialloopatend = ((1e9 - 1) - states[hsh]) % loopsize
pgs = states.select{|k,v| v == (states[hsh] + partialloopatend) }.first.first.chars
break
end
states[hsh] = i
end
pgs.join
end
# Part 1
def valueafter2017(stepsize)
vortex = [0]
idx = 0
idx2017 = nil
2017.times do |i|
n = i+1
# n will always be the vortext size, so use it instead of sizing the vortex
idx = ((idx + stepsize) % n) + 1
vortex.insert(idx, n)
idx2017 = idx if n == 2017
end
vortex[idx2017 + 1]
end
# Part 2
def valueafter0(stepsize)
idx = 0
after0 = nil
5e7.to_i.times do |i|
n = i+1
idx = ((idx + stepsize) % n) + 1
after0 = n if idx == 1
end
after0
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment