-
Notifications
You must be signed in to change notification settings - Fork 0
/
2017_18.cs
180 lines (156 loc) · 5.98 KB
/
2017_18.cs
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
namespace AOC.CSharp;
public static class AOC2017_18
{
public static long Solve1(string[] lines)
{
Line[] parsed = lines.Select(x => new Line(x)).ToArray();
RegisterFacade reg = new();
long lastPlayed = 0;
long ip = 0;
while (true)
{
Line line = parsed[ip];
switch (line.Instruction)
{
case "snd":
lastPlayed = reg.Get(line.Arg1);
ip++;
break;
case "set":
reg.Set(line.Arg1, line.Arg2);
ip++;
break;
case "add":
reg.Add(line.Arg1, line.Arg2);
ip++;
break;
case "mul":
reg.Mul(line.Arg1, line.Arg2);
ip++;
break;
case "mod":
reg.Mod(line.Arg1, line.Arg2);
ip++;
break;
case "rcv":
if (reg.Get(line.Arg1) != 0)
{
return lastPlayed;
}
ip++;
break;
case "jgz":
long amount = reg.Get(line.Arg1) > 0 ? reg.Get(line.Arg2) : 1;
ip += amount;
break;
}
}
}
public static long Solve2(string[] lines)
{
Line[] parsed = lines.Select(x => new Line(x)).ToArray();
// Maintain two copies of everything - one for each program
RegisterFacade[] reg = new RegisterFacade[2];
Queue<long>[] queues = new Queue<long>[2];
long[] ip = new long[2];
bool[] isWaiting = new bool[2];
long[] sendCounts = new long[2];
for (int i = 0; i <= 1; i++)
{
reg[i] = new();
reg[i].Set("p", i.ToString());
queues[i] = new();
}
// Keep track of which program index is executing and which one is waiting
int running = 0;
int waiting = 1;
while (true)
{
Line line = parsed[ip[running]];
switch (line.Instruction)
{
case "snd":
sendCounts[running]++;
queues[waiting].Enqueue(reg[running].Get(line.Arg1));
ip[running]++;
break;
case "set":
reg[running].Set(line.Arg1, line.Arg2);
ip[running]++;
break;
case "add":
reg[running].Add(line.Arg1, line.Arg2);
ip[running]++;
break;
case "mul":
reg[running].Mul(line.Arg1, line.Arg2);
ip[running]++;
break;
case "mod":
reg[running].Mod(line.Arg1, line.Arg2);
ip[running]++;
break;
case "rcv":
if (queues[running].TryDequeue(out long result))
{
// Tried to receive and had something on the queue. We can continue
// executing this program
reg[running].Set(line.Arg1, result);
ip[running]++;
isWaiting[running] = false;
}
else if (isWaiting[waiting] && queues[waiting].Count == 0)
{
// Deadlock. Neither program is able to continue since both are waiting
// to receive and there is nothing on either queue.
return sendCounts[1];
}
else
{
// Tried to receive and had nothing on the queue (but did not land in
// the termination condition yet). Mark this program as waiting and do
// a context switch
isWaiting[running] = true;
(running, waiting) = (waiting, running);
}
break;
case "jgz":
long amount = reg[running].Get(line.Arg1) > 0 ? reg[running].Get(line.Arg2) : 1;
ip[running] += amount;
break;
}
}
}
private class RegisterFacade
{
private readonly Dictionary<string, long> _values = new();
public void Set(string name, string value) => _values[name] = GetRegOrLiteral(value);
public void Set(string name, long value) => _values[name] = value;
public void Add(string name, string value) =>
_values[name] = Get(name) + GetRegOrLiteral(value);
public void Mul(string name, string value) =>
_values[name] = Get(name) * GetRegOrLiteral(value);
public void Mod(string name, string value) =>
_values[name] = Get(name) % GetRegOrLiteral(value);
// Get the value of the register or the literal if the argument is numeric (bypass
// the register lookup). Encapsulating the key/literal decisions here eliminates
// conditionals in the instruction processing logic above
public long Get(string value) => GetRegOrLiteral(value);
private long GetRegOrLiteral(string value) =>
long.TryParse(value, out long parsed) ? parsed : GetReg(value);
private long GetReg(string name) => _values.TryGetValue(name, out long value) ? value : 0L;
}
private class Line
{
public Line(string line)
{
string[] splits = line.Split(" ");
Instruction = splits[0];
Arg1 = splits[1];
Arg2 = splits.Length == 3 ? splits[2] : null;
}
public string Instruction { get; }
public string Arg1 { get; }
public string Arg2 { get; }
}
}