diff --git a/example/obs_json/observation_1.json b/example/obs_json/observation_1.json new file mode 100644 index 0000000..be0ebb9 --- /dev/null +++ b/example/obs_json/observation_1.json @@ -0,0 +1,3810 @@ +{ + "target_passcode": [ + 24, + 12, + 3, + 53 + ], + "observations": [ + { + "keypad": [ + [ + 0, + 37, + 47, + 30, + 49, + 23, + 24, + 43, + 8 + ], + [ + 18, + 19, + 20, + 12, + 40, + 50, + 33, + 52, + 44 + ], + [ + 9, + 28, + 2, + 3, + 13, + 32, + 51, + 7, + 35 + ], + [ + 36, + 10, + 11, + 39, + 22, + 5, + 15, + 34, + 26 + ], + [ + 27, + 46, + 29, + 48, + 31, + 41, + 42, + 25, + 17 + ], + [ + 45, + 1, + 38, + 21, + 4, + 14, + 6, + 16, + 53 + ] + ], + "key_selection": [ + 0, + 1, + 2, + 5 + ] + }, + { + "keypad": [ + [ + 45, + 46, + 2, + 3, + 31, + 50, + 6, + 7, + 35 + ], + [ + 9, + 28, + 29, + 21, + 13, + 23, + 51, + 34, + 53 + ], + [ + 18, + 1, + 11, + 30, + 40, + 5, + 33, + 25, + 17 + ], + [ + 36, + 19, + 20, + 12, + 22, + 41, + 15, + 16, + 26 + ], + [ + 27, + 37, + 47, + 39, + 49, + 32, + 42, + 43, + 44 + ], + [ + 0, + 10, + 38, + 48, + 4, + 14, + 24, + 52, + 8 + ] + ], + "key_selection": [ + 5, + 3, + 0, + 1 + ] + }, + { + "keypad": [ + [ + 27, + 46, + 11, + 21, + 40, + 32, + 42, + 34, + 8 + ], + [ + 45, + 10, + 47, + 48, + 31, + 14, + 24, + 16, + 17 + ], + [ + 18, + 37, + 20, + 3, + 49, + 5, + 15, + 43, + 35 + ], + [ + 9, + 28, + 38, + 39, + 4, + 41, + 33, + 52, + 26 + ], + [ + 36, + 1, + 29, + 12, + 13, + 50, + 6, + 7, + 44 + ], + [ + 0, + 19, + 2, + 30, + 22, + 23, + 51, + 25, + 53 + ] + ], + "key_selection": [ + 1, + 4, + 2, + 5 + ] + }, + { + "keypad": [ + [ + 18, + 10, + 2, + 30, + 49, + 32, + 15, + 43, + 17 + ], + [ + 36, + 37, + 38, + 48, + 40, + 23, + 6, + 34, + 53 + ], + [ + 0, + 28, + 11, + 12, + 4, + 14, + 42, + 25, + 26 + ], + [ + 45, + 46, + 47, + 21, + 31, + 5, + 24, + 16, + 8 + ], + [ + 9, + 19, + 29, + 3, + 22, + 41, + 33, + 7, + 35 + ], + [ + 27, + 1, + 20, + 39, + 13, + 50, + 51, + 52, + 44 + ] + ], + "key_selection": [ + 3, + 2, + 4, + 1 + ] + }, + { + "keypad": [ + [ + 27, + 37, + 38, + 39, + 31, + 50, + 6, + 25, + 44 + ], + [ + 0, + 1, + 2, + 21, + 40, + 41, + 42, + 34, + 17 + ], + [ + 9, + 19, + 47, + 48, + 4, + 5, + 51, + 16, + 26 + ], + [ + 36, + 10, + 11, + 12, + 13, + 32, + 15, + 43, + 35 + ], + [ + 18, + 28, + 29, + 30, + 22, + 14, + 24, + 52, + 53 + ], + [ + 45, + 46, + 20, + 3, + 49, + 23, + 33, + 7, + 8 + ] + ], + "key_selection": [ + 4, + 3, + 5, + 4 + ] + }, + { + "keypad": [ + [ + 0, + 37, + 47, + 12, + 49, + 23, + 51, + 34, + 53 + ], + [ + 9, + 1, + 2, + 30, + 13, + 32, + 42, + 25, + 26 + ], + [ + 27, + 19, + 29, + 21, + 22, + 5, + 6, + 43, + 8 + ], + [ + 36, + 28, + 11, + 3, + 4, + 14, + 15, + 52, + 17 + ], + [ + 45, + 46, + 20, + 48, + 31, + 50, + 33, + 16, + 35 + ], + [ + 18, + 10, + 38, + 39, + 40, + 41, + 24, + 7, + 44 + ] + ], + "key_selection": [ + 5, + 0, + 3, + 0 + ] + }, + { + "keypad": [ + [ + 36, + 37, + 47, + 39, + 31, + 5, + 15, + 25, + 35 + ], + [ + 18, + 10, + 29, + 3, + 22, + 32, + 6, + 7, + 17 + ], + [ + 45, + 1, + 20, + 48, + 4, + 23, + 51, + 34, + 8 + ], + [ + 0, + 19, + 2, + 12, + 49, + 14, + 33, + 43, + 53 + ], + [ + 27, + 46, + 11, + 30, + 13, + 41, + 24, + 16, + 44 + ], + [ + 9, + 28, + 38, + 21, + 40, + 50, + 42, + 52, + 26 + ] + ], + "key_selection": [ + 4, + 3, + 1, + 3 + ] + }, + { + "keypad": [ + [ + 27, + 37, + 47, + 21, + 4, + 41, + 15, + 52, + 26 + ], + [ + 45, + 28, + 20, + 12, + 40, + 23, + 33, + 25, + 53 + ], + [ + 9, + 1, + 38, + 30, + 49, + 5, + 42, + 34, + 17 + ], + [ + 0, + 10, + 2, + 48, + 13, + 50, + 6, + 7, + 44 + ], + [ + 36, + 19, + 11, + 39, + 31, + 14, + 51, + 43, + 8 + ], + [ + 18, + 46, + 29, + 3, + 22, + 32, + 24, + 16, + 35 + ] + ], + "key_selection": [ + 5, + 1, + 5, + 1 + ] + }, + { + "keypad": [ + [ + 0, + 1, + 47, + 12, + 49, + 41, + 15, + 7, + 53 + ], + [ + 9, + 28, + 11, + 39, + 40, + 23, + 42, + 34, + 26 + ], + [ + 45, + 37, + 2, + 30, + 13, + 5, + 33, + 25, + 44 + ], + [ + 27, + 46, + 38, + 21, + 22, + 32, + 51, + 52, + 8 + ], + [ + 36, + 19, + 20, + 48, + 4, + 14, + 6, + 16, + 17 + ], + [ + 18, + 10, + 29, + 3, + 31, + 50, + 24, + 43, + 35 + ] + ], + "key_selection": [ + 5, + 0, + 5, + 0 + ] + }, + { + "keypad": [ + [ + 18, + 10, + 47, + 30, + 31, + 32, + 6, + 25, + 17 + ], + [ + 45, + 28, + 2, + 39, + 13, + 50, + 15, + 43, + 26 + ], + [ + 9, + 1, + 38, + 21, + 4, + 41, + 24, + 16, + 8 + ], + [ + 0, + 37, + 11, + 3, + 49, + 5, + 42, + 52, + 44 + ], + [ + 36, + 19, + 29, + 12, + 40, + 23, + 51, + 34, + 53 + ], + [ + 27, + 46, + 20, + 48, + 22, + 14, + 33, + 7, + 35 + ] + ], + "key_selection": [ + 2, + 4, + 3, + 4 + ] + }, + { + "keypad": [ + [ + 36, + 10, + 11, + 39, + 13, + 50, + 33, + 7, + 8 + ], + [ + 9, + 19, + 47, + 12, + 4, + 5, + 15, + 52, + 53 + ], + [ + 27, + 37, + 2, + 30, + 22, + 23, + 42, + 16, + 35 + ], + [ + 18, + 46, + 29, + 21, + 40, + 32, + 6, + 34, + 17 + ], + [ + 0, + 1, + 20, + 48, + 31, + 14, + 24, + 25, + 44 + ], + [ + 45, + 28, + 38, + 3, + 49, + 41, + 51, + 43, + 26 + ] + ], + "key_selection": [ + 4, + 1, + 5, + 1 + ] + }, + { + "keypad": [ + [ + 27, + 46, + 47, + 48, + 31, + 23, + 42, + 25, + 17 + ], + [ + 9, + 28, + 2, + 12, + 49, + 5, + 24, + 16, + 8 + ], + [ + 45, + 37, + 29, + 39, + 13, + 32, + 33, + 7, + 35 + ], + [ + 0, + 10, + 11, + 21, + 40, + 50, + 15, + 43, + 53 + ], + [ + 18, + 19, + 38, + 3, + 22, + 41, + 6, + 52, + 26 + ], + [ + 36, + 1, + 20, + 30, + 4, + 14, + 51, + 34, + 44 + ] + ], + "key_selection": [ + 1, + 1, + 4, + 3 + ] + }, + { + "keypad": [ + [ + 18, + 10, + 38, + 12, + 40, + 41, + 24, + 43, + 44 + ], + [ + 0, + 46, + 47, + 30, + 49, + 32, + 42, + 16, + 17 + ], + [ + 9, + 19, + 29, + 48, + 13, + 5, + 51, + 25, + 8 + ], + [ + 27, + 28, + 2, + 21, + 22, + 50, + 15, + 7, + 53 + ], + [ + 36, + 1, + 11, + 3, + 4, + 23, + 33, + 52, + 35 + ], + [ + 45, + 37, + 20, + 39, + 31, + 14, + 6, + 34, + 26 + ] + ], + "key_selection": [ + 0, + 0, + 4, + 3 + ] + }, + { + "keypad": [ + [ + 27, + 37, + 47, + 48, + 40, + 14, + 51, + 25, + 8 + ], + [ + 0, + 1, + 11, + 39, + 22, + 5, + 15, + 43, + 44 + ], + [ + 45, + 28, + 29, + 30, + 31, + 32, + 24, + 16, + 26 + ], + [ + 9, + 19, + 38, + 21, + 49, + 23, + 33, + 52, + 35 + ], + [ + 36, + 46, + 20, + 12, + 13, + 41, + 42, + 34, + 17 + ], + [ + 18, + 10, + 2, + 3, + 4, + 50, + 6, + 7, + 53 + ] + ], + "key_selection": [ + 2, + 4, + 5, + 5 + ] + }, + { + "keypad": [ + [ + 27, + 28, + 47, + 3, + 49, + 32, + 42, + 52, + 44 + ], + [ + 18, + 10, + 20, + 12, + 13, + 14, + 24, + 7, + 17 + ], + [ + 0, + 46, + 38, + 48, + 4, + 50, + 15, + 34, + 53 + ], + [ + 36, + 1, + 29, + 39, + 31, + 41, + 33, + 25, + 35 + ], + [ + 9, + 19, + 11, + 21, + 22, + 5, + 6, + 43, + 26 + ], + [ + 45, + 37, + 2, + 30, + 40, + 23, + 51, + 16, + 8 + ] + ], + "key_selection": [ + 1, + 1, + 0, + 2 + ] + }, + { + "keypad": [ + [ + 45, + 1, + 2, + 3, + 22, + 23, + 24, + 43, + 8 + ], + [ + 9, + 28, + 29, + 12, + 4, + 50, + 33, + 25, + 53 + ], + [ + 18, + 19, + 20, + 39, + 49, + 32, + 15, + 52, + 35 + ], + [ + 36, + 46, + 47, + 21, + 31, + 41, + 42, + 16, + 17 + ], + [ + 27, + 10, + 11, + 30, + 40, + 5, + 51, + 7, + 44 + ], + [ + 0, + 37, + 38, + 48, + 13, + 14, + 6, + 34, + 26 + ] + ], + "key_selection": [ + 0, + 1, + 0, + 1 + ] + }, + { + "keypad": [ + [ + 45, + 28, + 20, + 30, + 40, + 32, + 51, + 52, + 44 + ], + [ + 36, + 10, + 11, + 48, + 49, + 41, + 42, + 25, + 53 + ], + [ + 18, + 46, + 2, + 3, + 13, + 23, + 15, + 7, + 26 + ], + [ + 27, + 19, + 38, + 21, + 31, + 50, + 33, + 43, + 17 + ], + [ + 9, + 1, + 47, + 12, + 4, + 14, + 24, + 34, + 8 + ], + [ + 0, + 37, + 29, + 39, + 22, + 5, + 6, + 16, + 35 + ] + ], + "key_selection": [ + 4, + 4, + 2, + 1 + ] + }, + { + "keypad": [ + [ + 27, + 37, + 47, + 48, + 13, + 14, + 24, + 52, + 35 + ], + [ + 18, + 28, + 29, + 3, + 40, + 50, + 15, + 25, + 53 + ], + [ + 9, + 1, + 2, + 39, + 49, + 41, + 6, + 16, + 44 + ], + [ + 0, + 10, + 20, + 30, + 22, + 5, + 51, + 43, + 8 + ], + [ + 45, + 46, + 38, + 12, + 31, + 23, + 42, + 34, + 26 + ], + [ + 36, + 19, + 11, + 21, + 4, + 32, + 33, + 7, + 17 + ] + ], + "key_selection": [ + 0, + 4, + 1, + 1 + ] + }, + { + "keypad": [ + [ + 0, + 10, + 20, + 3, + 49, + 23, + 42, + 7, + 26 + ], + [ + 45, + 28, + 2, + 39, + 22, + 32, + 33, + 52, + 8 + ], + [ + 27, + 46, + 47, + 30, + 4, + 14, + 24, + 25, + 53 + ], + [ + 18, + 19, + 38, + 48, + 40, + 5, + 6, + 43, + 35 + ], + [ + 36, + 37, + 29, + 12, + 31, + 41, + 15, + 16, + 17 + ], + [ + 9, + 1, + 11, + 21, + 13, + 50, + 51, + 34, + 44 + ] + ], + "key_selection": [ + 2, + 4, + 0, + 2 + ] + }, + { + "keypad": [ + [ + 9, + 1, + 38, + 21, + 22, + 5, + 24, + 52, + 8 + ], + [ + 27, + 19, + 11, + 3, + 40, + 50, + 42, + 7, + 44 + ], + [ + 18, + 46, + 29, + 12, + 13, + 41, + 6, + 25, + 17 + ], + [ + 0, + 28, + 47, + 48, + 4, + 14, + 33, + 43, + 35 + ], + [ + 45, + 10, + 2, + 39, + 49, + 23, + 51, + 34, + 53 + ], + [ + 36, + 37, + 20, + 30, + 31, + 32, + 15, + 16, + 26 + ] + ], + "key_selection": [ + 0, + 2, + 1, + 4 + ] + }, + { + "keypad": [ + [ + 36, + 46, + 29, + 3, + 22, + 50, + 33, + 7, + 35 + ], + [ + 27, + 1, + 20, + 21, + 40, + 5, + 15, + 52, + 26 + ], + [ + 0, + 37, + 38, + 30, + 4, + 32, + 6, + 34, + 17 + ], + [ + 18, + 10, + 11, + 39, + 13, + 14, + 42, + 16, + 44 + ], + [ + 9, + 28, + 47, + 48, + 31, + 23, + 24, + 43, + 53 + ], + [ + 45, + 19, + 2, + 12, + 49, + 41, + 51, + 25, + 8 + ] + ], + "key_selection": [ + 4, + 5, + 0, + 4 + ] + }, + { + "keypad": [ + [ + 9, + 10, + 47, + 39, + 4, + 50, + 42, + 52, + 17 + ], + [ + 36, + 1, + 11, + 30, + 40, + 32, + 51, + 34, + 35 + ], + [ + 18, + 28, + 38, + 3, + 49, + 41, + 15, + 25, + 44 + ], + [ + 45, + 37, + 20, + 21, + 13, + 23, + 6, + 43, + 53 + ], + [ + 0, + 46, + 29, + 12, + 22, + 14, + 24, + 7, + 26 + ], + [ + 27, + 19, + 2, + 48, + 31, + 5, + 33, + 16, + 8 + ] + ], + "key_selection": [ + 4, + 4, + 2, + 3 + ] + }, + { + "keypad": [ + [ + 36, + 1, + 47, + 30, + 49, + 32, + 33, + 34, + 8 + ], + [ + 27, + 28, + 29, + 48, + 4, + 41, + 6, + 43, + 35 + ], + [ + 18, + 37, + 2, + 12, + 22, + 23, + 51, + 25, + 44 + ], + [ + 0, + 46, + 38, + 3, + 31, + 14, + 15, + 16, + 17 + ], + [ + 45, + 10, + 20, + 21, + 13, + 50, + 42, + 52, + 53 + ], + [ + 9, + 19, + 11, + 39, + 40, + 5, + 24, + 7, + 26 + ] + ], + "key_selection": [ + 5, + 2, + 3, + 4 + ] + }, + { + "keypad": [ + [ + 27, + 19, + 11, + 21, + 22, + 23, + 42, + 34, + 26 + ], + [ + 0, + 28, + 47, + 39, + 13, + 5, + 33, + 16, + 35 + ], + [ + 45, + 46, + 38, + 3, + 40, + 14, + 6, + 25, + 8 + ], + [ + 36, + 1, + 2, + 30, + 31, + 50, + 51, + 43, + 44 + ], + [ + 18, + 10, + 20, + 48, + 49, + 41, + 15, + 7, + 53 + ], + [ + 9, + 37, + 29, + 12, + 4, + 32, + 24, + 52, + 17 + ] + ], + "key_selection": [ + 5, + 5, + 2, + 4 + ] + }, + { + "keypad": [ + [ + 36, + 1, + 38, + 48, + 49, + 5, + 33, + 52, + 44 + ], + [ + 45, + 28, + 29, + 12, + 40, + 32, + 42, + 16, + 8 + ], + [ + 0, + 37, + 11, + 39, + 31, + 14, + 24, + 25, + 17 + ], + [ + 18, + 19, + 47, + 21, + 13, + 41, + 51, + 34, + 26 + ], + [ + 9, + 46, + 2, + 3, + 22, + 23, + 6, + 7, + 53 + ], + [ + 27, + 10, + 20, + 30, + 4, + 50, + 15, + 43, + 35 + ] + ], + "key_selection": [ + 2, + 1, + 4, + 4 + ] + }, + { + "keypad": [ + [ + 9, + 46, + 11, + 3, + 4, + 32, + 42, + 25, + 26 + ], + [ + 36, + 19, + 38, + 48, + 40, + 5, + 15, + 52, + 44 + ], + [ + 45, + 10, + 29, + 30, + 31, + 14, + 33, + 7, + 53 + ], + [ + 0, + 1, + 20, + 39, + 49, + 41, + 24, + 34, + 35 + ], + [ + 27, + 37, + 47, + 12, + 13, + 23, + 6, + 16, + 17 + ], + [ + 18, + 28, + 2, + 21, + 22, + 50, + 51, + 43, + 8 + ] + ], + "key_selection": [ + 3, + 4, + 0, + 2 + ] + }, + { + "keypad": [ + [ + 0, + 10, + 11, + 39, + 22, + 32, + 15, + 43, + 8 + ], + [ + 45, + 37, + 38, + 30, + 40, + 41, + 33, + 34, + 17 + ], + [ + 18, + 46, + 29, + 12, + 31, + 5, + 42, + 16, + 26 + ], + [ + 36, + 28, + 2, + 48, + 13, + 23, + 51, + 52, + 35 + ], + [ + 9, + 1, + 20, + 3, + 49, + 50, + 6, + 25, + 44 + ], + [ + 27, + 19, + 47, + 21, + 4, + 14, + 24, + 7, + 53 + ] + ], + "key_selection": [ + 5, + 2, + 4, + 5 + ] + }, + { + "keypad": [ + [ + 9, + 19, + 29, + 30, + 40, + 5, + 42, + 25, + 17 + ], + [ + 36, + 1, + 2, + 12, + 22, + 32, + 6, + 16, + 35 + ], + [ + 18, + 46, + 38, + 21, + 31, + 50, + 15, + 43, + 44 + ], + [ + 0, + 10, + 20, + 48, + 13, + 14, + 33, + 52, + 53 + ], + [ + 27, + 28, + 11, + 3, + 4, + 41, + 24, + 34, + 8 + ], + [ + 45, + 37, + 47, + 39, + 49, + 23, + 51, + 7, + 26 + ] + ], + "key_selection": [ + 4, + 1, + 4, + 3 + ] + }, + { + "keypad": [ + [ + 36, + 10, + 29, + 39, + 22, + 23, + 33, + 43, + 53 + ], + [ + 9, + 37, + 11, + 48, + 13, + 41, + 15, + 16, + 44 + ], + [ + 0, + 28, + 20, + 3, + 40, + 14, + 6, + 34, + 26 + ], + [ + 18, + 1, + 2, + 21, + 4, + 5, + 24, + 7, + 8 + ], + [ + 27, + 19, + 47, + 12, + 49, + 32, + 51, + 25, + 35 + ], + [ + 45, + 46, + 38, + 30, + 31, + 50, + 42, + 52, + 17 + ] + ], + "key_selection": [ + 3, + 4, + 2, + 0 + ] + }, + { + "keypad": [ + [ + 9, + 28, + 38, + 48, + 4, + 50, + 24, + 25, + 26 + ], + [ + 18, + 46, + 2, + 3, + 22, + 32, + 15, + 7, + 44 + ], + [ + 0, + 19, + 47, + 30, + 13, + 23, + 6, + 52, + 8 + ], + [ + 45, + 1, + 20, + 21, + 40, + 14, + 33, + 16, + 35 + ], + [ + 36, + 37, + 29, + 39, + 31, + 5, + 51, + 43, + 17 + ], + [ + 27, + 10, + 11, + 12, + 49, + 41, + 42, + 34, + 53 + ] + ], + "key_selection": [ + 0, + 5, + 1, + 5 + ] + }, + { + "keypad": [ + [ + 36, + 28, + 11, + 12, + 13, + 14, + 33, + 34, + 44 + ], + [ + 18, + 1, + 38, + 39, + 4, + 41, + 24, + 16, + 8 + ], + [ + 0, + 46, + 2, + 3, + 49, + 23, + 51, + 25, + 26 + ], + [ + 27, + 37, + 47, + 48, + 40, + 5, + 15, + 43, + 35 + ], + [ + 45, + 10, + 29, + 30, + 31, + 32, + 6, + 52, + 53 + ], + [ + 9, + 19, + 20, + 21, + 22, + 50, + 42, + 7, + 17 + ] + ], + "key_selection": [ + 1, + 0, + 2, + 4 + ] + }, + { + "keypad": [ + [ + 18, + 10, + 29, + 39, + 13, + 41, + 24, + 7, + 35 + ], + [ + 0, + 37, + 38, + 3, + 22, + 32, + 6, + 52, + 8 + ], + [ + 9, + 46, + 11, + 12, + 49, + 50, + 51, + 43, + 53 + ], + [ + 27, + 19, + 47, + 21, + 40, + 23, + 42, + 25, + 26 + ], + [ + 45, + 28, + 20, + 48, + 4, + 14, + 33, + 34, + 44 + ], + [ + 36, + 1, + 2, + 30, + 31, + 5, + 15, + 16, + 17 + ] + ], + "key_selection": [ + 0, + 2, + 1, + 2 + ] + }, + { + "keypad": [ + [ + 45, + 37, + 11, + 48, + 40, + 5, + 15, + 16, + 8 + ], + [ + 9, + 19, + 38, + 21, + 13, + 14, + 33, + 7, + 26 + ], + [ + 18, + 28, + 47, + 3, + 31, + 32, + 6, + 34, + 17 + ], + [ + 27, + 1, + 2, + 39, + 22, + 50, + 51, + 52, + 35 + ], + [ + 0, + 46, + 29, + 30, + 49, + 41, + 42, + 25, + 53 + ], + [ + 36, + 10, + 20, + 12, + 4, + 23, + 24, + 43, + 44 + ] + ], + "key_selection": [ + 5, + 5, + 2, + 4 + ] + }, + { + "keypad": [ + [ + 9, + 28, + 2, + 48, + 13, + 32, + 42, + 16, + 35 + ], + [ + 0, + 1, + 11, + 21, + 40, + 50, + 33, + 25, + 53 + ], + [ + 27, + 19, + 47, + 12, + 49, + 5, + 51, + 34, + 8 + ], + [ + 36, + 10, + 38, + 3, + 31, + 14, + 24, + 43, + 26 + ], + [ + 45, + 46, + 29, + 30, + 22, + 23, + 6, + 7, + 44 + ], + [ + 18, + 37, + 20, + 39, + 4, + 41, + 15, + 52, + 17 + ] + ], + "key_selection": [ + 3, + 2, + 3, + 1 + ] + }, + { + "keypad": [ + [ + 36, + 37, + 2, + 12, + 40, + 41, + 15, + 7, + 53 + ], + [ + 18, + 28, + 11, + 3, + 13, + 32, + 33, + 34, + 8 + ], + [ + 9, + 1, + 20, + 30, + 4, + 5, + 24, + 16, + 44 + ], + [ + 45, + 46, + 38, + 48, + 22, + 23, + 6, + 43, + 26 + ], + [ + 27, + 19, + 47, + 39, + 31, + 14, + 42, + 52, + 17 + ], + [ + 0, + 10, + 29, + 21, + 49, + 50, + 51, + 25, + 35 + ] + ], + "key_selection": [ + 2, + 0, + 1, + 0 + ] + }, + { + "keypad": [ + [ + 36, + 28, + 2, + 3, + 13, + 41, + 24, + 43, + 53 + ], + [ + 18, + 10, + 29, + 48, + 49, + 5, + 51, + 34, + 35 + ], + [ + 45, + 46, + 20, + 21, + 31, + 23, + 6, + 52, + 8 + ], + [ + 27, + 37, + 38, + 12, + 4, + 14, + 42, + 16, + 44 + ], + [ + 9, + 19, + 11, + 30, + 22, + 50, + 15, + 25, + 26 + ], + [ + 0, + 1, + 47, + 39, + 40, + 32, + 33, + 7, + 17 + ] + ], + "key_selection": [ + 0, + 3, + 0, + 0 + ] + }, + { + "keypad": [ + [ + 45, + 28, + 29, + 48, + 4, + 14, + 6, + 34, + 53 + ], + [ + 18, + 10, + 20, + 39, + 31, + 50, + 24, + 16, + 26 + ], + [ + 0, + 37, + 2, + 12, + 13, + 41, + 15, + 7, + 35 + ], + [ + 27, + 1, + 47, + 3, + 22, + 5, + 51, + 43, + 8 + ], + [ + 9, + 46, + 11, + 21, + 49, + 23, + 42, + 25, + 44 + ], + [ + 36, + 19, + 38, + 30, + 40, + 32, + 33, + 52, + 17 + ] + ], + "key_selection": [ + 1, + 2, + 3, + 0 + ] + }, + { + "keypad": [ + [ + 27, + 37, + 47, + 30, + 4, + 32, + 24, + 34, + 44 + ], + [ + 45, + 28, + 38, + 21, + 31, + 23, + 33, + 52, + 8 + ], + [ + 9, + 19, + 20, + 3, + 13, + 50, + 42, + 16, + 35 + ], + [ + 0, + 1, + 2, + 48, + 40, + 5, + 6, + 43, + 17 + ], + [ + 36, + 46, + 11, + 12, + 22, + 41, + 51, + 7, + 53 + ], + [ + 18, + 10, + 29, + 39, + 49, + 14, + 15, + 25, + 26 + ] + ], + "key_selection": [ + 0, + 4, + 2, + 4 + ] + }, + { + "keypad": [ + [ + 27, + 10, + 47, + 3, + 4, + 23, + 42, + 43, + 53 + ], + [ + 36, + 46, + 20, + 39, + 13, + 14, + 33, + 16, + 35 + ], + [ + 0, + 37, + 11, + 21, + 40, + 50, + 24, + 52, + 17 + ], + [ + 45, + 1, + 29, + 12, + 31, + 5, + 15, + 34, + 8 + ], + [ + 9, + 28, + 2, + 30, + 22, + 41, + 6, + 7, + 26 + ], + [ + 18, + 19, + 38, + 48, + 49, + 32, + 51, + 25, + 44 + ] + ], + "key_selection": [ + 2, + 3, + 0, + 0 + ] + }, + { + "keypad": [ + [ + 0, + 37, + 38, + 12, + 4, + 41, + 33, + 43, + 44 + ], + [ + 9, + 1, + 20, + 3, + 49, + 50, + 42, + 7, + 35 + ], + [ + 36, + 10, + 29, + 48, + 40, + 23, + 51, + 34, + 26 + ], + [ + 45, + 19, + 11, + 39, + 31, + 5, + 24, + 16, + 8 + ], + [ + 27, + 46, + 2, + 21, + 13, + 14, + 6, + 25, + 53 + ], + [ + 18, + 28, + 47, + 30, + 22, + 32, + 15, + 52, + 17 + ] + ], + "key_selection": [ + 3, + 0, + 1, + 4 + ] + }, + { + "keypad": [ + [ + 36, + 28, + 47, + 30, + 13, + 50, + 15, + 34, + 8 + ], + [ + 27, + 19, + 20, + 48, + 31, + 41, + 6, + 52, + 35 + ], + [ + 18, + 46, + 29, + 3, + 22, + 32, + 33, + 7, + 17 + ], + [ + 45, + 1, + 38, + 21, + 4, + 23, + 24, + 16, + 53 + ], + [ + 0, + 37, + 11, + 12, + 49, + 14, + 42, + 25, + 26 + ], + [ + 9, + 10, + 2, + 39, + 40, + 5, + 51, + 43, + 44 + ] + ], + "key_selection": [ + 3, + 4, + 2, + 3 + ] + }, + { + "keypad": [ + [ + 0, + 46, + 47, + 3, + 22, + 5, + 42, + 7, + 8 + ], + [ + 36, + 19, + 38, + 12, + 40, + 41, + 15, + 34, + 44 + ], + [ + 9, + 10, + 20, + 21, + 13, + 32, + 6, + 25, + 53 + ], + [ + 27, + 37, + 2, + 48, + 4, + 50, + 24, + 43, + 35 + ], + [ + 18, + 1, + 11, + 39, + 49, + 14, + 51, + 16, + 26 + ], + [ + 45, + 28, + 29, + 30, + 31, + 23, + 33, + 52, + 17 + ] + ], + "key_selection": [ + 3, + 1, + 0, + 2 + ] + }, + { + "keypad": [ + [ + 27, + 37, + 20, + 3, + 22, + 32, + 33, + 7, + 53 + ], + [ + 18, + 1, + 29, + 21, + 13, + 50, + 15, + 34, + 17 + ], + [ + 0, + 10, + 2, + 12, + 49, + 23, + 42, + 16, + 26 + ], + [ + 36, + 46, + 38, + 48, + 40, + 5, + 24, + 43, + 44 + ], + [ + 9, + 28, + 11, + 30, + 4, + 41, + 51, + 52, + 35 + ], + [ + 45, + 19, + 47, + 39, + 31, + 14, + 6, + 25, + 8 + ] + ], + "key_selection": [ + 3, + 2, + 0, + 0 + ] + }, + { + "keypad": [ + [ + 0, + 10, + 2, + 3, + 40, + 50, + 15, + 43, + 26 + ], + [ + 27, + 1, + 38, + 21, + 31, + 41, + 42, + 25, + 35 + ], + [ + 36, + 19, + 29, + 30, + 49, + 32, + 24, + 7, + 8 + ], + [ + 9, + 28, + 20, + 12, + 4, + 5, + 51, + 34, + 44 + ], + [ + 18, + 37, + 11, + 48, + 22, + 14, + 6, + 52, + 53 + ], + [ + 45, + 46, + 47, + 39, + 13, + 23, + 33, + 16, + 17 + ] + ], + "key_selection": [ + 2, + 3, + 0, + 4 + ] + }, + { + "keypad": [ + [ + 18, + 19, + 2, + 30, + 49, + 14, + 6, + 52, + 17 + ], + [ + 9, + 37, + 29, + 3, + 13, + 50, + 42, + 34, + 8 + ], + [ + 36, + 28, + 20, + 39, + 4, + 5, + 15, + 25, + 35 + ], + [ + 45, + 46, + 38, + 12, + 22, + 41, + 33, + 43, + 26 + ], + [ + 27, + 1, + 47, + 21, + 40, + 23, + 51, + 7, + 53 + ], + [ + 0, + 10, + 11, + 48, + 31, + 32, + 24, + 16, + 44 + ] + ], + "key_selection": [ + 5, + 3, + 1, + 4 + ] + }, + { + "keypad": [ + [ + 36, + 46, + 38, + 39, + 4, + 32, + 33, + 16, + 17 + ], + [ + 45, + 37, + 47, + 48, + 49, + 14, + 51, + 7, + 26 + ], + [ + 0, + 1, + 29, + 21, + 13, + 50, + 24, + 52, + 44 + ], + [ + 27, + 19, + 20, + 30, + 31, + 41, + 6, + 43, + 53 + ], + [ + 18, + 10, + 11, + 12, + 40, + 5, + 15, + 25, + 8 + ], + [ + 9, + 28, + 2, + 3, + 22, + 23, + 42, + 34, + 35 + ] + ], + "key_selection": [ + 2, + 4, + 5, + 3 + ] + }, + { + "keypad": [ + [ + 9, + 1, + 38, + 39, + 4, + 32, + 42, + 16, + 53 + ], + [ + 18, + 28, + 11, + 21, + 22, + 50, + 33, + 25, + 17 + ], + [ + 0, + 10, + 29, + 12, + 31, + 5, + 24, + 52, + 35 + ], + [ + 36, + 19, + 47, + 30, + 49, + 14, + 15, + 34, + 26 + ], + [ + 27, + 37, + 2, + 48, + 40, + 23, + 6, + 43, + 8 + ], + [ + 45, + 46, + 20, + 3, + 13, + 41, + 51, + 7, + 44 + ] + ], + "key_selection": [ + 2, + 2, + 5, + 0 + ] + }, + { + "keypad": [ + [ + 18, + 28, + 20, + 21, + 22, + 14, + 33, + 25, + 26 + ], + [ + 27, + 10, + 2, + 3, + 13, + 5, + 51, + 43, + 44 + ], + [ + 9, + 19, + 38, + 12, + 31, + 41, + 15, + 16, + 53 + ], + [ + 45, + 1, + 47, + 39, + 40, + 50, + 6, + 7, + 17 + ], + [ + 0, + 46, + 29, + 30, + 49, + 32, + 42, + 52, + 8 + ], + [ + 36, + 37, + 11, + 48, + 4, + 23, + 24, + 34, + 35 + ] + ], + "key_selection": [ + 5, + 2, + 1, + 2 + ] + }, + { + "keypad": [ + [ + 9, + 46, + 29, + 48, + 4, + 14, + 24, + 16, + 26 + ], + [ + 45, + 19, + 20, + 30, + 22, + 32, + 33, + 7, + 53 + ], + [ + 27, + 37, + 47, + 12, + 40, + 23, + 42, + 43, + 8 + ], + [ + 36, + 1, + 2, + 3, + 31, + 41, + 15, + 52, + 35 + ], + [ + 18, + 28, + 38, + 21, + 13, + 5, + 6, + 34, + 17 + ], + [ + 0, + 10, + 11, + 39, + 49, + 50, + 51, + 25, + 44 + ] + ], + "key_selection": [ + 0, + 2, + 3, + 1 + ] + }, + { + "keypad": [ + [ + 45, + 37, + 11, + 12, + 31, + 41, + 24, + 7, + 44 + ], + [ + 0, + 28, + 29, + 21, + 4, + 5, + 42, + 16, + 17 + ], + [ + 36, + 10, + 47, + 39, + 40, + 23, + 6, + 34, + 35 + ], + [ + 18, + 1, + 20, + 30, + 13, + 14, + 15, + 43, + 8 + ], + [ + 9, + 19, + 38, + 3, + 49, + 50, + 51, + 25, + 53 + ], + [ + 27, + 46, + 2, + 48, + 22, + 32, + 33, + 52, + 26 + ] + ], + "key_selection": [ + 0, + 0, + 4, + 4 + ] + } + ] +} \ No newline at end of file diff --git a/example/obs_png/run_001/observation_001.png b/example/obs_png/run_001/observation_001.png new file mode 100644 index 0000000..43c1365 Binary files /dev/null and b/example/obs_png/run_001/observation_001.png differ diff --git a/example/obs_png/run_001/observation_002.png b/example/obs_png/run_001/observation_002.png new file mode 100644 index 0000000..ab4efc4 Binary files /dev/null and b/example/obs_png/run_001/observation_002.png differ diff --git a/example/obs_png/run_001/observation_003.png b/example/obs_png/run_001/observation_003.png new file mode 100644 index 0000000..4239315 Binary files /dev/null and b/example/obs_png/run_001/observation_003.png differ diff --git a/example/obs_png/run_001/observation_004.png b/example/obs_png/run_001/observation_004.png new file mode 100644 index 0000000..5bff1ed Binary files /dev/null and b/example/obs_png/run_001/observation_004.png differ diff --git a/example/obs_png/run_001/observation_005.png b/example/obs_png/run_001/observation_005.png new file mode 100644 index 0000000..1872cba Binary files /dev/null and b/example/obs_png/run_001/observation_005.png differ diff --git a/example/obs_png/run_001/observation_006.png b/example/obs_png/run_001/observation_006.png new file mode 100644 index 0000000..10af2f0 Binary files /dev/null and b/example/obs_png/run_001/observation_006.png differ diff --git a/example/obs_png/run_001/observation_007.png b/example/obs_png/run_001/observation_007.png new file mode 100644 index 0000000..7bc8970 Binary files /dev/null and b/example/obs_png/run_001/observation_007.png differ diff --git a/example/obs_png/run_001/observation_008.png b/example/obs_png/run_001/observation_008.png new file mode 100644 index 0000000..4adbe51 Binary files /dev/null and b/example/obs_png/run_001/observation_008.png differ diff --git a/example/obs_png/run_001/observation_009.png b/example/obs_png/run_001/observation_009.png new file mode 100644 index 0000000..73ca6a6 Binary files /dev/null and b/example/obs_png/run_001/observation_009.png differ diff --git a/example/obs_png/run_001/observation_010.png b/example/obs_png/run_001/observation_010.png new file mode 100644 index 0000000..87dde84 Binary files /dev/null and b/example/obs_png/run_001/observation_010.png differ diff --git a/example/obs_png/run_001/observation_011.png b/example/obs_png/run_001/observation_011.png new file mode 100644 index 0000000..1bd48f4 Binary files /dev/null and b/example/obs_png/run_001/observation_011.png differ diff --git a/example/obs_png/run_001/observation_012.png b/example/obs_png/run_001/observation_012.png new file mode 100644 index 0000000..33319aa Binary files /dev/null and b/example/obs_png/run_001/observation_012.png differ diff --git a/example/obs_png/run_001/observation_013.png b/example/obs_png/run_001/observation_013.png new file mode 100644 index 0000000..40d818a Binary files /dev/null and b/example/obs_png/run_001/observation_013.png differ diff --git a/example/obs_png/run_001/observation_014.png b/example/obs_png/run_001/observation_014.png new file mode 100644 index 0000000..f1e5847 Binary files /dev/null and b/example/obs_png/run_001/observation_014.png differ diff --git a/example/obs_png/run_001/observation_015.png b/example/obs_png/run_001/observation_015.png new file mode 100644 index 0000000..624a610 Binary files /dev/null and b/example/obs_png/run_001/observation_015.png differ diff --git a/example/obs_png/run_001/observation_016.png b/example/obs_png/run_001/observation_016.png new file mode 100644 index 0000000..62b467e Binary files /dev/null and b/example/obs_png/run_001/observation_016.png differ diff --git a/example/obs_png/run_001/observation_017.png b/example/obs_png/run_001/observation_017.png new file mode 100644 index 0000000..f5ad56d Binary files /dev/null and b/example/obs_png/run_001/observation_017.png differ diff --git a/example/obs_png/run_001/observation_018.png b/example/obs_png/run_001/observation_018.png new file mode 100644 index 0000000..0b71682 Binary files /dev/null and b/example/obs_png/run_001/observation_018.png differ diff --git a/example/obs_png/run_001/observation_019.png b/example/obs_png/run_001/observation_019.png new file mode 100644 index 0000000..eec52e2 Binary files /dev/null and b/example/obs_png/run_001/observation_019.png differ diff --git a/example/obs_png/run_001/observation_020.png b/example/obs_png/run_001/observation_020.png new file mode 100644 index 0000000..bb09be3 Binary files /dev/null and b/example/obs_png/run_001/observation_020.png differ diff --git a/example/obs_png/run_001/observation_021.png b/example/obs_png/run_001/observation_021.png new file mode 100644 index 0000000..9bce116 Binary files /dev/null and b/example/obs_png/run_001/observation_021.png differ diff --git a/example/obs_png/run_001/observation_022.png b/example/obs_png/run_001/observation_022.png new file mode 100644 index 0000000..701dd41 Binary files /dev/null and b/example/obs_png/run_001/observation_022.png differ diff --git a/example/obs_png/run_001/observation_023.png b/example/obs_png/run_001/observation_023.png new file mode 100644 index 0000000..c0a24c5 Binary files /dev/null and b/example/obs_png/run_001/observation_023.png differ diff --git a/example/obs_png/run_001/observation_024.png b/example/obs_png/run_001/observation_024.png new file mode 100644 index 0000000..bd7f903 Binary files /dev/null and b/example/obs_png/run_001/observation_024.png differ diff --git a/example/obs_png/run_001/observation_025.png b/example/obs_png/run_001/observation_025.png new file mode 100644 index 0000000..2709e8e Binary files /dev/null and b/example/obs_png/run_001/observation_025.png differ diff --git a/example/obs_png/run_001/observation_026.png b/example/obs_png/run_001/observation_026.png new file mode 100644 index 0000000..dd65c25 Binary files /dev/null and b/example/obs_png/run_001/observation_026.png differ diff --git a/example/obs_png/run_001/observation_027.png b/example/obs_png/run_001/observation_027.png new file mode 100644 index 0000000..3e66c5e Binary files /dev/null and b/example/obs_png/run_001/observation_027.png differ diff --git a/example/obs_png/run_001/observation_028.png b/example/obs_png/run_001/observation_028.png new file mode 100644 index 0000000..372bde1 Binary files /dev/null and b/example/obs_png/run_001/observation_028.png differ diff --git a/example/obs_png/run_001/observation_029.png b/example/obs_png/run_001/observation_029.png new file mode 100644 index 0000000..6640bda Binary files /dev/null and b/example/obs_png/run_001/observation_029.png differ diff --git a/example/obs_png/run_001/observation_030.png b/example/obs_png/run_001/observation_030.png new file mode 100644 index 0000000..714ed32 Binary files /dev/null and b/example/obs_png/run_001/observation_030.png differ diff --git a/example/obs_png/run_001/observation_031.png b/example/obs_png/run_001/observation_031.png new file mode 100644 index 0000000..10f4d51 Binary files /dev/null and b/example/obs_png/run_001/observation_031.png differ diff --git a/example/obs_png/run_001/observation_032.png b/example/obs_png/run_001/observation_032.png new file mode 100644 index 0000000..b20f966 Binary files /dev/null and b/example/obs_png/run_001/observation_032.png differ diff --git a/example/obs_png/run_001/observation_033.png b/example/obs_png/run_001/observation_033.png new file mode 100644 index 0000000..b4ec189 Binary files /dev/null and b/example/obs_png/run_001/observation_033.png differ diff --git a/example/obs_png/run_001/observation_034.png b/example/obs_png/run_001/observation_034.png new file mode 100644 index 0000000..d4f6a77 Binary files /dev/null and b/example/obs_png/run_001/observation_034.png differ diff --git a/example/obs_png/run_001/observation_035.png b/example/obs_png/run_001/observation_035.png new file mode 100644 index 0000000..8ab013f Binary files /dev/null and b/example/obs_png/run_001/observation_035.png differ diff --git a/example/obs_png/run_001/observation_036.png b/example/obs_png/run_001/observation_036.png new file mode 100644 index 0000000..ee35418 Binary files /dev/null and b/example/obs_png/run_001/observation_036.png differ diff --git a/example/obs_png/run_001/observation_037.png b/example/obs_png/run_001/observation_037.png new file mode 100644 index 0000000..4ab0519 Binary files /dev/null and b/example/obs_png/run_001/observation_037.png differ diff --git a/example/obs_png/run_001/observation_038.png b/example/obs_png/run_001/observation_038.png new file mode 100644 index 0000000..89d10ed Binary files /dev/null and b/example/obs_png/run_001/observation_038.png differ diff --git a/example/obs_png/run_001/observation_039.png b/example/obs_png/run_001/observation_039.png new file mode 100644 index 0000000..c974adb Binary files /dev/null and b/example/obs_png/run_001/observation_039.png differ diff --git a/example/obs_png/run_001/observation_040.png b/example/obs_png/run_001/observation_040.png new file mode 100644 index 0000000..4c79e40 Binary files /dev/null and b/example/obs_png/run_001/observation_040.png differ diff --git a/example/obs_png/run_001/observation_041.png b/example/obs_png/run_001/observation_041.png new file mode 100644 index 0000000..a2a2e5e Binary files /dev/null and b/example/obs_png/run_001/observation_041.png differ diff --git a/example/obs_png/run_001/observation_042.png b/example/obs_png/run_001/observation_042.png new file mode 100644 index 0000000..7d20666 Binary files /dev/null and b/example/obs_png/run_001/observation_042.png differ diff --git a/example/obs_png/run_001/observation_043.png b/example/obs_png/run_001/observation_043.png new file mode 100644 index 0000000..f1af348 Binary files /dev/null and b/example/obs_png/run_001/observation_043.png differ diff --git a/example/obs_png/run_001/observation_044.png b/example/obs_png/run_001/observation_044.png new file mode 100644 index 0000000..5cfe764 Binary files /dev/null and b/example/obs_png/run_001/observation_044.png differ diff --git a/example/obs_png/run_001/observation_045.png b/example/obs_png/run_001/observation_045.png new file mode 100644 index 0000000..faaf4f2 Binary files /dev/null and b/example/obs_png/run_001/observation_045.png differ diff --git a/example/obs_png/run_001/observation_046.png b/example/obs_png/run_001/observation_046.png new file mode 100644 index 0000000..5005f2e Binary files /dev/null and b/example/obs_png/run_001/observation_046.png differ diff --git a/example/obs_png/run_001/observation_047.png b/example/obs_png/run_001/observation_047.png new file mode 100644 index 0000000..332ef48 Binary files /dev/null and b/example/obs_png/run_001/observation_047.png differ diff --git a/example/obs_png/run_001/observation_048.png b/example/obs_png/run_001/observation_048.png new file mode 100644 index 0000000..865b95a Binary files /dev/null and b/example/obs_png/run_001/observation_048.png differ diff --git a/example/obs_png/run_001/observation_049.png b/example/obs_png/run_001/observation_049.png new file mode 100644 index 0000000..2f72ebb Binary files /dev/null and b/example/obs_png/run_001/observation_049.png differ diff --git a/example/obs_png/run_001/observation_050.png b/example/obs_png/run_001/observation_050.png new file mode 100644 index 0000000..1d70781 Binary files /dev/null and b/example/obs_png/run_001/observation_050.png differ diff --git a/notebooks/evilkode.ipynb b/notebooks/evilkode.ipynb index 64ef545..23257d5 100644 --- a/notebooks/evilkode.ipynb +++ b/notebooks/evilkode.ipynb @@ -10,7 +10,8 @@ }, "cell_type": "code", "source": [ - "from src.benchmark import shuffle_benchmark, ShuffleTypes\n", + "from src.benchmark import shuffle_benchmark\n", + "from src.utils import ShuffleTypes\n", "import matplotlib.pyplot as plt\n", "from pathlib import Path" ], diff --git a/src/benchmark.py b/src/benchmark.py index 73a71c7..4f451b5 100644 --- a/src/benchmark.py +++ b/src/benchmark.py @@ -1,82 +1,17 @@ -from src.evilkode import Observation, Evilkode -from src.keypad import Keypad -import random +from src.evilkode import Evilkode from dataclasses import dataclass from statistics import mean, variance -from enum import Enum from pathlib import Path +from src.utils import ShuffleTypes, observations, passcode_generator + + @dataclass class Benchmark: mean: int variance: int runs: list[int] -class ShuffleTypes(Enum): - FULL_SHUFFLE = "FULL_SHUFFLE" - SPLIT_SHUFFLE = "SPLIT_SHUFFLE" - -def observations(number_of_keys, properties_per_key, passcode_len, complexity: int, disparity: int, shuffle_type: ShuffleTypes): - k = number_of_keys - p = properties_per_key - n = passcode_len - passcode = passcode_generator(k, p, n, complexity, disparity) - keypad = Keypad.new_keypad(k, p) - - def obs_gen(): - for _ in range(100): # finite number of yields - yield Observation( - keypad=keypad.keypad.copy(), - key_selection=keypad.key_entry(target_passcode=passcode) - ) - match shuffle_type: - case ShuffleTypes.FULL_SHUFFLE: - keypad.full_shuffle() - case ShuffleTypes.SPLIT_SHUFFLE: - keypad.split_shuffle() - case _: - raise Exception(f"no shuffle type {shuffle_type}") - - return obs_gen() - -def passcode_generator(k: int, p: int, n: int, c: int, d: int) -> list[int]: - assert n >= c - assert p*k >= c - - assert n >= d - assert p >= d - passcode_prop = [] - passcode_set = [] - valid_choices = {i for i in range(k*p)} - repeat_set = n-d - repeat_prop = n-c - prop_added = set() - set_added = set() - - for _ in range(n): - prop = random.choice(list(valid_choices)) - prop_set = prop//p - passcode_prop.append(prop) - passcode_set.append(prop_set) - - if prop in prop_added: - repeat_prop -= 1 - if prop_set in set_added: - repeat_set -= 1 - - prop_added.add(prop) - set_added.add(prop_set) - - if repeat_prop <= 0: - valid_choices -= prop_added - - if repeat_set <= 0: - for el in valid_choices.copy(): - if el // p in set_added: - valid_choices.remove(el) - - return passcode_prop - def shuffle_benchmark( number_of_keys: int, @@ -105,13 +40,14 @@ def shuffle_benchmark( ) runs = [] for _ in range(run_count): + passcode = passcode_generator(number_of_keys, properties_per_key, passcode_len, complexity, disparity) evilkode = Evilkode( observations=observations( + target_passcode=passcode, number_of_keys=number_of_keys, properties_per_key=properties_per_key, - passcode_len=passcode_len, - complexity=complexity, - disparity=disparity, + min_complexity=complexity, + min_disparity=disparity, shuffle_type=shuffle_type, ), number_of_keys=number_of_keys, @@ -144,13 +80,14 @@ def full_shuffle_benchmark( ) -> Benchmark: runs = [] for _ in range(run_count): + passcode = passcode_generator(number_of_keys, properties_per_key, passcode_len, complexity, disparity) evilkode = Evilkode( observations=observations( + target_passcode=passcode, number_of_keys=number_of_keys, properties_per_key=properties_per_key, - passcode_len=passcode_len, - complexity=complexity, - disparity=disparity, + min_complexity=complexity, + min_disparity=disparity, shuffle_type=ShuffleTypes.FULL_SHUFFLE, ), number_of_keys=number_of_keys, diff --git a/src/utils.py b/src/utils.py index d95c9a2..63f9a05 100644 --- a/src/utils.py +++ b/src/utils.py @@ -1,7 +1,79 @@ +import random +from enum import Enum from math import factorial, comb +from src.evilkode import Observation +from src.keypad import Keypad + + def total_valid_nkode_states(k: int, p: int) -> int: return factorial(k) ** (p-1) def total_shuffle_states(k: int, p: int) -> int: return comb((p-1), (p-1) // 2) * factorial(k) + + +class ShuffleTypes(Enum): + FULL_SHUFFLE = "FULL_SHUFFLE" + SPLIT_SHUFFLE = "SPLIT_SHUFFLE" + + +def observations(target_passcode: list[int], number_of_keys:int, properties_per_key: int, min_complexity: int, min_disparity: int, shuffle_type: ShuffleTypes, number_of_observations: int = 100): + k = number_of_keys + p = properties_per_key + keypad = Keypad.new_keypad(k, p) + + def obs_gen(): + for _ in range(number_of_observations): + yield Observation( + keypad=keypad.keypad.copy(), + key_selection=keypad.key_entry(target_passcode=target_passcode) + ) + match shuffle_type: + case ShuffleTypes.FULL_SHUFFLE: + keypad.full_shuffle() + case ShuffleTypes.SPLIT_SHUFFLE: + keypad.split_shuffle() + case _: + raise Exception(f"no shuffle type {shuffle_type}") + + return obs_gen() + + +def passcode_generator(k: int, p: int, n: int, c: int, d: int) -> list[int]: + assert n >= c + assert p*k >= c + + assert n >= d + assert p >= d + passcode_prop = [] + passcode_set = [] + valid_choices = {i for i in range(k*p)} + repeat_set = n-d + repeat_prop = n-c + prop_added = set() + set_added = set() + + for _ in range(n): + prop = random.choice(list(valid_choices)) + prop_set = prop//p + passcode_prop.append(prop) + passcode_set.append(prop_set) + + if prop in prop_added: + repeat_prop -= 1 + if prop_set in set_added: + repeat_set -= 1 + + prop_added.add(prop) + set_added.add(prop_set) + + if repeat_prop <= 0: + valid_choices -= prop_added + + if repeat_set <= 0: + for el in valid_choices.copy(): + if el // p in set_added: + valid_choices.remove(el) + + return passcode_prop diff --git a/src/visualnkode.py b/src/visualnkode.py new file mode 100644 index 0000000..2a0215c --- /dev/null +++ b/src/visualnkode.py @@ -0,0 +1,229 @@ +import json +from dataclasses import dataclass, asdict +from evilkode import Observation +from utils import observations, passcode_generator, ShuffleTypes +from pathlib import Path +from PIL import Image, ImageDraw, ImageFont +from typing import Iterable + +# Project root = parent of *this* file's directory +PROJECT_ROOT = Path(__file__).resolve().parent.parent +OUTPUT_DIR = PROJECT_ROOT / "example" / "obs_json" +PNG_DIR = PROJECT_ROOT / "example" / "obs_png" + +@dataclass +class ObservationSequence: + target_passcode: list[int] + observations: list[Observation] + +def new_observation_sequence( + number_of_keys: int, + properties_per_key: int, + passcode_len: int, + complexity: int, + disparity: int, + numb_runs: int, +) -> ObservationSequence: + passcode = passcode_generator(number_of_keys, properties_per_key, passcode_len, complexity, disparity) + obs_seq = ObservationSequence(target_passcode=passcode, observations=[]) + obs_gen = observations( + target_passcode=passcode, + number_of_keys=number_of_keys, + properties_per_key=properties_per_key, + min_complexity=complexity, + min_disparity=disparity, + shuffle_type=ShuffleTypes.FULL_SHUFFLE, + number_of_observations=numb_runs, + ) + for obs in obs_gen: + obs.keypad = obs.keypad.tolist() + obs_seq.observations.append(obs) + + return obs_seq + +def _next_json_filename(base_dir: Path) -> Path: + """Find the next available observation_X.json file in base_dir.""" + counter = 1 + while True: + candidate = base_dir / f"observation_{counter}.json" + if not candidate.exists(): + return candidate + counter += 1 + +def save_observation_sequence_to_json(seq: ObservationSequence, filename: Path | None = None) -> None: + """ + Save ObservationSequence to JSON. + - If filename is None, put it under PROJECT_ROOT/output/obs_json/ as observation_{n}.json + - Creates directory if needed + """ + if filename is None: + base_dir = OUTPUT_DIR + base_dir.mkdir(parents=True, exist_ok=True) + filename = _next_json_filename(base_dir) + else: + filename.parent.mkdir(parents=True, exist_ok=True) + + with filename.open("w", encoding="utf-8") as f: + json.dump(asdict(seq), f, indent=4) + +# ---------- Helpers ---------- +def _load_font(preferred: str, size: int) -> ImageFont.FreeTypeFont | ImageFont.ImageFont: + """Try a preferred TTF, fall back to common monospace, then PIL default.""" + candidates = [ + preferred, + "DejaVuSansMono.ttf", # common on Linux + "Consolas.ttf", # Windows + "Menlo.ttc", "Menlo.ttf", # macOS + "Courier New.ttf", + ] + for c in candidates: + try: + return ImageFont.truetype(c, size) + except Exception: + continue + return ImageFont.load_default() + +def _text_size(draw: ImageDraw.ImageDraw, text: str, font: ImageFont.ImageFont) -> tuple[int, int]: + """Get (w, h) using font bbox for accurate layout.""" + left, top, right, bottom = draw.textbbox((0, 0), text, font=font) + return right - left, bottom - top + +def _join_nums(nums: Iterable[int]) -> str: + return " ".join(str(n) for n in nums) + +def _next_available_path(path: Path) -> Path: + """If path exists, append _1, _2, ...""" + if not path.exists(): + return path + base, suffix = path.stem, path.suffix or ".png" + i = 1 + while True: + candidate = path.with_name(f"{base}_{i}{suffix}") + if not candidate.exists(): + return candidate + i += 1 + +# ---------- Core rendering ---------- +def render_observation_to_png( + target_passcode: list[int], + obs: Observation, + out_path: Path, + *, + header_font_name: str = "DejaVuSans.ttf", + body_font_name: str = "DejaVuSans.ttf", + header_size: int = 28, + body_size: int = 24, + margin: int = 32, + row_padding_xy: tuple[int, int] = (16, 12), # (x, y) padding inside row box + row_spacing: int = 14, + header_spacing: int = 10, + section_spacing: int = 18, + bg_color: str = "white", + fg_color: str = "black", + row_fill: str = "#f7f7f7", + row_outline: str = "#222222", +): + """ + Render a single observation: + - Top lines: + Target Passcode: {target} + Selected Keys: {selected keys} + - Then a stack of row boxes representing the keypad rows. + """ + out_path.parent.mkdir(parents=True, exist_ok=True) + out_path = _next_available_path(out_path) + + # Fonts + header_font = _load_font(header_font_name, header_size) + body_font = _load_font(body_font_name, body_size) + + # Prepare strings + header1 = f"Target Passcode: {_join_nums(target_passcode)}" + header2 = f"Selected Keys: {_join_nums(obs.key_selection)}" + row_texts = [_join_nums(row) for row in obs.keypad] + + # Measure to compute canvas size + # Provisional image for measurement + temp_img = Image.new("RGB", (1, 1), bg_color) + d = ImageDraw.Draw(temp_img) + + h1_w, h1_h = _text_size(d, header1, header_font) + h2_w, h2_h = _text_size(d, header2, header_font) + + row_text_sizes = [_text_size(d, t, body_font) for t in row_texts] + row_box_widths = [tw + 2 * row_padding_xy[0] for (tw, th) in row_text_sizes] + row_box_heights = [th + 2 * row_padding_xy[1] for (tw, th) in row_text_sizes] + + content_width = max([h1_w, h2_w] + (row_box_widths or [0])) + total_rows_height = sum(row_box_heights) + row_spacing * max(0, len(row_box_heights) - 1) + + width = content_width + 2 * margin + height = ( + margin + + h1_h + + header_spacing + + h2_h + + section_spacing + + total_rows_height + + margin + ) + + # Create final image + img = Image.new("RGB", (max(width, 300), max(height, 200)), bg_color) + draw = ImageDraw.Draw(img) + + # Draw headers + x = margin + y = margin + draw.text((x, y), header1, font=header_font, fill=fg_color) + y += h1_h + header_spacing + draw.text((x, y), header2, font=header_font, fill=fg_color) + y += h2_h + section_spacing + + # Draw row boxes + for (text, (tw, th), box_h) in zip(row_texts, row_text_sizes, row_box_heights): + box_left = x + box_top = y + box_right = x + max(row_box_widths) # make all boxes same width for neatness + box_bottom = y + box_h + + # rectangle + draw.rectangle([box_left, box_top, box_right, box_bottom], fill=row_fill, outline=row_outline, width=2) + + # text centered vertically, left-padded + text_x = box_left + row_padding_xy[0] + text_y = box_top + (box_h - th) // 2 + draw.text((text_x, text_y), text, font=body_font, fill=fg_color) + + y = box_bottom + row_spacing + + img.save(out_path, format="PNG") + +def _next_run_dir(base_dir: Path) -> Path: + """Find the next available run directory under base_dir (run_001, run_002, ...).""" + counter = 1 + while True: + run_dir = base_dir / f"run_{counter:03d}" + if not run_dir.exists(): + run_dir.mkdir(parents=True) + return run_dir + counter += 1 + +def render_sequence_to_pngs(seq: ObservationSequence, out_dir: Path | None = None) -> None: + """ + Render each observation to its own PNG inside a fresh run directory. + Default: PROJECT_ROOT/output/obs_png/run_XXX/observation_001.png + """ + base_dir = PNG_DIR if out_dir is None else out_dir + base_dir.mkdir(parents=True, exist_ok=True) + + # Create a fresh run dir + run_dir = _next_run_dir(base_dir) + + for i, obs in enumerate(seq.observations, start=1): + filename = run_dir / f"observation_{i:03d}.png" + render_observation_to_png(seq.target_passcode, obs, filename) +if __name__ == "__main__": + obs_seq = new_observation_sequence(6, 9,4,0,0,numb_runs=50) + save_observation_sequence_to_json(obs_seq) + render_sequence_to_pngs(obs_seq) \ No newline at end of file diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index eaee76f..da0b305 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -1,4 +1,4 @@ -from src.benchmark import passcode_generator +from src.utils import passcode_generator import pytest @pytest.mark.parametrize(