Przeszukiwanie przestrzeni stanów za pomocą BFS

This commit is contained in:
Patryk Drzewiński 2021-04-16 12:52:35 +02:00
parent 26ce5b770e
commit 6c9bda39e6
18 changed files with 304 additions and 92 deletions

Binary file not shown.

Binary file not shown.

View File

@ -3,16 +3,94 @@ from container.piece import Piece
class Agent(Piece): class Agent(Piece):
def __init__(self,x_y): def __init__(self,x_y, square_size):
self.name = "Agent" self.name = "Agent"
self.row = x_y[0] self.col = x_y[0]
self.col = x_y[1] self.row = x_y[1]
self.angle = 0
self.moving = 0
self.rotating = 0
self.move_to = (self.row, self.col)
self.points = 0 self.points = 0
self.img = pygame.image.load(r'container\detective.png') self.img = pygame.image.load(r'container\new_detective.png')
self.square_size = square_size
self.img = pygame.transform.scale(self.img, (int(self.square_size[0]), int(self.square_size[1])))
def draw(self, win):
x = (self.col + 0.5 + (self.move_to[0] - self.col)/10*self.moving)*self.square_size[0]
y = (self.row + 0.5 + (self.move_to[1] - self.row)/10*self.moving)*self.square_size[1]
#win.blit(self.img, (x, y))
self.blitRotate(win, self.img, (x, y), (self.square_size[0]/2, self.square_size[1]/2), self.angle*90 + self.rotating*90/10)
def rotate(self, angle):
if self.moving == self.rotating == 0:
self.rotating += angle
def move(self):
if self.moving == self.rotating == 0:
move_to = (0,-1)
if self.angle == 1: move_to = (-1,0)
if self.angle == 2: move_to = (0,1)
if self.angle == 3: move_to = (1,0)
self.move_to = (self.col + move_to[0], self.row + move_to[1])
self.moving += 1
def update_animation(self):
if self.moving > 0:
self.moving += 1
if self.moving >= 10:
self.moving = 0
self.col, self.row = self.move_to
if self.rotating > 0:
self.rotating += 1
if self.rotating >= 10:
self.rotating = 0
self.angle = (self.angle + 1) % 4
if self.rotating < 0:
self.rotating -= 1
if self.rotating <= -10:
self.rotating = 0
self.angle = (self.angle - 1) % 4
def blitRotate(self, surf, image, pos, originPos, angle):
# calcaulate the axis aligned bounding box of the rotated image
w, h = image.get_size()
box = [pygame.math.Vector2(p) for p in [(0, 0), (w, 0), (w, -h), (0, -h)]]
box_rotate = [p.rotate(angle) for p in box]
min_box = (min(box_rotate, key=lambda p: p[0])[0], min(box_rotate, key=lambda p: p[1])[1])
max_box = (max(box_rotate, key=lambda p: p[0])[0], max(box_rotate, key=lambda p: p[1])[1])
# calculate the translation of the pivot
pivot = pygame.math.Vector2(originPos[0], -originPos[1])
pivot_rotate = pivot.rotate(angle)
pivot_move = pivot_rotate - pivot
# calculate the upper left origin of the rotated image
origin = (pos[0] - originPos[0] + min_box[0] - pivot_move[0], pos[1] - originPos[1] - max_box[1] + pivot_move[1])
# get a rotated image
rotated_image = pygame.transform.rotate(image, angle)
# rotate and blit the image
surf.blit(rotated_image, origin)
# draw rectangle around the image
#pygame.draw.rect(surf, (255, 0, 0), (*origin, *rotated_image.get_size()),2)

View File

@ -1,25 +1,12 @@
import pygame import pygame
import random import random
#sth goes wrong with imports so its for preventing errors
"""
try:
from .constans import GREEN,GREEN_2,WHITE,ROWS,COLUMNS,SQUARE_SIZE,MARGIN
except (ModuleNotFoundError, ImportError):
from constans import GREEN,GREEN_2,WHITE,ROWS,COLUMNS,SQUARE_SIZE,MARGIN
#sth goes wrong with imports so its for preventing errors
try:
from .piece import *
except (ModuleNotFoundError, ImportError):
from piece import *
from agent import *
#from .constans import GREEN,GREEN_2,WHITE,ROWS,COLUMNS,SQUARE_SIZE
"""
from container.constans import * from container.constans import *
from container.tree import Tree from container.tree import Tree
from container.mushroom import Mushroom from container.mushroom import Mushroom
from container.agent import Agent from container.agent import Agent
from container.state import State
from container.graph import Graph
class Board: class Board:
def __init__(self, x = 0, y = 0, width = WIDTH, height = HEIGHT, row = ROWS, col = COLUMNS): def __init__(self, x = 0, y = 0, width = WIDTH, height = HEIGHT, row = ROWS, col = COLUMNS):
@ -29,12 +16,14 @@ class Board:
self.height = height self.height = height
self.row = row self.row = row
self.col = col self.col = col
self.square_size = (self.width // self.col, self.height // self.row) self.square_size = (self.width / self.col, self.height / self.row)
self.board = [[False for j in range(self.col)] for i in range(self.row)] self.board = [[False for j in range(self.row)] for i in range(self.col)]
self.free_spaces = [] self.free_spaces = []
self.update_free_spaces() self.update_free_spaces()
self.agent = Agent(self.free_spaces.pop()) self.agent = Agent(self.free_spaces.pop(), self.square_size)
print(f"Board {col}x{row} with agent on ({self.agent.col},{self.agent.row})")
self.surface = pygame.Surface((self.width, self.height)) self.surface = pygame.Surface((self.width, self.height))
@ -47,64 +36,159 @@ class Board:
x_y = self.free_spaces.pop() x_y = self.free_spaces.pop()
self.board[x_y[0]][x_y[1]] = Mushroom(x_y, random.randint(0, 2)) self.board[x_y[0]][x_y[1]] = Mushroom(x_y, random.randint(0, 2))
for i in range(POISON_MUSHROOMS_MAX): for i in range(POISON_MUSHROOMS_START):
x_y = self.free_spaces.pop() x_y = self.free_spaces.pop()
self.board[x_y[0]][x_y[1]] = Mushroom(x_y, random.randint(0, 2), True) self.board[x_y[0]][x_y[1]] = Mushroom(x_y, random.randint(0, 2), True)
#generowanie przestrzeni stanów
# dla każdego pola (nie będącego drzewem) tworzę 4 stany dla 4 pozycji obrotu
# potem dla każdego stanu dodaję listę stanów sąsiadujących i połączenia te nazywam "rotate_left" "rotate_right" "move"
self.set_of_states = []
id_couunt = 0
for x in range(self.col):
for y in range(self.row):
if self.board[x][y] == False or self.board[x][y].name != "Tree":
for angle in range(4):
self.set_of_states.append(State(id_couunt, x, y, angle))
id_couunt += 1
self.set_of_states[id_couunt-4].adjacent_states.append((id_couunt-3, "rotate_left"))
self.set_of_states[id_couunt-4].adjacent_states.append((id_couunt-1, "rotate_right"))
self.set_of_states[id_couunt-3].adjacent_states.append((id_couunt-4, "rotate_right"))
self.set_of_states[id_couunt-3].adjacent_states.append((id_couunt-2, "rotate_left"))
self.set_of_states[id_couunt-2].adjacent_states.append((id_couunt-3, "rotate_right"))
self.set_of_states[id_couunt-2].adjacent_states.append((id_couunt-1, "rotate_left"))
self.set_of_states[id_couunt-1].adjacent_states.append((id_couunt-4, "rotate_left"))
self.set_of_states[id_couunt-1].adjacent_states.append((id_couunt-2, "rotate_right"))
for state in self.set_of_states:
for s in self.set_of_states:
if state.angle == s.angle == 0 and state.x == s.x and state.y - 1 == s.y: state.adjacent_states.append((s.id, "move"))
elif state.angle == s.angle == 1 and state.x - 1 == s.x and state.y == s.y: state.adjacent_states.append((s.id, "move"))
elif state.angle == s.angle == 2 and state.x == s.x and state.y + 1 == s.y: state.adjacent_states.append((s.id, "move"))
elif state.angle == s.angle == 3 and state.x + 1 == s.x and state.y == s.y: state.adjacent_states.append((s.id, "move"))
self.graph = None
self.path = []
def update_free_spaces(self): def update_free_spaces(self):
self.free_spaces = [] self.free_spaces = []
for x in range(self.row): for x in range(self.col):
for y in range(self.col): for y in range(self.row):
if self.board[x][y] == False: self.free_spaces.append((x,y)) if self.board[x][y] == False: self.free_spaces.append((x,y))
random.shuffle(self.free_spaces) random.shuffle(self.free_spaces)
def get_piece(self,x,y):
#print(self.board[x][y], x, y)
return self.board[x][y]
def draw_squares(self,win): def draw_squares(self,win):
self.surface.fill(GREEN_2) self.surface.fill(GREEN_2)
for row in range(self.row): for x in range(self.col):
for col in range(self.col): for y in range(self.row):
if (row+col) % 2 == 0: if (x+y) % 2 == 0:
pygame.draw.rect(self.surface,GREEN,(col*self.square_size[0], row*self.square_size[1], self.square_size[0], self.square_size[1])) pygame.draw.rect(self.surface,GREEN,(x*self.square_size[0], y*self.square_size[1], self.square_size[0], self.square_size[1]))
win.blit(self.surface, (self.x, self.y)) win.blit(self.surface, (self.x, self.y))
def draw_agent(self,win): def draw_agent(self,win):
self.agent.draw(self.surface, self.square_size) self.agent.draw(self.surface)
win.blit(self.surface, (self.x, self.y)) win.blit(self.surface, (self.x, self.y))
def draw_pieces(self,win): def draw_pieces(self,win):
for row in range(self.row): for x in range(self.col):
for col in range(self.col): for y in range(self.row):
if self.board[row][col] != False: if self.board[x][y] != False:
self.board[row][col].draw(self.surface, self.square_size) self.board[x][y].draw(self.surface, self.square_size)
win.blit(self.surface, (self.x, self.y)) win.blit(self.surface, (self.x, self.y))
def draw_info(self,win): def draw_info(self,win):
myfont = pygame.font.SysFont('Comic Sans MS', 30) myfont = pygame.font.SysFont('Comic Sans MS', 30)
textsurface = myfont.render(str(self.agent.points), False, (0, 0, 0)) textsurface = myfont.render(str(self.agent.points), False, (0, 0, 0))
win.blit(textsurface,(self.x+self.width-textsurface.get_width()-5,self.y-40)) win.blit(textsurface,(self.x+self.width-textsurface.get_width()-5,self.y-40))
def move(self, x, y): # kolumna agneta
if 0 <= self.agent.row + x < self.row and 0 <= self.agent.col + y < self.col: textsurface = myfont.render("c: "+str(self.agent.col), False, (0, 0, 0))
if self.board[self.agent.row + x][self.agent.col + y] == False or self.board[self.agent.row + x][self.agent.col + y].name != "Tree": win.blit(textsurface,(self.x+1,self.y-40))
self.agent.col += y
self.agent.row += x # wiersz agneta
if self.board[self.agent.row][self.agent.col] != False: textsurface = myfont.render("r: "+str(self.agent.row), False, (0, 0, 0))
self.agent.points += self.board[self.agent.row][self.agent.col].points win.blit(textsurface,(self.x+100,self.y-40))
self.board[self.agent.row][self.agent.col] = False
# kierunek agenta
textsurface = myfont.render("a: "+str(self.agent.angle), False, (0, 0, 0))
win.blit(textsurface,(self.x+200,self.y-40))
# id stanu agenta
state = 0
for s in self.set_of_states:
if self.agent.col == s.x and self.agent.row == s.y and self.agent.angle == s.angle: state = s.id
textsurface = myfont.render("s: "+str(state), False, (0, 0, 0))
win.blit(textsurface,(self.x+300,self.y-40))
def update_agent(self):
self.agent.update_animation()
if self.board[self.agent.col][self.agent.row] != False and self.board[self.agent.col][self.agent.row].name == "Mushroom":
self.agent.points += self.board[self.agent.col][self.agent.row].points
self.board[self.agent.col][self.agent.row] = False
self.free_spaces.append((self.agent.col, self.agent.row))
# wykonaj następny ruch na ścieżce
if len(self.path) > 0:
if self.agent.moving == self.agent.rotating == 0:
move = self.path.pop(0)
print(f"execute {move}")
if move[1] == "move": self.agent.move()
elif move[1] == "rotate_left": self.agent.rotate(1)
elif move[1] == "rotate_right": self.agent.rotate(-1)
def next_move(self):
start_state = 0
for state in self.set_of_states:
if state.x == self.agent.col and state.y == self.agent.row and state.angle == self.agent.angle: start_state = state.id
self.graph = Graph(start_state)
state_to_add = [start_state]
self.path = []
# BFS
while len(state_to_add) > 0:
state = state_to_add.pop(0)
print(f"checking {state}, x:{self.set_of_states[state].x}, y:{self.set_of_states[state].y}, a:{self.set_of_states[state].angle}")
self.graph.visit(state)
# test czy znaleźliśmy grzyba
if self.board[self.set_of_states[state].x][self.set_of_states[state].y] != False and self.board[self.set_of_states[state].x][self.set_of_states[state].y].name == "Mushroom" and self.board[self.set_of_states[state].x][self.set_of_states[state].y].poison == False:
self.path = self.graph.get_path(state)
break
# dodawanie kolejnych stanów
for s in self.set_of_states[state].adjacent_states:
print(f"\t checking {s[0]}, x:{self.set_of_states[s[0]].x}, y:{self.set_of_states[s[0]].y}, a:{self.set_of_states[s[0]].angle}, s:{s[1]}")
if self.graph.is_visited(s[0]) == False:
self.graph.add(s[0], state, s[1])
state_to_add.append(s[0])
print(f"\t add {s[0]} {s[1]}")
#print(self.path)
print("-------------------------")
#for v in self.graph.vertices:
# print(f" id:{v.id} parent:{v.parent} move:{v.move}, visited:{v.visited}")

View File

@ -3,8 +3,8 @@ import pygame
#board size variables #board size variables
WIDTH = 1000 WIDTH = 1000
HEIGHT = 700 HEIGHT = 700
ROWS = 7 COLUMNS = 20
COLUMNS = 10 ROWS = 14
#number of mushrooms #number of mushrooms
@ -12,7 +12,7 @@ MUSHROOMS_START = 5
MUSHROOMS_MAX = 10 MUSHROOMS_MAX = 10
POISON_MUSHROOMS_START = 5 POISON_MUSHROOMS_START = 5
POISON_MUSHROOMS_MAX = 10 POISON_MUSHROOMS_MAX = 10
TREES = 5 TREES = 50
#colors in game in rgb #colors in game in rgb

55
container/graph.py Normal file
View File

@ -0,0 +1,55 @@
class Vertex():
def __init__(self, id, parent, depth, move):
self.id = id
self.parent = parent
self.child = []
self.visited = False
self.depth = depth
self.move = move
class Graph():
def __init__(self, root):
self.root = root
self.vertices = [Vertex(root, None, 0, None)]
def add(self, id, parent, move):
for v in self.vertices:
if v.id == id and v.parent == parent:
return
for v in self.vertices:
if v.id == parent:
self.vertices.append(Vertex(id, parent, v.depth+1, move))
v.child.append(id)
return
def visit(self, id):
for v in self.vertices:
if v.id == id: v.visited = True
def is_visited(self, id):
for v in self.vertices:
if v.id == id: return v.visited
return False
def get_path(self, id):
result = []
next = None
for v in self.vertices:
if v.id == id:
result.append([v.id, v.move])
next = v.parent
while next != None:
for v in self.vertices:
if v.id == next:
result.append([v.id, v.move])
next = v.parent
return result[::-1]

View File

@ -4,11 +4,15 @@ import pygame
class Mushroom(Piece): class Mushroom(Piece):
def __init__(self,x_y, img = 0, poison = False): def __init__(self,x_y, img = 0, poison = False):
self.name = "Mushroom" self.name = "Mushroom"
self.row = x_y[0] self.col = x_y[0]
self.col = x_y[1] self.row = x_y[1]
self.poison = poison self.poison = poison
self.img = pygame.image.load(r'container\mushrooms\m'+str(img)+'.png') self.img = pygame.image.load(r'container\mushrooms\m'+str(img)+'.png')
if poison: self.img = pygame.image.load(r'container\mushrooms\pm'+str(img)+'.png') if poison: self.img = pygame.image.load(r'container\mushrooms\pm'+str(img)+'.png')
self.points = img+1 self.points = img+1
if poison: self.points *= -1 if poison: self.points *= -1

BIN
container/new_detective.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -4,8 +4,8 @@ class Piece:
def __init__(self,x_y): def __init__(self,x_y):
self.name = "" self.name = ""
self.row = x_y[0] self.col = x_y[0]
self.col = x_y[1] self.row = x_y[1]
self.img = '' self.img = ''
self.mushroom = False self.mushroom = False
self.isSbThere = False self.isSbThere = False
@ -15,7 +15,7 @@ class Piece:
self.isSbThere = not self.isSbThere self.isSbThere = not self.isSbThere
def draw(self, win, square_size): def draw(self, win, square_size):
win.blit(pygame.transform.scale(self.img, square_size), (self.col*square_size[0], self.row*square_size[1])) win.blit(pygame.transform.scale(self.img, (int(square_size[0]), int(square_size[1]))), (self.col*square_size[0], self.row*square_size[1]))

9
container/state.py Normal file
View File

@ -0,0 +1,9 @@
class State():
def __init__(self, id, x, y, angle):
self.id = id
self.x = x
self.y = y
self.angle = angle
self.adjacent_states = []

View File

@ -4,8 +4,8 @@ import pygame
class Tree(Piece): class Tree(Piece):
def __init__(self,x_y, img = 0): def __init__(self,x_y, img = 0):
self.name = "Tree" self.name = "Tree"
self.row = x_y[0] self.col = x_y[0]
self.col = x_y[1] self.row = x_y[1]
self.img = pygame.image.load(r'container\trees\tree'+str(img)+'.png') self.img = pygame.image.load(r'container\trees\tree'+str(img)+'.png')

38
main.py
View File

@ -2,7 +2,7 @@ import pygame
from container.constans import WIDTH, HEIGHT, ROWS, COLUMNS, GREEN from container.constans import WIDTH, HEIGHT, ROWS, COLUMNS, GREEN
from container.board import Board from container.board import Board
FPS = 8 FPS = 30
#creating game window #creating game window
WIN = pygame.display.set_mode((WIDTH,HEIGHT)) WIN = pygame.display.set_mode((WIDTH,HEIGHT))
@ -18,51 +18,33 @@ def main():
run = True run = True
clock = pygame.time.Clock() #for fps clock = pygame.time.Clock() #for fps
board = Board(0,40,WIDTH,HEIGHT-40) board = Board(0,40,WIDTH,HEIGHT-40)
#board.manage_rows_and_col(ROWS,COLUMNS)
#managing agent location
#current_column = 0
#current_row = 0
#current_piece = board.get_piece(current_row,current_column)
#current_piece.change_status()
#calculate desireable location to pixels
def claculate_position(x,y):
x = SQUARE_SIZE * x
y = SQUARE_SIZE * y
return [x,y]
while run: while run:
clock.tick(FPS) clock.tick(FPS)
#print(current_column,current_row)
for event in pygame.event.get(): for event in pygame.event.get():
if event.type == pygame.QUIT: if event.type == pygame.QUIT:
run = False run = False
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE: board.next_move()
#managing arrow click #managing arrow click
key_input = pygame.key.get_pressed() key_input = pygame.key.get_pressed()
if key_input[pygame.K_LEFT]: board.move(0,-1) if key_input[pygame.K_LEFT]: board.agent.rotate(1)
if key_input[pygame.K_UP]: board.move(-1,0) if key_input[pygame.K_UP]: board.agent.move()
if key_input[pygame.K_RIGHT]: board.move(0,1) if key_input[pygame.K_RIGHT]: board.agent.rotate(-1)
if key_input[pygame.K_DOWN]: board.move(1,0)
"""
#managing agent location
current_piece.change_status()
current_piece = board.get_piece(current_row,current_column)
current_piece.change_status()
"""
#drawing map and detective #drawing map and detective
WIN.fill(GREEN) WIN.fill(GREEN)
board.update_agent()
board.draw_squares(WIN) board.draw_squares(WIN)
board.draw_pieces(WIN) board.draw_pieces(WIN)
board.draw_agent(WIN) board.draw_agent(WIN)
board.draw_info(WIN) board.draw_info(WIN)
#WIN.blit(detective, (claculate_position(current_column,current_row)[0], claculate_position(current_column,current_row)[1]))
pygame.display.update() pygame.display.update()
pygame.quit() pygame.quit()