#!/usr/bin/env python3

import sys

class Amp:
  def __init__(self, instructions, id):
    self.instructions = instructions
    self.pcounter = 0
    self.finished = 0
    self.ampid = id
    self.inputs = []

  def terminated(self):
    return self.finished

  def r(self, pos, mode):
    if mode == 0:
      return int(self.instructions[self.instructions[pos]])
    else: 
      return int(self.instructions[pos])

  def w(self, pos, v, mode):
    if mode == 0:
      self.instructions[self.instructions[pos]] = v
    else:
      print("broken!", self.instructions, pos, v, mode)

  def perform(self, inputs):
    outputs = []

    for inp in inputs:
      self.inputs.append(inp)

    while 1:
      fullopcode = self.instructions[self.pcounter]
      opcode = fullopcode % 100
      mode_c = (int(fullopcode/100) % 10)
      mode_b = (int(fullopcode/1000) % 10)
      mode_a = (int(fullopcode/10000) % 10)
      pos_c = self.pcounter+1
      pos_b = self.pcounter+2
      pos_a = self.pcounter+3

      #print(self.ampid, "OP:", opcode, mode_c, mode_b, mode_a, pos_c, pos_b, pos_a)

      # add
      if opcode == 1:
        val = self.r(pos_c,mode_c) + self.r(pos_b,mode_b)
        self.w(pos_a, val, mode_a)
        self.pcounter += 4

      # multiply
      elif opcode == 2:
        val = self.r(pos_c, mode_c) * self.r(pos_b, mode_b)
        self.w(pos_a, val, mode_a)
        self.pcounter += 4

      # input
      elif opcode == 3:
        #print ("input:", self.inputs)
        store = self.inputs.pop(0)
        self.w(pos_c, store, mode_c)
        self.pcounter += 2

      # output
      elif opcode == 4:
        outputs.append(self.r(pos_c, mode_c))
        self.pcounter += 2
        #print("output:", outputs)
        return (outputs, self.finished)

      # jump-if-true
      elif opcode == 5:
        t = self.r(pos_c, mode_c)
        if t != 0:
          self.pcounter = self.r(pos_b, mode_b)
        else:
          self.pcounter += 3

      # jump-if-false
      elif opcode == 6:
        t = self.r(pos_c, mode_c)
        if t == 0:
          self.pcounter = self.r(pos_b, mode_b)
        else:
          self.pcounter += 3

      # less-than
      elif opcode == 7:
        c = self.r(pos_c, mode_c)
        b = self.r(pos_b, mode_b)
        if c < b:
          self.w(pos_a, 1, mode_a)
        else:
          self.w(pos_a, 0, mode_a)
        self.pcounter += 4

      # equals
      elif opcode == 8:
        c = self.r(pos_c, mode_c)
        b = self.r(pos_b, mode_b)
        if c == b:
          self.w(pos_a, 1, mode_a)
        else:
          self.w(pos_a, 0, mode_a)
        self.pcounter += 4

      # stop
      elif opcode == 99:
        self.finished = 1
        break

    return (outputs, self.finished)

def runamps(instructions, phase):
  amps = []
  r = [0]

  # Set up amps
  for i in range(0, 5):
    ints = []
    for j in instructions:
      ints.append(int(j))

    input = [phase[i], r[0]]
    a = Amp(ints,i)
    ret = a.perform(input)
    amps.append(a)
    r = ret[0]

  # Loop over amps until they're done processing.
  finished = 0
  while 1:
    if finished:
      break
    for i in range(0, 5):
      input = [r[0]]
      ret = amps[i].perform(input)
      if amps[i].terminated():
        finished = 1
      else:
        r = ret[0]
  return(r)

def permute(nums):
  result_perms = [[]]
  for n in nums:
    new_perms = []
    for perm in result_perms:
      for i in range(len(perm)+1):
        new_perms.append(perm[:i] + [n] + perm[i:])
        result_perms = new_perms
  return result_perms

f = open(sys.argv[1], "r")
line = f.readline()
instructions = line.rstrip().split(',')

print(runamps(instructions,[9,7,8,5,6]))

for a in permute([5,6,7,8,9]):
  ret = runamps(instructions, a)
  print("%s %s" % (ret[0], a))

faa89ed8331c6189f4c871df031a5e730bce7825
<mask token>


class Amp:

    def __init__(self, instructions, id):
        self.instructions = instructions
        self.pcounter = 0
        self.finished = 0
        self.ampid = id
        self.inputs = []

    def terminated(self):
        return self.finished

    def r(self, pos, mode):
        if mode == 0:
            return int(self.instructions[self.instructions[pos]])
        else:
            return int(self.instructions[pos])

    def w(self, pos, v, mode):
        if mode == 0:
            self.instructions[self.instructions[pos]] = v
        else:
            print('broken!', self.instructions, pos, v, mode)

    def perform(self, inputs):
        outputs = []
        for inp in inputs:
            self.inputs.append(inp)
        while 1:
            fullopcode = self.instructions[self.pcounter]
            opcode = fullopcode % 100
            mode_c = int(fullopcode / 100) % 10
            mode_b = int(fullopcode / 1000) % 10
            mode_a = int(fullopcode / 10000) % 10
            pos_c = self.pcounter + 1
            pos_b = self.pcounter + 2
            pos_a = self.pcounter + 3
            if opcode == 1:
                val = self.r(pos_c, mode_c) + self.r(pos_b, mode_b)
                self.w(pos_a, val, mode_a)
                self.pcounter += 4
            elif opcode == 2:
                val = self.r(pos_c, mode_c) * self.r(pos_b, mode_b)
                self.w(pos_a, val, mode_a)
                self.pcounter += 4
            elif opcode == 3:
                store = self.inputs.pop(0)
                self.w(pos_c, store, mode_c)
                self.pcounter += 2
            elif opcode == 4:
                outputs.append(self.r(pos_c, mode_c))
                self.pcounter += 2
                return outputs, self.finished
            elif opcode == 5:
                t = self.r(pos_c, mode_c)
                if t != 0:
                    self.pcounter = self.r(pos_b, mode_b)
                else:
                    self.pcounter += 3
            elif opcode == 6:
                t = self.r(pos_c, mode_c)
                if t == 0:
                    self.pcounter = self.r(pos_b, mode_b)
                else:
                    self.pcounter += 3
            elif opcode == 7:
                c = self.r(pos_c, mode_c)
                b = self.r(pos_b, mode_b)
                if c < b:
                    self.w(pos_a, 1, mode_a)
                else:
                    self.w(pos_a, 0, mode_a)
                self.pcounter += 4
            elif opcode == 8:
                c = self.r(pos_c, mode_c)
                b = self.r(pos_b, mode_b)
                if c == b:
                    self.w(pos_a, 1, mode_a)
                else:
                    self.w(pos_a, 0, mode_a)
                self.pcounter += 4
            elif opcode == 99:
                self.finished = 1
                break
        return outputs, self.finished


<mask token>

<mask token>


class Amp:

    def __init__(self, instructions, id):
        self.instructions = instructions
        self.pcounter = 0
        self.finished = 0
        self.ampid = id
        self.inputs = []

    def terminated(self):
        return self.finished

    def r(self, pos, mode):
        if mode == 0:
            return int(self.instructions[self.instructions[pos]])
        else:
            return int(self.instructions[pos])

    def w(self, pos, v, mode):
        if mode == 0:
            self.instructions[self.instructions[pos]] = v
        else:
            print('broken!', self.instructions, pos, v, mode)

    def perform(self, inputs):
        outputs = []
        for inp in inputs:
            self.inputs.append(inp)
        while 1:
            fullopcode = self.instructions[self.pcounter]
            opcode = fullopcode % 100
            mode_c = int(fullopcode / 100) % 10
            mode_b = int(fullopcode / 1000) % 10
            mode_a = int(fullopcode / 10000) % 10
            pos_c = self.pcounter + 1
            pos_b = self.pcounter + 2
            pos_a = self.pcounter + 3
            if opcode == 1:
                val = self.r(pos_c, mode_c) + self.r(pos_b, mode_b)
                self.w(pos_a, val, mode_a)
                self.pcounter += 4
            elif opcode == 2:
                val = self.r(pos_c, mode_c) * self.r(pos_b, mode_b)
                self.w(pos_a, val, mode_a)
                self.pcounter += 4
            elif opcode == 3:
                store = self.inputs.pop(0)
                self.w(pos_c, store, mode_c)
                self.pcounter += 2
            elif opcode == 4:
                outputs.append(self.r(pos_c, mode_c))
                self.pcounter += 2
                return outputs, self.finished
            elif opcode == 5:
                t = self.r(pos_c, mode_c)
                if t != 0:
                    self.pcounter = self.r(pos_b, mode_b)
                else:
                    self.pcounter += 3
            elif opcode == 6:
                t = self.r(pos_c, mode_c)
                if t == 0:
                    self.pcounter = self.r(pos_b, mode_b)
                else:
                    self.pcounter += 3
            elif opcode == 7:
                c = self.r(pos_c, mode_c)
                b = self.r(pos_b, mode_b)
                if c < b:
                    self.w(pos_a, 1, mode_a)
                else:
                    self.w(pos_a, 0, mode_a)
                self.pcounter += 4
            elif opcode == 8:
                c = self.r(pos_c, mode_c)
                b = self.r(pos_b, mode_b)
                if c == b:
                    self.w(pos_a, 1, mode_a)
                else:
                    self.w(pos_a, 0, mode_a)
                self.pcounter += 4
            elif opcode == 99:
                self.finished = 1
                break
        return outputs, self.finished


def runamps(instructions, phase):
    amps = []
    r = [0]
    for i in range(0, 5):
        ints = []
        for j in instructions:
            ints.append(int(j))
        input = [phase[i], r[0]]
        a = Amp(ints, i)
        ret = a.perform(input)
        amps.append(a)
        r = ret[0]
    finished = 0
    while 1:
        if finished:
            break
        for i in range(0, 5):
            input = [r[0]]
            ret = amps[i].perform(input)
            if amps[i].terminated():
                finished = 1
            else:
                r = ret[0]
    return r


def permute(nums):
    result_perms = [[]]
    for n in nums:
        new_perms = []
        for perm in result_perms:
            for i in range(len(perm) + 1):
                new_perms.append(perm[:i] + [n] + perm[i:])
                result_perms = new_perms
    return result_perms


<mask token>

<mask token>


class Amp:

    def __init__(self, instructions, id):
        self.instructions = instructions
        self.pcounter = 0
        self.finished = 0
        self.ampid = id
        self.inputs = []

    def terminated(self):
        return self.finished

    def r(self, pos, mode):
        if mode == 0:
            return int(self.instructions[self.instructions[pos]])
        else:
            return int(self.instructions[pos])

    def w(self, pos, v, mode):
        if mode == 0:
            self.instructions[self.instructions[pos]] = v
        else:
            print('broken!', self.instructions, pos, v, mode)

    def perform(self, inputs):
        outputs = []
        for inp in inputs:
            self.inputs.append(inp)
        while 1:
            fullopcode = self.instructions[self.pcounter]
            opcode = fullopcode % 100
            mode_c = int(fullopcode / 100) % 10
            mode_b = int(fullopcode / 1000) % 10
            mode_a = int(fullopcode / 10000) % 10
            pos_c = self.pcounter + 1
            pos_b = self.pcounter + 2
            pos_a = self.pcounter + 3
            if opcode == 1:
                val = self.r(pos_c, mode_c) + self.r(pos_b, mode_b)
                self.w(pos_a, val, mode_a)
                self.pcounter += 4
            elif opcode == 2:
                val = self.r(pos_c, mode_c) * self.r(pos_b, mode_b)
                self.w(pos_a, val, mode_a)
                self.pcounter += 4
            elif opcode == 3:
                store = self.inputs.pop(0)
                self.w(pos_c, store, mode_c)
                self.pcounter += 2
            elif opcode == 4:
                outputs.append(self.r(pos_c, mode_c))
                self.pcounter += 2
                return outputs, self.finished
            elif opcode == 5:
                t = self.r(pos_c, mode_c)
                if t != 0:
                    self.pcounter = self.r(pos_b, mode_b)
                else:
                    self.pcounter += 3
            elif opcode == 6:
                t = self.r(pos_c, mode_c)
                if t == 0:
                    self.pcounter = self.r(pos_b, mode_b)
                else:
                    self.pcounter += 3
            elif opcode == 7:
                c = self.r(pos_c, mode_c)
                b = self.r(pos_b, mode_b)
                if c < b:
                    self.w(pos_a, 1, mode_a)
                else:
                    self.w(pos_a, 0, mode_a)
                self.pcounter += 4
            elif opcode == 8:
                c = self.r(pos_c, mode_c)
                b = self.r(pos_b, mode_b)
                if c == b:
                    self.w(pos_a, 1, mode_a)
                else:
                    self.w(pos_a, 0, mode_a)
                self.pcounter += 4
            elif opcode == 99:
                self.finished = 1
                break
        return outputs, self.finished


def runamps(instructions, phase):
    amps = []
    r = [0]
    for i in range(0, 5):
        ints = []
        for j in instructions:
            ints.append(int(j))
        input = [phase[i], r[0]]
        a = Amp(ints, i)
        ret = a.perform(input)
        amps.append(a)
        r = ret[0]
    finished = 0
    while 1:
        if finished:
            break
        for i in range(0, 5):
            input = [r[0]]
            ret = amps[i].perform(input)
            if amps[i].terminated():
                finished = 1
            else:
                r = ret[0]
    return r


def permute(nums):
    result_perms = [[]]
    for n in nums:
        new_perms = []
        for perm in result_perms:
            for i in range(len(perm) + 1):
                new_perms.append(perm[:i] + [n] + perm[i:])
                result_perms = new_perms
    return result_perms


<mask token>
print(runamps(instructions, [9, 7, 8, 5, 6]))
for a in permute([5, 6, 7, 8, 9]):
    ret = runamps(instructions, a)
    print('%s %s' % (ret[0], a))

import sys


class Amp:

    def __init__(self, instructions, id):
        self.instructions = instructions
        self.pcounter = 0
        self.finished = 0
        self.ampid = id
        self.inputs = []

    def terminated(self):
        return self.finished

    def r(self, pos, mode):
        if mode == 0:
            return int(self.instructions[self.instructions[pos]])
        else:
            return int(self.instructions[pos])

    def w(self, pos, v, mode):
        if mode == 0:
            self.instructions[self.instructions[pos]] = v
        else:
            print('broken!', self.instructions, pos, v, mode)

    def perform(self, inputs):
        outputs = []
        for inp in inputs:
            self.inputs.append(inp)
        while 1:
            fullopcode = self.instructions[self.pcounter]
            opcode = fullopcode % 100
            mode_c = int(fullopcode / 100) % 10
            mode_b = int(fullopcode / 1000) % 10
            mode_a = int(fullopcode / 10000) % 10
            pos_c = self.pcounter + 1
            pos_b = self.pcounter + 2
            pos_a = self.pcounter + 3
            if opcode == 1:
                val = self.r(pos_c, mode_c) + self.r(pos_b, mode_b)
                self.w(pos_a, val, mode_a)
                self.pcounter += 4
            elif opcode == 2:
                val = self.r(pos_c, mode_c) * self.r(pos_b, mode_b)
                self.w(pos_a, val, mode_a)
                self.pcounter += 4
            elif opcode == 3:
                store = self.inputs.pop(0)
                self.w(pos_c, store, mode_c)
                self.pcounter += 2
            elif opcode == 4:
                outputs.append(self.r(pos_c, mode_c))
                self.pcounter += 2
                return outputs, self.finished
            elif opcode == 5:
                t = self.r(pos_c, mode_c)
                if t != 0:
                    self.pcounter = self.r(pos_b, mode_b)
                else:
                    self.pcounter += 3
            elif opcode == 6:
                t = self.r(pos_c, mode_c)
                if t == 0:
                    self.pcounter = self.r(pos_b, mode_b)
                else:
                    self.pcounter += 3
            elif opcode == 7:
                c = self.r(pos_c, mode_c)
                b = self.r(pos_b, mode_b)
                if c < b:
                    self.w(pos_a, 1, mode_a)
                else:
                    self.w(pos_a, 0, mode_a)
                self.pcounter += 4
            elif opcode == 8:
                c = self.r(pos_c, mode_c)
                b = self.r(pos_b, mode_b)
                if c == b:
                    self.w(pos_a, 1, mode_a)
                else:
                    self.w(pos_a, 0, mode_a)
                self.pcounter += 4
            elif opcode == 99:
                self.finished = 1
                break
        return outputs, self.finished


def runamps(instructions, phase):
    amps = []
    r = [0]
    for i in range(0, 5):
        ints = []
        for j in instructions:
            ints.append(int(j))
        input = [phase[i], r[0]]
        a = Amp(ints, i)
        ret = a.perform(input)
        amps.append(a)
        r = ret[0]
    finished = 0
    while 1:
        if finished:
            break
        for i in range(0, 5):
            input = [r[0]]
            ret = amps[i].perform(input)
            if amps[i].terminated():
                finished = 1
            else:
                r = ret[0]
    return r


def permute(nums):
    result_perms = [[]]
    for n in nums:
        new_perms = []
        for perm in result_perms:
            for i in range(len(perm) + 1):
                new_perms.append(perm[:i] + [n] + perm[i:])
                result_perms = new_perms
    return result_perms


f = open(sys.argv[1], 'r')
line = f.readline()
instructions = line.rstrip().split(',')
print(runamps(instructions, [9, 7, 8, 5, 6]))
for a in permute([5, 6, 7, 8, 9]):
    ret = runamps(instructions, a)
    print('%s %s' % (ret[0], a))

#!/usr/bin/env python3

import sys

class Amp:
  def __init__(self, instructions, id):
    self.instructions = instructions
    self.pcounter = 0
    self.finished = 0
    self.ampid = id
    self.inputs = []

  def terminated(self):
    return self.finished

  def r(self, pos, mode):
    if mode == 0:
      return int(self.instructions[self.instructions[pos]])
    else: 
      return int(self.instructions[pos])

  def w(self, pos, v, mode):
    if mode == 0:
      self.instructions[self.instructions[pos]] = v
    else:
      print("broken!", self.instructions, pos, v, mode)

  def perform(self, inputs):
    outputs = []

    for inp in inputs:
      self.inputs.append(inp)

    while 1:
      fullopcode = self.instructions[self.pcounter]
      opcode = fullopcode % 100
      mode_c = (int(fullopcode/100) % 10)
      mode_b = (int(fullopcode/1000) % 10)
      mode_a = (int(fullopcode/10000) % 10)
      pos_c = self.pcounter+1
      pos_b = self.pcounter+2
      pos_a = self.pcounter+3

      #print(self.ampid, "OP:", opcode, mode_c, mode_b, mode_a, pos_c, pos_b, pos_a)

      # add
      if opcode == 1:
        val = self.r(pos_c,mode_c) + self.r(pos_b,mode_b)
        self.w(pos_a, val, mode_a)
        self.pcounter += 4

      # multiply
      elif opcode == 2:
        val = self.r(pos_c, mode_c) * self.r(pos_b, mode_b)
        self.w(pos_a, val, mode_a)
        self.pcounter += 4

      # input
      elif opcode == 3:
        #print ("input:", self.inputs)
        store = self.inputs.pop(0)
        self.w(pos_c, store, mode_c)
        self.pcounter += 2

      # output
      elif opcode == 4:
        outputs.append(self.r(pos_c, mode_c))
        self.pcounter += 2
        #print("output:", outputs)
        return (outputs, self.finished)

      # jump-if-true
      elif opcode == 5:
        t = self.r(pos_c, mode_c)
        if t != 0:
          self.pcounter = self.r(pos_b, mode_b)
        else:
          self.pcounter += 3

      # jump-if-false
      elif opcode == 6:
        t = self.r(pos_c, mode_c)
        if t == 0:
          self.pcounter = self.r(pos_b, mode_b)
        else:
          self.pcounter += 3

      # less-than
      elif opcode == 7:
        c = self.r(pos_c, mode_c)
        b = self.r(pos_b, mode_b)
        if c < b:
          self.w(pos_a, 1, mode_a)
        else:
          self.w(pos_a, 0, mode_a)
        self.pcounter += 4

      # equals
      elif opcode == 8:
        c = self.r(pos_c, mode_c)
        b = self.r(pos_b, mode_b)
        if c == b:
          self.w(pos_a, 1, mode_a)
        else:
          self.w(pos_a, 0, mode_a)
        self.pcounter += 4

      # stop
      elif opcode == 99:
        self.finished = 1
        break

    return (outputs, self.finished)

def runamps(instructions, phase):
  amps = []
  r = [0]

  # Set up amps
  for i in range(0, 5):
    ints = []
    for j in instructions:
      ints.append(int(j))

    input = [phase[i], r[0]]
    a = Amp(ints,i)
    ret = a.perform(input)
    amps.append(a)
    r = ret[0]

  # Loop over amps until they're done processing.
  finished = 0
  while 1:
    if finished:
      break
    for i in range(0, 5):
      input = [r[0]]
      ret = amps[i].perform(input)
      if amps[i].terminated():
        finished = 1
      else:
        r = ret[0]
  return(r)

def permute(nums):
  result_perms = [[]]
  for n in nums:
    new_perms = []
    for perm in result_perms:
      for i in range(len(perm)+1):
        new_perms.append(perm[:i] + [n] + perm[i:])
        result_perms = new_perms
  return result_perms

f = open(sys.argv[1], "r")
line = f.readline()
instructions = line.rstrip().split(',')

print(runamps(instructions,[9,7,8,5,6]))

for a in permute([5,6,7,8,9]):
  ret = runamps(instructions, a)
  print("%s %s" % (ret[0], a))
