merged bfs into master

This commit is contained in:
s452645 2021-04-18 18:23:14 +02:00
commit 7b87cb71ed
6 changed files with 118 additions and 64 deletions

View File

@ -3,8 +3,9 @@ import project_constants as const
import json_generator as js import json_generator as js
import json import json
# Class of our agent, initialization of it # Class of our agent, initialization of it
# movment functions (those defiend by the 'go_' prefix are not meant to actually move our agent, they just return some values # movement functions (those defiend by the 'go_' prefix are not meant to actually move our agent, they just return some values
# that are later used by another function called 'is_valid_move' (which is defined in Minefield)); # that are later used by another function called 'is_valid_move' (which is defined in Minefield));
class Agent: class Agent:
@ -14,26 +15,26 @@ class Agent:
self.row, self.column = data['agent_starting_position'].split(",") self.row, self.column = data['agent_starting_position'].split(",")
self.position = [int(self.row), int(self.column)] self.position = [int(self.row), int(self.column)]
# self.direction = const.Direction() # self.direction = const.Direction()
self.direction = 0 self.direction = const.Direction.UP
def rotate_left(self): def rotate_left(self):
self.direction = self.direction.previous() self.direction = self.direction.previous()
def rotate_right(self): def rotate_right(self):
self.direction = self.direction.next() self.direction = self.direction.next()
def go(self): def go(self):
if (self.direction == const.Direction.RIGHT ): if self.direction == const.Direction.RIGHT:
temp = go_right() temp = self.go_right()
self.position[1] = temp[1] self.position[1] = temp[1]
elif (self.direction == const.Direction.LEFT ): elif self.direction == const.Direction.LEFT:
temp = go_left() temp = self.go_left()
self.position[1] = temp[1] self.position[1] = temp[1]
elif (self.direction == const.Direction.UP): elif self.direction == const.Direction.UP:
temp = go_up() temp = self.go_up()
self.position[0] = temp[0] self.position[0] = temp[0]
elif (self.direction == const.Direction.DOWN): elif self.direction == const.Direction.DOWN:
temp = temp = go_down() temp = self.go_down()
self.position[0] = temp[0] self.position[0] = temp[0]
def go_right(self): def go_right(self):
@ -51,4 +52,3 @@ class Agent:
def go_down(self): def go_down(self):
return self.position[0] + 1, self.position[1] return self.position[0] + 1, self.position[1]

View File

@ -29,7 +29,7 @@ def display_sapper(sapper_x, sapper_y, sapper_dir):
if sapper_dir == const.Direction.RIGHT: if sapper_dir == const.Direction.RIGHT:
const.SCREEN.blit( const.SCREEN.blit(
pygame.transform.rotate(const.ASSET_SAPPER, 90), pygame.transform.rotate(const.ASSET_SAPPER, 270),
sapper_screen_coords sapper_screen_coords
) )
@ -41,7 +41,7 @@ def display_sapper(sapper_x, sapper_y, sapper_dir):
if sapper_dir == const.Direction.LEFT: if sapper_dir == const.Direction.LEFT:
const.SCREEN.blit( const.SCREEN.blit(
pygame.transform.rotate(const.ASSET_SAPPER, 270), pygame.transform.rotate(const.ASSET_SAPPER, 90),
sapper_screen_coords sapper_screen_coords
) )

26
main.py
View File

@ -1,10 +1,13 @@
# libraries # libraries
import pygame import pygame
import time
from pyglet.gl import * # for blocky textures from pyglet.gl import * # for blocky textures
# other files of this project # other files of this project
import project_constants as const import project_constants as const
import minefield as mf import minefield as mf
import searching_algorithms.bfs as bfs
from display_assets import display_sapper from display_assets import display_sapper
@ -22,6 +25,12 @@ def main():
# create an instance of Minefield, pass necessary data # create an instance of Minefield, pass necessary data
minefield = mf.Minefield(const.MAP_RANDOM_10x10) minefield = mf.Minefield(const.MAP_RANDOM_10x10)
# get sequence of actions found by BFS algorythm
action_sequence = bfs.graphsearch(initial_state=bfs.State(row=minefield.agent.position[0],
column=minefield.agent.position[1],
direction=const.Direction.UP),
minefield=minefield)
running = True running = True
while running: while running:
# FPS control # FPS control
@ -48,16 +57,25 @@ def main():
display_sapper( display_sapper(
minefield.agent.position[0], minefield.agent.position[0],
minefield.agent.position[1], minefield.agent.position[1],
const.Direction.UP minefield.agent.direction
) )
# update graphics after blitting # update graphics after blitting
pygame.display.update() pygame.display.update()
# ============== # # make the next move from sequence of actions
# === EVENTS === # if any(action_sequence):
# ============== # action = action_sequence.pop(0)
if action == const.Action.ROTATE_LEFT:
minefield.agent.rotate_left()
elif action == const.Action.ROTATE_RIGHT:
minefield.agent.rotate_right()
elif action == const.Action.GO:
minefield.agent.go()
time.sleep(const.ACTION_INTERVAL)
else:
for event in pygame.event.get(): for event in pygame.event.get():
if event.type == pygame.QUIT: if event.type == pygame.QUIT:

View File

@ -93,7 +93,7 @@ class Minefield:
def is_valid_move(self, target_row: int, target_column: int): def is_valid_move(self, target_row: int, target_column: int):
if 0 <= target_row < const.V_GRID_VER_TILES \ if 0 <= target_row < const.V_GRID_VER_TILES \
and 0 <= target_column < const.V_GRID_HOR_TILES \ and 0 <= target_column < const.V_GRID_HOR_TILES \
and self.matrix[target_row][target_column] is None: and self.matrix[target_row][target_column].mine is None:
return True return True

View File

@ -17,6 +17,8 @@ V_NAME_OF_WINDOW = "MineFusion TM"
ASSETS_DIR = os.path.join("resources", "assets") ASSETS_DIR = os.path.join("resources", "assets")
V_FPS = 60 V_FPS = 60
ACTION_INTERVAL = 1 # interval between two actions in seconds
V_TILE_SIZE = 60 V_TILE_SIZE = 60
V_GRID_VER_TILES = V_GRID_HOR_TILES = 10 # vertical (number of rows), horizontal (number of columns) V_GRID_VER_TILES = V_GRID_HOR_TILES = 10 # vertical (number of rows), horizontal (number of columns)
V_SCREEN_PADDING = 10 V_SCREEN_PADDING = 10

View File

@ -1,10 +1,12 @@
from __future__ import annotations from __future__ import annotations
from typing import List, Set from typing import List
import ctypes
from project_constants import Direction, Action from project_constants import Direction, Action
from minefield import Minefield
# temporary goal for testing # temporary goal for testing
GOAL = (9, 9) GOAL = (13, 9)
class State: class State:
@ -27,38 +29,51 @@ def goal_test(state: State):
return False return False
# TODO: depends od Agent Class (rotate/go implementation) def get_successors(state: State, minefield: Minefield):
def get_successors(state: State):
successors = list() successors = list()
# state_left = get Agent State after rotate_left() state_left = State(state.row, state.column, state.direction.previous())
# successors.add("rotate_left", state_left) successors.append((Action.ROTATE_LEFT, state_left))
# state_right = get Agent State after rotate_right() state_right = State(state.row, state.column, state.direction.next())
# successors.add("rotate_right", state_right) successors.append((Action.ROTATE_RIGHT, state_right))
# target = get Agent position after go() target = go(state.row, state.column, state.direction)
# if is_valid_move(target):
# state_go = Agent State after go() if minefield.is_valid_move(target[0], target[1]):
# successors.add("go", state_go) state_go = State(target[0], target[1], state.direction)
successors.append((Action.GO, state_go))
return successors return successors
def graphsearch(fringe: List[Node], explored: Set[Node], initial_state: State): def graphsearch(initial_state: State, minefield: Minefield, fringe: List[Node] = None, explored: List[Node] = None):
# fringe and explored initialization
if fringe is None:
fringe = list()
if explored is None:
explored = list()
explored_states = set()
fringe_states = set()
# root Node
fringe.append(Node(initial_state)) fringe.append(Node(initial_state))
fringe_states.add((initial_state.row, initial_state.column, initial_state.direction))
while True: while True:
# fringe empty -> solution not found # fringe empty -> solution not found
if not len(fringe): if not any(fringe):
return False ctypes.windll.user32.MessageBoxW(0, "Brak rozwiązania", "GAME OVER", 1)
return []
# get first element from fringe
element = fringe.pop(0) element = fringe.pop(0)
fringe_states.remove((element.state.row, element.state.column, element.state.direction))
# solution found, prepare and return actions sequence # if solution was found, prepare and return actions sequence
if goal_test(element.state): if goal_test(element.state):
actions_sequence = list() actions_sequence = [element.action]
parent = element.parent parent = element.parent
while parent is not None: while parent is not None:
@ -67,20 +82,39 @@ def graphsearch(fringe: List[Node], explored: Set[Node], initial_state: State):
actions_sequence.append(parent.action) actions_sequence.append(parent.action)
parent = parent.parent parent = parent.parent
return actions_sequence.reverse() actions_sequence.reverse()
return actions_sequence
explored.add(element) # add current node to explored (prevents infinite cycles)
explored.append(element)
explored_states.add((element.state.row, element.state.column, element.state.direction))
for successor in get_successors(element.state): # loop through every possible next action
# either me or the pseudocode is dumb for successor in get_successors(element.state, minefield):
# somebody has to verify it
fringe_states = [el.state for el in fringe]
explored_states = [el.state for el in explored]
if successor.state not in fringe_states and \ # make sure not to fall into a cycle
successor.state not in explored_states: successor_state = (successor[1].row, successor[1].column, successor[1].direction)
if successor_state not in fringe_states and \
new_node = Node(state=successor.state, successor_state not in explored_states:
# create new Node and add it at the end of fringe
new_node = Node(state=successor[1],
parent=element, parent=element,
action=successor.action) action=successor[0])
fringe.append(new_node) fringe.append(new_node)
fringe_states.add((new_node.state.row, new_node.state.column, new_node.state.direction))
# TEMPORARY METHOD
def go(row, column, direction):
target = tuple()
if direction == Direction.RIGHT:
target = row, column + 1
elif direction == Direction.LEFT:
target = row, column - 1
elif direction == Direction.UP:
target = row - 1, column
elif direction == Direction.DOWN:
target = row + 1, column
return target