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
|
||||
from classes import minesweeper, system
|
||||
from classes import minesweeper, system, bfs
|
||||
from random import randrange
|
||||
|
||||
class AI:
|
||||
@ -19,14 +19,33 @@ class AI:
|
||||
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)
|
||||
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
|
||||
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,6 +287,10 @@ class Minesweeper:
|
||||
if self.offset_x!=0 or self.offset_y!=0:
|
||||
return
|
||||
|
||||
if dir==-1:
|
||||
dir = self.rotation_degrees
|
||||
else:
|
||||
self.rotation_degrees=dir
|
||||
self.rotated_image = pygame.transform.rotate(self.image, dir)
|
||||
|
||||
move_legal=True
|
||||
@ -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
|
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
|
||||
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
|
||||
|
19
main.py
19
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()
|
||||
@ -33,6 +38,7 @@ def main():
|
||||
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()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user