Browse Source

Icky day 21.

Abstract elfcode handling into its own file.
master
Chris Smith 5 years ago
parent
commit
edeba1b77f
6 changed files with 122 additions and 74 deletions
  1. 2
    0
      answers/21.txt
  2. 32
    0
      data/21.txt
  3. 5
    28
      day16.nim
  4. 7
    46
      day19.nim
  5. 27
    0
      day21.nim
  6. 49
    0
      elfcode.nim

+ 2
- 0
answers/21.txt View File

@@ -0,0 +1,2 @@
1
+3345459
2
+5857354

+ 32
- 0
data/21.txt View File

@@ -0,0 +1,32 @@
1
+#ip 2
2
+seti 123 0 1            # r1 = 123        <-\
3
+bani 1 456 1            # r1 = r1 and 456   | F
4
+eqri 1 72 1             # r1 = r1 == 72  ---+
5
+addr 1 2 2              # jmp r1            | T
6
+seti 0 0 2              # jmp @1            |
7
+seti 0 9 1              # r1 = 0          <-/
8
+bori 1 65536 4          # r4 = r1 or 65536  <------------------\
9
+seti 16298264 8 1       # r1 = 16298264                        |
10
+bani 4 255 5            # r5 = r4 and 255    <------\          |
11
+addr 1 5 1              # r1 = r1 + r5              |          |
12
+bani 1 16777215 1       # r1 = r1 and 16777215      |          |
13
+muli 1 65899 1          # r1 = r1 * 65899           |          |
14
+bani 1 16777215 1       # r1 = r1 and 16777215      |          |
15
+gtir 256 4 5            # r5 = 256 > r4  -----------------\    |
16
+addr 5 2 2              # jmp @r5                   |     |    |
17
+addi 2 1 2              # jmp 1                     |     |    |
18
+seti 27 1 2             # jmp @28                   |  F  |    |
19
+seti 0 3 5              # r5 = 0          <---------------+    |
20
+addi 5 1 3              # r3 = r5 + 1               |     | T  |
21
+muli 3 256 3            # r3 = r3 * 256             |     |    |
22
+gtrr 3 4 3              # r3 = r3 > r4              |     |    |
23
+addr 3 2 2              # jmp @r3          ----\    |     |    |
24
+addi 2 1 2              # jmp 1                |    |     |    |
25
+seti 25 4 2             # jmp @26            F |    |     |    |
26
+addi 5 1 5              # r5 = r5 + 1      <---+    |     |    |
27
+seti 17 1 2             # jmp @18            T |    |     |    |
28
+setr 5 3 4              # r4 = r5          <---/    |     |    |
29
+seti 7 7 2              # jmp @8        ------------/     |    | F
30
+eqrr 1 0 5              # r5 = r1 == r0                   \----+
31
+addr 5 2 2              # jmp @r5                              | T
32
+seti 5 3 2              # jmp @6                               v 

+ 5
- 28
day16.nim View File

@@ -1,29 +1,4 @@
1
-import sequtils, strutils
2
-
3
-let ops = [
4
-    proc(regs: seq[int], a,b: int): int = regs[a] + b,
5
-    proc(regs: seq[int], a,b: int): int = regs[a] + regs[b],
6
-
7
-    proc(regs: seq[int], a,b: int): int = regs[a] * b,
8
-    proc(regs: seq[int], a,b: int): int = regs[a] * regs[b],
9
-
10
-    proc(regs: seq[int], a,b: int): int = regs[a] and b,
11
-    proc(regs: seq[int], a,b: int): int = regs[a] and regs[b],
12
-
13
-    proc(regs: seq[int], a,b: int): int = regs[a] or b,
14
-    proc(regs: seq[int], a,b: int): int = regs[a] or regs[b],
15
-
16
-    proc(regs: seq[int], a,b: int): int = a,
17
-    proc(regs: seq[int], a,b: int): int = regs[a],
18
-
19
-    proc(regs: seq[int], a,b: int): int = cast[int](a > regs[b]),
20
-    proc(regs: seq[int], a,b: int): int = cast[int](regs[a] > b),
21
-    proc(regs: seq[int], a,b: int): int = cast[int](regs[a] > regs[b]),
22
-
23
-    proc(regs: seq[int], a,b: int): int = cast[int](a == regs[b]),
24
-    proc(regs: seq[int], a,b: int): int = cast[int](regs[a] == b),
25
-    proc(regs: seq[int], a,b: int): int = cast[int](regs[a] == regs[b]),
26
-]
1
+import elfcode, sequtils, strutils, tables
27 2
 
28 3
 func toInstr(line: string): seq[int] = line.strip.split(" ").map(parseInt)
29 4
 func toRegisterSample(line: string): seq[int] = line.substr(9, line.len - 2).split(", ").map(parseInt)
@@ -31,6 +6,8 @@ func toRegisterSample(line: string): seq[int] = line.substr(9, line.len - 2).spl
31 6
 proc execute(regs: var seq[int], instr: seq[int], opcodes: array[16, proc(regs: seq[int], a,b: int): int]) =
32 7
     regs[instr[3]] = opcodes[instr[0]](regs, instr[1], instr[2])
33 8
 
9
+let opsSeq = toSeq(ops.values)
10
+
34 11
 var
35 12
     before, instr, after: seq[int]
36 13
     opPossibilities: array[16, array[16, bool]]
@@ -49,7 +26,7 @@ for line in readFile("data/16.txt").splitlines:
49 26
     elif step == 2:
50 27
         after = line.toRegisterSample
51 28
         var count = 0
52
-        for i, op in ops:
29
+        for i, op in opsSeq:
53 30
             var actual: seq[int]
54 31
             actual.shallowCopy(before)
55 32
             actual[instr[3]] = op(before, instr[1], instr[2])
@@ -71,7 +48,7 @@ for line in readFile("data/16.txt").splitlines:
71 48
                 if matrix.count((false, false)) == 1:
72 49
                     let index = matrix.find((false, false))
73 50
                     found[index] = true
74
-                    opMappings[opcode] = ops[index]
51
+                    opMappings[opcode] = opsSeq[index]
75 52
         step = -1
76 53
     
77 54
     if step == -1 and line.len > 5:

+ 7
- 46
day19.nim View File

@@ -1,44 +1,8 @@
1
-import math, sequtils, strutils, tables
1
+import elfcode, math, sequtils, strutils, tables
2 2
 
3
-type instr = tuple[op: string, a,b,c: int]
3
+var instructionSet = readInstructions(readFile("data/19.txt").strip.splitlines)
4 4
 
5
-let ops = {
6
-    "addi": proc(regs: seq[int], a,b: int): int = regs[a] + b,
7
-    "addr": proc(regs: seq[int], a,b: int): int = regs[a] + regs[b],
8
-
9
-    "muli": proc(regs: seq[int], a,b: int): int = regs[a] * b,
10
-    "mulr": proc(regs: seq[int], a,b: int): int = regs[a] * regs[b],
11
-
12
-    "bani": proc(regs: seq[int], a,b: int): int = regs[a] and b,
13
-    "banr": proc(regs: seq[int], a,b: int): int = regs[a] and regs[b],
14
-
15
-    "bori": proc(regs: seq[int], a,b: int): int = regs[a] or b,
16
-    "borr": proc(regs: seq[int], a,b: int): int = regs[a] or regs[b],
17
-
18
-    "seti": proc(regs: seq[int], a,b: int): int = a,
19
-    "setr": proc(regs: seq[int], a,b: int): int = regs[a],
20
-
21
-    "gtir": proc(regs: seq[int], a,b: int): int = cast[int](a > regs[b]),
22
-    "gtri": proc(regs: seq[int], a,b: int): int = cast[int](regs[a] > b),
23
-    "gtrr": proc(regs: seq[int], a,b: int): int = cast[int](regs[a] > regs[b]),
24
-
25
-    "eqir": proc(regs: seq[int], a,b: int): int = cast[int](a == regs[b]),
26
-    "eqri": proc(regs: seq[int], a,b: int): int = cast[int](regs[a] == b),
27
-    "eqrr": proc(regs: seq[int], a,b: int): int = cast[int](regs[a] == regs[b]),
28
-}.toTable
29
-
30
-var
31
-    instructions: seq[instr]
32
-    ip: int
33
-
34
-for line in readFile("data/19.txt").strip.splitlines:
35
-    var parts = line.split(' ')
36
-    if parts[0] == "#ip":
37
-        ip = parts[1].parseInt
38
-    else:
39
-        instructions.add((parts[0], parts[1].parseInt, parts[2].parseInt, parts[3].parseInt))
40
-
41
-proc findTarget(part2: bool): int =
5
+proc findTarget(part2: bool = false): int =
42 6
     # The instructions calculate the sum of all factors of a target number. The
43 7
     # target is initialised first, and then execution jumps back to near the
44 8
     # start of the program to perform the calculation. To find the target
@@ -46,12 +10,9 @@ proc findTarget(part2: bool): int =
46 10
     # register. (Yuck.)
47 11
     var registers = @[if part2: 1 else: 0, 0, 0, 0, 0, 0]
48 12
     while true:
49
-        let
50
-            i = registers[ip]
51
-            instr = instructions[i]
52
-        registers[instr.c] = ops[instr.op](registers, instr.a, instr.b)
53
-        registers[ip].inc
54
-        if registers[ip] < i:
13
+        let i = instructionSet.ip(registers)
14
+        instructionSet.step(registers)
15
+        if instructionSet.ip(registers) < i:
55 16
             return registers.max
56 17
 
57 18
 proc factors(n: int): seq[int] =
@@ -60,5 +21,5 @@ proc factors(n: int): seq[int] =
60 21
             result.add(x)
61 22
             result.add(n div x)
62 23
    
63
-echo findTarget(false).factors.sum
24
+echo findTarget().factors.sum
64 25
 echo findTarget(true).factors.sum

+ 27
- 0
day21.nim View File

@@ -0,0 +1,27 @@
1
+import elfcode, math, sequtils, strutils, sets
2
+
3
+var
4
+    instructionSet = readInstructions(readFile("data/21.txt").strip.splitlines)
5
+    seen = initSet[int](15000.nextPowerOfTwo)
6
+    last = 0
7
+
8
+iterator emulate(): int =
9
+    var r1, r4 = 0
10
+    
11
+    while true:
12
+        r4 = r1 or 65536
13
+        r1 = instructionSet.instructions[7].a
14
+        
15
+        while r4 > 0:
16
+            r1 = (((r1 + (r4 and 255)) and instructionSet.instructions[10].b) *
17
+                    instructionSet.instructions[11].b) and instructionSet.instructions[12].b
18
+            r4 = r4 div 256
19
+        yield r1
20
+
21
+for i in emulate():
22
+    if seen.len == 0:
23
+        echo i
24
+    if seen.containsOrIncl(i):
25
+        echo last
26
+        break
27
+    last = i

+ 49
- 0
elfcode.nim View File

@@ -0,0 +1,49 @@
1
+import strutils, tables
2
+
3
+type
4
+    instr* = tuple[op: string, a,b,c: int]
5
+    instructionSet* = tuple[ipr: int, instructions: seq[instr]]
6
+
7
+let ops* = {
8
+    "addi": proc(regs: seq[int], a,b: int): int = regs[a] + b,
9
+    "addr": proc(regs: seq[int], a,b: int): int = regs[a] + regs[b],
10
+
11
+    "muli": proc(regs: seq[int], a,b: int): int = regs[a] * b,
12
+    "mulr": proc(regs: seq[int], a,b: int): int = regs[a] * regs[b],
13
+
14
+    "bani": proc(regs: seq[int], a,b: int): int = regs[a] and b,
15
+    "banr": proc(regs: seq[int], a,b: int): int = regs[a] and regs[b],
16
+
17
+    "bori": proc(regs: seq[int], a,b: int): int = regs[a] or b,
18
+    "borr": proc(regs: seq[int], a,b: int): int = regs[a] or regs[b],
19
+
20
+    "seti": proc(regs: seq[int], a,b: int): int = a,
21
+    "setr": proc(regs: seq[int], a,b: int): int = regs[a],
22
+
23
+    "gtir": proc(regs: seq[int], a,b: int): int = cast[int](a > regs[b]),
24
+    "gtri": proc(regs: seq[int], a,b: int): int = cast[int](regs[a] > b),
25
+    "gtrr": proc(regs: seq[int], a,b: int): int = cast[int](regs[a] > regs[b]),
26
+
27
+    "eqir": proc(regs: seq[int], a,b: int): int = cast[int](a == regs[b]),
28
+    "eqri": proc(regs: seq[int], a,b: int): int = cast[int](regs[a] == b),
29
+    "eqrr": proc(regs: seq[int], a,b: int): int = cast[int](regs[a] == regs[b]),
30
+}.toTable
31
+
32
+proc readInstructions*(input: seq[string]): instructionSet =
33
+    for line in input:
34
+        var parts = line.split(' ')
35
+        if parts[0] == "#ip":
36
+            result.ipr = parts[1].parseInt
37
+        else:
38
+            result.instructions.add((parts[0], parts[1].parseInt, parts[2].parseInt, parts[3].parseInt))
39
+
40
+proc ip*(instructionSet: instructionSet, registers: seq[int]): int {.inline.} =
41
+    registers[instructionSet.ipr]
42
+
43
+proc currentInstr*(instructionSet: instructionSet, registers: seq[int]): instr {.inline.} =
44
+    instructionSet.instructions[instructionSet.ip(registers)]
45
+
46
+proc step*(instructionSet: instructionSet, registers: var seq[int]) {.inline.} =
47
+    let instr = instructionSet.currentInstr(registers)
48
+    registers[instr.c] = ops[instr.op](registers, instr.a, instr.b)
49
+    registers[instructionSet.ipr].inc