@@ -207,6 +207,242 @@ def check(self):
207
207
c += 1
208
208
if c % 10 == 0 :
209
209
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
+
210
446
211
447
def par1 (instructions ):
212
448
alu = ALU (instructions )
@@ -215,22 +451,100 @@ def par1(instructions):
215
451
216
452
#print('Part 1: ', par1(read_input('input')))
217
453
218
- def test_procedures (instrs ):
219
- alu = ALU (instrs )
454
+ # def test_procedures(instrs):
455
+ # alu = ALU(instrs)
220
456
221
- # print(
222
- # alu.detect_procedure_behaviour(13)
223
- # )
457
+ # # print(
458
+ # # alu.detect_procedure_behaviour(13)
459
+ # # )
224
460
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)
231
467
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 )]
235
547
236
- test_procedures (read_input ('input' ))
548
+ while q :
549
+ proc_id , target = q .pop ()
550
+
0 commit comments