Bonjour,
A Noël j’ai un vu un jeu de pentominos, n’ayant pas trouvé de solution à la main, je me suis dis ca doit ce résoudre par du bactracking.
J’ai donc réalisé un programme qui fonctionne mais qui n’est vraiment pas efficace, si il trouve une solution pour les modèles 0,1,2 et 4, le modèle 2 prend déjà beaucoup de temps à résoudre et j’ai interrompu le prog avant de voir une solution pour le 3. (les modèles sont des config pour les quels il existe des solutions).
-
Je ne vois pas bien comment optimiser le programme, peut être chercher à chaque pieces si je crée une zone dans la quelle je ne pourrais plus poser de pieces, mais cela risque aussi de prendre du temps.
-
Si je parviens à l’optimiser suffisamment, j’aimerais pourvoir obtenir toutes les solutions possibles.
-
De plus je me demande pourquoi le même programme lancé dans 2 environnements different ne donne pas le même résultats, je pense que c’est du à la récursion , mais sans vraiment comprendre.
Dans le terminal de Spyder:
Une solution en 38727 cycles, hier pour ce modèle javais une solution 73 cycles.
In [36]: b = Board(4)
In [37]: resoud(b,0,'')
╔═════════════╗╔═══════╗
╚═════════════╝╚═════╗ ║
╔═╗╔══════════╗╔════╗║ ║
║ ║╚═════╗ ╔══╝╚══╗ ║║ ║
║ ╚══╗╔═╗║ ║╔═╗╔═╗║ ║║ ║
╚══╗ ║╚═╝╚═╝║ ║╚═╝║ ║╚═╝
╔═╗║ ╚══╗╔══╝ ╚══╗║ ╚══╗
║ ║╚════╝╚══╗ ╔══╝╚════╝
║ ╚═════╗╔═╗║ ║╔════╗╔═╗
╚══╗ ╔══╝║ ║╚═╝╚══╗ ║║ ║
╔═╗║ ║╔═╗║ ║╔═╗╔═╗║ ║║ ║
║ ║╚═╝╚═╝║ ║║ ║╚═╝║ ║║ ║
║ ╚══╗╔══╝ ║║ ║╔══╝ ║║ ║
║ ║║ ╔══╝║ ║╚════╝║ ║
║ ║║ ║╔══╝ ╚══╗╔══╝ ║
╚════╝╚═╝╚═══════╝╚════╝
38727
Out[37]: True
Dans un onglet Ipython du terminal Konsole:
Une autre solution en 12834 cycles.
In [11]: b = Board(4)
In [12]: resoud(b,0,'')
╔═╗╔════╗╔═╗╔═══════╗╔═╗
║ ║║ ╔══╝║ ║╚══╗ ║║ ║
║ ║║ ║╔══╝ ╚══╗║ ║║ ║
║ ║║ ║╚══╗ ╔══╝╚════╝║ ║
║ ║║ ║╔═╗║ ║╔═╗╔═╗╔══╝ ║
║ ║║ ║╚═╝╚═╝║ ║╚═╝║ ╔══╝
║ ║║ ║╔═════╝ ║╔═╗║ ║╔═╗
║ ║╚═╝╚═════╗ ║║ ║╚═╝║ ║
║ ║╔════╗╔═╗║ ║║ ╚═══╝ ║
╚═╝║ ╔══╝║ ║╚═╝╚═══════╝
╔══╝ ║╔═╗║ ╚══╗╔═╗╔═╗╔═╗
║ ╔══╝╚═╝║ ╔══╝╚═╝║ ║║ ║
║ ║╔═╗╔══╝ ║╔═════╝ ║║ ║
╚═╝║ ║╚════╝║ ╔═════╝║ ║
╔══╝ ╚═════╗║ ║╔═════╝ ║
╚══════════╝╚═╝╚═══════╝
12834
Out[12]: True
Code python :
s_pieces = """@@@@@
@@@@
@
@@@
@
@
@
@@@
@
@@
@
@@
@
@@@
@
@@@
@@
@
@@
@@
@@
@@
@
@@@
@@
@@
@
@@
@@@@
@"""
pieces = {}
for np,p in zip('ILVXUTNWFPZY',s_pieces.split('\n\n')):
pieces[np]=[]
print(np,'--\n',p,sep='')
l = max(map(len,p.split('\n')))
for r in p.split('\n'):
pieces[np].append(r.ljust(l))
def coord(piece):
ans = []
for y,r in enumerate(piece.split('\n')):
for x,c in enumerate(r):
if c=='@':
ans.append((y,x))
y,x = min(ans)
ans = sorted((r-y,c-x) for r,c in ans)
return ans
def transfo(piece):
ans = set()
for p in (piece,piece[::-1]):
for _ in range(4):
p = [''.join(r[::-1]) for r in zip(*p)]
a = '\n'.join(p)
#print(a,'\n---')
ans.add(a)
return ans
def toutes_pieces(pieces):
ans = {}
for i,p in pieces.items():
ans[i] = list(map(coord,transfo(p)))
return ans
class Board:
def __init__(self,modele=0):
if modele<4:
c,r = [(10,6),(12,5),(15,4),(20,3)][modele]
self.grid = [[' ']*c for i in range(r)]
else:
c = r = 8
self.grid = [[' ']*c for i in range(r)]
for x,y in ((2,2),(2,5),(5,2),(5,5)):
self.grid[y][x] = '#'
self.X, self.Y, self.S = c, r, c*r
self.tests = 0
PIECES = toutes_pieces(pieces)
# PIECES est un dictionnaire avec une entrée pour chaque piece
# et la liste des rotations/ reflection possibles de chaque pentomino
board = Board(5)
ed = '║ ╚ ╗ ╔ ═ ╝'
"""
0
1X2
3
"""
edges = {
(0,0,0,0):(' ',' ',' '),
(0,0,0,1):(' ',' ','═══'),
(0,0,1,0):(' ║',' ║',' ║'),
(0,0,1,1):(' ║',' ║','══╝'),
(0,1,0,0):('║ ','║ ','║ '),
(0,1,0,1):('║ ','║ ','╚══'),
(0,1,1,0):('║ ║','║ ║','║ ║'),
(0,1,1,1):('║ ║','║ ║','╚═╝'),
(1,0,0,0):('═══',' ',' '),
(1,0,0,1):('═══',' ','═══'),
(1,0,1,0):('══╗',' ║',' ║'),
(1,0,1,1):('══╗',' ║','══╝'),
(1,1,0,0):('╔══','║ ','║ '),
(1,1,0,1):('╔══','║ ','╚══'),
(1,1,1,0):('╔═╗','║ ║','║ ║'),
(1,1,1,1):('╔═╗','║ ║','╚═╝'),
}
def nbg(board,x,y):
r = []
for dx,dy in [(0,-1),(-1,0),(1,0),(0,1)]:
nx, ny = x+dx, y+dy
c = board.grid[y][x]
v = 0 if board.X>nx>=0<=ny<board.Y and board.grid[ny][nx]==c else 1
r.append(v)
return tuple(r)
def affb(board):
g = [['']*(3*board.X) for _ in range(2*board.Y)]
for y in range(board.Y):
for x in range(board.X):
e = edges[nbg(board,x,y)][::2]
for dy,row in enumerate(e):
for dx,c in enumerate(row):
g[y*2+dy][x*3+dx] = c
gy, gx = len(g), len(g[0])
for y in range(gy):
for x in range(gx):
c = g[y][x]
if c!=' ':continue
if x>0 and y>0 and g[y][x-1]=='═' and g[y-1][x]=='║':
c = '╝'
if x<gx-1 and y>0 and g[y][x+1]=='═' and g[y-1][x]=='║':
c = '╚'
if x>0 and y<gy-1 and g[y][x-1]=='═' and g[y+1][x]=='║':
c = '╗'
if x<gx-1 and y<gy-1 and g[y][x+1]=='═' and g[y+1][x]=='║':
c = '╔'
g[y][x] = c
print(''.join(g[y]))
def affb0(board):
print( '+'+'-'*board.X+'+')
for row in board.grid:
print('|'+''.join(row)+'|')
print( '+'+'-'*board.X+'+')
def next_pos(board,pos):
while pos<board.S and board.grid[pos//board.X][pos%board.X]!=' ':
pos += 1
return pos
def valide(board,piece,pos):
x,y = pos % board.X, pos // board.X
return all(board.X>x+dx>=0<=y+dy<board.Y and board.grid[y+dy][x+dx]==' '
for dy,dx in piece)
def place(board,piece,pos,symbol='@'):
x, y = pos % board.X, pos // board.X
for dy,dx in piece:
board.grid[y+dy][x+dx] = symbol
board.tests += 1
def efface(board,piece):
for y,row in enumerate(board.grid):
for x,c in enumerate(row):
if c==piece:
board.grid[y][x] = ' '
def resoud(board,pos,prec_pieces):
npos = next_pos(board,pos)
if npos == board.S:
affb(board)
print(board.tests)
return True
reste = [p for p in PIECES if p not in prec_pieces]
for p in reste:
for c in PIECES[p]:
if valide(board,c,npos):
place(board,c,npos,p)
if resoud(board,npos,prec_pieces+p):
return True
if prec_pieces:
efface(board,prec_pieces[-1])
return False