jest jakaś funkcja następnika i grafsearch

This commit is contained in:
Yurii 2022-04-07 00:55:36 +02:00
parent f4da3bc9fa
commit 1ad0ffd38f
12 changed files with 271 additions and 22 deletions

8
.idea/.gitignore vendored Normal file
View 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

View 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>

View 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
View 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
View 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
View 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>

View File

@ -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)
self.saper.rotate("E")
self.saper.move()

98
classes/bfs.py Normal file
View 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)

View File

@ -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

19
classes/node.py Normal file
View 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

View File

@ -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

23
main.py
View File

@ -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()