view 2017/day18.d @ 23:5cf02601cd14

day 18
author Jordi Gutiérrez Hermoso <jordigh@octave.org>
date Mon, 18 Dec 2017 23:35:03 -0500
parents
children 776d882c78b8
line wrap: on
line source

import std.stdio;
import std.array: array;
import std.string: split;
import std.conv: to, ConvException;
import std.datetime: msecs;
import std.concurrency;

void runProgram(immutable string[] opcodes, ulong pid, Tid otherProg) {
  // Connect the two threads
  if (otherProg == ownerTid) {
    otherProg = receiveOnly!Tid();
  } else {
    send(otherProg, thisTid());
  }

  long ip = 0;
  long[char] regs = ['p': pid];
  long sent = 0;

  while(0 <= ip && ip < opcodes.length) {
    auto opcode = opcodes[ip].split;
    auto op = opcode[0];
    auto reg = opcode[1][0];
    long val = 0;
    if (opcode.length > 2) {
      try {
        val = to!long(opcode[2]);
      }
      catch(ConvException){
        val = regs.get(opcode[2][0], 0);
      }
    }
    switch(op) {
    case "snd":
      send(otherProg, regs.get(reg, 0));
      sent++;
      goto default;
    case "rcv":
      if (!receiveTimeout(100.msecs, (long val) {regs[reg] = val;})) {
        goto done;
      }
      goto default;
    case "set":
      regs[reg] = val;
      goto default;
    case "add":
      regs[reg] = regs.get(reg, 0) + val;
      goto default;
    case "mul":
      regs[reg] = regs.get(reg, 0) * val;
      goto default;
    case "mod":
      regs[reg] = regs.get(reg, 0) % val;
      goto default;
    case "jgz":
      long cmp;
      try {
        cmp = to!long(opcode[1]);
      }
      catch(ConvException) {
        cmp = regs.get(reg, 0);
      }
      if (cmp > 0) {
        ip += val;
        break;
      }
      goto default;
    default:
      ip++;
    }
  }

  // We're done, dad!
  done:
  send(ownerTid, thisTid, sent);
}

void main(string[] args) {
  immutable auto opcodes = File(args[1]).byLineCopy.array.idup;
  auto tid1 = spawn(&runProgram, opcodes, 0, thisTid);
  auto tid2 = spawn(&runProgram, opcodes, 1, tid1);

  // Wait for both children to let us know they're done.
  auto done1 = receiveOnly!(Tid, long);
  auto done2 = receiveOnly!(Tid, long);
  if (done1[0] == tid2) {
    writeln(done1[1]);
  }
  else {
    writeln(done2[1]);
  }
}