multi-puzzle-solver 0.9.15__tar.gz → 0.9.20__tar.gz

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.

Potentially problematic release.


This version of multi-puzzle-solver might be problematic. Click here for more details.

Files changed (95) hide show
  1. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/PKG-INFO +509 -11
  2. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/README.md +508 -10
  3. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/multi_puzzle_solver.egg-info/PKG-INFO +509 -11
  4. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/multi_puzzle_solver.egg-info/SOURCES.txt +9 -0
  5. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/__init__.py +5 -1
  6. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/core/utils_ortools.py +21 -17
  7. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/galaxies/galaxies.py +2 -2
  8. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/galaxies/parse_map/parse_map.py +1 -1
  9. multi_puzzle_solver-0.9.20/src/puzzle_solver/puzzles/norinori/norinori.py +101 -0
  10. multi_puzzle_solver-0.9.20/src/puzzle_solver/puzzles/slant/parse_map/parse_map.py +133 -0
  11. multi_puzzle_solver-0.9.20/src/puzzle_solver/puzzles/slant/slant.py +117 -0
  12. multi_puzzle_solver-0.9.20/src/puzzle_solver/puzzles/slitherlink/slitherlink.py +248 -0
  13. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/stitches/parse_map/parse_map.py +37 -4
  14. multi_puzzle_solver-0.9.20/src/puzzle_solver/puzzles/unequal/unequal.py +128 -0
  15. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_galaxies.py +2 -7
  16. multi_puzzle_solver-0.9.20/tests/test_norinori.py +204 -0
  17. multi_puzzle_solver-0.9.20/tests/test_slant.py +141 -0
  18. multi_puzzle_solver-0.9.20/tests/test_slitherlink.py +68 -0
  19. multi_puzzle_solver-0.9.20/tests/test_unequal.py +137 -0
  20. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/pyproject.toml +0 -0
  21. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/setup.cfg +0 -0
  22. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/multi_puzzle_solver.egg-info/dependency_links.txt +0 -0
  23. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/multi_puzzle_solver.egg-info/requires.txt +0 -0
  24. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/multi_puzzle_solver.egg-info/top_level.txt +0 -0
  25. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/core/utils.py +0 -0
  26. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/aquarium/aquarium.py +0 -0
  27. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/battleships/battleships.py +0 -0
  28. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/black_box/black_box.py +0 -0
  29. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/bridges/bridges.py +0 -0
  30. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/chess_range/chess_melee.py +0 -0
  31. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/chess_range/chess_range.py +0 -0
  32. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/chess_range/chess_solo.py +0 -0
  33. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/dominosa/dominosa.py +0 -0
  34. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/filling/filling.py +0 -0
  35. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/guess/guess.py +0 -0
  36. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/inertia/inertia.py +0 -0
  37. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/inertia/parse_map/parse_map.py +0 -0
  38. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/inertia/tsp.py +0 -0
  39. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/kakurasu/kakurasu.py +0 -0
  40. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/keen/keen.py +0 -0
  41. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/light_up/light_up.py +0 -0
  42. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/lits/lits.py +0 -0
  43. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/magnets/magnets.py +0 -0
  44. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/map/map.py +0 -0
  45. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/minesweeper/minesweeper.py +0 -0
  46. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/mosaic/mosaic.py +0 -0
  47. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/nonograms/nonograms.py +0 -0
  48. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/pearl/pearl.py +0 -0
  49. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/range/range.py +0 -0
  50. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/signpost/signpost.py +0 -0
  51. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/singles/singles.py +0 -0
  52. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/star_battle/star_battle.py +0 -0
  53. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/star_battle/star_battle_shapeless.py +0 -0
  54. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/stitches/stitches.py +0 -0
  55. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/sudoku/sudoku.py +0 -0
  56. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/tents/tents.py +0 -0
  57. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/thermometers/thermometers.py +0 -0
  58. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/towers/towers.py +0 -0
  59. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/tracks/tracks.py +0 -0
  60. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/undead/undead.py +0 -0
  61. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/puzzles/unruly/unruly.py +0 -0
  62. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/src/puzzle_solver/utils/visualizer.py +0 -0
  63. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_aquarium.py +0 -0
  64. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_battleships.py +0 -0
  65. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_black_box.py +0 -0
  66. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_bridges.py +0 -0
  67. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_chess_melee.py +0 -0
  68. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_chess_range.py +0 -0
  69. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_chess_solo.py +0 -0
  70. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_dominosa.py +0 -0
  71. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_filling.py +0 -0
  72. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_guess.py +0 -0
  73. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_inertia.py +0 -0
  74. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_kakurasu.py +0 -0
  75. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_keen.py +0 -0
  76. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_light_up.py +0 -0
  77. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_lits.py +0 -0
  78. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_magnets.py +0 -0
  79. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_map.py +0 -0
  80. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_minesweeper.py +0 -0
  81. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_mosaic.py +0 -0
  82. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_nonograms.py +0 -0
  83. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_pearl.py +0 -0
  84. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_range.py +0 -0
  85. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_signpost.py +0 -0
  86. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_singles.py +0 -0
  87. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_star_battle.py +0 -0
  88. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_stitches.py +0 -0
  89. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_sudoku.py +0 -0
  90. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_tents.py +0 -0
  91. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_thermometers.py +0 -0
  92. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_towers.py +0 -0
  93. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_tracks.py +0 -0
  94. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_undead.py +0 -0
  95. {multi_puzzle_solver-0.9.15 → multi_puzzle_solver-0.9.20}/tests/test_unruly.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multi-puzzle-solver
3
- Version: 0.9.15
3
+ Version: 0.9.20
4
4
  Summary: Efficient solvers for numerous popular and esoteric logic puzzles using CP-SAT
5
5
  Author: Ar-Kareem
6
6
  Project-URL: Homepage, https://github.com/Ar-Kareem/puzzle_solver
@@ -39,22 +39,35 @@ pip install multi-puzzle-solver
39
39
  Use:
40
40
 
41
41
  ```python
42
- from puzzle_solver import nonograms_solver
43
- solver = nonograms_solver.Board(top=[[2], [3], [1], [1, 1]], side=[[3], [1], [2, 1], [1]])
44
- solutions = solver.solve_and_print()
42
+ from puzzle_solver import nonograms_solver as solver
43
+ top_numbers = [[8, 2], [5, 4], [2, 1, 4], [2, 4], [2, 1, 4], [2, 5], [2, 8], [3, 2], [1, 6], [1, 9], [1, 6, 1], [1, 5, 3], [3, 2, 1], [4, 2], [1, 5]]
44
+ side_numbers = [[7, 3], [7, 1, 1], [2, 3], [2, 3], [3, 2], [1, 1, 1, 1, 2], [1, 6, 1], [1, 9], [9], [2, 4], [8], [11], [7, 1, 1], [4, 3], [3, 2]]
45
+ binst = solver.Board(top=top_numbers, side=side_numbers)
46
+ solutions = binst.solve_and_print()
45
47
  ```
46
48
 
47
49
  Output:
48
50
 
49
51
  ```python
50
52
  Solution found
51
- [[' ' 'B' 'B' 'B']
52
- [' ' 'B' ' ' ' ']
53
- ['B' 'B' ' ' 'B']
54
- ['B' ' ' ' ' ' ']]
53
+ [['B' 'B' 'B' 'B' 'B' 'B' 'B' ' ' 'B' 'B' 'B' ' ' ' ' ' ' ' ']
54
+ ['B' 'B' 'B' 'B' 'B' 'B' 'B' ' ' ' ' ' ' ' ' ' ' 'B' ' ' 'B']
55
+ ['B' 'B' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' 'B' 'B' 'B' ' ']
56
+ ['B' 'B' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' 'B' 'B' 'B']
57
+ ['B' 'B' 'B' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' 'B' 'B']
58
+ ['B' ' ' ' ' ' ' 'B' ' ' 'B' ' ' ' ' 'B' ' ' ' ' ' ' 'B' 'B']
59
+ ['B' ' ' ' ' ' ' ' ' ' ' 'B' 'B' 'B' 'B' 'B' 'B' ' ' ' ' 'B']
60
+ ['B' ' ' ' ' ' ' ' ' ' ' 'B' 'B' 'B' 'B' 'B' 'B' 'B' 'B' 'B']
61
+ [' ' ' ' ' ' ' ' ' ' 'B' 'B' 'B' 'B' 'B' 'B' 'B' 'B' 'B' ' ']
62
+ [' ' ' ' ' ' ' ' ' ' 'B' 'B' ' ' 'B' 'B' 'B' 'B' ' ' ' ' ' ']
63
+ [' ' ' ' ' ' ' ' 'B' 'B' 'B' 'B' 'B' 'B' 'B' 'B' ' ' ' ' ' ']
64
+ ['B' 'B' 'B' 'B' 'B' 'B' 'B' 'B' 'B' 'B' 'B' ' ' ' ' ' ' ' ']
65
+ ['B' 'B' 'B' 'B' 'B' 'B' 'B' ' ' ' ' 'B' ' ' 'B' ' ' ' ' ' ']
66
+ [' ' 'B' 'B' 'B' 'B' ' ' ' ' ' ' ' ' 'B' 'B' 'B' ' ' ' ' ' ']
67
+ [' ' 'B' 'B' 'B' ' ' ' ' ' ' ' ' ' ' ' ' ' ' 'B' 'B' ' ' ' ']]
55
68
  Solutions found: 1
56
69
  status: OPTIMAL
57
- Time taken: 0.00 seconds
70
+ Time taken: 0.04 seconds
58
71
  ```
59
72
  (Note: Printing can be turned off by setting `verbose=False`)
60
73
 
@@ -269,6 +282,33 @@ These are all the puzzles that are implemented in this repo. <br> Click on any o
269
282
  <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/black_box_solved.png" alt="Black Box" width="140">
270
283
  </a>
271
284
  </td>
285
+ <td align="center">
286
+ <a href="#galaxies-puzzle-type-35"><b>Galaxies</b><br><br>
287
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/galaxies_solved.png" alt="Galaxies" width="140">
288
+ </a>
289
+ </td>
290
+ </tr>
291
+ <tr>
292
+ <td align="center">
293
+ <a href="#slant-puzzle-type-36"><b>Slant</b><br><br>
294
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/slant_solved.png" alt="Slant" width="140">
295
+ </a>
296
+ </td>
297
+ <td align="center">
298
+ <a href="#unequal-puzzle-type-37"><b>Unequal</b><br><br>
299
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/unequal_solved.png" alt="Unequal" width="140">
300
+ </a>
301
+ </td>
302
+ <td align="center">
303
+ <a href="#norinori-puzzle-type-38"><b>Norinori</b><br><br>
304
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/norinori_solved.png" alt="Norinori" width="140">
305
+ </a>
306
+ </td>
307
+ <td align="center">
308
+ <a href="#slitherlink-puzzle-type-39"><b>Slitherlink</b><br><br>
309
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/slitherlink_solved.png" alt="Slitherlink" width="140">
310
+ </a>
311
+ </td>
272
312
  </tr>
273
313
  </table>
274
314
 
@@ -318,6 +358,11 @@ These are all the puzzles that are implemented in this repo. <br> Click on any o
318
358
  - [Star Battle Shapeless (Puzzle Type #32)](#star-battle-shapeless-puzzle-type-32)
319
359
  - [Lits (Puzzle Type #33)](#lits-puzzle-type-33)
320
360
  - [Black Box (Puzzle Type #34)](#black-box-puzzle-type-34)
361
+ - [Galaxies (Puzzle Type #35)](#galaxies-puzzle-type-35)
362
+ - [Slant (Puzzle Type #36)](#slant-puzzle-type-36)
363
+ - [Unequal (Puzzle Type #37)](#unequal-puzzle-type-37)
364
+ - [Norinori (Puzzle Type #38)](#norinori-puzzle-type-38)
365
+ - [Slitherlink (Puzzle Type #39)](#slitherlink-puzzle-type-39)
321
366
  - [Why SAT / CP-SAT?](#why-sat--cp-sat)
322
367
  - [Testing](#testing)
323
368
  - [Contributing](#contributing)
@@ -1772,8 +1817,8 @@ Thus the solver was developed with the additional much harder goal of collecting
1772
1817
  It does so using the following high level steps:
1773
1818
 
1774
1819
  1. Model the board as a directed graph where the cells are nodes and legal moves as directed edges with unit cost. Each gem has to a group of edges where traversing any one of them collects that gem.
1775
- 2. Model step (1) as a [Generalized Traveling Salesman Problem (GTSP)](https://en.wikipedia.org/wiki/Set_TSP_problem), where each gems edge group forms a cluster.
1776
- 3. Apply the [Noon–Bean transformation](https://deepblue.lib.umich.edu/bitstream/handle/2027.42/6834/ban3102.0001.001.pdf?sequence=5) **(Noon & Bean, 1991)** to convert the GTSP from step (2) into an equivalent Asymmetric TSP (ATSP) that can be solved with OR-Tools routing solver. (Noon-Bean transformation is mentioned but not described in the [TSP wikipedia page](https://en.wikipedia.org/wiki/Travelling_salesman_problem).)
1820
+ 2. Model step (1) as a [Generalized Traveling Salesman Problem (GTSP)](https://en.wikipedia.org/wiki/Set_TSP_problem), where each gem's edge group forms a cluster.
1821
+ 3. Apply the [Noon–Bean transformation](https://deepblue.lib.umich.edu/bitstream/handle/2027.42/6834/ban3102.0001.001.pdf?sequence=5) **(Noon & Bean, 1991)** to convert the GTSP from step (2) into an equivalent Asymmetric TSP (ATSP) that can be solved with OR-Tools' routing solver. (Noon-Bean transformation is mentioned but not described in the [TSP wikipedia page](https://en.wikipedia.org/wiki/Travelling_salesman_problem).)
1777
1822
  4. Use a [Vehicle Routing Problem (VRP)](https://en.wikipedia.org/wiki/Vehicle_routing_problem) solver using the [OR-Tools VRP solver](https://developers.google.com/optimization/routing/routing_tasks) to solve the ATSP.
1778
1823
 
1779
1824
  This achieves a final sequence of moves that is empirically always faster than the website's solution.
@@ -2892,6 +2937,454 @@ Time taken: 30.33 seconds
2892
2937
 
2893
2938
  ---
2894
2939
 
2940
+ ## Galaxies (Puzzle Type #35)
2941
+
2942
+ * [**Play online**](https://www.chiark.greenend.org.uk/~sgtatham/puzzles/js/galaxies.html)
2943
+
2944
+ * [**Instructions**](https://www.chiark.greenend.org.uk/~sgtatham/puzzles/doc/galaxies.html#galaxies)
2945
+
2946
+ * [**Solver Code**][35]
2947
+
2948
+ <details>
2949
+ <summary><strong>Rules</strong></summary>
2950
+
2951
+ You have a rectangular grid containing a number of dots. Your aim is to partition the rectangle into connected regions of squares, in such a way that every region is 180° rotationally symmetric, and contains exactly one dot which is located at its centre of symmetry.
2952
+
2953
+ To enter your solution, you draw lines along the grid edges to mark the boundaries of the regions. The puzzle is complete when the marked lines on the grid are precisely those that separate two squares belonging to different regions.
2954
+
2955
+ </details>
2956
+
2957
+ **Unsolved puzzle**
2958
+
2959
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/galaxies_unsolved.png" alt="Galaxies unsolved" width="500">
2960
+
2961
+ Code to utilize this package and solve the puzzle:
2962
+
2963
+ Note: The number are arbitrary and simply number each galaxy as an integer.
2964
+
2965
+ ```python
2966
+ from puzzle_solver import galaxies_solver as solver
2967
+ galaxies = np.array([
2968
+ [' ', ' ', '00', ' ', ' ', '01', '01', '02', '02', '03', '03', ' ', '04', '04', ' '],
2969
+ ['05', '05', ' ', ' ', '06', '01', '01', '02', '02', ' ', ' ', ' ', '07', ' ', ' '],
2970
+ ['08', ' ', ' ', ' ', '06', ' ', '09', '09', ' ', ' ', '10', ' ', ' ', ' ', ' '],
2971
+ [' ', ' ', ' ', ' ', ' ', ' ', '11', '11', '12', ' ', ' ', ' ', ' ', '13', '13'],
2972
+ ['14', ' ', ' ', ' ', '15', ' ', '11', '11', ' ', ' ', ' ', ' ', '16', ' ', ' '],
2973
+ [' ', '17', ' ', ' ', '15', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '16', ' ', '18'],
2974
+ [' ', '17', '19', ' ', ' ', ' ', ' ', ' ', ' ', '20', ' ', ' ', ' ', '21', '18'],
2975
+ [' ', '22', ' ', ' ', '23', ' ', ' ', ' ', ' ', '20', ' ', '24', '24', '21', '25'],
2976
+ ['26', '27', '27', '28', '28', '29', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '30', '30'],
2977
+ [' ', '27', '27', '28', '28', '31', '31', ' ', ' ', ' ', ' ', '32', ' ', '30', '30'],
2978
+ [' ', ' ', ' ', '33', '33', '31', '31', '34', ' ', ' ', '35', ' ', ' ', ' ', ' '],
2979
+ ['36', ' ', ' ', '33', '33', ' ', ' ', '34', ' ', ' ', ' ', ' ', ' ', '37', ' '],
2980
+ [' ', ' ', '38', '38', ' ', '39', ' ', '40', '40', '41', '41', '42', ' ', '37', ' '],
2981
+ ['43', '44', '38', '38', '45', '45', '46', '40', '40', '41', '41', '42', ' ', ' ', ' '],
2982
+ ['43', ' ', ' ', ' ', ' ', ' ', ' ', '47', ' ', ' ', ' ', ' ', '48', '48', ' ']
2983
+ ])
2984
+ binst = solver.Board(galaxies=galaxies)
2985
+ solutions = binst.solve_and_print()
2986
+ ```
2987
+ **Script Output**
2988
+
2989
+ As the instructions say, the solution to this puzzle is not garunteed to be unique.
2990
+
2991
+ ```python
2992
+ Solution found
2993
+ [
2994
+ ['00', '00', '00', '00', '00', '01', '01', '02', '02', '03', '03', '04', '04', '04', '04'],
2995
+ ['05', '05', '15', '06', '06', '01', '01', '02', '02', '10', '10', '07', '07', '07', '13'],
2996
+ ['08', '15', '15', '15', '06', '06', '09', '09', '10', '10', '10', '10', '10', '13', '13'],
2997
+ ['14', '15', '15', '15', '15', '15', '11', '11', '12', '20', '10', '10', '16', '13', '13'],
2998
+ ['14', '15', '15', '15', '15', '15', '11', '11', '20', '20', '20', '20', '16', '13', '13'],
2999
+ ['14', '17', '17', '15', '15', '15', '15', '15', '20', '20', '20', '20', '16', '13', '18'],
3000
+ ['17', '17', '19', '15', '15', '15', '15', '15', '20', '20', '20', '24', '16', '21', '18'],
3001
+ ['26', '22', '27', '27', '23', '15', '15', '15', '20', '20', '20', '24', '24', '21', '25'],
3002
+ ['26', '27', '27', '28', '28', '29', '15', '20', '20', '20', '20', '32', '24', '30', '30'],
3003
+ ['26', '27', '27', '28', '28', '31', '31', '20', '20', '20', '20', '32', '37', '30', '30'],
3004
+ ['27', '27', '33', '33', '33', '31', '31', '34', '34', '20', '35', '32', '37', '37', '37'],
3005
+ ['36', '38', '38', '33', '33', '33', '34', '34', '41', '41', '41', '41', '37', '37', '37'],
3006
+ ['44', '44', '38', '38', '45', '39', '46', '40', '40', '41', '41', '42', '37', '37', '37'],
3007
+ ['43', '44', '38', '38', '45', '45', '46', '40', '40', '41', '41', '42', '37', '37', '37'],
3008
+ ['43', '44', '44', '38', '38', '45', '46', '47', '41', '41', '41', '41', '48', '48', '37'],
3009
+ ]
3010
+ Solutions found: 1
3011
+ status: OPTIMAL
3012
+ Time taken: 0.07 seconds
3013
+ ```
3014
+
3015
+ **Solved puzzle**
3016
+
3017
+ Applying the solution to the puzzle visually:
3018
+
3019
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/galaxies_solved.png" alt="Galaxies solved" width="500">
3020
+
3021
+ ---
3022
+
3023
+ ## Slant (Puzzle Type #36)
3024
+
3025
+ * [**Play online**](https://www.chiark.greenend.org.uk/~sgtatham/puzzles/js/slant.html)
3026
+
3027
+ * [**Instructions**](https://www.chiark.greenend.org.uk/~sgtatham/puzzles/doc/slant.html#slant)
3028
+
3029
+ * [**Solver Code**][36]
3030
+
3031
+ <details>
3032
+ <summary><strong>Rules</strong></summary>
3033
+
3034
+ You have a grid of squares. Your aim is to draw a diagonal line through each square, and choose which way each line slants so that the following conditions are met:
3035
+
3036
+ - The diagonal lines never form a loop.
3037
+ - Any point with a circled number has precisely that many lines meeting at it. (Thus, a 4 is the centre of a cross shape, whereas a zero is the centre of a diamond shape – or rather, a partial diamond shape, because a zero can never appear in the middle of the grid because that would immediately cause a loop.)
3038
+
3039
+ </details>
3040
+
3041
+ **Unsolved puzzle**
3042
+
3043
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/slant_unsolved.png" alt="Slant unsolved" width="500">
3044
+
3045
+ Code to utilize this package and solve the puzzle:
3046
+
3047
+ Note: For an NxM board you need an (N+1)x(M+1) array because the puzzle is to solve for the cells while the input is the values at the corners (there's always one more corner than cells in each dimension).
3048
+
3049
+ ```python
3050
+ from puzzle_solver import slant_solver as solver
3051
+ board = np.array([
3052
+ [' ', ' ', '1', ' ', '1', ' ', '1', ' ', '1', ' ', ' ', ' ', ' '],
3053
+ [' ', '1', '2', ' ', ' ', '2', ' ', '2', ' ', '2', ' ', '1', '1'],
3054
+ [' ', '2', '2', ' ', '2', '3', '2', ' ', '3', ' ', ' ', '1', ' '],
3055
+ ['1', '1', ' ', '3', '1', '2', ' ', '1', ' ', ' ', '3', ' ', ' '],
3056
+ [' ', ' ', '1', '1', ' ', ' ', ' ', '1', '1', '3', ' ', '3', ' '],
3057
+ ['1', '2', ' ', '2', '2', ' ', '2', ' ', ' ', '1', '2', ' ', ' '],
3058
+ [' ', '2', '2', '2', ' ', ' ', '2', '3', '2', ' ', ' ', ' ', ' '],
3059
+ [' ', '1', '2', ' ', ' ', '2', ' ', '2', ' ', ' ', ' ', '1', ' '],
3060
+ [' ', ' ', ' ', '3', '2', '2', ' ', '3', '1', ' ', ' ', ' ', '1'],
3061
+ [' ', '2', '1', '1', '2', ' ', '1', ' ', '1', ' ', '1', '1', ' '],
3062
+ [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '1', ' ', ' '],
3063
+ ])
3064
+ binst = solver.Board(numbers=board)
3065
+ solutions = binst.solve_and_print()
3066
+ ```
3067
+ **Script Output**
3068
+
3069
+ ```python
3070
+ Solution found
3071
+ [
3072
+ [ / \ \ / / / / \ \ \ / \ ]
3073
+ [ \ \ \ \ \ \ / \ / / \ \ ]
3074
+ [ \ \ \ / / \ / \ \ \ \ / ]
3075
+ [ \ / \ \ / \ / / \ / \ / ]
3076
+ [ / \ \ / \ \ \ / / / \ \ ]
3077
+ [ / \ \ / \ \ \ / \ / \ \ ]
3078
+ [ / \ \ / \ / / / \ / / \ ]
3079
+ [ \ \ \ \ \ / / / \ / \ \ ]
3080
+ [ / / / \ \ / / \ \ / \ \ ]
3081
+ [ \ \ / / / \ / \ / \ \ / ]
3082
+ ]
3083
+ Solutions found: 1
3084
+ status: OPTIMAL
3085
+ Time taken: 0.06 seconds
3086
+ ```
3087
+
3088
+ **Solved puzzle**
3089
+
3090
+ Applying the solution to the puzzle visually:
3091
+
3092
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/slant_solved.png" alt="Slant solved" width="500">
3093
+
3094
+ ---
3095
+
3096
+ ## Unequal (Puzzle Type #37)
3097
+
3098
+ Also called "Futoshiki" or Renzoku"
3099
+
3100
+ * [**Play online**](https://www.chiark.greenend.org.uk/~sgtatham/puzzles/js/unequal.html)
3101
+
3102
+ * [**Instructions**](https://www.chiark.greenend.org.uk/~sgtatham/puzzles/doc/unequal.html#unequal)
3103
+
3104
+ * [**Solver Code**][37]
3105
+
3106
+ <details>
3107
+ <summary><strong>Rules</strong></summary>
3108
+
3109
+ You have a square grid; each square may contain a digit from 1 to the size of the grid, and some squares have clue signs between them. Your aim is to fully populate the grid with numbers such that:
3110
+
3111
+ - Each row contains only one occurrence of each digit
3112
+ - Each column contains only one occurrence of each digit
3113
+ - All the clue signs are satisfied.
3114
+
3115
+ There are two modes for this game, 'Unequal' and 'Adjacent'.
3116
+
3117
+ In 'Unequal' mode, the clue signs are greater-than symbols indicating one square's value is greater than its neighbour's. In this mode not all clues may be visible, particularly at higher difficulty levels.
3118
+
3119
+ In 'Adjacent' mode, the clue signs are bars indicating one square's value is numerically adjacent (i.e. one higher or one lower) than its neighbour. In this mode all clues are always visible: absence of a bar thus means that a square's value is definitely not numerically adjacent to that neighbour's.
3120
+
3121
+ In 'Trivial' difficulty level (available via the 'Custom' game type selector), there are no greater-than signs in 'Unequal' mode; the puzzle is to solve the Latin square only.
3122
+
3123
+ </details>
3124
+
3125
+ **Unsolved puzzle**
3126
+
3127
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/unequal_unsolved.png" alt="Unequal unsolved" width="500">
3128
+
3129
+ Code to utilize this package and solve the puzzle:
3130
+
3131
+ Note: For an NxM board you need an (2N-1)x(2M-1) array because the puzzle involves input in between the cells. Each numbered cell has neighbors horizontally to represent ">", "<", and "|" (where "|" represents adjacency) and vertically to represent "∧", "∨" and "-" (where "-" represents adjacency). The "X" in the input are unused corners that shouldnt contain anything (just a corner). The numbers should never appear orthogonal to an "X", only diagonally to it. vice-versa for the comparison operators.
3132
+
3133
+ ```python
3134
+ from puzzle_solver import unequal_solver as solver
3135
+ board = np.array([
3136
+ [' ', ' ', ' ', ' ', '9', ' ', '1', ' ', '7', '>', ' ', '>', ' ', ' ', ' ', ' ', ' ', '>', ' '],
3137
+ [' ', 'X', 'V', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', '∧', 'X', ' ', 'X', ' ', 'X', ' '],
3138
+ [' ', ' ', ' ', ' ', ' ', ' ', '6', ' ', ' ', ' ', '9', ' ', ' ', ' ', '5', ' ', '3', ' ', ' '],
3139
+ [' ', 'X', ' ', 'X', '∧', 'X', ' ', 'X', '∧', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' '],
3140
+ [' ', ' ', ' ', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '6', ' ', '9', ' ', ' ', ' ', ' '],
3141
+ [' ', 'X', ' ', 'X', 'V', 'X', 'V', 'X', 'V', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', 'V'],
3142
+ [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', ' ', '<', ' ', '>', ' ', ' ', ' ', ' ', ' '],
3143
+ [' ', 'X', ' ', 'X', '∧', 'X', 'V', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' '],
3144
+ [' ', ' ', '3', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', ' ', ' ', ' '],
3145
+ [' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', '∧', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' '],
3146
+ [' ', '<', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '5', ' ', ' ', '>', ' ', '<', ' ', ' ', '4'],
3147
+ ['V', 'X', '∧', 'X', 'V', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', 'V', 'X', ' ', 'X', ' '],
3148
+ [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '>', ' ', ' ', ' ', ' ', ' '],
3149
+ [' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', '∧', 'X', ' ', 'X', ' ', 'X', 'V'],
3150
+ [' ', ' ', ' ', '<', ' ', ' ', ' ', '<', ' ', ' ', ' ', '<', ' ', '<', ' ', ' ', ' ', '<', ' '],
3151
+ [' ', 'X', ' ', 'X', ' ', 'X', 'V', 'X', ' ', 'X', 'V', 'X', '∧', 'X', ' ', 'X', ' ', 'X', ' '],
3152
+ [' ', ' ', ' ', ' ', ' ', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '>', ' ', ' ', '9', ' ', ' '],
3153
+ ['V', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', 'V'],
3154
+ [' ', '>', ' ', ' ', ' ', '>', ' ', ' ', ' ', ' ', '4', '<', ' ', '<', ' ', '<', '7', ' ', '2'],
3155
+ ])
3156
+ binst = solver.Board(board=board)
3157
+ solutions = binst.solve_and_print()
3158
+ ```
3159
+ **Script Output**
3160
+
3161
+ ```python
3162
+ Solution found
3163
+ [
3164
+ [ 6 5 9 1 7 2 0 8 4 3 ]
3165
+ [ 7 1 0 6 4 9 2 5 3 8 ]
3166
+ [ 3 4 2 8 5 0 6 9 1 7 ]
3167
+ [ 5 9 1 7 3 6 8 4 2 0 ]
3168
+ [ 8 3 5 4 0 7 1 2 6 9 ]
3169
+ [ 2 6 7 0 1 5 9 3 8 4 ]
3170
+ [ 0 7 4 9 2 8 3 1 5 6 ]
3171
+ [ 9 2 6 5 8 3 4 7 0 1 ]
3172
+ [ 4 8 3 2 6 1 7 0 9 5 ]
3173
+ [ 1 0 8 3 9 4 5 6 7 2 ]
3174
+ ]
3175
+ Solutions found: 1
3176
+ status: OPTIMAL
3177
+ Time taken: 0.05 seconds
3178
+ ```
3179
+
3180
+ **Solved puzzle**
3181
+
3182
+ Applying the solution to the puzzle visually:
3183
+
3184
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/unequal_solved.png" alt="Unequal solved" width="500">
3185
+
3186
+ ---
3187
+
3188
+ ## Norinori (Puzzle Type #38)
3189
+
3190
+ * [**Play online**](https://www.puzzle-norinori.com)
3191
+
3192
+ * [**Solver Code**][38]
3193
+
3194
+ <details>
3195
+ <summary><strong>Rules</strong></summary>
3196
+
3197
+ You have to shade some of the cells in such a way that:
3198
+ - Exactly 2 cells are shaded in each region.
3199
+ - Each shaded cell should be a part of a domino*. Dominoes can cross the region borders.
3200
+ - The dominoes cannot touch each other except diagonally.
3201
+
3202
+ * A domino is a shape made of 2 shaded cells next to each other (1x2 or 2x1).
3203
+
3204
+ </details>
3205
+
3206
+ **Unsolved puzzle**
3207
+
3208
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/norinori_unsolved.png" alt="Norinori unsolved" width="500">
3209
+
3210
+ Code to utilize this package and solve the puzzle:
3211
+
3212
+ ```python
3213
+ from puzzle_solver import norinori_solver as solver
3214
+ board = np.array([
3215
+ ['00', '01', '01', '01', '01', '02', '03', '03', '04', '04', '04', '05', '05', '05', '06', '07', '08', '08', '09', '09'],
3216
+ ['00', '00', '01', '01', '01', '02', '03', '04', '04', '10', '11', '11', '05', '06', '06', '07', '08', '08', '12', '12'],
3217
+ ['13', '13', '13', '01', '01', '03', '03', '10', '10', '10', '11', '14', '05', '14', '07', '07', '07', '12', '12', '12'],
3218
+ ['13', '15', '13', '16', '16', '16', '17', '17', '17', '18', '18', '14', '14', '14', '07', '07', '07', '07', '07', '12'],
3219
+ ['13', '15', '15', '16', '19', '19', '17', '17', '17', '18', '18', '18', '14', '20', '07', '07', '21', '21', '21', '21'],
3220
+ ['13', '19', '19', '19', '19', '19', '17', '22', '22', '22', '22', '18', '14', '20', '20', '07', '21', '23', '23', '21'],
3221
+ ['24', '24', '25', '25', '25', '25', '26', '27', '27', '27', '28', '28', '20', '20', '29', '29', '30', '30', '31', '31'],
3222
+ ['24', '24', '25', '32', '33', '33', '26', '27', '27', '34', '28', '35', '35', '36', '36', '29', '37', '30', '31', '31'],
3223
+ ['38', '32', '32', '32', '33', '27', '27', '27', '27', '34', '28', '28', '35', '35', '29', '29', '37', '37', '31', '37'],
3224
+ ['38', '38', '32', '39', '33', '40', '34', '34', '34', '34', '28', '35', '35', '35', '41', '37', '37', '37', '37', '37'],
3225
+ ['42', '38', '39', '39', '40', '40', '43', '43', '34', '44', '28', '35', '45', '45', '41', '41', '41', '41', '46', '46'],
3226
+ ['42', '42', '39', '47', '47', '40', '40', '44', '44', '44', '48', '48', '48', '48', '48', '41', '49', '49', '49', '46'],
3227
+ ['50', '50', '39', '39', '40', '40', '40', '40', '51', '51', '51', '52', '48', '48', '53', '41', '54', '54', '49', '46'],
3228
+ ['50', '39', '39', '55', '55', '40', '40', '40', '56', '51', '51', '52', '53', '48', '53', '41', '41', '54', '49', '46'],
3229
+ ['39', '39', '39', '57', '56', '56', '56', '56', '56', '56', '53', '53', '53', '53', '53', '58', '58', '58', '59', '59'],
3230
+ ['60', '39', '39', '57', '57', '61', '61', '61', '62', '56', '56', '63', '63', '63', '63', '63', '59', '59', '59', '59'],
3231
+ ['60', '64', '65', '65', '61', '61', '66', '66', '62', '62', '62', '67', '63', '63', '68', '69', '69', '69', '69', '69'],
3232
+ ['60', '64', '65', '65', '65', '65', '66', '70', '70', '70', '70', '67', '67', '71', '68', '69', '72', '73', '73', '69'],
3233
+ ['60', '60', '60', '65', '66', '66', '66', '66', '74', '75', '75', '75', '67', '71', '68', '68', '72', '73', '73', '73'],
3234
+ ['76', '76', '76', '76', '76', '77', '77', '74', '74', '74', '74', '67', '67', '71', '71', '71', '72', '73', '78', '78']
3235
+ ])
3236
+ binst = solver.Board(board=board)
3237
+ solutions = binst.solve_and_print()
3238
+ ```
3239
+ **Script Output**
3240
+
3241
+ ```python
3242
+ Solution found
3243
+ [
3244
+ [ 'X', ' ', ' ', ' ', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', ' ', 'X', ' ', 'X', ' ', 'X', 'X' ],
3245
+ [ 'X', ' ', 'X', ' ', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', ' ', 'X', ' ', 'X', ' ', ' ', ' ' ],
3246
+ [ ' ', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', 'X', ' ', ' ', ' ', 'X', ' ', ' ' ],
3247
+ [ 'X', 'X', ' ', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', ' ', ' ', ' ', ' ', ' ', 'X', ' ', 'X' ],
3248
+ [ ' ', ' ', 'X', 'X', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'X', 'X', ' ', ' ', 'X', 'X', ' ', ' ', 'X' ],
3249
+ [ ' ', 'X', ' ', ' ', 'X', ' ', ' ', 'X', 'X', ' ', ' ', ' ', ' ', 'X', 'X', ' ', ' ', 'X', 'X', ' ' ],
3250
+ [ ' ', 'X', ' ', ' ', 'X', ' ', 'X', ' ', ' ', 'X', ' ', 'X', ' ', ' ', ' ', 'X', 'X', ' ', ' ', 'X' ],
3251
+ [ 'X', ' ', 'X', 'X', ' ', ' ', 'X', ' ', ' ', 'X', ' ', 'X', ' ', 'X', 'X', ' ', ' ', 'X', ' ', 'X' ],
3252
+ [ 'X', ' ', ' ', ' ', 'X', ' ', ' ', ' ', 'X', ' ', ' ', ' ', ' ', ' ', ' ', 'X', ' ', 'X', ' ', ' ' ],
3253
+ [ ' ', 'X', 'X', ' ', 'X', ' ', ' ', ' ', 'X', ' ', 'X', 'X', ' ', ' ', ' ', 'X', ' ', ' ', ' ', ' ' ],
3254
+ [ 'X', ' ', ' ', ' ', ' ', ' ', 'X', 'X', ' ', 'X', ' ', ' ', 'X', 'X', ' ', ' ', ' ', 'X', 'X', ' ' ],
3255
+ [ 'X', ' ', ' ', 'X', 'X', ' ', ' ', ' ', ' ', 'X', ' ', ' ', ' ', ' ', 'X', ' ', 'X', ' ', ' ', ' ' ],
3256
+ [ ' ', 'X', 'X', ' ', ' ', ' ', ' ', 'X', 'X', ' ', ' ', 'X', ' ', ' ', 'X', ' ', 'X', ' ', 'X', 'X' ],
3257
+ [ 'X', ' ', ' ', 'X', 'X', ' ', 'X', ' ', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', 'X', ' ', ' ' ],
3258
+ [ 'X', ' ', ' ', ' ', ' ', ' ', 'X', ' ', ' ', 'X', ' ', ' ', ' ', 'X', ' ', 'X', ' ', 'X', ' ', ' ' ],
3259
+ [ ' ', ' ', ' ', 'X', 'X', ' ', ' ', 'X', 'X', ' ', ' ', 'X', ' ', ' ', 'X', ' ', 'X', ' ', ' ', 'X' ],
3260
+ [ ' ', 'X', ' ', ' ', ' ', 'X', 'X', ' ', ' ', 'X', ' ', 'X', ' ', ' ', 'X', ' ', 'X', ' ', ' ', 'X' ],
3261
+ [ ' ', 'X', ' ', 'X', 'X', ' ', ' ', 'X', ' ', 'X', ' ', ' ', 'X', 'X', ' ', ' ', ' ', 'X', 'X', ' ' ],
3262
+ [ 'X', ' ', 'X', ' ', ' ', ' ', ' ', 'X', ' ', ' ', 'X', 'X', ' ', ' ', 'X', ' ', 'X', ' ', ' ', ' ' ],
3263
+ [ 'X', ' ', 'X', ' ', ' ', 'X', 'X', ' ', 'X', 'X', ' ', ' ', ' ', ' ', 'X', ' ', 'X', ' ', 'X', 'X' ],
3264
+ ]
3265
+ Solutions found: 1
3266
+ status: OPTIMAL
3267
+ Time taken: 0.04 seconds
3268
+ ```
3269
+
3270
+ **Solved puzzle**
3271
+
3272
+ Applying the solution to the puzzle visually:
3273
+
3274
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/norinori_solved.png" alt="Norinori solved" width="500">
3275
+
3276
+ ---
3277
+
3278
+ ## Slitherlink (Puzzle Type #39)
3279
+
3280
+ Also known as Fences and Loop the Loop
3281
+
3282
+ * [**Play online**](https://www.puzzle-loop.com)
3283
+
3284
+ * [**Solver Code**][39]
3285
+
3286
+ <details>
3287
+ <summary><strong>Rules</strong></summary>
3288
+
3289
+ You have to draw lines between the dots to form a single loop without crossings or branches. The numbers indicate how many lines surround it.
3290
+
3291
+ A line forming a single loop without crossings or branches means that every corner has either 2 or 0 lines touching it.
3292
+
3293
+ </details>
3294
+
3295
+ **Unsolved puzzle**
3296
+
3297
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/slitherlink_unsolved.png" alt="Slitherlink unsolved" width="500">
3298
+
3299
+ Code to utilize this package and solve the puzzle:
3300
+
3301
+ ```python
3302
+ from puzzle_solver import slitherlink_solver as solver
3303
+ board = np.array([
3304
+ ['3', ' ', ' ', '2', ' ', ' ', ' ', ' ', ' ', '3', ' ', ' ', ' ', ' ', ' ', '3', ' ', ' ', '1', ' '],
3305
+ [' ', ' ', '3', ' ', '3', ' ', ' ', ' ', '3', ' ', '2', '2', ' ', '2', ' ', '2', '2', ' ', '2', '3'],
3306
+ ['2', '2', ' ', ' ', ' ', '2', '1', ' ', '1', '1', ' ', ' ', '3', '1', ' ', '2', ' ', ' ', ' ', '2'],
3307
+ [' ', ' ', '2', ' ', ' ', '2', '2', ' ', ' ', ' ', '3', ' ', ' ', ' ', ' ', ' ', '2', '2', '3', ' '],
3308
+ ['1', '2', '1', ' ', ' ', ' ', '2', '1', ' ', '3', '2', ' ', '3', '2', '2', '3', ' ', '3', '2', '2'],
3309
+ [' ', '3', '2', '2', '1', '2', ' ', '3', ' ', ' ', ' ', ' ', '2', '2', '3', ' ', '1', '1', ' ', '2'],
3310
+ ['1', ' ', ' ', ' ', ' ', ' ', '2', ' ', ' ', '2', ' ', '1', '3', ' ', ' ', ' ', ' ', '2', '2', '2'],
3311
+ [' ', '3', ' ', '2', '0', '1', '2', '1', ' ', '1', '3', ' ', '2', ' ', ' ', '2', ' ', '2', '1', ' '],
3312
+ ['2', ' ', ' ', ' ', '2', ' ', '3', ' ', ' ', ' ', ' ', '2', ' ', ' ', '1', '2', ' ', ' ', '1', '3'],
3313
+ [' ', ' ', '1', ' ', ' ', ' ', ' ', '2', '0', ' ', '1', ' ', '2', ' ', '0', ' ', '2', ' ', '3', '2'],
3314
+ [' ', '3', ' ', '3', ' ', '1', '3', ' ', '3', ' ', '2', ' ', ' ', '2', '2', '2', '3', ' ', ' ', ' '],
3315
+ ['3', ' ', ' ', ' ', ' ', ' ', ' ', '0', '2', '1', ' ', ' ', '2', ' ', ' ', '1', ' ', '0', '2', ' '],
3316
+ [' ', ' ', ' ', ' ', ' ', ' ', '3', ' ', '3', '2', '3', ' ', ' ', '2', ' ', '1', ' ', ' ', ' ', ' '],
3317
+ ['2', '2', ' ', '3', '0', ' ', ' ', '3', ' ', ' ', '2', ' ', ' ', ' ', ' ', '2', '2', ' ', '3', ' '],
3318
+ [' ', '2', '0', ' ', ' ', '3', ' ', '1', ' ', ' ', '2', ' ', '2', '2', ' ', ' ', ' ', '2', ' ', '2'],
3319
+ [' ', ' ', '1', '3', '1', ' ', ' ', ' ', ' ', ' ', '2', ' ', '2', '1', ' ', '1', '2', '2', ' ', ' '],
3320
+ ['2', ' ', '2', '2', ' ', '1', '3', ' ', '2', ' ', '3', '1', '2', ' ', '3', '2', ' ', '1', '1', ' '],
3321
+ [' ', ' ', '2', ' ', '1', ' ', ' ', ' ', '2', ' ', ' ', ' ', '2', ' ', '1', '0', ' ', ' ', ' ', '3'],
3322
+ [' ', '2', ' ', ' ', '2', ' ', '2', '3', '2', ' ', '2', '2', ' ', '3', '2', '2', '3', '3', '1', ' '],
3323
+ ['0', '0', ' ', '3', '2', ' ', ' ', ' ', ' ', ' ', '2', '1', '2', '1', ' ', ' ', ' ', '2', '1', ' '],
3324
+ ])
3325
+ binst = solver.Board(board=board)
3326
+ solutions = binst.solve_and_print()
3327
+ ```
3328
+ **Script Output**
3329
+
3330
+ ```python
3331
+ Solution found
3332
+ 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1
3333
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
3334
+ ┌───┐ ┌───────┐ ┌───────────────────┐ ┌───────┐ ┌───┐ ┌───────────┐
3335
+ 0│ 3 │ · │ · 2 │ · │ · · · · 3 │ · · │ · · │ · │ 3 │ · │ · 1 · │
3336
+ │ │ └───┐ │ │ ┌───────┐ ┌───┘ ┌───┘ ┌───┘ │ │ └───┐ ┌───┘
3337
+ 1│ · │ · 3 │ · │ 3 │ · │ · · │ 3 │ · 2 │ 2 · │ 2 · │ 2 │ 2 · │ 2 │ 3
3338
+ │ │ ┌───┘ └───┘ │ └───┘ ┌───┘ ┌───┘ │ └───────┘ └───┐
3339
+ 2│ 2 │ 2 │ · · · 2 │ 1 · 1 1 │ · · │ 3 1 · │ 2 · · · 2 │
3340
+ │ │ │ ┌───────────┘ ┌───┐ └───┐ └───────┐ └───────┐ ┌───┐ │
3341
+ 3│ · │ · │ 2 │ · · 2 2 │ · │ · · 3 │ · · · │ · · 2 │ 2 │ 3 │ · │
3342
+ │ └───┘ └───────────────┘ └───┐ ┌───┘ ┌───┐ │ ┌───┐ │ │ │ │
3343
+ 4│ 1 2 1 · · · 2 1 · │ 3 │ 2 · │ 3 │ 2 │ 2 │ 3 │ · │ 3 │ 2 │ 2 │
3344
+ │ ┌───────────────────────────┐ └───┘ ┌───┘ │ │ │ │ └───┘ │ │
3345
+ 5│ · │ 3 2 2 1 2 · 3 │ · · · │ · 2 │ 2 │ 3 │ · │ 1 1 · │ 2 │
3346
+ │ └───────────┐ ┌───────────┘ ┌───────┘ ┌───┘ └───┘ │ ┌───┘ │
3347
+ 6│ 1 · · · │ · │ · 2 · · │ 2 · 1 │ 3 · · · │ · 2 │ 2 2 │
3348
+ │ ┌───────────┘ └───────────────┘ ┌───┐ └───────────┐ └───────┘ ┌───┘
3349
+ 7│ · │ 3 · 2 0 1 2 1 · 1 │ 3 │ · 2 · · │ 2 · 2 1 │ ·
3350
+ │ └───┐ ┌───┐ ┌───┐ ┌───┐ │ └───────────┐ └───┐ ┌───┐ └───┐
3351
+ 8│ 2 · │ · │ · │ 2 · │ 3 │ · │ · │ · │ · 2 · · │ 1 2 │ · │ · │ 1 3 │
3352
+ └───┐ └───┘ └───┐ │ └───┘ └───┘ ┌───┐ ┌───┘ └───┘ │ ┌───┘
3353
+ 9 · │ · 1 · · │ · │ · 2 0 · 1 │ · │ 2 │ · 0 · 2 · │ 3 │ 2
3354
+ └───┐ ┌───────┘ │ ┌───┐ ┌───┐ │ │ │ ┌───────┐ └───┘
3355
+ 10 · 3 │ · │ 3 · 1 │ 3 │ · │ 3 │ · │ 2 │ · │ · │ 2 2 │ 2 3 │ · · ·
3356
+ ┌───────┘ └───────┐ └───┘ └───┘ │ │ │ └───────┘ ┌───┘ ┌───┐
3357
+ 11│ 3 · · · · │ · · 0 2 1 │ · │ · │ 2 · · 1 │ · 0 2 │ · │
3358
+ └───┐ ┌───────┐ │ ┌───┐ ┌───┐ │ │ └───┐ ┌───┐ └───┐ ┌───┘ │
3359
+ 12 · │ · │ · · │ · │ · │ 3 │ · │ 3 │ 2 │ 3 │ · · │ 2 │ · │ 1 · │ · │ · · │
3360
+ ┌───┘ │ ┌───┘ └───┘ │ │ │ └───┘ ┌───┘ │ │ ┌───┘ └───┐ │
3361
+ 13│ 2 2 │ · │ 3 0 · · │ 3 │ · │ · 2 · │ · · │ · │ 2 │ 2 · 3 │ · │
3362
+ │ ┌───┘ └───┐ ┌───┐ └───┘ └───────────┘ ┌───┘ │ │ ┌───────┘ │
3363
+ 14│ · │ 2 0 · │ · │ 3 │ · 1 · · 2 · 2 │ 2 · │ · │ · │ 2 · 2 │
3364
+ │ │ ┌───┘ │ │ ┌───────────────────┘ └───┘ │ ┌───────┘
3365
+ 15│ · │ · 1 │ 3 1 │ · │ · · │ · · 2 · 2 1 · 1 2 │ 2 │ · ·
3366
+ │ └───┐ └───┐ │ └───┐ │ ┌───────────────────┐ ┌───┘ └───────┐
3367
+ 16│ 2 · │ 2 2 │ · │ 1 3 │ · │ 2 · │ 3 1 2 · 3 │ 2 │ · 1 1 · │
3368
+ └───┐ └───┐ └───┘ ┌───┘ └───┐ └───┐ ┌───────────┘ └───────┐ ┌───┘
3369
+ 17 · │ · 2 │ · 1 · │ · · 2 │ · · │ · │ 2 · 1 0 · · │ · │ 3
3370
+ └───┐ └───┐ ┌───┘ ┌───┐ │ │ │ ┌───┐ ┌───┐ │ └───┐
3371
+ 18 · 2 │ · · │ 2 │ · 2 │ 3 │ 2 │ · 2 │ 2 │ · │ 3 │ 2 2 │ 3 │ 3 │ 1 · │
3372
+ └───┐ │ │ ┌───┘ │ └───────┘ └───┘ └───────┘ └───┘ │
3373
+ 19 0 0 · │ 3 │ 2 │ · │ · · │ · · 2 1 2 1 · · · 2 1 · │
3374
+ └───┘ └───┘ └───────────────────────────────────────────────┘
3375
+ Solutions found: 1
3376
+ status: OPTIMAL
3377
+ Time taken: 2.39 seconds
3378
+ ```
3379
+
3380
+ **Solved puzzle**
3381
+
3382
+ Applying the solution to the puzzle visually:
3383
+
3384
+ <img src="https://raw.githubusercontent.com/Ar-Kareem/puzzle_solver/master/images/slitherlink_solved.png" alt="Slitherlink solved" width="500">
3385
+
3386
+ ---
3387
+
2895
3388
  ---
2896
3389
 
2897
3390
  ## Why SAT / CP-SAT?
@@ -2977,3 +3470,8 @@ Issues and PRs welcome!
2977
3470
  [32]: https://github.com/Ar-Kareem/puzzle_solver/tree/master/src/puzzle_solver/puzzles/star_battle_shapeless "puzzle_solver/src/puzzle_solver/puzzles/star_battle_shapeless at master · Ar-Kareem/puzzle_solver · GitHub"
2978
3471
  [33]: https://github.com/Ar-Kareem/puzzle_solver/tree/master/src/puzzle_solver/puzzles/lits "puzzle_solver/src/puzzle_solver/puzzles/lits at master · Ar-Kareem/puzzle_solver · GitHub"
2979
3472
  [34]: https://github.com/Ar-Kareem/puzzle_solver/tree/master/src/puzzle_solver/puzzles/black_box "puzzle_solver/src/puzzle_solver/puzzles/black_box at master · Ar-Kareem/puzzle_solver · GitHub"
3473
+ [35]: https://github.com/Ar-Kareem/puzzle_solver/tree/master/src/puzzle_solver/puzzles/galaxies "puzzle_solver/src/puzzle_solver/puzzles/galaxies at master · Ar-Kareem/puzzle_solver · GitHub"
3474
+ [36]: https://github.com/Ar-Kareem/puzzle_solver/tree/master/src/puzzle_solver/puzzles/slant "puzzle_solver/src/puzzle_solver/puzzles/slant at master · Ar-Kareem/puzzle_solver · GitHub"
3475
+ [37]: https://github.com/Ar-Kareem/puzzle_solver/tree/master/src/puzzle_solver/puzzles/unequal "puzzle_solver/src/puzzle_solver/puzzles/unequal at master · Ar-Kareem/puzzle_solver · GitHub"
3476
+ [38]: https://github.com/Ar-Kareem/puzzle_solver/tree/master/src/puzzle_solver/puzzles/norinori "puzzle_solver/src/puzzle_solver/puzzles/norinori at master · Ar-Kareem/puzzle_solver · GitHub"
3477
+ [39]: https://github.com/Ar-Kareem/puzzle_solver/tree/master/src/puzzle_solver/puzzles/slitherlink "puzzle_solver/src/puzzle_solver/puzzles/slitherlink at master · Ar-Kareem/puzzle_solver · GitHub"