-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path13.q
121 lines (93 loc) · 3.73 KB
/
13.q
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/ 13.q
/ Advent of Code 2019
/ Public domain as declared by Sturm Mabie
\l 0.q
init:("J"$) each "," vs (read0 `:13.txt)[0] / instruction data
unit:-1
buf:()
/ resolve value parameters
resolve:{[amp; mode; val]
$[mode=1; val; / immediate mode
mode=2; get_tape[amp;] val+get_prop[amp; `base]; / relative base mode
get_tape[amp; val]]} / position mode
/ generate values for each parameter, should not be used for assignment
params:{[amp; x; y; z] (resolve[amp;;]/) each (neg z) _ flip (x; y)} / resolve first n params
/ add/mul higher-order function
gen_am:{[amp; info; values; f]
mod_tape[amp; last values; last info;] f params[amp; info; values; 1]; unit}
/ jump-if-true/jump-if-false higher-order function
gen_jj:{[amp; info; values; f] xs:params[amp; info; values; 0];
$[not f[0; first xs]; unit; last xs]}
/ less-than/equal higher-order function
gen_le:{[amp; info; values; f] xs:params[amp; info; values; 1];
mod_tape[amp; last values; last info;] $[f[xs[0]; xs[1]]; 1; 0]; unit}
op_add:{gen_am[x; y; z; sum]} / 1,x,y,z -> z=x+y
op_mul:{gen_am[x; y; z; prd]} / 2,x,y,z -> z=x*y
paddle:()
ball:()
op_read:{[amp; info; values] / 3,x -> x<-input
f:{@[;0] x where y=@[;0] flip (2_) each x};
coords:stk where not v:{(-1; 0)~-1_ x} each stk:3 cut buf;
if[0<>count r:f[coords; 3]; paddle::r];
if[0<>count r:f[coords; 4]; ball::r];
dir:$[paddle[0]=ball[0]; 0; paddle[0]<ball[0]; 1; -1];
buf::();
mod_tape[amp; first values; first info;] dir; unit}
op_show:{[amp; info; values] / 4,x -> output<-x
obj:resolve[amp;] over info,values; buf,:obj; unit}
op_jit:{gen_jj[x; y; z; <>]} / 5,x,y -> jmp y if x!=0
op_jif:{gen_jj[x; y; z; =]} / 6,x,y -> jmp y if x=0
op_lt:{gen_le[x; y; z; <]} / 7,x,y -> z=x<y
op_eql:{gen_le[x; y; z; =]} / 8,x,y -> z=x=y
op_base:{[amp; info; values] / 9,x -> BASE=x
mod_prop[amp; `base;] get_prop[amp; `base]+(resolve[amp;] . info,values); unit}
/ instruction table
ops:1 2 3 4 5 6 7 8 9!((op_add; 3); (op_mul; 3); (op_read; 1);
(op_show; 1); (op_jit; 2); (op_jif; 2); (op_lt; 3); (op_eql; 3);
(op_base; 1))
/ parse opcode
read_op:{xs:((2-count op+len:(ops[last op])[1])#0),op:10 vs x;
(10 sv len _ ys),reverse (neg 2) _ ys:((2+len-count op)#0),op}
/ run opcode
run_op:{[amp; op_info; values] f:ops[first op_info][0]; f[amp; 1 _ op_info; values]}
/ execute instruction
step:{[amp] idx:get_prop[amp; `idx];
if[99=op:get_tape[amp; idx]; :`end];
len:last ops[first info:read_op op];
mod_prop[amp; `idx;] idx+len+1;
$[unit=r:run_op[amp; info;] (idx+1; len) sublist get_prop[amp; `tape]; amp;
mod_prop[amp; `idx; r]]}
/ run machine until exiting
run:{[sym]
cur:sym;
while[cur<>`end; cur:step cur];
}
/ create dictionary that stores tape state
/ tape - the instruction tape
/ len - length of tape
/ base - relative base offset (mode 2)
/ idx - current instruction pointer location
mk_tape:{[sym] sym set `tape`len`base`idx!(init; count init; 0; 0)}
/ extend the tape if necessary
extend_tape:{[amp; idx]
if[idx>=len:get_prop[amp; `len];
@[amp; `tape; :;] @[(idx+1)#0; til len; :;] get_prop[amp; `tape];
mod_prop[amp; `len;] idx+1];
}
/ get dictionary property
get_prop:{[amp; sym] get[amp]sym}
/ modify property
mod_prop:{[amp; sym; val] @[amp; sym; :; val]}
/ modify tape, add relative base to index if mode=2
mod_tape:{[amp; idx; mode; val]
addr:idx+$[mode=2; get_prop[amp; `base]; 0];
extend_tape[amp; addr]; .[amp; (`tape; addr); :; val]}
/ return value at specified tape index
get_tape:{[amp; idx] extend_tape[amp; idx]; get[amp][`tape]idx}
run mk_tape `a;
part1 @[;0] sum 2=(2_) each 3 cut buf;
mk_tape `a;
mod_tape[`a; 0; 0; 2];
run `a;
part2 max @[;0] flip (2_) each (3 cut buf);
exit 0