multi-puzzle-solver 1.1.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- multi_puzzle_solver-1.1.8.dist-info/METADATA +4326 -0
- multi_puzzle_solver-1.1.8.dist-info/RECORD +106 -0
- multi_puzzle_solver-1.1.8.dist-info/WHEEL +5 -0
- multi_puzzle_solver-1.1.8.dist-info/top_level.txt +1 -0
- puzzle_solver/__init__.py +184 -0
- puzzle_solver/core/utils.py +298 -0
- puzzle_solver/core/utils_ortools.py +333 -0
- puzzle_solver/core/utils_visualizer.py +575 -0
- puzzle_solver/puzzles/abc_view/abc_view.py +75 -0
- puzzle_solver/puzzles/aquarium/aquarium.py +97 -0
- puzzle_solver/puzzles/area_51/area_51.py +159 -0
- puzzle_solver/puzzles/battleships/battleships.py +139 -0
- puzzle_solver/puzzles/binairo/binairo.py +98 -0
- puzzle_solver/puzzles/binairo/binairo_plus.py +7 -0
- puzzle_solver/puzzles/black_box/black_box.py +243 -0
- puzzle_solver/puzzles/branches/branches.py +64 -0
- puzzle_solver/puzzles/bridges/bridges.py +104 -0
- puzzle_solver/puzzles/chess_range/chess_melee.py +6 -0
- puzzle_solver/puzzles/chess_range/chess_range.py +406 -0
- puzzle_solver/puzzles/chess_range/chess_solo.py +9 -0
- puzzle_solver/puzzles/chess_sequence/chess_sequence.py +262 -0
- puzzle_solver/puzzles/circle_9/circle_9.py +44 -0
- puzzle_solver/puzzles/clouds/clouds.py +81 -0
- puzzle_solver/puzzles/connect_the_dots/connect_the_dots.py +50 -0
- puzzle_solver/puzzles/cow_and_cactus/cow_and_cactus.py +66 -0
- puzzle_solver/puzzles/dominosa/dominosa.py +67 -0
- puzzle_solver/puzzles/filling/filling.py +94 -0
- puzzle_solver/puzzles/flip/flip.py +64 -0
- puzzle_solver/puzzles/flood_it/flood_it.py +174 -0
- puzzle_solver/puzzles/flood_it/parse_map/parse_map.py +197 -0
- puzzle_solver/puzzles/galaxies/galaxies.py +110 -0
- puzzle_solver/puzzles/galaxies/parse_map/parse_map.py +216 -0
- puzzle_solver/puzzles/guess/guess.py +232 -0
- puzzle_solver/puzzles/heyawake/heyawake.py +152 -0
- puzzle_solver/puzzles/hidden_stars/hidden_stars.py +52 -0
- puzzle_solver/puzzles/hidoku/hidoku.py +59 -0
- puzzle_solver/puzzles/inertia/inertia.py +121 -0
- puzzle_solver/puzzles/inertia/parse_map/parse_map.py +207 -0
- puzzle_solver/puzzles/inertia/tsp.py +400 -0
- puzzle_solver/puzzles/kakurasu/kakurasu.py +38 -0
- puzzle_solver/puzzles/kakuro/kakuro.py +81 -0
- puzzle_solver/puzzles/kakuro/krypto_kakuro.py +95 -0
- puzzle_solver/puzzles/keen/keen.py +76 -0
- puzzle_solver/puzzles/kropki/kropki.py +94 -0
- puzzle_solver/puzzles/light_up/light_up.py +58 -0
- puzzle_solver/puzzles/linesweeper/linesweeper.py +71 -0
- puzzle_solver/puzzles/link_a_pix/link_a_pix.py +91 -0
- puzzle_solver/puzzles/lits/lits.py +138 -0
- puzzle_solver/puzzles/magnets/magnets.py +96 -0
- puzzle_solver/puzzles/map/map.py +56 -0
- puzzle_solver/puzzles/mathema_grids/mathema_grids.py +119 -0
- puzzle_solver/puzzles/mathrax/mathrax.py +93 -0
- puzzle_solver/puzzles/minesweeper/minesweeper.py +123 -0
- puzzle_solver/puzzles/mosaic/mosaic.py +38 -0
- puzzle_solver/puzzles/n_queens/n_queens.py +71 -0
- puzzle_solver/puzzles/nonograms/nonograms.py +121 -0
- puzzle_solver/puzzles/nonograms/nonograms_colored.py +220 -0
- puzzle_solver/puzzles/norinori/norinori.py +96 -0
- puzzle_solver/puzzles/number_path/number_path.py +76 -0
- puzzle_solver/puzzles/numbermaze/numbermaze.py +97 -0
- puzzle_solver/puzzles/nurikabe/nurikabe.py +130 -0
- puzzle_solver/puzzles/palisade/palisade.py +91 -0
- puzzle_solver/puzzles/pearl/pearl.py +107 -0
- puzzle_solver/puzzles/pipes/pipes.py +82 -0
- puzzle_solver/puzzles/range/range.py +59 -0
- puzzle_solver/puzzles/rectangles/rectangles.py +128 -0
- puzzle_solver/puzzles/ripple_effect/ripple_effect.py +83 -0
- puzzle_solver/puzzles/rooms/rooms.py +75 -0
- puzzle_solver/puzzles/schurs_numbers/schurs_numbers.py +73 -0
- puzzle_solver/puzzles/shakashaka/shakashaka.py +201 -0
- puzzle_solver/puzzles/shingoki/shingoki.py +116 -0
- puzzle_solver/puzzles/signpost/signpost.py +93 -0
- puzzle_solver/puzzles/singles/singles.py +53 -0
- puzzle_solver/puzzles/slant/parse_map/parse_map.py +135 -0
- puzzle_solver/puzzles/slant/slant.py +111 -0
- puzzle_solver/puzzles/slitherlink/slitherlink.py +130 -0
- puzzle_solver/puzzles/snail/snail.py +97 -0
- puzzle_solver/puzzles/split_ends/split_ends.py +93 -0
- puzzle_solver/puzzles/star_battle/star_battle.py +75 -0
- puzzle_solver/puzzles/star_battle/star_battle_shapeless.py +7 -0
- puzzle_solver/puzzles/stitches/parse_map/parse_map.py +267 -0
- puzzle_solver/puzzles/stitches/stitches.py +96 -0
- puzzle_solver/puzzles/sudoku/sudoku.py +267 -0
- puzzle_solver/puzzles/suguru/suguru.py +55 -0
- puzzle_solver/puzzles/suko/suko.py +54 -0
- puzzle_solver/puzzles/tapa/tapa.py +97 -0
- puzzle_solver/puzzles/tatami/tatami.py +64 -0
- puzzle_solver/puzzles/tents/tents.py +80 -0
- puzzle_solver/puzzles/thermometers/thermometers.py +82 -0
- puzzle_solver/puzzles/towers/towers.py +89 -0
- puzzle_solver/puzzles/tracks/tracks.py +88 -0
- puzzle_solver/puzzles/trees_logic/trees_logic.py +48 -0
- puzzle_solver/puzzles/troix/dumplings.py +7 -0
- puzzle_solver/puzzles/troix/troix.py +75 -0
- puzzle_solver/puzzles/twiddle/twiddle.py +112 -0
- puzzle_solver/puzzles/undead/undead.py +130 -0
- puzzle_solver/puzzles/unequal/unequal.py +128 -0
- puzzle_solver/puzzles/unruly/unruly.py +54 -0
- puzzle_solver/puzzles/vectors/vectors.py +94 -0
- puzzle_solver/puzzles/vermicelli/vermicelli.py +74 -0
- puzzle_solver/puzzles/walls/walls.py +52 -0
- puzzle_solver/puzzles/yajilin/yajilin.py +87 -0
- puzzle_solver/puzzles/yin_yang/parse_map/parse_map.py +172 -0
- puzzle_solver/puzzles/yin_yang/yin_yang.py +103 -0
- puzzle_solver/utils/etc/parser/board_color_digit.py +497 -0
- puzzle_solver/utils/visualizer.py +155 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
puzzle_solver/__init__.py,sha256=NYPVckpg9PKDgPK80Nr-zqhFeR83MS_TX9yCOUp9hlU,8307
|
|
2
|
+
puzzle_solver/core/utils.py,sha256=SQJIugj5EGoV8YNprGSXCZdE24Moo56UWd38BCQ2-2g,10990
|
|
3
|
+
puzzle_solver/core/utils_ortools.py,sha256=p0Gco5tUWMKw5xIA7YLLoyGYW591lV6EUEpf4cQAZAs,15111
|
|
4
|
+
puzzle_solver/core/utils_visualizer.py,sha256=IdNI9UB1Y_E300ksOIYUEprRywkTvavOMYetbg4FIoo,23662
|
|
5
|
+
puzzle_solver/puzzles/abc_view/abc_view.py,sha256=Qr0rZKmKQ2teStHjQ5VPQ4k-XptsjJAlZ1WXWk5Aax4,4570
|
|
6
|
+
puzzle_solver/puzzles/aquarium/aquarium.py,sha256=dGqYEWMoh4di5DN4sd-GtYb6QeTpVYFQJHBkrrmrudQ,5649
|
|
7
|
+
puzzle_solver/puzzles/area_51/area_51.py,sha256=noiDSdDTVQFHR6ztVzyxmVbEFACsaWn-vRZlLSRLVlc,9967
|
|
8
|
+
puzzle_solver/puzzles/battleships/battleships.py,sha256=U4xJ_NJC2baHvfaAfJ01YEBjixq9gD0h8GP9L1V-_oM,7223
|
|
9
|
+
puzzle_solver/puzzles/binairo/binairo.py,sha256=EBpXYD9Mxuig4uJl3xkcQ6_tbnoG13mVV7RZpQEXm38,5790
|
|
10
|
+
puzzle_solver/puzzles/binairo/binairo_plus.py,sha256=TvLG3olwANtft3LuCF-y4OofpU9PNa4IXDqgZqsD-g0,267
|
|
11
|
+
puzzle_solver/puzzles/black_box/black_box.py,sha256=7CxCdkP_JC3_9mrObkg7lrYGLBMok_DdBd3Nx0xCSkA,12560
|
|
12
|
+
puzzle_solver/puzzles/branches/branches.py,sha256=BKrzZNU-y80uNiwahEr-eUM7X7baEVPzAdc18--XOlE,3691
|
|
13
|
+
puzzle_solver/puzzles/bridges/bridges.py,sha256=HSoYBlht92TMknhe8IaC0B3ilNaSh5xMorB_Gs1Jatg,5395
|
|
14
|
+
puzzle_solver/puzzles/chess_range/chess_melee.py,sha256=D-_Oi8OyxsVe1j3dIKYwRlxgeb3NWLmDWGcv-oclY0c,195
|
|
15
|
+
puzzle_solver/puzzles/chess_range/chess_range.py,sha256=St8Fk-HOhInvIJy02zbW1Pa1t2qjpli-Fes07tjgBRU,21472
|
|
16
|
+
puzzle_solver/puzzles/chess_range/chess_solo.py,sha256=ByDfcRsk5FVmFicpU_DpLoLTJ99Kr___vX4y8ln8_EQ,400
|
|
17
|
+
puzzle_solver/puzzles/chess_sequence/chess_sequence.py,sha256=6ap3Wouf2PxHV4P56B9ol1QT98Ym6VHaxorQZWl6LnY,13692
|
|
18
|
+
puzzle_solver/puzzles/circle_9/circle_9.py,sha256=Y94GM2eVYZc0YRu0XJ_ynMbBJZALKUZqbZA6Fe1ZwVQ,2401
|
|
19
|
+
puzzle_solver/puzzles/clouds/clouds.py,sha256=NAPDq_62Unfa9oYGqMt0hbA9TVw1tYQzYvEuoZC84i8,4100
|
|
20
|
+
puzzle_solver/puzzles/connect_the_dots/connect_the_dots.py,sha256=lxLUk7KjiTLND0CJ4f9IY_DS23rOYE-q0g1FKcRPaeo,3158
|
|
21
|
+
puzzle_solver/puzzles/cow_and_cactus/cow_and_cactus.py,sha256=tsVZZMNUtmJ5mj2thw3z7_n6zW0l8IAC9gtnFyfKcrk,3648
|
|
22
|
+
puzzle_solver/puzzles/dominosa/dominosa.py,sha256=YezNDc7RHUmOe3Ip6G2aHY0PadYGyo7CDacxplE2-9E,3362
|
|
23
|
+
puzzle_solver/puzzles/filling/filling.py,sha256=ILgGJqVI7yd6HPvWeKEsr620qorxLtAQYKTq65PqarY,4952
|
|
24
|
+
puzzle_solver/puzzles/flip/flip.py,sha256=cei6irTfntqctaLS3-rdYu8M2tw7ibzlHHvTIHW18yo,3518
|
|
25
|
+
puzzle_solver/puzzles/flood_it/flood_it.py,sha256=jnCtH1sZIt6K4hbQDSsiM1Cd8FjQNP7cfw2ObUW5fEQ,7948
|
|
26
|
+
puzzle_solver/puzzles/flood_it/parse_map/parse_map.py,sha256=m7gcpvN3THZdYLowdR_Jwx3HyttaV4K2DqrX_U7uFqU,8209
|
|
27
|
+
puzzle_solver/puzzles/galaxies/galaxies.py,sha256=IiKPU3fz5Aokhj5OjeT5jd_vdNuWnLzjZylGOTepsNU,5600
|
|
28
|
+
puzzle_solver/puzzles/galaxies/parse_map/parse_map.py,sha256=XmFqVN_oRfq9AZFWy5ViUJ2Szjgx-srrRkFPJXEEyFo,9358
|
|
29
|
+
puzzle_solver/puzzles/guess/guess.py,sha256=MpyrF6YVu0S1fzX-BllwxGKRGacWJpeLbNn5GetuEyo,10792
|
|
30
|
+
puzzle_solver/puzzles/heyawake/heyawake.py,sha256=HwCg1MQr6K742S-L5PjrkM1YYZWEFGV5gurTgT7q-6Q,9086
|
|
31
|
+
puzzle_solver/puzzles/hidden_stars/hidden_stars.py,sha256=LkzcDJNBZmuQJHyuEQz3YJJIZ8AHOj0FEwsl_uXvoxM,3154
|
|
32
|
+
puzzle_solver/puzzles/hidoku/hidoku.py,sha256=9Bj4ObmdgL6MCAYkPUTPj9fv0nr5XkJ92uNxSPgqqEA,3414
|
|
33
|
+
puzzle_solver/puzzles/inertia/inertia.py,sha256=-Y5fr7aK20zwmGHsZql7pYCq1kyMZglvkVZ6uIDf1HA,5658
|
|
34
|
+
puzzle_solver/puzzles/inertia/tsp.py,sha256=mAhlSjCWespASeN8uLZ0JkYDw-ZqFEpal6NM-ubpCXw,15313
|
|
35
|
+
puzzle_solver/puzzles/inertia/parse_map/parse_map.py,sha256=x0d64gTBd0HC2lO5uOpX2VKWfwj8rRiz0mQM_lqNmWs,8457
|
|
36
|
+
puzzle_solver/puzzles/kakurasu/kakurasu.py,sha256=ts4oPrFNeakNGi1rgAd6CIVQgeWSgnBGtA3qev_6ffY,1894
|
|
37
|
+
puzzle_solver/puzzles/kakuro/kakuro.py,sha256=9Sk-Q3EQsflyaJo5zywV-OpJn4WnNbbNAfiMFzN00F4,4440
|
|
38
|
+
puzzle_solver/puzzles/kakuro/krypto_kakuro.py,sha256=pppZk_gnl249Wta_2Um-tMDB-HLb7itkOgecCozfak4,5598
|
|
39
|
+
puzzle_solver/puzzles/keen/keen.py,sha256=0sxLE-fN5LpebT4EnDFe4WR2D4LG98A-My4OfJGTRuQ,4197
|
|
40
|
+
puzzle_solver/puzzles/kropki/kropki.py,sha256=fmmmACrRVqbsYSAcMT0aF3puijEND9URXMrZeywr_gQ,5821
|
|
41
|
+
puzzle_solver/puzzles/light_up/light_up.py,sha256=a6TLaGnCfzhB2GMf9qmNx2xK_oCPRA1SSrmGYWjasIw,2898
|
|
42
|
+
puzzle_solver/puzzles/linesweeper/linesweeper.py,sha256=LOj86CygiN00RUyG9IgZK5MQIsqyhcvVrivmzhHlf-w,4027
|
|
43
|
+
puzzle_solver/puzzles/link_a_pix/link_a_pix.py,sha256=1xh8c9V7FdtWrARWkya-8Z5fWP2o6BFj7PKf-ybSsbs,4752
|
|
44
|
+
puzzle_solver/puzzles/lits/lits.py,sha256=QeXFiCnWNI9jzUj3QLgU20mXxE2DD9o4BJsUb0TswKk,7231
|
|
45
|
+
puzzle_solver/puzzles/magnets/magnets.py,sha256=APg41g7_xSVUqHbSUxcWicnlmSKzkpnG2yXgQ0qMZmE,5437
|
|
46
|
+
puzzle_solver/puzzles/map/map.py,sha256=sxc57tapB8Tsgam-yoDitln1o-EB_SbIYvO6WEYy3us,2582
|
|
47
|
+
puzzle_solver/puzzles/mathema_grids/mathema_grids.py,sha256=wXj3pfXUMh3deFA6XXndZXod6ZNyCVt9vX1akt9zz20,6380
|
|
48
|
+
puzzle_solver/puzzles/mathrax/mathrax.py,sha256=qMO7h7pb3pRDw1hjJTqU8ALvARrajfTT8yuKzbTYRIM,4854
|
|
49
|
+
puzzle_solver/puzzles/minesweeper/minesweeper.py,sha256=vRckTvI5LeaWJ8PMG0applOQtiZWg430Sa3Sdf2RaW8,5865
|
|
50
|
+
puzzle_solver/puzzles/mosaic/mosaic.py,sha256=T89tkyTbob3LT20vwY3hkkEtNi8bxp2_CLaVi1gzhBc,1974
|
|
51
|
+
puzzle_solver/puzzles/n_queens/n_queens.py,sha256=ii1w0Pi0lcQz_XT1gkpNYlkWgwW_Jtvm0HL8OAg9fRY,4161
|
|
52
|
+
puzzle_solver/puzzles/nonograms/nonograms.py,sha256=Q-VHI0IPR2igccnE617HPThj5tnBgt27MiLWIZPtYcI,5587
|
|
53
|
+
puzzle_solver/puzzles/nonograms/nonograms_colored.py,sha256=XpxzpJw0GA-tE7PiltlA-dfypaTvqNIDLnKl1LxIjD4,10500
|
|
54
|
+
puzzle_solver/puzzles/norinori/norinori.py,sha256=ZEDWrD7zvEuqXOdXGOrELh1n_mWzhzZa3chs6Zqd3Pc,4570
|
|
55
|
+
puzzle_solver/puzzles/number_path/number_path.py,sha256=3m-3rdcZCXHSRspAWYlDq9GIUGmvO6SgDtRn4jsVsSc,4468
|
|
56
|
+
puzzle_solver/puzzles/numbermaze/numbermaze.py,sha256=xcr-fB7tjFVgWnZI4e0IBRmKLOdbf8XAOH_s7h-baY0,6095
|
|
57
|
+
puzzle_solver/puzzles/nurikabe/nurikabe.py,sha256=hX0VcjPwO8PfY2kiIpQV45FWIvKRosFebk588tp5wzk,6603
|
|
58
|
+
puzzle_solver/puzzles/palisade/palisade.py,sha256=rUYI39DOxKu_XSJ-Y_mdQGpGM-YLgKw_kjDWes97ncQ,4701
|
|
59
|
+
puzzle_solver/puzzles/pearl/pearl.py,sha256=slPVCzPObQLNk4EYqe55YR4JeRCUs07Mjdks1fWKZSY,6696
|
|
60
|
+
puzzle_solver/puzzles/pipes/pipes.py,sha256=2HDHCWhD-fLYTRoJsx15gOrsgt_SbjlGF2QDS5UX6m8,4680
|
|
61
|
+
puzzle_solver/puzzles/range/range.py,sha256=4qxueHR2A1tbtx1lgIzHBW7v-vtmydxr6k1KhX9VtB8,3060
|
|
62
|
+
puzzle_solver/puzzles/rectangles/rectangles.py,sha256=6MuJHyw7woIljlqxt76zfhw8F2_2biKMFM7oiXdXZsg,7010
|
|
63
|
+
puzzle_solver/puzzles/ripple_effect/ripple_effect.py,sha256=a-Va-nAoS81j6DMozg4vBtwrkyRVX7ybqK_ZYgbfU0U,4433
|
|
64
|
+
puzzle_solver/puzzles/rooms/rooms.py,sha256=VDOo-uqSW_y0ErpKPXSv-gcoftt30MF71D_e0YPCIaE,4297
|
|
65
|
+
puzzle_solver/puzzles/schurs_numbers/schurs_numbers.py,sha256=EXaHpRZVlUh8xCjRFAy38V1c-4dc3dLltwemBiNgtoQ,2836
|
|
66
|
+
puzzle_solver/puzzles/shakashaka/shakashaka.py,sha256=SyyNVmSAkoZ0Ca-dupl2r7zcsGgnwiCK0vRrmlTncaM,9572
|
|
67
|
+
puzzle_solver/puzzles/shingoki/shingoki.py,sha256=rhKRRUz1sCdIb3yflUAkmwXfCONYOB0AOmWKXs-NNn4,6893
|
|
68
|
+
puzzle_solver/puzzles/signpost/signpost.py,sha256=38LlMvP5Fx4qrTXmw4aNCt3yUbG3fhdSk6-YXmhAHFg,3861
|
|
69
|
+
puzzle_solver/puzzles/singles/singles.py,sha256=X9NygVPZG8WT03HzijlbbTwVsvcsk5H8tZHBjxRt5aU,2910
|
|
70
|
+
puzzle_solver/puzzles/slant/slant.py,sha256=l4q9g0BfqQsA6zsySiemJC5iFsqsO6LoqTUqcTEqYEk,5897
|
|
71
|
+
puzzle_solver/puzzles/slant/parse_map/parse_map.py,sha256=8thQxWbq0qjehKb2VzgUP22PGj-9n9djwbt3LGMVLJw,4811
|
|
72
|
+
puzzle_solver/puzzles/slitherlink/slitherlink.py,sha256=cDAM-aLHschlWVfzx6TDt_TGklRvsCazBlhn5ZrCRb8,7119
|
|
73
|
+
puzzle_solver/puzzles/snail/snail.py,sha256=KZq9gsGDhWwn8CsY1-kMjgc4lvycUEB4BLFe0qbVThs,4315
|
|
74
|
+
puzzle_solver/puzzles/split_ends/split_ends.py,sha256=SkWFmQSSKEYItpI1dpgPGKVoMLRJifQ3dMKMLDNQBc4,5667
|
|
75
|
+
puzzle_solver/puzzles/star_battle/star_battle.py,sha256=K0_iekluZlQs34jLb-KOYmL6ZsyVKjd5NInCwUXcXgs,3843
|
|
76
|
+
puzzle_solver/puzzles/star_battle/star_battle_shapeless.py,sha256=lj05V0Y3A3NjMo1boMkPIwBhMtm6SWydjgAMeCf5EIo,225
|
|
77
|
+
puzzle_solver/puzzles/stitches/stitches.py,sha256=wj9z9979FaVtp2hcVu3YDTGlxtwljoQNBgMMM5U3icc,6109
|
|
78
|
+
puzzle_solver/puzzles/stitches/parse_map/parse_map.py,sha256=6BWrW2U2jnBeremQP2zEZA3V2Gu4K3TeTha8cBCylXs,11655
|
|
79
|
+
puzzle_solver/puzzles/sudoku/sudoku.py,sha256=-vYpcoEuTcvvCyP9-yQTMmqVpljBTeu5mkHAXED9cRk,13272
|
|
80
|
+
puzzle_solver/puzzles/suguru/suguru.py,sha256=pK7_ogW6SaqimMiZcZ-V0JgITbEvPnaTE_KUKiPoP_o,3077
|
|
81
|
+
puzzle_solver/puzzles/suko/suko.py,sha256=22q0h5DO44tRjvy1HFbu_-msMf6D_JuxPtReZJjRQBY,3176
|
|
82
|
+
puzzle_solver/puzzles/tapa/tapa.py,sha256=UkOFhVoBn_Z3ssbdjpoTbTiEuKjrEJAROqd8CMQ9_-M,5319
|
|
83
|
+
puzzle_solver/puzzles/tatami/tatami.py,sha256=9AiIj3-8Hb6rlSdXyBTaQ9U5FvwN3NRLt3Z683Yb9HQ,3993
|
|
84
|
+
puzzle_solver/puzzles/tents/tents.py,sha256=RRNJ9uafrGyI_SYtNpw9CfbNlKeYfMA5K472w8mujf8,4941
|
|
85
|
+
puzzle_solver/puzzles/thermometers/thermometers.py,sha256=bGcVmpPeqL5AJtj8jkK8gYThzv9aGCd_QrWEiYBCA2s,4011
|
|
86
|
+
puzzle_solver/puzzles/towers/towers.py,sha256=t019GNQooeMC_XvuxRqZjoZUrPhHZP7WIEQTAl9NjwY,4733
|
|
87
|
+
puzzle_solver/puzzles/tracks/tracks.py,sha256=oJuMaF1oeh5moXl_TABFxpKBsDdwcGI9BvG3dm5J0NY,4903
|
|
88
|
+
puzzle_solver/puzzles/trees_logic/trees_logic.py,sha256=bHLH1OPncGmOTQzsRgk6lQFQgaTBrzrIA1AkKECPN24,2787
|
|
89
|
+
puzzle_solver/puzzles/troix/dumplings.py,sha256=75GuHf2QS50u9Y2MAvjxt_5_xoS0jkN0XvFslNOM7uc,189
|
|
90
|
+
puzzle_solver/puzzles/troix/troix.py,sha256=TdWSm4YOSaBY9ehp5mgxkO54HMlSfCQLV-FvBDIbaWA,4240
|
|
91
|
+
puzzle_solver/puzzles/twiddle/twiddle.py,sha256=3gPoeD0DoiiZbIhtptdXFldO_t1QShL6IxkDqJMzjkk,5446
|
|
92
|
+
puzzle_solver/puzzles/undead/undead.py,sha256=Gv6oPs2j2BLMN58FL96_V50ImWLmR_VPwF3owlPJEsY,5748
|
|
93
|
+
puzzle_solver/puzzles/unequal/unequal.py,sha256=ExY2XDCrqROCDpRLfHo8uVr1zuli1QvbCdNCiDhlCac,6978
|
|
94
|
+
puzzle_solver/puzzles/unruly/unruly.py,sha256=_C6FhYm9rqwhlQa6TMTxYr3rWcP_QS-E93xo86CZQjg,2846
|
|
95
|
+
puzzle_solver/puzzles/vectors/vectors.py,sha256=kq0dB7JbtJaisFYu2WEkzwNiT-n6luP-fdVC8w0bCZY,4825
|
|
96
|
+
puzzle_solver/puzzles/vermicelli/vermicelli.py,sha256=C95Fklf9UAuELXmlMUfeVxS13rUUxVAkrmtqsBpm-6M,3904
|
|
97
|
+
puzzle_solver/puzzles/walls/walls.py,sha256=JPV8uQg4zq6UsDzB0MhdB9SqP8kb5ANaiytkEMBGi1Q,3044
|
|
98
|
+
puzzle_solver/puzzles/yajilin/yajilin.py,sha256=2_0nZzrWAvmuYVZ9KRH7T-XTdZU7iuwQggp2M8MIHuA,5226
|
|
99
|
+
puzzle_solver/puzzles/yin_yang/yin_yang.py,sha256=D0JacUdK5yPrfScmGqX-p8144VbwxfDgIaqF8hwLXlM,5039
|
|
100
|
+
puzzle_solver/puzzles/yin_yang/parse_map/parse_map.py,sha256=drjfoHqmFf6U-ZQUwrBbfGINRxDQpgbvy4U3D9QyMhM,6617
|
|
101
|
+
puzzle_solver/utils/visualizer.py,sha256=T2g5We9J3tkhyXWoN2OrIDIJDjt6w5sDd2ksOub0ZI8,6819
|
|
102
|
+
puzzle_solver/utils/etc/parser/board_color_digit.py,sha256=EnF1Cs72DiNPYbTrLyNkE8OiiijGF59yC7vrai5Biho,15627
|
|
103
|
+
multi_puzzle_solver-1.1.8.dist-info/METADATA,sha256=0D7be2kfV2f1160j3WFWhjgzRcTCbv48bhjK2NvAog8,326933
|
|
104
|
+
multi_puzzle_solver-1.1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
105
|
+
multi_puzzle_solver-1.1.8.dist-info/top_level.txt,sha256=exwVUQa-anK9vYrpKzBPvH8bX43iElWI4VeNiAyBGJY,14
|
|
106
|
+
multi_puzzle_solver-1.1.8.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
puzzle_solver
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
from puzzle_solver.puzzles.abc_view import abc_view as abc_view_solver
|
|
2
|
+
from puzzle_solver.puzzles.aquarium import aquarium as aquarium_solver
|
|
3
|
+
from puzzle_solver.puzzles.area_51 import area_51 as area_51_solver
|
|
4
|
+
from puzzle_solver.puzzles.battleships import battleships as battleships_solver
|
|
5
|
+
from puzzle_solver.puzzles.binairo import binairo as binairo_solver
|
|
6
|
+
from puzzle_solver.puzzles.binairo import binairo_plus as binairo_plus_solver
|
|
7
|
+
from puzzle_solver.puzzles.black_box import black_box as black_box_solver
|
|
8
|
+
from puzzle_solver.puzzles.branches import branches as branches_solver
|
|
9
|
+
from puzzle_solver.puzzles.bridges import bridges as bridges_solver
|
|
10
|
+
from puzzle_solver.puzzles.chess_range import chess_range as chess_range_solver
|
|
11
|
+
from puzzle_solver.puzzles.chess_range import chess_solo as chess_solo_solver
|
|
12
|
+
from puzzle_solver.puzzles.chess_range import chess_melee as chess_melee_solver
|
|
13
|
+
from puzzle_solver.puzzles.circle_9 import circle_9 as circle_9_solver
|
|
14
|
+
from puzzle_solver.puzzles.clouds import clouds as clouds_solver
|
|
15
|
+
from puzzle_solver.puzzles.connect_the_dots import connect_the_dots as connect_the_dots_solver
|
|
16
|
+
from puzzle_solver.puzzles.cow_and_cactus import cow_and_cactus as cow_and_cactus_solver
|
|
17
|
+
from puzzle_solver.puzzles.dominosa import dominosa as dominosa_solver
|
|
18
|
+
from puzzle_solver.puzzles.troix import dumplings as dumplings_solver
|
|
19
|
+
from puzzle_solver.puzzles.filling import filling as filling_solver
|
|
20
|
+
from puzzle_solver.puzzles.flood_it import flood_it as flood_it_solver
|
|
21
|
+
from puzzle_solver.puzzles.flip import flip as flip_solver
|
|
22
|
+
from puzzle_solver.puzzles.galaxies import galaxies as galaxies_solver
|
|
23
|
+
from puzzle_solver.puzzles.guess import guess as guess_solver
|
|
24
|
+
from puzzle_solver.puzzles.heyawake import heyawake as heyawake_solver
|
|
25
|
+
from puzzle_solver.puzzles.hidden_stars import hidden_stars as hidden_stars_solver
|
|
26
|
+
from puzzle_solver.puzzles.hidoku import hidoku as hidoku_solver
|
|
27
|
+
from puzzle_solver.puzzles.inertia import inertia as inertia_solver
|
|
28
|
+
from puzzle_solver.puzzles.kakurasu import kakurasu as kakurasu_solver
|
|
29
|
+
from puzzle_solver.puzzles.kakuro import kakuro as kakuro_solver
|
|
30
|
+
from puzzle_solver.puzzles.keen import keen as keen_solver
|
|
31
|
+
from puzzle_solver.puzzles.kropki import kropki as kropki_solver
|
|
32
|
+
from puzzle_solver.puzzles.kakuro import krypto_kakuro as krypto_kakuro_solver
|
|
33
|
+
from puzzle_solver.puzzles.light_up import light_up as light_up_solver
|
|
34
|
+
from puzzle_solver.puzzles.linesweeper import linesweeper as linesweeper_solver
|
|
35
|
+
from puzzle_solver.puzzles.link_a_pix import link_a_pix as link_a_pix_solver
|
|
36
|
+
from puzzle_solver.puzzles.magnets import magnets as magnets_solver
|
|
37
|
+
from puzzle_solver.puzzles.map import map as map_solver
|
|
38
|
+
from puzzle_solver.puzzles.mathema_grids import mathema_grids as mathema_grids_solver
|
|
39
|
+
from puzzle_solver.puzzles.mathrax import mathrax as mathrax_solver
|
|
40
|
+
from puzzle_solver.puzzles.minesweeper import minesweeper as minesweeper_solver
|
|
41
|
+
from puzzle_solver.puzzles.mosaic import mosaic as mosaic_solver
|
|
42
|
+
from puzzle_solver.puzzles.n_queens import n_queens as n_queens_solver
|
|
43
|
+
from puzzle_solver.puzzles.nonograms import nonograms as nonograms_solver
|
|
44
|
+
from puzzle_solver.puzzles.nonograms import nonograms_colored as nonograms_colored_solver
|
|
45
|
+
from puzzle_solver.puzzles.norinori import norinori as norinori_solver
|
|
46
|
+
from puzzle_solver.puzzles.number_path import number_path as number_path_solver
|
|
47
|
+
from puzzle_solver.puzzles.numbermaze import numbermaze as numbermaze_solver
|
|
48
|
+
from puzzle_solver.puzzles.nurikabe import nurikabe as nurikabe_solver
|
|
49
|
+
from puzzle_solver.puzzles.palisade import palisade as palisade_solver
|
|
50
|
+
from puzzle_solver.puzzles.lits import lits as lits_solver
|
|
51
|
+
from puzzle_solver.puzzles.pearl import pearl as pearl_solver
|
|
52
|
+
from puzzle_solver.puzzles.pipes import pipes as pipes_solver
|
|
53
|
+
from puzzle_solver.puzzles.range import range as range_solver
|
|
54
|
+
from puzzle_solver.puzzles.rectangles import rectangles as rectangles_solver
|
|
55
|
+
from puzzle_solver.puzzles.ripple_effect import ripple_effect as ripple_effect_solver
|
|
56
|
+
from puzzle_solver.puzzles.rooms import rooms as rooms_solver
|
|
57
|
+
from puzzle_solver.puzzles.schurs_numbers import schurs_numbers as schurs_numbers_solver
|
|
58
|
+
from puzzle_solver.puzzles.shakashaka import shakashaka as shakashaka_solver
|
|
59
|
+
from puzzle_solver.puzzles.shingoki import shingoki as shingoki_solver
|
|
60
|
+
from puzzle_solver.puzzles.signpost import signpost as signpost_solver
|
|
61
|
+
from puzzle_solver.puzzles.singles import singles as singles_solver
|
|
62
|
+
from puzzle_solver.puzzles.slant import slant as slant_solver
|
|
63
|
+
from puzzle_solver.puzzles.slitherlink import slitherlink as slitherlink_solver
|
|
64
|
+
from puzzle_solver.puzzles.snail import snail as snail_solver
|
|
65
|
+
from puzzle_solver.puzzles.split_ends import split_ends as split_ends_solver
|
|
66
|
+
from puzzle_solver.puzzles.star_battle import star_battle as star_battle_solver
|
|
67
|
+
from puzzle_solver.puzzles.star_battle import star_battle_shapeless as star_battle_shapeless_solver
|
|
68
|
+
from puzzle_solver.puzzles.stitches import stitches as stitches_solver
|
|
69
|
+
from puzzle_solver.puzzles.sudoku import sudoku as sudoku_solver
|
|
70
|
+
from puzzle_solver.puzzles.suguru import suguru as suguru_solver
|
|
71
|
+
from puzzle_solver.puzzles.suko import suko as suko_solver
|
|
72
|
+
from puzzle_solver.puzzles.tapa import tapa as tapa_solver
|
|
73
|
+
from puzzle_solver.puzzles.tatami import tatami as tatami_solver
|
|
74
|
+
from puzzle_solver.puzzles.tents import tents as tents_solver
|
|
75
|
+
from puzzle_solver.puzzles.thermometers import thermometers as thermometers_solver
|
|
76
|
+
from puzzle_solver.puzzles.towers import towers as towers_solver
|
|
77
|
+
from puzzle_solver.puzzles.tracks import tracks as tracks_solver
|
|
78
|
+
from puzzle_solver.puzzles.trees_logic import trees_logic as trees_logic_solver
|
|
79
|
+
from puzzle_solver.puzzles.troix import troix as troix_solver
|
|
80
|
+
from puzzle_solver.puzzles.twiddle import twiddle as twiddle_solver
|
|
81
|
+
from puzzle_solver.puzzles.undead import undead as undead_solver
|
|
82
|
+
from puzzle_solver.puzzles.unequal import unequal as unequal_solver
|
|
83
|
+
from puzzle_solver.puzzles.unruly import unruly as unruly_solver
|
|
84
|
+
from puzzle_solver.puzzles.vectors import vectors as vectors_solver
|
|
85
|
+
from puzzle_solver.puzzles.vermicelli import vermicelli as vermicelli_solver
|
|
86
|
+
from puzzle_solver.puzzles.walls import walls as walls_solver
|
|
87
|
+
from puzzle_solver.puzzles.yajilin import yajilin as yajilin_solver
|
|
88
|
+
from puzzle_solver.puzzles.yin_yang import yin_yang as yin_yang_solver
|
|
89
|
+
|
|
90
|
+
from puzzle_solver.puzzles.inertia.parse_map.parse_map import main as inertia_image_parser
|
|
91
|
+
|
|
92
|
+
__all__ = [
|
|
93
|
+
abc_view_solver,
|
|
94
|
+
aquarium_solver,
|
|
95
|
+
area_51_solver,
|
|
96
|
+
battleships_solver,
|
|
97
|
+
binairo_solver,
|
|
98
|
+
binairo_plus_solver,
|
|
99
|
+
black_box_solver,
|
|
100
|
+
branches_solver,
|
|
101
|
+
bridges_solver,
|
|
102
|
+
chess_range_solver,
|
|
103
|
+
chess_solo_solver,
|
|
104
|
+
chess_melee_solver,
|
|
105
|
+
circle_9_solver,
|
|
106
|
+
clouds_solver,
|
|
107
|
+
connect_the_dots_solver,
|
|
108
|
+
cow_and_cactus_solver,
|
|
109
|
+
dominosa_solver,
|
|
110
|
+
dumplings_solver,
|
|
111
|
+
filling_solver,
|
|
112
|
+
flood_it_solver,
|
|
113
|
+
flip_solver,
|
|
114
|
+
galaxies_solver,
|
|
115
|
+
guess_solver,
|
|
116
|
+
heyawake_solver,
|
|
117
|
+
hidden_stars_solver,
|
|
118
|
+
hidoku_solver,
|
|
119
|
+
inertia_solver,
|
|
120
|
+
kakurasu_solver,
|
|
121
|
+
kakuro_solver,
|
|
122
|
+
keen_solver,
|
|
123
|
+
kropki_solver,
|
|
124
|
+
krypto_kakuro_solver,
|
|
125
|
+
light_up_solver,
|
|
126
|
+
linesweeper_solver,
|
|
127
|
+
link_a_pix_solver,
|
|
128
|
+
magnets_solver,
|
|
129
|
+
map_solver,
|
|
130
|
+
mathema_grids_solver,
|
|
131
|
+
mathrax_solver,
|
|
132
|
+
minesweeper_solver,
|
|
133
|
+
mosaic_solver,
|
|
134
|
+
n_queens_solver,
|
|
135
|
+
nonograms_solver,
|
|
136
|
+
norinori_solver,
|
|
137
|
+
number_path_solver,
|
|
138
|
+
numbermaze_solver,
|
|
139
|
+
nonograms_colored_solver,
|
|
140
|
+
nurikabe_solver,
|
|
141
|
+
palisade_solver,
|
|
142
|
+
lits_solver,
|
|
143
|
+
pearl_solver,
|
|
144
|
+
pipes_solver,
|
|
145
|
+
range_solver,
|
|
146
|
+
rectangles_solver,
|
|
147
|
+
ripple_effect_solver,
|
|
148
|
+
rooms_solver,
|
|
149
|
+
schurs_numbers_solver,
|
|
150
|
+
shakashaka_solver,
|
|
151
|
+
shingoki_solver,
|
|
152
|
+
signpost_solver,
|
|
153
|
+
singles_solver,
|
|
154
|
+
slant_solver,
|
|
155
|
+
slitherlink_solver,
|
|
156
|
+
snail_solver,
|
|
157
|
+
split_ends_solver,
|
|
158
|
+
star_battle_solver,
|
|
159
|
+
star_battle_shapeless_solver,
|
|
160
|
+
stitches_solver,
|
|
161
|
+
sudoku_solver,
|
|
162
|
+
suguru_solver,
|
|
163
|
+
suko_solver,
|
|
164
|
+
tapa_solver,
|
|
165
|
+
tatami_solver,
|
|
166
|
+
tents_solver,
|
|
167
|
+
thermometers_solver,
|
|
168
|
+
towers_solver,
|
|
169
|
+
tracks_solver,
|
|
170
|
+
trees_logic_solver,
|
|
171
|
+
troix_solver,
|
|
172
|
+
twiddle_solver,
|
|
173
|
+
undead_solver,
|
|
174
|
+
unequal_solver,
|
|
175
|
+
unruly_solver,
|
|
176
|
+
vectors_solver,
|
|
177
|
+
vermicelli_solver,
|
|
178
|
+
walls_solver,
|
|
179
|
+
yajilin_solver,
|
|
180
|
+
yin_yang_solver,
|
|
181
|
+
inertia_image_parser,
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
__version__ = '1.1.8'
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Tuple, Iterable, Union
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Direction(Enum):
|
|
9
|
+
UP = 1
|
|
10
|
+
DOWN = 2
|
|
11
|
+
LEFT = 3
|
|
12
|
+
RIGHT = 4
|
|
13
|
+
|
|
14
|
+
class Direction8(Enum):
|
|
15
|
+
UP = 1
|
|
16
|
+
DOWN = 2
|
|
17
|
+
LEFT = 3
|
|
18
|
+
RIGHT = 4
|
|
19
|
+
UP_LEFT = 5
|
|
20
|
+
UP_RIGHT = 6
|
|
21
|
+
DOWN_LEFT = 7
|
|
22
|
+
DOWN_RIGHT = 8
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True, order=True)
|
|
25
|
+
class Pos:
|
|
26
|
+
x: int
|
|
27
|
+
y: int
|
|
28
|
+
|
|
29
|
+
def __add__(self, other: 'Pos') -> 'Pos':
|
|
30
|
+
return get_pos(self.x + other.x, self.y + other.y)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
Shape = frozenset[Pos] # a shape on the 2d board is just a set of positions
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_pos(x: int, y: int) -> Pos:
|
|
37
|
+
return Pos(x=x, y=y)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_next_pos(cur_pos: Pos, direction: Union[Direction, Direction8]) -> Pos:
|
|
41
|
+
delta_x, delta_y = get_deltas(direction)
|
|
42
|
+
return get_pos(cur_pos.x+delta_x, cur_pos.y+delta_y)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def get_ray(pos: Pos, direction: Union[Direction, Direction8], V: int, H: int, include_self: bool = False) -> list[Pos]:
|
|
46
|
+
out = []
|
|
47
|
+
if include_self:
|
|
48
|
+
out.append(pos)
|
|
49
|
+
while True:
|
|
50
|
+
pos = get_next_pos(pos, direction)
|
|
51
|
+
if not in_bounds(pos, V, H):
|
|
52
|
+
break
|
|
53
|
+
out.append(pos)
|
|
54
|
+
return out
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_neighbors4(pos: Pos, V: int, H: int, include_self: bool = False) -> Iterable[Pos]:
|
|
58
|
+
if include_self:
|
|
59
|
+
yield pos
|
|
60
|
+
for dx, dy in ((1,0),(-1,0),(0,1),(0,-1)):
|
|
61
|
+
p2 = get_pos(x=pos.x+dx, y=pos.y+dy)
|
|
62
|
+
if in_bounds(p2, V, H):
|
|
63
|
+
yield p2
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def get_neighbors8(pos: Pos, V: int, H: int, include_self: bool = False) -> Iterable[Pos]:
|
|
67
|
+
for dx in [-1, 0, 1]:
|
|
68
|
+
for dy in [-1, 0, 1]:
|
|
69
|
+
if not include_self and (dx, dy) == (0, 0):
|
|
70
|
+
continue
|
|
71
|
+
d_pos = get_pos(x=pos.x+dx, y=pos.y+dy)
|
|
72
|
+
if in_bounds(d_pos, V, H):
|
|
73
|
+
yield d_pos
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def get_row_pos(row_idx: int, H: int) -> Iterable[Pos]:
|
|
77
|
+
for x in range(H):
|
|
78
|
+
yield get_pos(x=x, y=row_idx)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def get_col_pos(col_idx: int, V: int) -> Iterable[Pos]:
|
|
82
|
+
for y in range(V):
|
|
83
|
+
yield get_pos(x=col_idx, y=y)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def get_all_pos(V: int, H: int) -> Iterable[Pos]:
|
|
87
|
+
for y in range(V):
|
|
88
|
+
for x in range(H):
|
|
89
|
+
yield get_pos(x=x, y=y)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def get_all_pos_to_idx_dict(V: int, H: int) -> dict[Pos, int]:
|
|
93
|
+
return {get_pos(x=x, y=y): y*H+x for y in range(V) for x in range(H)}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def get_char(board: np.array, pos: Pos) -> str:
|
|
97
|
+
return board[pos.y][pos.x]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def set_char(board: np.array, pos: Pos, char: str):
|
|
101
|
+
board[pos.y][pos.x] = char
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def in_bounds(pos: Pos, V: int, H: int) -> bool:
|
|
105
|
+
return 0 <= pos.y < V and 0 <= pos.x < H
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def get_opposite_direction(direction: Union[Direction, Direction8]) -> Union[Direction, Direction8]:
|
|
109
|
+
if direction == Direction.RIGHT:
|
|
110
|
+
return Direction.LEFT
|
|
111
|
+
elif direction == Direction.LEFT:
|
|
112
|
+
return Direction.RIGHT
|
|
113
|
+
elif direction == Direction.DOWN:
|
|
114
|
+
return Direction.UP
|
|
115
|
+
elif direction == Direction.UP:
|
|
116
|
+
return Direction.DOWN
|
|
117
|
+
elif direction == Direction8.RIGHT:
|
|
118
|
+
return Direction8.LEFT
|
|
119
|
+
elif direction == Direction8.LEFT:
|
|
120
|
+
return Direction8.RIGHT
|
|
121
|
+
elif direction == Direction8.DOWN:
|
|
122
|
+
return Direction8.UP
|
|
123
|
+
elif direction == Direction8.UP:
|
|
124
|
+
return Direction8.DOWN
|
|
125
|
+
elif direction == Direction8.UP_LEFT:
|
|
126
|
+
return Direction8.DOWN_RIGHT
|
|
127
|
+
elif direction == Direction8.UP_RIGHT:
|
|
128
|
+
return Direction8.DOWN_LEFT
|
|
129
|
+
elif direction == Direction8.DOWN_LEFT:
|
|
130
|
+
return Direction8.UP_RIGHT
|
|
131
|
+
elif direction == Direction8.DOWN_RIGHT:
|
|
132
|
+
return Direction8.UP_LEFT
|
|
133
|
+
else:
|
|
134
|
+
raise ValueError(f'invalid direction: {direction}')
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def get_deltas(direction: Union[Direction, Direction8]) -> Tuple[int, int]:
|
|
138
|
+
if direction == Direction.RIGHT or direction == Direction8.RIGHT:
|
|
139
|
+
return +1, 0
|
|
140
|
+
elif direction == Direction.LEFT or direction == Direction8.LEFT:
|
|
141
|
+
return -1, 0
|
|
142
|
+
elif direction == Direction.DOWN or direction == Direction8.DOWN:
|
|
143
|
+
return 0, +1
|
|
144
|
+
elif direction == Direction.UP or direction == Direction8.UP:
|
|
145
|
+
return 0, -1
|
|
146
|
+
elif direction == Direction8.UP_LEFT:
|
|
147
|
+
return -1, -1
|
|
148
|
+
elif direction == Direction8.UP_RIGHT:
|
|
149
|
+
return +1, -1
|
|
150
|
+
elif direction == Direction8.DOWN_LEFT:
|
|
151
|
+
return -1, +1
|
|
152
|
+
elif direction == Direction8.DOWN_RIGHT:
|
|
153
|
+
return +1, +1
|
|
154
|
+
else:
|
|
155
|
+
raise ValueError(f'invalid direction: {direction}')
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def polyominoes(N) -> set[Shape]:
|
|
159
|
+
"""Generate all polyominoes of size N. Every rotation and reflection is considered different and included in the result.
|
|
160
|
+
Translation is not considered different and is removed from the result (otherwise the result would be infinite).
|
|
161
|
+
|
|
162
|
+
Below is the number of unique polyominoes of size N (not including rotations and reflections) and the lenth of the returned result (which includes all rotations and reflections)
|
|
163
|
+
N name #shapes #results
|
|
164
|
+
1 monomino 1 1
|
|
165
|
+
2 domino 1 2
|
|
166
|
+
3 tromino 2 6
|
|
167
|
+
4 tetromino 5 19
|
|
168
|
+
5 pentomino 12 63
|
|
169
|
+
6 hexomino 35 216
|
|
170
|
+
7 heptomino 108 760
|
|
171
|
+
8 octomino 369 2,725
|
|
172
|
+
9 nonomino 1,285 9,910
|
|
173
|
+
10 decomino 4,655 36,446
|
|
174
|
+
11 undecomino 17,073 135,268
|
|
175
|
+
12 dodecomino 63,600 505,861
|
|
176
|
+
Source: https://en.wikipedia.org/wiki/Polyomino
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
N (int): The size of the polyominoes to generate.
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
set[(frozenset[Pos], int)]: A set of all polyominoes of size N (rotated and reflected up to D4 symmetry).
|
|
183
|
+
"""
|
|
184
|
+
assert N >= 1, 'N cannot be less than 1'
|
|
185
|
+
# need a frozenset because regular sets are not hashable
|
|
186
|
+
FastShape = frozenset[Tuple[int, int]]
|
|
187
|
+
shapes: set[FastShape] = {frozenset({(0, 0)})}
|
|
188
|
+
for i in range(1, N):
|
|
189
|
+
next_shapes: set[FastShape] = set()
|
|
190
|
+
directions = ((1,0),(-1,0),(0,1),(0,-1)) if i > 1 else (((1,0),(0,1))) # cannot take left on first step, if confused read: https://louridas.github.io/rwa/assignments/polyominoes/
|
|
191
|
+
for s in shapes:
|
|
192
|
+
# frontier of a single shape: all 4-neighbors of existing cells not already in the shape
|
|
193
|
+
frontier = set()
|
|
194
|
+
for x, y in s:
|
|
195
|
+
# only need to consider 3 directions and neighbors condition is (n.y > 0 or (n.y == 0 and n.x >= 0)) it's obvious if you plot it
|
|
196
|
+
# if confused read: https://louridas.github.io/rwa/assignments/polyominoes/
|
|
197
|
+
for dx, dy in directions:
|
|
198
|
+
n = (x + dx, y + dy)
|
|
199
|
+
if n not in s and (n[1] > 0 or (n[1] == 0 and n[0] >= 0)):
|
|
200
|
+
frontier.add(n)
|
|
201
|
+
for cell in frontier:
|
|
202
|
+
t = s | {cell}
|
|
203
|
+
# normalize by translation only: shift so min x,y is (0,0). This removes translational symmetries.
|
|
204
|
+
minx = min(x for x, y in t)
|
|
205
|
+
miny = min(y for x, y in t)
|
|
206
|
+
t0 = frozenset((x - minx, y - miny) for x, y in t)
|
|
207
|
+
next_shapes.add(t0)
|
|
208
|
+
shapes = next_shapes
|
|
209
|
+
# shapes is now complete, now classify up to D4 symmetry (rotations/reflections), translations ignored
|
|
210
|
+
shapes = {frozenset(Pos(x, y) for x, y in s) for s in shapes} # regular class, not the dirty-fast one
|
|
211
|
+
return shapes
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def polyominoes_with_shape_id(N):
|
|
215
|
+
"""Refer to polyominoes() for more details. This function returns a set of all polyominoes of size N (rotated and reflected up to D4 symmetry) along with a unique ID for each polyomino that is unique up to D4 symmetry.
|
|
216
|
+
Args:
|
|
217
|
+
N (int): The size of the polyominoes to generate.
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
set[(frozenset[Pos], int)]: A set of all polyominoes of size N (rotated and reflected up to D4 symmetry) along with a unique ID for each polyomino that is unique up to D4 symmetry.
|
|
221
|
+
"""
|
|
222
|
+
FastPos = Tuple[int, int]
|
|
223
|
+
FastShape = frozenset[Tuple[int, int]]
|
|
224
|
+
shapes = polyominoes(N)
|
|
225
|
+
shapes = {frozenset((p.x, p.y) for p in s) for s in shapes}
|
|
226
|
+
mats = (
|
|
227
|
+
( 1, 0, 0, 1), # regular
|
|
228
|
+
(-1, 0, 0, 1), # reflect about x
|
|
229
|
+
( 1, 0, 0,-1), # reflect about y
|
|
230
|
+
(-1, 0, 0,-1), # reflect about x and y
|
|
231
|
+
# trnaspose then all 4 above
|
|
232
|
+
( 0, 1, 1, 0), ( 0, 1, -1, 0), ( 0,-1, 1, 0), ( 0,-1, -1, 0),
|
|
233
|
+
)
|
|
234
|
+
# compute canonical representative for each shape (lexicographically smallest normalized transform)
|
|
235
|
+
shape_to_canon: dict[FastShape, tuple[FastPos, ...]] = {}
|
|
236
|
+
for s in shapes:
|
|
237
|
+
reps: list[tuple[FastPos, ...]] = []
|
|
238
|
+
for a, b, c, d in mats:
|
|
239
|
+
pts = {(a*x + b*y, c*x + d*y) for x, y in s}
|
|
240
|
+
minx = min(x for x, y in pts)
|
|
241
|
+
miny = min(y for x, y in pts)
|
|
242
|
+
rep = tuple(sorted((x - minx, y - miny) for x, y in pts))
|
|
243
|
+
reps.append(rep)
|
|
244
|
+
canon = min(reps)
|
|
245
|
+
shape_to_canon[s] = canon
|
|
246
|
+
|
|
247
|
+
canon_set = set(shape_to_canon.values())
|
|
248
|
+
canon_to_id = {canon: i for i, canon in enumerate(sorted(canon_set))}
|
|
249
|
+
result = {(s, canon_to_id[shape_to_canon[s]]) for s in shapes}
|
|
250
|
+
result = {(frozenset(Pos(x, y) for x, y in s), _id) for s, _id in result}
|
|
251
|
+
return result
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def shapes_between(A_pos: Pos, B_pos: Pos, N: int) -> set[Shape]:
|
|
255
|
+
"""Return all shapes of size N where it is possible to draw a path from A to B covering all cells in the shape."""
|
|
256
|
+
def manhattan(p: tuple[int, int], q: tuple[int, int]) -> int:
|
|
257
|
+
return abs(p[0] - q[0]) + abs(p[1] - q[1])
|
|
258
|
+
def is_possible(p: tuple[int, int], q: tuple[int, int], steps_needed: int) -> bool:
|
|
259
|
+
"""Returns whether it's possible to reach q from p in exactly steps_needed steps. Looks at manhattan distance and parity."""
|
|
260
|
+
dist = manhattan(p, q)
|
|
261
|
+
return dist <= steps_needed and (steps_needed - dist) % 2 == 0 # the %2 checks parity (i.e. when its false every possible path will overshoot or undershoot B by 1)
|
|
262
|
+
|
|
263
|
+
A, B = (A_pos.x, A_pos.y), (B_pos.x, B_pos.y)
|
|
264
|
+
ax, ay = A
|
|
265
|
+
bx, by = B
|
|
266
|
+
min_steps_needed = N - 1
|
|
267
|
+
# how far we're allowed to wander away from the A-B box
|
|
268
|
+
slack = (min_steps_needed - manhattan(A, B)) // 2
|
|
269
|
+
x_min = min(ax, bx) - slack
|
|
270
|
+
x_max = max(ax, bx) + slack
|
|
271
|
+
y_min = min(ay, by) - slack
|
|
272
|
+
y_max = max(ay, by) + slack
|
|
273
|
+
results: set[Shape] = set()
|
|
274
|
+
path: list[tuple[int, int]] = [A]
|
|
275
|
+
visited = {A}
|
|
276
|
+
|
|
277
|
+
def dfs(curr: tuple[int, int], cells_used: int):
|
|
278
|
+
moves_left = N - cells_used
|
|
279
|
+
if not is_possible(curr, B, moves_left):
|
|
280
|
+
return
|
|
281
|
+
if curr == B:
|
|
282
|
+
if cells_used == N: # we've reached B and have exactly N cells, this is a wanted shape!
|
|
283
|
+
results.add(frozenset(get_pos(x=x, y=y) for x, y in path))
|
|
284
|
+
return
|
|
285
|
+
x, y = curr
|
|
286
|
+
for nx, ny in ((x+1, y), (x-1, y), (x, y+1), (x, y-1)):
|
|
287
|
+
if not (x_min <= nx <= x_max and y_min <= ny <= y_max):
|
|
288
|
+
continue
|
|
289
|
+
nxt = (nx, ny)
|
|
290
|
+
if nxt in visited:
|
|
291
|
+
continue
|
|
292
|
+
visited.add(nxt)
|
|
293
|
+
path.append(nxt)
|
|
294
|
+
dfs(nxt, cells_used + 1)
|
|
295
|
+
path.pop()
|
|
296
|
+
visited.remove(nxt)
|
|
297
|
+
dfs(A, 1)
|
|
298
|
+
return results
|