jest jakaś funkcja następnika i grafsearch
This commit is contained in:
parent
f4da3bc9fa
commit
1ad0ffd38f
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
@ -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
|
10
.idea/InteligentnySaper.iml
Normal file
10
.idea/InteligentnySaper.iml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
4
.idea/misc.xml
Normal file
4
.idea/misc.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (InteligentnySaper)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/InteligentnySaper.iml" filepath="$PROJECT_DIR$/.idea/InteligentnySaper.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -1,5 +1,5 @@
|
|||||||
import pygame
|
import pygame
|
||||||
from classes import minesweeper, system
|
from classes import minesweeper, system, bfs
|
||||||
from random import randrange
|
from random import randrange
|
||||||
|
|
||||||
class AI:
|
class AI:
|
||||||
@ -19,14 +19,33 @@ class AI:
|
|||||||
def ready(self):
|
def ready(self):
|
||||||
self.saper.set_map(self.current_map)
|
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
|
#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:
|
if self.user_controlled:
|
||||||
self.minesweeper_controls()
|
self.minesweeper_controls()
|
||||||
return
|
return
|
||||||
|
self.chaos_controls() # <--------------------------zamiast tego trzeba wstawić jakiś algorytm
|
||||||
self.chaos_controls()
|
|
||||||
#TU pisać resztę
|
|
||||||
|
|
||||||
|
|
||||||
def minesweeper_controls(self):
|
def minesweeper_controls(self):
|
||||||
@ -43,10 +62,11 @@ class AI:
|
|||||||
def chaos_controls(self):
|
def chaos_controls(self):
|
||||||
dir = randrange(4)
|
dir = randrange(4)
|
||||||
if dir==0:
|
if dir==0:
|
||||||
self.saper.move(0)
|
self.saper.rotate("N")
|
||||||
elif dir==1:
|
elif dir==1:
|
||||||
self.saper.move(180)
|
self.saper.rotate("S")
|
||||||
elif dir==2:
|
elif dir==2:
|
||||||
self.saper.move(270)
|
self.saper.rotate("W")
|
||||||
elif dir==3:
|
elif dir==3:
|
||||||
self.saper.move(90)
|
self.saper.rotate("E")
|
||||||
|
self.saper.move()
|
98
classes/bfs.py
Normal file
98
classes/bfs.py
Normal file
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -201,6 +201,7 @@ class NPC:
|
|||||||
#saper
|
#saper
|
||||||
class Minesweeper:
|
class Minesweeper:
|
||||||
size:int
|
size:int
|
||||||
|
rotation_degrees:int
|
||||||
position_x:int
|
position_x:int
|
||||||
position_y:int
|
position_y:int
|
||||||
image:pygame.surface.Surface
|
image:pygame.surface.Surface
|
||||||
@ -223,6 +224,7 @@ class Minesweeper:
|
|||||||
self.image = pygame.image.load("assets/sprites/saper_fun_sized.png")
|
self.image = pygame.image.load("assets/sprites/saper_fun_sized.png")
|
||||||
self.image = pygame.transform.scale(self.image, (self.size, self.size))
|
self.image = pygame.transform.scale(self.image, (self.size, self.size))
|
||||||
self.rotated_image = self.image
|
self.rotated_image = self.image
|
||||||
|
self.rotation_degrees=0
|
||||||
|
|
||||||
def set_map(self, map:Map):
|
def set_map(self, map:Map):
|
||||||
self.current_map = map
|
self.current_map = map
|
||||||
@ -244,6 +246,8 @@ class Minesweeper:
|
|||||||
finished=True
|
finished=True
|
||||||
elif self.offset_y<0:
|
elif self.offset_y<0:
|
||||||
self.offset_y+=dist
|
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:
|
if self.offset_y>=0:
|
||||||
finished=True
|
finished=True
|
||||||
|
|
||||||
@ -258,7 +262,24 @@ class Minesweeper:
|
|||||||
window.blit(self.rotated_image, position_on_screen)
|
window.blit(self.rotated_image, position_on_screen)
|
||||||
self.update_offset(delta)
|
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
|
#południe - 0
|
||||||
#wschód - 90
|
#wschód - 90
|
||||||
#północ - 180
|
#północ - 180
|
||||||
@ -266,6 +287,10 @@ class Minesweeper:
|
|||||||
if self.offset_x!=0 or self.offset_y!=0:
|
if self.offset_x!=0 or self.offset_y!=0:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if dir==-1:
|
||||||
|
dir = self.rotation_degrees
|
||||||
|
else:
|
||||||
|
self.rotation_degrees=dir
|
||||||
self.rotated_image = pygame.transform.rotate(self.image, dir)
|
self.rotated_image = pygame.transform.rotate(self.image, dir)
|
||||||
|
|
||||||
move_legal=True
|
move_legal=True
|
||||||
@ -283,11 +308,9 @@ class Minesweeper:
|
|||||||
|
|
||||||
if next_x == self.current_map.tiles_x or next_x == -1:
|
if next_x == self.current_map.tiles_x or next_x == -1:
|
||||||
move_legal=False
|
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
|
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
|
|
||||||
if self.current_map.terrain_matrix[next_y][next_x]>9:
|
|
||||||
move_legal=False
|
move_legal=False
|
||||||
|
|
||||||
for cliff in self.current_map.cliffs:
|
for cliff in self.current_map.cliffs:
|
||||||
@ -335,6 +358,38 @@ class Minesweeper:
|
|||||||
def drop_civilians(self):
|
def drop_civilians(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def sensor(self):
|
def sensor(self, x:int=-1, y:int=-1):
|
||||||
sensor_list = [[],[],[]]
|
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
|
return sensor_list
|
19
classes/node.py
Normal file
19
classes/node.py
Normal file
@ -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
|
||||||
|
|
||||||
|
|
@ -6,12 +6,14 @@ class Window:
|
|||||||
height:int
|
height:int
|
||||||
title:str
|
title:str
|
||||||
icon_path:str
|
icon_path:str
|
||||||
|
paused:bool
|
||||||
|
|
||||||
def __init__(self, width:int=640, height:int=480, title="", icon_path=""):
|
def __init__(self, width:int=640, height:int=480, title="", icon_path=""):
|
||||||
self.set_resolution(width,height)
|
self.set_resolution(width,height)
|
||||||
self.set_title(title)
|
self.set_title(title)
|
||||||
self.set_icon(icon_path)
|
self.set_icon(icon_path)
|
||||||
self.mount()
|
self.mount()
|
||||||
|
self.paused=False
|
||||||
|
|
||||||
def set_resolution(self, width:int, height:int):
|
def set_resolution(self, width:int, height:int):
|
||||||
self.width = width
|
self.width = width
|
||||||
|
19
main.py
19
main.py
@ -3,7 +3,7 @@ import pygame
|
|||||||
#system - klasy związane z pygame
|
#system - klasy związane z pygame
|
||||||
#minesweeper - klasy związane z samym saperem
|
#minesweeper - klasy związane z samym saperem
|
||||||
#ai - klasa wykonująca ruchy sapera
|
#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
|
#ustalenie wielkości pojedyńczych kawałków mapy, oraz wielkości mapy
|
||||||
TILE_SIZE = 64
|
TILE_SIZE = 64
|
||||||
@ -11,7 +11,7 @@ TILES_X = int(12)
|
|||||||
TILES_Y = int(10)
|
TILES_Y = int(10)
|
||||||
|
|
||||||
#wł/wył muzyki
|
#wł/wył muzyki
|
||||||
MUSIC=True
|
MUSIC=False
|
||||||
|
|
||||||
#ustalenie FPS
|
#ustalenie FPS
|
||||||
FPS = 60
|
FPS = 60
|
||||||
@ -24,6 +24,11 @@ def main():
|
|||||||
#utworzenie okna do gry
|
#utworzenie okna do gry
|
||||||
window = system.Window(TILE_SIZE*TILES_X, TILE_SIZE*TILES_Y, "Intelligent Minesweeper", "icon.png")
|
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
|
#utworzenie objektu mapy, wygenerowanie jej i narysowanie na ekranie
|
||||||
map = minesweeper.Map(window, TILE_SIZE, TILES_X, TILES_Y)
|
map = minesweeper.Map(window, TILE_SIZE, TILES_X, TILES_Y)
|
||||||
map.generate()
|
map.generate()
|
||||||
@ -33,6 +38,7 @@ def main():
|
|||||||
saper = minesweeper.Minesweeper(0,0, TILE_SIZE)
|
saper = minesweeper.Minesweeper(0,0, TILE_SIZE)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#utworzenie objektu klasy AI
|
#utworzenie objektu klasy AI
|
||||||
AI = ai.AI(window, map, saper)
|
AI = ai.AI(window, map, saper)
|
||||||
#wykonanie funkcji ready() AI
|
#wykonanie funkcji ready() AI
|
||||||
@ -46,13 +52,20 @@ def main():
|
|||||||
delta = clock.tick(FPS)
|
delta = clock.tick(FPS)
|
||||||
|
|
||||||
#wykonanie funkcji update() AI
|
#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
|
#narysowanie terenu i obiektów
|
||||||
map.draw_tiles()
|
map.draw_tiles()
|
||||||
map.draw_objects()
|
map.draw_objects()
|
||||||
saper.draw(window.window, delta)
|
saper.draw(window.window, delta)
|
||||||
|
|
||||||
|
#pauza
|
||||||
|
if window.paused:
|
||||||
|
window.window.blit(pause_menu, (0,0))
|
||||||
|
|
||||||
#odświeżenie ekranu
|
#odświeżenie ekranu
|
||||||
pygame.display.update()
|
pygame.display.update()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user