I was assigned a group project in Intro to AI course at uni.
The topic was: “implement an AI to play a puzzle game by itself using a blind search algo and a heuristic search algo.”
The required programming language is Python. If me and my friends use other languages, our project grade will reduce by half.
We pick Minesweeper as the game, DFS for blind search.
This is our code for DFS:
from memory_profiler import profile
import tkinter as tk
from tkinter.messagebox import showinfo, showerror
import time
class solution:
def __init__(self, matrix, last_flag = None):
self.size = len(matrix)
self.matrix = matrix
self.last_flag = last_flag
self.list_flag = []
list_cl = []
for i in range(self.size):
for j in range(self.size):
if matrix[i][j] == -1 or matrix[i][j] == -2:
list_cl += [(i,j)]
self.list_close = list_cl
def print_matrix(self):
for row in self.matrix:
for element in row:
print(element, end=' ')
print()
def place_flag(self):
rf,cf = (0,0)
if self.last_flag == None:
rf,cf = self.list_close[0]
else:
for i in range(len(self.list_close)-1):
if self.last_flag == self.list_close[i]:
rf,cf = self.list_close[i+1]
break
self.matrix[rf][cf] = -2
self.list_flag += [(rf,cf)]
self.last_flag = (rf,cf)
def replace_flag(self):
if self.last_flag == self.list_close[-1]:
r,c = self.last_flag
self.matrix[r][c] = -1
self.list_flag = self.list_flag[:-1]
self.last_flag = self.list_flag[-1]
self.replace_flag()
else:
r,c = self.last_flag
self.matrix[r][c] = -1
self.list_flag = self.list_flag[:-1]
for i in range(len(self.list_close)-1):
if self.last_flag == self.list_close[i]:
rf,cf = self.list_close[i+1]
self.matrix[rf][cf] = -2
self.last_flag = (rf,cf)
self.list_flag += [(rf,cf)]
def next_stage(self):
if self.last_flag == None:
is_flag_valid = True
else:
is_flag_valid = self.check_valid_flag(self.last_flag)
if is_flag_valid == True:
self.place_flag()
else:
self.replace_flag()
def get_arround_cell(self, cell):
r,c = cell
list_temp = [(r-1,c),(r+1,c),(r,c-1),(r,c+1),(r-1,c+1),(r-1,c-1),(r+1,c+1),(r+1,c-1),]
list = [i for i in list_temp if i[1]>=0 and i[0]>=0 and i[1]<=self.size-1 and i[0]<=self.size-1]
return list
def count_flag(self,cell):
list_arround = self.get_arround_cell(cell)
num_flag = 0
for i in list_arround:
if self.matrix[i[0]][i[1]] == -2:
num_flag += 1
return num_flag
def compare_value_with_num_flag(self, cell):
value = self.matrix[cell[0]][cell[1]]
num_flag = self.count_flag(cell)
if num_flag < value :
return -1
if num_flag == value:
return 0
if num_flag > value:
return 1
def check_valid_flag(self, flag):
if flag == self.list_close[-1]:
return False
list_cell_arround_flag = self.get_arround_cell(flag)
for cell in list_cell_arround_flag:
if self.matrix[cell[0]][cell[1]] >=0:
if self.compare_value_with_num_flag(cell) > 0:
return False
return True
def check_end(self):
for i in range(self.size):
for j in range(self.size):
if self.matrix[i][j] >=0:
val = self.compare_value_with_num_flag((i,j))
if val == -1 or val == 1:
return False
return True
def create_matrix(self):
rows = len(self.matrix)
cols = len(self.matrix[0])
new_matrix = []
for i in range(0,self.size):
new_matrix += [[]]
for j in range(0,self.size):
if self.matrix[i][j] == -1 :
new_matrix[i] += " "
elif self.matrix[i][j] == -2:
new_matrix[i] += '????'
else:
new_matrix[i] += str(self.matrix[i][j])
for i in range(rows):
for j in range(cols):
label = tk.Label(window, text=str(new_matrix[i][j]), borderwidth=1, relief="solid", width=8, height=3)
label.grid(row=i, column=j)
update_button = tk.Button(window, text="Next Step", command=self.update_matrix)
update_button.grid(row=self.size + 1, columnspan=self.size)
end_button = tk.Button(window, text="End", command=self.end)
end_button.grid(row=self.size + 2, columnspan=self.size)
def end(self):
isFinish = False
while isFinish == False:
self.next_stage()
isFinish = self.check_end()
self.end_matrix()
def update_matrix(self):
self.next_stage()
finish = self.check_end()
if finish == True:
self.end_matrix()
return
for widget in window.winfo_children():
widget.grid_forget()
self.create_matrix()
def end_matrix(self):
rows = len(self.matrix)
cols = len(self.matrix[0])
new_matrix = []
for i in range(0,self.size):
new_matrix += [[]]
for j in range(0,self.size):
if self.matrix[i][j] == -1 or self.matrix[i][j] == -3:
new_matrix[i] += " "
elif self.matrix[i][j] == -2:
new_matrix[i] += '????'
else:
new_matrix[i] += str(self.matrix[i][j])
for widget in window.winfo_children():
widget.grid_forget()
for i in range(rows):
for j in range(cols):
label = tk.Label(window, text=str(new_matrix[i][j]), borderwidth=1, relief="solid", width=8, height=3)
label.grid(row=i, column=j)
def emp_cell_0(self, cell):
list_arround = self.get_arround_cell(cell)
list_arround = [i for i in list_arround if self.matrix[i[0]][i[1]] == -1]
for i in list_arround:
self.matrix[i[0]][i[1]] = -3
def DFS(self):
global window
window = tk.Tk()
self.create_matrix()
window.mainloop()
grid1 = [
[-1, 1, 2, -1, -1, 2, -1],
[2, -1, -1, 3, 3, 3, -1],
[2, -1, 3, 2, -1, -1, 1],
[1, -1, -1, 4, -1, -1, 0],
[1, -1, -1, 4, -1, -1, -1],
[1, -1, -1, -1, -1, -1, 2],
[-1, -1, 1, -1, -1, 3, -1],
]
sl = solution(grid1, None)
sl.DFS()
I run:
python3 <this-file-name.py
on my Ubuntu-running laptop.
There will be a popup window displaying a 7×7 matrix of a predetermined minesweeper game. (written in grid1
variable). Also, there will be “Next Step” and “End” button placed at the bottom center.
Initially, “Next Step” is intended to display the next step to solve the puzzle, “End” is for immediately clear the puzzle. The hyphen character ‘-‘ will be filled into the blank tiles, it represents the removed tiles. (no mine exists there)
But, “Next Step” as well as “End” did not work as expected.
As shown in the below screenshots
The pop window as soon as I run the command
Expectation
Reality (kinda like that)