diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/InteligentnySaper.iml b/.idea/InteligentnySaper.iml
new file mode 100644
index 0000000..74d515a
--- /dev/null
+++ b/.idea/InteligentnySaper.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..8e1d7b1
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..55dbd56
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/classes/ai.py b/classes/ai.py
index b25f94e..98d3614 100644
--- a/classes/ai.py
+++ b/classes/ai.py
@@ -1,5 +1,5 @@
import pygame
-from classes import minesweeper, system
+from classes import minesweeper, system, bfs
from random import randrange
class AI:
@@ -18,15 +18,34 @@ class AI:
#co ma zrobić tylko na początku
def ready(self):
self.saper.set_map(self.current_map)
+
+ goal_state = [minesweeper.Map.mines[0].position_x, minesweeper.Map.mines[0].position_y]
+ print(goal_state)
+
+ find_path = bfs.BFS(self.saper)
+ find_path.graphsearch([], [], bfs.BFS.successor, goal_state)
#co ma robić przy każdym FPS'ie
- def update(self):
+ def updateFPS(self):
+ pass
+
+ #co ma zrobić przy każdym ruchu <------------------------- najważniejsze
+ def updateTile(self):
+ #aktualne pola (do debugu)
+ sensor = self.saper.sensor()
+ #print(sensor[0])
+ #print(sensor[1])
+ #print(sensor[2])
+ #print("-------")
+
+ #podniesienie bomby jeśli jest jakaś na tym polu
+ self.saper.pick_up()
+
+ #poruszenie się
if self.user_controlled:
self.minesweeper_controls()
return
-
- self.chaos_controls()
- #TU pisać resztę
+ self.chaos_controls() # <--------------------------zamiast tego trzeba wstawić jakiś algorytm
def minesweeper_controls(self):
@@ -43,10 +62,11 @@ class AI:
def chaos_controls(self):
dir = randrange(4)
if dir==0:
- self.saper.move(0)
+ self.saper.rotate("N")
elif dir==1:
- self.saper.move(180)
+ self.saper.rotate("S")
elif dir==2:
- self.saper.move(270)
+ self.saper.rotate("W")
elif dir==3:
- self.saper.move(90)
\ No newline at end of file
+ self.saper.rotate("E")
+ self.saper.move()
\ No newline at end of file
diff --git a/classes/bfs.py b/classes/bfs.py
new file mode 100644
index 0000000..106896f
--- /dev/null
+++ b/classes/bfs.py
@@ -0,0 +1,98 @@
+import heapq # dla utrzymania fringe
+from classes import node, minesweeper
+import time
+
+
+class BFS:
+
+ agent: minesweeper.Minesweeper
+ node: node.Node
+
+ def __init__(self, agent):
+ self.agent = agent
+
+ def successor(self, current_position):
+ new_nodes = []
+ neighbours_list = self.agent.sensor(current_position[0], current_position[1])
+
+
+ if neighbours_list[1][0] not in ['wall', 'cliff_south', 'cliff_east', 'cliff_north', 'cliff_west']:
+ new_nodes.append([1 + current_position[0] - 1, 0 + current_position[1] - 1])
+ if neighbours_list[2][1] not in ['wall', 'cliff_south', 'cliff_east', 'cliff_north', 'cliff_west']:
+ new_nodes.append([2 + current_position[0] - 1, 1 + current_position[1] - 1])
+ if neighbours_list[1][2] not in ['wall', 'cliff_south', 'cliff_east', 'cliff_north', 'cliff_west']:
+ new_nodes.append([1 + current_position[0] - 1, 2 + current_position[1] -1])
+ if neighbours_list[0][1] not in ['wall', 'cliff_south', 'cliff_east', 'cliff_north', 'cliff_west']:
+ new_nodes.append([0 + current_position[0] - 1, 1 + current_position[1] - 1])
+
+ return new_nodes
+
+
+
+ # fringe = struktura danych przeszowyjąca wierchowki do odwiedzenia
+ # explored = lista odwiedzonych stanow
+ # position_at_beginning = stan poczatkowy
+ # succ = funkcja nastempnika
+ # goaltest = test spewnienia celu
+
+ def graphsearch(self, fringe, explored, succ, goaltest):
+
+ positiont_at_beginning = [self.agent.position_x, self.agent.position_y, self.agent.rotation_degrees] # x, y, gdzie_patczy
+ final_action_list = []
+ root = node.Node(None, None, positiont_at_beginning[:2]) # parent, action, position
+ counter = 0
+ heapq.heappush(fringe, (counter, root))
+ visited_position = []
+
+
+ while len(fringe) != 0:
+ flag = True
+
+
+ if len(fringe) == 0:
+ return False
+ break
+
+ tmp_node = heapq.heappop(fringe) # node
+ #print(f'my parent is {tmp_node[1].get_parent()}')
+ tmp_node_position = tmp_node[1].get_position()
+
+ print(f'Position of our node {tmp_node_position[:2]}')
+
+ visited_position.append(tmp_node_position[:2])
+ #print(f'visited position: {visited_position}')
+
+ if tmp_node_position[:2] == goaltest:
+ print(' we find node')
+ # print(visited_position)
+
+ print(fringe)
+ #break
+ while tmp_node[1].get_parent() is not None:
+ #print('sdfhdfg')
+ #print(tmp_node[1].get_parent())
+ final_action_list.append(tmp_node[1].get_action())
+ #print(final_action_list)
+ tmp_node = tmp_node[1].get_parent()
+ final_action_list = reversed(final_action_list)
+ print(final_action_list)
+ break
+
+ # return final_action_list
+
+
+ explored.append(tmp_node)
+
+ neighbours_list_of_our_node = self.successor(tmp_node_position[:2])
+ # print(neighbours_list_of_our_node)
+ for node_ in neighbours_list_of_our_node:
+ # jesli pozucja wezla nie jest w fringe i nie jest w explored
+ if [node_[0], node_[1]] not in visited_position and node_[0] >= 0 and node_[1] >=0:
+ counter += 1
+ x = node.Node(tmp_node, None, [node_[0], node_[1]]) # action
+ heapq.heappush(fringe, (counter, x))
+ # time.sleep(0.5)
+
+
+
+
diff --git a/classes/minesweeper.py b/classes/minesweeper.py
index 241a4b4..e591683 100644
--- a/classes/minesweeper.py
+++ b/classes/minesweeper.py
@@ -201,6 +201,7 @@ class NPC:
#saper
class Minesweeper:
size:int
+ rotation_degrees:int
position_x:int
position_y:int
image:pygame.surface.Surface
@@ -223,6 +224,7 @@ class Minesweeper:
self.image = pygame.image.load("assets/sprites/saper_fun_sized.png")
self.image = pygame.transform.scale(self.image, (self.size, self.size))
self.rotated_image = self.image
+ self.rotation_degrees=0
def set_map(self, map:Map):
self.current_map = map
@@ -244,6 +246,8 @@ class Minesweeper:
finished=True
elif self.offset_y<0:
self.offset_y+=dist
+ if self.offset_y<-self.size and self.offset_y>-1.2*self.size:
+ pygame.mixer.Channel(1).play(pygame.mixer.Sound("assets/sounds/ledge.wav"))
if self.offset_y>=0:
finished=True
@@ -258,7 +262,24 @@ class Minesweeper:
window.blit(self.rotated_image, position_on_screen)
self.update_offset(delta)
- def move(self, dir:int):
+ def rotate(self, dir:str):
+ dirr=0
+ if dir=="N":
+ dirr=180
+ elif dir=="S":
+ dirr=0
+ elif dir=="W":
+ dirr=270
+ elif dir=="E":
+ dirr=90
+ else:
+ return
+
+ self.rotation_degrees=dirr
+ self.rotated_image = pygame.transform.rotate(self.image, dirr)
+
+
+ def move(self, dir:int=-1):
#południe - 0
#wschód - 90
#północ - 180
@@ -266,7 +287,11 @@ class Minesweeper:
if self.offset_x!=0 or self.offset_y!=0:
return
- self.rotated_image = pygame.transform.rotate(self.image, dir)
+ if dir==-1:
+ dir = self.rotation_degrees
+ else:
+ self.rotation_degrees=dir
+ self.rotated_image = pygame.transform.rotate(self.image, dir)
move_legal=True
cliff_jump=False
@@ -283,11 +308,9 @@ class Minesweeper:
if next_x == self.current_map.tiles_x or next_x == -1:
move_legal=False
- if next_y == self.current_map.tiles_y or next_y == -1:
+ elif next_y == self.current_map.tiles_y or next_y == -1:
move_legal=False
- if self.current_map.terrain_matrix[next_y][next_x]>9:
- move_legal=False
- if self.current_map.terrain_matrix[next_y][next_x]>9:
+ elif self.current_map.terrain_matrix[next_y][next_x]>9:
move_legal=False
for cliff in self.current_map.cliffs:
@@ -335,6 +358,38 @@ class Minesweeper:
def drop_civilians(self):
pass
- def sensor(self):
- sensor_list = [[],[],[]]
+ def sensor(self, x:int=-1, y:int=-1):
+ if x==-1:
+ x = self.position_x
+ if y==-1:
+ y = self.position_y
+ sensor_list = [["","",""],["","",""],["","",""]]
+ for i in range(3):
+ for j in range(3):
+ posx = x-1+j
+ posy = y-1+i
+ if posx >= self.current_map.tiles_x or posx <= -1:
+ sensor_list[i][j]="wall"
+ elif posy >= self.current_map.tiles_y or posy <= -1:
+ sensor_list[i][j]="wall"
+ elif self.current_map.terrain_matrix[posy][posx]>9:
+ sensor_list[i][j]="wall"
+ else:
+ sensor_list[i][j]="sand"
+ for cliff in self.current_map.cliffs:
+ if (posx, posy) == (cliff.position_x, cliff.position_y):
+ if cliff.rotation==0:
+ sensor_list[i][j]="cliff_south"
+ elif cliff.rotation==90:
+ sensor_list[i][j]="cliff_east"
+ elif cliff.rotation==180:
+ sensor_list[i][j]="cliff_north"
+ elif cliff.rotation==270:
+ sensor_list[i][j]="cliff_west"
+ break
+ for mine in self.current_map.mines:
+ if (posx, posy) == (mine.position_x, mine.position_y):
+ sensor_list[i][j]="mine"
+ break
+
return sensor_list
\ No newline at end of file
diff --git a/classes/node.py b/classes/node.py
new file mode 100644
index 0000000..accc175
--- /dev/null
+++ b/classes/node.py
@@ -0,0 +1,19 @@
+class Node:
+ def __init__(self, parent, action, state_array):
+ self.parent = parent
+ self.action = action
+ self.position = state_array
+
+ def get_position(self):
+ return self.position
+
+ def get_action(self):
+ return self.action
+
+ def get_parent(self):
+ return self.parent
+
+ def set_parent(self, parent):
+ self.parent = parent
+
+
diff --git a/classes/system.py b/classes/system.py
index e2faba0..52b67db 100644
--- a/classes/system.py
+++ b/classes/system.py
@@ -6,12 +6,14 @@ class Window:
height:int
title:str
icon_path:str
+ paused:bool
def __init__(self, width:int=640, height:int=480, title="", icon_path=""):
self.set_resolution(width,height)
self.set_title(title)
self.set_icon(icon_path)
self.mount()
+ self.paused=False
def set_resolution(self, width:int, height:int):
self.width = width
diff --git a/main.py b/main.py
index 883b076..0f94171 100644
--- a/main.py
+++ b/main.py
@@ -3,7 +3,7 @@ import pygame
#system - klasy związane z pygame
#minesweeper - klasy związane z samym saperem
#ai - klasa wykonująca ruchy sapera
-from classes import system, minesweeper, ai
+from classes import system, minesweeper, ai, bfs
#ustalenie wielkości pojedyńczych kawałków mapy, oraz wielkości mapy
TILE_SIZE = 64
@@ -11,7 +11,7 @@ TILES_X = int(12)
TILES_Y = int(10)
#wł/wył muzyki
-MUSIC=True
+MUSIC=False
#ustalenie FPS
FPS = 60
@@ -24,6 +24,11 @@ def main():
#utworzenie okna do gry
window = system.Window(TILE_SIZE*TILES_X, TILE_SIZE*TILES_Y, "Intelligent Minesweeper", "icon.png")
+ #utworzenie ekranu pauzy
+ pause_menu = pygame.Surface((TILE_SIZE*TILES_X, TILE_SIZE*TILES_Y))
+ pause_menu.set_alpha(128)
+ pause_menu.fill((0,0,0))
+
#utworzenie objektu mapy, wygenerowanie jej i narysowanie na ekranie
map = minesweeper.Map(window, TILE_SIZE, TILES_X, TILES_Y)
map.generate()
@@ -31,8 +36,9 @@ def main():
#utworzenie sapera
saper = minesweeper.Minesweeper(0,0, TILE_SIZE)
-
-
+
+
+
#utworzenie objektu klasy AI
AI = ai.AI(window, map, saper)
#wykonanie funkcji ready() AI
@@ -46,13 +52,20 @@ def main():
delta = clock.tick(FPS)
#wykonanie funkcji update() AI
- AI.update()
+ AI.updateFPS()
+
+ if saper.offset_x==0 and saper.offset_y==0:
+ AI.updateTile()
#narysowanie terenu i obiektów
map.draw_tiles()
map.draw_objects()
saper.draw(window.window, delta)
+ #pauza
+ if window.paused:
+ window.window.blit(pause_menu, (0,0))
+
#odświeżenie ekranu
pygame.display.update()