tilingPuzzles 0.2.0__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.
Files changed (40) hide show
  1. tilingpuzzles/__init__.py +6 -0
  2. tilingpuzzles/benchmark/README.md +10 -0
  3. tilingpuzzles/benchmark/__init__.py +0 -0
  4. tilingpuzzles/benchmark/data/timingResulsts.csv +193 -0
  5. tilingpuzzles/benchmark/git_state.py +22 -0
  6. tilingpuzzles/benchmark/run_benchmark.py +105 -0
  7. tilingpuzzles/examples/README.md +3 -0
  8. tilingpuzzles/examples/__init__.py +0 -0
  9. tilingpuzzles/examples/rectangularPentomino.py +40 -0
  10. tilingpuzzles/examples/scaledStones.py +163 -0
  11. tilingpuzzles/examples/tests/__init__.py +0 -0
  12. tilingpuzzles/examples/tests/test_rectangularPentomino.py +24 -0
  13. tilingpuzzles/examples/tests/test_scaledStones.py +8 -0
  14. tilingpuzzles/games/__init__.py +2 -0
  15. tilingpuzzles/games/game.py +20 -0
  16. tilingpuzzles/games/generic.py +7 -0
  17. tilingpuzzles/games/komino.py +147 -0
  18. tilingpuzzles/games/realisations.py +78 -0
  19. tilingpuzzles/games/stone.py +536 -0
  20. tilingpuzzles/games/stone_core.py +48 -0
  21. tilingpuzzles/games/tests/__init__.py +0 -0
  22. tilingpuzzles/games/tests/test_game.py +7 -0
  23. tilingpuzzles/games/tests/test_komino.py +30 -0
  24. tilingpuzzles/games/tests/test_realisations.py +28 -0
  25. tilingpuzzles/games/tests/test_stone.py +172 -0
  26. tilingpuzzles/games/tests/test_tile.py +19 -0
  27. tilingpuzzles/games/tile.py +39 -0
  28. tilingpuzzles/logUtils/__init__.py +0 -0
  29. tilingpuzzles/logUtils/callGraph.py +47 -0
  30. tilingpuzzles/logger.py +39 -0
  31. tilingpuzzles/solvers/__init__.py +0 -0
  32. tilingpuzzles/solvers/hights.py +3 -0
  33. tilingpuzzles/solvers/kominoSolver.py +191 -0
  34. tilingpuzzles/solvers/tests/test_komino_solver.py +30 -0
  35. tilingpuzzles/visualize/__init__.py +0 -0
  36. tilingpuzzles/visualize/visualize.py +61 -0
  37. tilingpuzzles-0.2.0.dist-info/METADATA +44 -0
  38. tilingpuzzles-0.2.0.dist-info/RECORD +40 -0
  39. tilingpuzzles-0.2.0.dist-info/WHEEL +4 -0
  40. tilingpuzzles-0.2.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,20 @@
1
+
2
+ from . import stone
3
+
4
+ import logging
5
+
6
+
7
+ class Game:
8
+
9
+ def __init__(self,tilesToFill):
10
+ self.T=stone.Stone(tilesToFill)
11
+
12
+ pass
13
+
14
+ def to_mask(self):
15
+ s=self.T
16
+ s=s.shift_positive()
17
+
18
+ return s.to_mask()
19
+
20
+ pass
@@ -0,0 +1,7 @@
1
+
2
+ from .game import Game
3
+
4
+ class Generic(Game):
5
+ pass
6
+
7
+
@@ -0,0 +1,147 @@
1
+ from __future__ import annotations
2
+ #from .game import Game
3
+ #from .stone import Stone
4
+ from random import choice
5
+ #from .tile import Tile
6
+ from logging import info, warning
7
+
8
+
9
+
10
+ #from logger import Logger
11
+ #
12
+ from . import stone, tile ,game
13
+
14
+ class Komino(game.Game):
15
+
16
+
17
+ def __init__(self,TilesToFill,k=5):
18
+ super().__init__(TilesToFill)
19
+ self.k=k
20
+
21
+ @classmethod
22
+ def generate(cls,M,k=5,return_solution=False):
23
+ # TODO return used stones Dictionary
24
+ from . import tile # Why ???
25
+
26
+ boundary={tile.Tile((0,0))}
27
+ T=set()
28
+ solution:list[stone.Stone]=[]
29
+ while boundary and M:
30
+ c=choice(list(boundary))
31
+ boundary.remove(c)
32
+ toCheck={c}
33
+
34
+ tilesFound :set[tile.Tile]=set()
35
+
36
+ while toCheck and len(tilesFound)<k:
37
+ front : tile.Tile= toCheck.pop()
38
+ #toCheck.remove(front)
39
+ if front in T or front in tilesFound:
40
+ continue
41
+ toCheck.update(front.get_neighbores())
42
+ tilesFound.add(front)
43
+
44
+ tilesFound=stone.Stone(tilesFound)
45
+ if len(tilesFound)==k:
46
+ T|=tilesFound
47
+ solution.append(tilesFound)
48
+
49
+ neig: set[tile.Tile]=set()
50
+ for tile in tilesFound:
51
+ neig.update(tile.get_neighbores())
52
+ neig -= T
53
+ neig -= tilesFound
54
+ boundary.update(neig)
55
+ M-=1
56
+
57
+ usedStones={}
58
+ for st in solution:
59
+ norm=st.normalize()
60
+ if norm in usedStones:
61
+ usedStones[st.normalize()]+=1
62
+ else:
63
+ usedStones[norm]=1
64
+
65
+ if return_solution:
66
+ return Komino(TilesToFill=T,k=k),usedStones,solution
67
+ else:
68
+ return Komino(TilesToFill=T,k=k),usedStones
69
+
70
+ pass
71
+
72
+
73
+ def unique_stones(self,_k=None) -> set[stone.Stone]:
74
+ if _k is None:
75
+ _k=self.k
76
+ if _k==1:
77
+ return {stone.Stone(((0,0),))}
78
+
79
+ prev=self.unique_stones(_k-1)
80
+
81
+ res=set()
82
+
83
+ for s in prev:
84
+ s:stone.Stone
85
+ bound=s.outer_bound()
86
+
87
+ for t in bound:
88
+ s_new=stone.Stone(s | {t})
89
+ s_new=s_new.normalize()
90
+ res.add(s_new)
91
+ return res
92
+
93
+
94
+
95
+
96
+ def unique_stones_dict(self,N):
97
+ """
98
+ dictionary that says >>all stones are N times available<<
99
+ """
100
+ res={}
101
+ for s in self.unique_stones():
102
+ res[s]=N
103
+ return res
104
+
105
+ pass
106
+
107
+ def find_solution(self,limits:dict[stone.Stone]|int=None,display=True):
108
+ from tilingpuzzles.solvers import kominoSolver
109
+ from tilingpuzzles.visualize import visualize
110
+
111
+ if limits is None:
112
+ #TODO
113
+ assert False, "not implemented"
114
+ if isinstance(limits,int):
115
+ limits=self.unique_stones_dict(limits)
116
+
117
+ solver=kominoSolver.KominoSolverLimited(self,limits)
118
+ res=solver.solve()
119
+
120
+ if display:
121
+ vz =visualize.Visualize()
122
+ vz.add_stone(self.T)
123
+
124
+ for st in res:
125
+ vz.add_stone(st)
126
+
127
+ vz.render()
128
+
129
+
130
+ return res
131
+
132
+ pass
133
+
134
+ def count_solutions(self,limits:dict[stone.Stone]|int=None,progressLevel=1):
135
+ from tilingpuzzles.solvers import kominoSolver
136
+
137
+ if limits is None:
138
+ solver = kominoSolver.KominoSolverUnlimted(self, k=self.k)
139
+ res = solver.solve(progressLevel)
140
+ return res
141
+
142
+ else:
143
+ #TODO count limited
144
+ assert False, "counting with limitations not implemented yet"
145
+
146
+
147
+ pass
@@ -0,0 +1,78 @@
1
+
2
+ from __future__ import annotations
3
+ import logging
4
+
5
+ from . import stone
6
+
7
+ class Realisations():
8
+ """
9
+ Used to genrate Mixed Integer Program for solving with highs Algorithm
10
+ not needed for now
11
+ """
12
+ # FIXME outdated
13
+
14
+ def __init__(self,msk):
15
+ assert msk
16
+ self.msk=stone.Stone(msk)
17
+ self.indexToReal={}
18
+ self.stoneToReal={}
19
+
20
+
21
+
22
+ def add_stone(self,stone: stone.Stone):
23
+
24
+ # if realisation already exists do nothing
25
+ if stone in self.stoneToReal:
26
+ return
27
+
28
+
29
+ stone=stone.shift_positive()
30
+ logging.info(f"{self.stoneToReal = }")
31
+ self.stoneToReal[stone]=[]
32
+ logging.info(f"{ stone = }")
33
+
34
+ # FIXME use actual Symetries, stone.get_symetries
35
+
36
+ symetries=[stone]
37
+
38
+ symetries.sort()
39
+
40
+
41
+ (X_min,Y_min),(X_max,Y_max)=self.msk.bounding_Box
42
+
43
+ logging.info(f"\n mask bounding box = {self.msk.bounding_Box}")
44
+
45
+
46
+ for sym in symetries:
47
+ sym=sym.shift_positive()
48
+ (x_min,y_min),(x_max,y_max)=sym.bounding_Box
49
+
50
+ logging.info(f"\nBounding box symetrie = {sym.bounding_Box}")
51
+
52
+
53
+
54
+ for dx in range(X_min -x_min,X_max-x_max+1):
55
+ for dy in range(Y_min-y_min,Y_max-y_max+1):
56
+ new_stone=sym.shift(dx,dy)
57
+ if not new_stone <= self.msk:
58
+ continue
59
+ n=len(self.indexToReal)
60
+ self.indexToReal[n]=new_stone
61
+ self.stoneToReal[stone].append(new_stone)
62
+ return
63
+
64
+
65
+
66
+ def to_matrix(self):
67
+ pass
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+