You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.1KB

  1. import collections
  2. import itertools
  3. import re
  4. def parse(string):
  5. memory = collections.defaultdict(int)
  6. memory.update(enumerate(int(n) for n in re.findall(r'-?\d+', string)))
  7. return dict(memory)
  8. def get_parameters(ns, pos, modes, N, writes, relbase):
  9. for c in writes:
  10. # paradox: return immediate mode to use positionally outside
  11. modes[ord(c) - ord('a')] += '-special'
  12. for mode, x in zip(modes, [ns[y] for y in range(pos, pos + N)]):
  13. yield {
  14. '0': lambda: ns[x],
  15. '1': lambda: x,
  16. '2': lambda: ns[x + relbase],
  17. '0-special': lambda: x,
  18. '2-special': lambda: x + relbase,
  19. }[mode]()
  20. yield pos + N
  21. def compute(ns, in_iter):
  22. if isinstance(ns, str):
  23. ns = parse(ns)
  24. if isinstance(in_iter, int):
  25. in_iter = itertools.cycle([in_iter])
  26. pos = 0
  27. relbase = 0
  28. consume = lambda n, writes='': get_parameters(ns, pos, modes, n, writes, relbase)
  29. while True:
  30. op = ns[pos] % 100
  31. # instructions stupidly say ABC referring to parameters 3, 2, 1
  32. # we do a, b, c
  33. modes = list(str(ns[pos] // 100).zfill(3)[::-1])
  34. pos += 1
  35. if op == 1:
  36. a, b, c, pos = consume(3, 'c')
  37. ns[c] = a + b
  38. elif op == 2:
  39. a, b, c, pos = consume(3, 'c')
  40. ns[c] = a * b
  41. elif op == 3:
  42. a, pos = consume(1, 'a')
  43. ns[a] = next(in_iter)
  44. elif op == 4:
  45. a, pos = consume(1)
  46. yield a
  47. elif op == 5:
  48. a, b, pos = consume(2)
  49. if a != 0:
  50. pos = b
  51. elif op == 6:
  52. a, b, pos = consume(2)
  53. if a == 0:
  54. pos = b
  55. elif op == 7:
  56. a, b, c, pos = consume(3, 'c')
  57. ns[c] = int(a < b)
  58. elif op == 8:
  59. a, b, c, pos = consume(3, 'c')
  60. ns[c] = int(a == b)
  61. elif op == 9:
  62. a, pos = consume(1)
  63. relbase += a
  64. elif op == 99:
  65. return
  66. else:
  67. raise RuntimeError(op)