I want to build a maze using sat solver. Please help me to correctly compose the algorithm for generating conditions. I tried to implement some conditions, but they turned out to be wrong.
This picture explains how I represent the maze using the example 4*4 -> enter image description here
This is my code
main.py
from tkinter import *
import random
import formulas
from pysat.solvers import Solver
from itertools import cycle
import numpy as np
width = int(input("width - "))
height = int(input("height - "))
root = Tk()
root.title("Labirint")
root.state('zoomed')
z = PhotoImage(width=1, height=1)
root.configure(bg='white')
res = formulas.formula_1(width, height) + formulas.formula_2(width,height) + formulas.formula_3(width,height) + formulas.formula_4(width,height)
def reverse(mas):
arr = np.array(mas)
arr = -arr
return arr.tolist()
def solve(): # function that finds a solution for an array of conditions res
solver = Solver(name="g4")
for clause in res:
solver.add_clause(clause)
flag = solver.solve() # SAT | UNSAT
if flag:
solution = solver.get_model()
res.append(list(map(lambda x: x * -1, solution)))
i = 0
while i<1000:
for clause in res:
solver.add_clause(clause)
flag = solver.solve() # SAT | UNSAT
solution = solver.get_model()
i+=1
res.append(list(map(lambda x: x * -1, solution)))
print(len(res))
def draw_walls(width, height):
num1 = random.randint(0, (height * 2) - 1)
num2 = random.randint(0, (width * 2) - 1)
# maze walls are buttons so that we can manually change the maze as we want
# num_1 and num_2 are the entrance and exit of the maze
# vertical and horizontal arrays draw walls along the edges of the maze
# arrays of green orange and paint the walls as in the picture
# pink is the intersection of walls
vertical = []
for i in range(2): # vertical walls
for f in range(height):
vertical.append(
Checkbutton(root, indicatoron=0, background="white", selectcolor="black", image=z, compound='c',
width=5, height=11, highlightthickness=0, bd=0))
vertical[-1].place(x=i * width * 20, y=7 + (f * 20))
vertical[-1].select()
vertical[num1].deselect()
horizontal = []
for i in range(2):
for f in range(width):
horizontal.append(
Checkbutton(root, indicatoron=0, background="white", selectcolor="black", image=z, compound='c',
width=11, height=5, highlightthickness=0, bd=0))
horizontal[-1].place(x=7 + f * 20, y=i * height * 20)
horizontal[-1].select()
horizontal[num2].deselect()
green = []
for i in range(height): # vertical walls
for f in range(width - 1):
green.append(
Checkbutton(root, indicatoron=0, background="white", selectcolor="black", image=z, compound='c',
width=5, height=11, highlightthickness=0, bd=0))
green[-1].place(x=20 + f * 20, y=7 + (i * 20))
green[-1].select()
orange = []
for i in range(height - 1): # horizontal walls
for f in range(width):
orange.append(
Checkbutton(root, indicatoron=0, background="white", selectcolor="black", image=z, compound='c',
width=11, height=5, highlightthickness=0, bd=0))
orange[-1].place(x=7 + (f * 20), y=20 + (i * 20))
orange[-1].select()
pink = []
for i in range(height + 1): # pink dots
for f in range(width + 1):
pink.append(Checkbutton(root, indicatoron=0, background="white", selectcolor="black", image=z, compound='c',
width=5, height=5, highlightthickness=0, bd=0))
pink[-1].place(x=0 + (f * 20), y=0 + (i * 20))
pink[-1].select()
return green, orange
walls = draw_walls(width, height)
licycle_1 = cycle(walls[0])
licycle_2 = cycle(walls[1])
solve()
end = res
u = random.randint(len(res) - 10 , len(res) - 1)
end = res[u]
end = reverse(end)
def draw_1():
for i in range(height):
for f in range(width - 1):
t = next(licycle_1)
if end[f + (i * ((width * 2) - 1))] < 0:
t.deselect()
def draw_2():
for i in range(height - 1):
for f in range(width):
t = next(licycle_2)
if end[(((width - 1) + f) + (((width * 2) - 1) * i))] < 0:
t.deselect()
draw_1()
draw_2()
root.mainloop()
formulas.py
# count_walls = ((height-1)*width)+((width-1)*height)
def formula_1(width, height): # There must be at least one wall in a 2*2 square
tab = []
delta = (width * 2) - 1
for i in range(height - 1):
for f in range(width - 1):
l = [f + 1 + i * delta, f + width + i * delta, f + width + 1 + i * delta, f + (width * 2) + i * delta]
tab.append(l)
return tab
def formula_2(width, height): # there cannot be a separate wall horizontally
tab = []
delta = (width * 2) - 1
for i in range(height - 1):
for f in range(width - 2):
l = [f + 1 + i * delta, f + 2 + i * delta, f + width + i * delta,
f + 2 + width + i * delta, f + (width * 2) + i * delta, f + 1 + (width * 2) + i * delta]
tab.append(l)
return tab
def formula_3(width, height): # there cannot be a separate wall vertically
term = (width * 2) - 1
tab = []
for f in range(width - 1):
for i in range(height - 2):
l = [f + 1 + term * i,
f + 1 + term * i + width,
f + 1 + term * i + 3 * width - 1,
f + 1 + term * i + 4 * width - 2,
f + 1 + term * i + 3 * width - 2,
f + 1 + term * i + width - 1]
tab.append(l)
return tab
def formula_4(width, height): # there can't be an isolated 1*1 square
tab = []
for i in range(width-2):
l = [-(width + 1 + i), -((width * 2) + i) , -((width * 2) + 1 + i), -((width * 3) + i)]
tab.append(l)
for i in range(width-3):
for f in range(height-2):
l = [-((width * 3 * (i + 1)) - ((width + 1) * i) + f),
-((width * 3 * (i + 1)) - ((width + 1) * i) + width - 1 + f),
-((width * 3 * (i + 1)) - ((width + 1) * i) + width + f),
-((width * 3 * (i + 1)) - ((width + 1) * i) + (width * 2) - 1 +f)]
tab.append(l)
return tab
# there can't be an isolated 1*1 square on the borders and in the corners
With formula_1, I want to set a condition so that there is at least one wall in a 2 * 2 square. With formula_2, I want to set a condition so that there are no separate horizontal walls. With formula_3, I want to set a condition so that there are no separate vertical walls. And with аormula_4 I want to set a condition so that there are no isolated squares.
I did not make a function where there cannot be an isolated 1 * 1 square on the borders and in the corners, because most likely I will make a mistake
The output is clauses in cnf.
I use PySat to solve problem.
This is a labyrinth with a size of 15 * 15 -> enter image description here
But if you take a size larger, it looks bad. For example 20*20 -> enter image description here
Please help me write the clauses correctly. You may notice inaccuracies in using the sat solver. Thank you in advance