Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package Advent2018;
- import util.AdventOfCode;
- import util.FileIO;
- import java.util.*;
- import java.util.function.IntBinaryOperator;
- import java.util.function.ToIntFunction;
- public class Day16 extends AdventOfCode {
- public Day16(List<String> input) {
- super(input);
- title = "Chronal Classification";
- part1Description = "Samples with 3 or more valid opcodes: ";
- part2Description = "Value at register 0 after running test program: ";
- }
- class Sample {
- int[] before = new int[4];
- int[] after = new int[4];
- int[] codes = new int[4];
- }
- List<Sample> samples;
- List<int[]> program;
- Command[] commandMap = new Command[16];
- class Operation {
- int aReg;
- int aVal;
- int bReg;
- int bVal;
- int c;
- Command cmd;
- public Operation(int aReg, int aVal, int bReg, int bVal, int c, Command cmd) {
- this.aReg = aReg;
- this.aVal = aVal;
- this.bReg = bReg;
- this.bVal = bVal;
- this.c = c;
- this.cmd = cmd;
- }
- }
- enum Command {
- ADDR((x, y) -> x + y, Command::rr),
- ADDI((x, y) -> x + y, Command::ri),
- BANR((x, y) -> x & y, Command::rr),
- BANI((x, y) -> x & y, Command::ri),
- BORR((x, y) -> x | y, Command::rr),
- BORI((x, y) -> x | y, Command::ri),
- MULR((x, y) -> x * y, Command::rr),
- MULI((x, y) -> x * y, Command::ri),
- SETR((x, y) -> x, Command::rr),
- SETI((x, y) -> x, Command::ir),
- EQRI(Command::eq, Command::ri),
- EQIR(Command::eq, Command::ir),
- EQRR(Command::eq, Command::rr),
- GTIR(Command::gt, Command::ir),
- GTRR(Command::gt, Command::rr),
- GTRI(Command::gt, Command::ri);
- IntBinaryOperator function;
- ToIntFunction<Operation> opcode;
- Command(IntBinaryOperator function, ToIntFunction<Operation> opcode) {
- this.function = function;
- this.opcode = opcode;
- }
- static int gt(int x, int y) {
- return x > y ? 1 : 0;
- }
- static int eq(int x, int y) {
- return x == y ? 1 : 0;
- }
- static int rr(Operation op) {
- return op.cmd.function.applyAsInt(op.aReg, op.bReg);
- }
- static int ri(Operation op) {
- return op.cmd.function.applyAsInt(op.aReg, op.bVal);
- }
- static int ir(Operation op) {
- return op.cmd.function.applyAsInt(op.aVal, op.bReg);
- }
- }
- void run(int[] reg, int[] codes, Command cmd) {
- int a = codes[1];
- int b = codes[2];
- int c = codes[3];
- Operation op = new Operation(reg[a], a, reg[b], b, reg[c], cmd);
- reg[c] = cmd.opcode.applyAsInt(op);
- }
- @Override
- public Object part1() {
- int hasThree = 0;
- // use this to order enums for part 2
- Map<Integer, Set<Command>> cmdFreq = new HashMap<>();
- for (Sample sample : samples) {
- int count = 0;
- for (Command cmd : Command.values()) {
- int[] copy = new int[sample.before.length];
- System.arraycopy(sample.before, 0, copy, 0, sample.before.length);
- run(copy, sample.codes, cmd);;
- if (Arrays.equals(copy, sample.after)) {
- cmdFreq.putIfAbsent(sample.codes[0], new HashSet<>());
- cmdFreq.get(sample.codes[0]).add(cmd);
- count++;
- }
- }
- if (count > 2) hasThree++;
- }
- // find command order
- int done = 0;
- while (done < 16) {
- done = 0;
- for (int i = 0; i < 16; i++) {
- if (cmdFreq.get(i).size() == 1) {
- Command cmd = cmdFreq.get(i).toArray(new Command[0])[0];
- done++;
- for (int j = 0; j < 16; j++) {
- if (j != i) {
- cmdFreq.get(j).remove(cmd);
- }
- }
- }
- }
- }
- // load into lookup table
- for (int i = 0; i < 16; i++) {
- commandMap[i] = cmdFreq.get(i).stream().findFirst().orElse(null);
- }
- return hasThree;
- }
- @Override
- public Object part2() {
- int[] register = { 0, 0, 0, 0 };
- for (int[] line : program) {
- run(register, line, commandMap[line[0]]);
- }
- return register[0];
- }
- @Override
- public void parse() {
- samples = new ArrayList<>();
- program = new ArrayList<>();
- boolean part2 = false;
- Sample sample;
- for (int i = 0; i < input.size(); i++) {
- String line = input.get(i);
- if (part2) {
- program.add(FileIO.StringArrayToInt(line.split(" ")));
- } else {
- if (line.startsWith("Before")) {
- sample = new Sample();
- String[] split = line.substring(9, line.indexOf(']'))
- .split(", ");
- sample.before = FileIO.StringArrayToInt(split);
- String codes = input.get(++i);
- String after = input.get(++i);
- sample.codes = FileIO.StringArrayToInt(codes.split(" "));
- sample.after = FileIO.StringArrayToInt(after
- .substring(9, after.indexOf(']'))
- .split(", "));
- samples.add(sample);
- } else {
- if (line.isEmpty()) {
- if (input.get(i + 1).isEmpty() && input.get(i + 2).isEmpty()) {
- i += 2;
- part2 = true;
- }
- }
- }
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement