#!/usr/bin/env liberate coffee # Huh?
These are my solutions for 2016’s Advent of Code days 1 through 5.
#!/usr/bin/env coffee
Preliminaries
This program accepts the day on the command line. For example to solve day one, run:
./aoc.coffee.md day1 < input.txt
output = console.log
debug = (msg) ->
ARGV = day: process.argv[2]
main = ->
day = if ARGV.day then Days[ARGV.day] else "wat"
throw "#{ARGV.day} not implemented" unless day
day and do ->
input = ""
process.stdin.on 'readable', ->
chunk = process.stdin.read()
chunk && input = input + chunk
process.stdin.on 'end', ->
day(input)
Util =
invalid_triangle: (a,b,c) -> (+a)+(+b) <= (+c) or (+a)+(+c) <= (+b) or (+b)+(+c) <= (+a)
Days =
Day One
day1: (input) ->
directions = ['n', 'e', 's', 'w']
d = 'n'
turngrid =
nL: 'w'
nR: 'e'
eL: 'n'
eR: 's'
sL: 'e'
sR: 'w'
wL: 's'
wR: 'n'
x = y = 0
input.split(', ').map (item) ->
turndir = item[0]
steps = item.slice(1)
d = turngrid["#{d}#{turndir}"]
switch d
when 'n' then y += +steps
when 's' then y -= +steps
when 'e' then x += +steps
when 'w' then x -= +steps
debug "#{item}: #{x}, #{y} = #{Math.abs(x)+Math.abs(y)}"
output "#{x}, #{y} = #{Math.abs(x)+Math.abs(y)}"
day2: (input) ->
grid = [
[1,2,3],
[4,5,6],
[7,8,9],
]
y = 1
x = 1
input.split('\n').map (line) ->
line.split('').map (d) ->
switch d
when 'L' then x = Math.max 0, Math.min 2, x-1
when 'R' then x = Math.max 0, Math.min 2, x+1
when 'U' then y = Math.max 0, Math.min 2, y-1
when 'D' then y = Math.max 0, Math.min 2, y+1
output grid[y][x]
day3: (input) ->
reducer = (accum, cur) ->
if cur is "" then return accum
[a,b,c] = cur.trim().split /\s+/
if Util.invalid_triangle(a, b, c) then accum else accum+1
console.log input.trim().split('\n').reduce reducer, 0
day3part2: (input) ->
lines = input.split '\n'
idx = 0
count = 0
while idx < lines.length-2
[a,b,c] = lines[idx].trim().split /\s+/
[h,j,k] = lines[idx+1].trim().split /\s+/
[x,y,z] = lines[idx+2].trim().split /\s+/
++count unless Util.invalid_triangle(a, h, x)
++count unless Util.invalid_triangle(b, j, y)
++count unless Util.invalid_triangle(c, k, z)
idx += 3
console.log count
day4: (input) ->
total = 0
input.trim().split('\n').map (line) ->
seen = {}
result = line.match /([-\w]+)-(\d\d\d)\[(\w\w\w\w\w)\]/
[unused, str, id, hash] = result
str.split('').map (ch) ->
return if ch is '-'
if seen[ch] then ++seen[ch] else seen[ch] = 1
counts = []
for k, v of seen
if !counts[v] then counts[v] = ''
counts[v] += k
debug "Seen: #{JSON.stringify seen}"
debug "Counts: #{JSON.stringify counts}"
result = ''
until result.length >= 5 or counts.length == 0
el = ''
el = counts.pop() until el
result += el.split('').sort().join('')
debug result.slice(0,5)
if hash == result.slice(0,5)
console.log "ID: #{id}"
total += +id
output total
day4part2: (input) ->
total = 0
input.trim().split('\n').map (line) ->
seen = {}
result = line.match /([-\w]+)-(\d\d\d)\[(\w\w\w\w\w)\]/
[unused, str, id, hash] = result
str.split('').map (ch) ->
return if ch is '-'
if seen[ch] then ++seen[ch] else seen[ch] = 1
counts = []
for k, v of seen
if !counts[v] then counts[v] = ''
counts[v] += k
debug "Seen: #{JSON.stringify seen}"
debug "Counts: #{JSON.stringify counts}"
result = ''
until result.length >= 5 or counts.length == 0
el = ''
el = counts.pop() until el
result += el.split('').sort().join('')
debug result.slice(0,5)
shift = id % 26
if hash == result.slice(0,5)
cipher = (c) ->
if c is '-' then return ' '
String.fromCharCode (c.charCodeAt(0) - 97 + shift) % 26 + 97
output "[#{id}] #{str} = #{str.split('').map(cipher).join ''}"
day5: (input) ->
md5 = require 'js-md5'
i = 0
found = 0
input = input.trim()
while found < 8
hash = md5.create()
hash.update "#{input}#{i}"
hex = hash.hex()
if hex[0..4] is '00000'
output "\n\nFrom #{hex}: #{hex[5]}"
found++
i++
if i % 1000 == 0 then process.stdout.write "\r#{i}...(#{hex}): #{hex[0..4]}"
main()
module.exports = Days