Skip to content

Commit f2422e0

Browse files
committed
🚧 🚧
1 parent fcbb2c1 commit f2422e0

File tree

1 file changed

+329
-15
lines changed

1 file changed

+329
-15
lines changed

day24-arithmetic-logic-unit/solution.py

Lines changed: 329 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,242 @@ def check(self):
207207
c += 1
208208
if c % 10 == 0:
209209
print(c, proc_id, len(q))
210+
211+
def assert_procedure(self, proc_id, proc, tests=1000):
212+
passed = 0
213+
failed = 0
214+
for i in range(0, tests):
215+
for d in range(1, 10):
216+
expected = self.exec_proc(proc_id, i, d)['z']
217+
value = proc(i, d)
218+
if value != expected:
219+
print('Failed for procedure {} on digit {} (input {}). Expected {}, but got {} instead.'.format(
220+
proc_id, d, i, expected, value))
221+
failed += 1
222+
else:
223+
passed += 1
224+
print('Tests: {}. Failed: {}. Passed: {}'.format((failed+passed), failed, passed))
225+
return failed
226+
227+
228+
def procedure_0(z, w):
229+
return z * 26 + w + 14
230+
231+
def rev_procedure_0(target):
232+
# return z * 26 + w + 14
233+
'''
234+
z * 26 + w + 14 = t
235+
z * 26 = t - 14 - w
236+
237+
t - w - 14
238+
z = -----------
239+
26
240+
'''
241+
results = {}
242+
243+
for w in range(1, 10):
244+
p = target - w - 14
245+
if p < 0:
246+
continue
247+
if p % 26:
248+
continue
249+
results[w] = results.get(w) or []
250+
results[w].append(p//26)
251+
252+
return results
253+
254+
def procedure_1(z, w):
255+
return z * 26 + w + 6
256+
257+
def rev_procedure_1(target):
258+
results = {}
259+
260+
for w in range(1, 10):
261+
p = target - w - 6
262+
if p < 0:
263+
continue
264+
if p % 26:
265+
continue
266+
results[w] = results.get(w) or []
267+
results[w].append(p//26)
268+
269+
return results
270+
271+
procedure_2 = procedure_1
272+
rev_procedure_2 = rev_procedure_1
273+
274+
def procedure_3(z, w):
275+
return z * 26 + w + 13
276+
277+
def rev_procedure_3(target):
278+
results = {}
279+
280+
for w in range(1, 10):
281+
p = target - w - 13
282+
if p < 0:
283+
continue
284+
if p % 26:
285+
continue
286+
results[w] = results.get(w) or []
287+
results[w].append(p//26)
288+
289+
return results
290+
291+
292+
293+
def procedure_4(z, w):
294+
if (z % 26) - 12 == w: # z%26 must be [13 to 21]
295+
return (z // 26)
296+
else:
297+
# will increase with steps of length 26
298+
return (z // 26) * 26 + (w + 8) # always positive
299+
300+
def rev_procedure_4(target):
301+
results = {n:[] for n in range(1, 10)}
302+
for i in range(21, 13-1, -1):
303+
results[i-12].append(target*26 + i)
304+
for i in range(1, 10):
305+
if target%26 == (i+8):
306+
results[i].append(target - (target%26))
307+
return results
308+
309+
def procedure_5(z, w):
310+
return z * 26 + w + 8
311+
312+
def rev_procedure_5(target):
313+
results = {}
314+
315+
for w in range(1, 10):
316+
p = target - w - 8
317+
if p < 0:
318+
continue
319+
if p % 26:
320+
continue
321+
results[w] = results.get(w) or []
322+
results[w].append(p//26)
323+
324+
return results
325+
326+
def procedure_6(z, w):
327+
if (z % 26) - 15 == w: # for z % 26 in [16 to 24]
328+
return (z // 26)
329+
else:
330+
# will increase with steps of length 26
331+
return (z // 26) * 26 + (w + 7) # always positive
332+
333+
def rev_procedure_6(target):
334+
results = {n:[] for n in range(1, 10)}
335+
for i in range(24, 16-1, -1):
336+
results[i-15].append(target*26 + i)
337+
for i in range(1, 10):
338+
if target%26 == (i+7):
339+
results[i].append(target - (target%26))
340+
return results
341+
342+
343+
def procedure_7(z, w):
344+
return z * 26 + w + 10
345+
346+
def rev_procedure_7(target):
347+
results = {}
348+
349+
for w in range(1, 10):
350+
p = target - w - 10
351+
if p < 0:
352+
continue
353+
if p % 26:
354+
continue
355+
results[w] = results.get(w) or []
356+
results[w].append(p//26)
357+
358+
return results
359+
360+
procedure_8 = procedure_5
361+
rev_procedure_8 = rev_procedure_5
362+
363+
def procedure_9(z, w):
364+
if (z % 26) - 13 == w: # z%26 must be [14 to 22]
365+
return (z // 26)
366+
else:
367+
# will increase with steps of length 26
368+
return (z // 26) * 26 + (w + 12) # always positive
369+
370+
def rev_procedure_9(target):
371+
results = {n:[] for n in range(1, 10)}
372+
for i in range(22, 14-1, -1):
373+
results[i-13].append(target*26 + i)
374+
for i in range(1, 10):
375+
if target%26 == (i+12):
376+
results[i].append(target - (target%26))
377+
return results
378+
379+
def procedure_10(z, w):
380+
if (z % 26) - 13 == w: # z%26 must be [14 to 22]
381+
return (z // 26)
382+
else:
383+
# will increase with steps of length 26
384+
return (z // 26) * 26 + (w + 10) # always positive
385+
386+
def rev_procedure_10(target):
387+
results = {n:[] for n in range(1, 10)}
388+
for i in range(22, 14-1, -1):
389+
results[i-13].append(target*26 + i)
390+
for i in range(1, 10):
391+
if target%26 == (i+10):
392+
results[i].append(target - (target%26))
393+
return results
394+
395+
396+
def procedure_11(z, w):
397+
if (z % 26) - 14 == w: # z%26 must be [15 to 23]
398+
return (z // 26)
399+
else:
400+
# will increase with steps of length 26
401+
return (z // 26) * 26 + (w + 8) # always positive
402+
403+
def rev_procedure_11(target):
404+
results = {n:[] for n in range(1, 10)}
405+
for i in range(23, 15-1, -1):
406+
results[i-14].append(target*26 + i)
407+
for i in range(1, 10):
408+
if target%26 == (i+8):
409+
results[i].append(target - (target%26))
410+
return results
411+
412+
def procedure_12(z, w):
413+
if (z % 26) - 2 == w: # z%26 must be [3 to 11]
414+
return (z // 26)
415+
else:
416+
# will increase with steps of length 26
417+
return (z // 26) * 26 + (w + 8) # always positive
418+
419+
420+
def rev_procedure_12(target):
421+
results = {n:[] for n in range(1, 10)}
422+
for i in range(11, 3-1, -1):
423+
results[i-2].append(target*26 + i)
424+
for i in range(1, 10):
425+
if target%26 == (i+8):
426+
results[i].append(target - (target%26))
427+
return results
428+
429+
def procedure_13(z, w):
430+
if (z % 26) - 9 == w: # z%26 must be [10 to 18]
431+
return (z // 26) # z must be less than 26 - so z can be [10,...,18]
432+
else:
433+
# will increase with steps of length 26
434+
return (z // 26) * 26 + (w + 7) # always positive
435+
436+
437+
def rev_procedure_13(target):
438+
results = {n:[] for n in range(1, 10)}
439+
for i in range(18, 10-1, -1):
440+
results[i-9].append(target*26 + i)
441+
for i in range(1, 7):
442+
if target%26 == (i+7):
443+
results[i].append(target - (target%26))
444+
return results
445+
210446

211447
def par1(instructions):
212448
alu = ALU(instructions)
@@ -215,22 +451,100 @@ def par1(instructions):
215451

216452
#print('Part 1: ', par1(read_input('input')))
217453

218-
def test_procedures(instrs):
219-
alu = ALU(instrs)
454+
# def test_procedures(instrs):
455+
# alu = ALU(instrs)
220456

221-
# print(
222-
# alu.detect_procedure_behaviour(13)
223-
# )
457+
# # print(
458+
# # alu.detect_procedure_behaviour(13)
459+
# # )
224460

225-
# for p in range(14):
226-
# print('Proc: ', p)
227-
# print('==========')
228-
# for d in range(1, 10):
229-
# r = alu.detect_procedure_behaviour_per_digit(p, d)
230-
# print(' >', d, r)
461+
# # for p in range(14):
462+
# # print('Proc: ', p)
463+
# # print('==========')
464+
# # for d in range(1, 10):
465+
# # r = alu.detect_procedure_behaviour_per_digit(p, d)
466+
# # print(' >', d, r)
231467

232-
#print(alu.find_target_p(12, 9))
233-
alu.check()
234-
468+
# # print(alu.find_target_p(12, 9))
469+
# # alu.check()
470+
471+
472+
473+
# #alu.assert_procedure(12, procedure_12, 10_000)
474+
# # for i, proc in enumerate(alu.procedures()):
475+
# # print('Procedure:', i)
476+
# # for p in proc:
477+
# # print(' '.join(p))
478+
479+
# for i in range(100):
480+
# print('==', i)
481+
# for w, pos in rev_procedure_13(i).items():
482+
# #print(z, pos)
483+
# for z in pos:
484+
# r = procedure_13(z, w)
485+
# print(' >', r, (z, w))
486+
# print(' >>', alu.exec_proc(13, z, w)['z'])
487+
488+
489+
# test_procedures(read_input('input'))
490+
# import os
491+
# os.exit(1)
492+
# # for i in range(30):
493+
# # print(procedure_0(i, 9))
494+
495+
procedures = [
496+
(procedure_0, rev_procedure_0),
497+
(procedure_1, rev_procedure_1),
498+
(procedure_2, rev_procedure_2),
499+
(procedure_3, rev_procedure_3),
500+
(procedure_4, rev_procedure_4),
501+
(procedure_5, rev_procedure_5),
502+
(procedure_6, rev_procedure_6),
503+
(procedure_7, rev_procedure_7),
504+
(procedure_8, rev_procedure_8),
505+
(procedure_9, rev_procedure_9),
506+
(procedure_10, rev_procedure_10),
507+
(procedure_11, rev_procedure_11),
508+
(procedure_12, rev_procedure_12),
509+
(procedure_13, rev_procedure_13),
510+
]
511+
512+
513+
514+
515+
516+
def preliminary_tests(instructions, size=10_000):
517+
alu = ALU(instructions)
518+
519+
def _assert(truth, expected, actual):
520+
if not truth:
521+
raise Exception('Expected: {}, but got: {}'.format(expected, actual))
522+
523+
for proc_id in range(14):
524+
print('Testing procedure: ', proc_id)
525+
procedure, rev_procedure = procedures[proc_id]
526+
print('Asserting basic equivalence...')
527+
failed = alu.assert_procedure(proc_id, procedure)
528+
assert failed == 0
529+
print('All OK')
530+
print('Testing reverse procedures...')
531+
for target in range(size+1):
532+
for w, possible in rev_procedure(target).items():
533+
for z in possible:
534+
value = procedure(z, w)
535+
_assert( value == target, target, value)
536+
# compare against the actual interpreter
537+
expected = alu.exec_proc(proc_id, z, w)['z']
538+
_assert(value == expected, expected, value)
539+
print('All OK.')
540+
541+
preliminary_tests(read_input('input'))
542+
543+
def part1(instructions):
544+
alu = ALU(instrcutions)
545+
546+
q = [(0, 0)]
235547

236-
test_procedures(read_input('input'))
548+
while q:
549+
proc_id, target = q.pop()
550+

0 commit comments

Comments
 (0)