diff --git a/day2.cr b/day2.cr index 5a5515a..4730600 100644 --- a/day2.cr +++ b/day2.cr @@ -1,25 +1,11 @@ +require "./intcode.cr" lines = File.read("day2.txt").lines.map(&.split(",").map(&.to_i32)).flatten -def run(lines, noun, verb) - lines[1] = noun - lines[2] = verb - pos = 0 - loop do - case lines[pos] - when 1 - lines[lines[pos+3]] = lines[lines[pos+1]] + lines[lines[pos+2]] - pos += 4 - when 2 - lines[lines[pos+3]] = lines[lines[pos+1]] * lines[lines[pos+2]] - pos += 4 - when 99 - break - end - end - lines[0] -end 100.times do |noun| 100.times do |verb| - if run(lines.dup, noun, verb) == 19690720 + prog = lines.clone + prog[1] = noun + prog[2] = verb + if run(prog, [] of Int32)[1][0] == 19690720 puts 100*noun + verb break end diff --git a/day5.cr b/day5.cr index 7ec0c43..db464b4 100644 --- a/day5.cr +++ b/day5.cr @@ -1,49 +1,4 @@ +require "./intcode.cr" lines = File.read("day5.txt").chomp.split(",").map(&.to_i32) -def run(lines, input) - output = [] of Int32 - pos = 0 - get = ->(x : Char, p : Int32) { - x == '0' ? lines[lines[pos+p]] : lines[pos+p] - } - loop do - str = "000" + lines[pos].to_s - case str - when .ends_with?("1") - lines[lines[pos+3]] = get.call(str[-3], 1) + get.call(str[-4], 2) - pos += 4 - when .ends_with?("2") - lines[lines[pos+3]] = get.call(str[-3], 1) * get.call(str[-4], 2) - pos += 4 - when .ends_with?("3") - lines[lines[pos+1]] = input.pop - pos += 2 - when .ends_with?("4") - output << get.call(str[-3], 1) - pos += 2 - when .ends_with?("5") - if get.call(str[-3], 1) != 0 - pos = get.call(str[-4], 2) - else - pos += 3 - end - when .ends_with?("6") - if get.call(str[-3], 1) == 0 - pos = get.call(str[-4], 2) - else - pos += 3 - end - when .ends_with?("7") - lines[lines[pos+3]] = (get.call(str[-3], 1) < get.call(str[-4], 2)) ? 1 : 0 - pos += 4 - when .ends_with?("8") - lines[lines[pos+3]] = (get.call(str[-3], 1) == get.call(str[-4], 2)) ? 1 : 0 - pos += 4 - when .ends_with?("99") - break - else - raise "aahhh #{str}" - end - end - {output, lines} -end -puts run(lines, [5]) +puts run(lines.clone, [1]) +puts run(lines.clone, [5]) diff --git a/day7.cr b/day7.cr new file mode 100644 index 0000000..e8ed3b4 --- /dev/null +++ b/day7.cr @@ -0,0 +1,35 @@ +require "./intcode.cr" +require "./intcode_fibers.cr" + +prog = File.read("day7.txt").chomp.split(",").map(&.to_i32) + +def chain_amplifiers(prog, perm, loop = false) + chans = perm.map { |f| new_interpreter(f, prog) } + chans.zip perm do |amp, freq| + amp[0].send freq + end + + chans[0][0].send 0 + + i = 0 + history = Array(Int32).new(chans.size, 0) + loop do + j = (i+1) % chans.size + break unless received = chans[i][1].receive + history[i] = received + chans[j][0].send received + i = j + break if i == 0 && !loop + end + + history[4] +end + +max_single = [0,1,2,3,4].permutations.max_of do |perm| + chain_amplifiers(prog.clone, perm) +end +puts max_single +max_cycled = [5,6,7,8,9].permutations.max_of do |perm| + chain_amplifiers(prog.clone, perm, loop=true) +end +puts max_cycled diff --git a/intcode.cr b/intcode.cr new file mode 100644 index 0000000..483dd2d --- /dev/null +++ b/intcode.cr @@ -0,0 +1,47 @@ +def run(lines, input) + output = [] of Int32 + pos = 0 + get = ->(x : Char, p : Int32) { + x == '0' ? lines[lines[pos+p]] : lines[pos+p] + } + loop do + str = "000" + lines[pos].to_s + case str + when .ends_with?("1") + lines[lines[pos+3]] = get.call(str[-3], 1) + get.call(str[-4], 2) + pos += 4 + when .ends_with?("2") + lines[lines[pos+3]] = get.call(str[-3], 1) * get.call(str[-4], 2) + pos += 4 + when .ends_with?("3") + lines[lines[pos+1]] = input.pop + pos += 2 + when .ends_with?("4") + output << get.call(str[-3], 1) + pos += 2 + when .ends_with?("5") + if get.call(str[-3], 1) != 0 + pos = get.call(str[-4], 2) + else + pos += 3 + end + when .ends_with?("6") + if get.call(str[-3], 1) == 0 + pos = get.call(str[-4], 2) + else + pos += 3 + end + when .ends_with?("7") + lines[lines[pos+3]] = (get.call(str[-3], 1) < get.call(str[-4], 2)) ? 1 : 0 + pos += 4 + when .ends_with?("8") + lines[lines[pos+3]] = (get.call(str[-3], 1) == get.call(str[-4], 2)) ? 1 : 0 + pos += 4 + when .ends_with?("99") + break + else + raise "Invalid instruction" + end + end + {output, lines} +end diff --git a/intcode_fibers.cr b/intcode_fibers.cr new file mode 100644 index 0000000..18ee2e1 --- /dev/null +++ b/intcode_fibers.cr @@ -0,0 +1,42 @@ +def new_interpreter(f, prog) + prog = prog.clone + input = Channel(Int32).new + output = Channel(Int32?).new + spawn do + op = "" + pc = 0 + arg = ->(i : Int32) { op[-(3+i)] == '0' ? prog[prog[pc+1+i]] : prog[pc+1+i] } + loop do + op = "0000" + prog[pc].to_s + case op + when .ends_with? "1" + prog[prog[pc+3]] = arg.call(0) + arg.call(1) + pc += 4 + when .ends_with? "2" + prog[prog[pc+3]] = arg.call(0) * arg.call(1) + pc += 4 + when .ends_with? "3" + prog[prog[pc+1]] = input.receive + pc += 2 + when .ends_with? "4" + output.send(arg.call(0)) + pc += 2 + when .ends_with? "5" + pc = arg.call(0) != 0 ? arg.call(1) : pc + 3 + when .ends_with? "6" + pc = arg.call(0) == 0 ? arg.call(1) : pc + 3 + when .ends_with? "7" + prog[prog[pc+3]] = arg.call(0) < arg.call(1) ? 1 : 0 + pc += 4 + when .ends_with? "8" + prog[prog[pc+3]] = arg.call(0) == arg.call(1) ? 1 : 0 + pc += 4 + when .ends_with? "99" + input.receive + output.send(nil) + break + end + end + end + {input, output} +end