merged new agent, display_assets and bfs
This commit is contained in:
parent
1efe763937
commit
fd6fabfc00
25
agent.py
25
agent.py
@ -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:
|
||||||
@ -13,6 +14,28 @@ class Agent:
|
|||||||
data = json.load(json_data)
|
data = json.load(json_data)
|
||||||
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.UP
|
||||||
|
|
||||||
|
def rotate_left(self):
|
||||||
|
self.direction = self.direction.previous()
|
||||||
|
|
||||||
|
def rotate_right(self):
|
||||||
|
self.direction = self.direction.next()
|
||||||
|
|
||||||
|
def go(self):
|
||||||
|
if self.direction == const.Direction.RIGHT:
|
||||||
|
temp = self.go_right()
|
||||||
|
self.position[1] = temp[1]
|
||||||
|
elif self.direction == const.Direction.LEFT:
|
||||||
|
temp = self.go_left()
|
||||||
|
self.position[1] = temp[1]
|
||||||
|
elif self.direction == const.Direction.UP:
|
||||||
|
temp = self.go_up()
|
||||||
|
self.position[0] = temp[0]
|
||||||
|
elif self.direction == const.Direction.DOWN:
|
||||||
|
temp = self.go_down()
|
||||||
|
self.position[0] = temp[0]
|
||||||
|
|
||||||
def go_right(self):
|
def go_right(self):
|
||||||
|
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
47
main.py
47
main.py
@ -1,10 +1,12 @@
|
|||||||
# 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 +24,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,43 +56,30 @@ 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 len(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:
|
||||||
running = False
|
running = False
|
||||||
|
|
||||||
# Assigning all input from keyboard as variables into an array
|
|
||||||
keys = pygame.key.get_pressed()
|
|
||||||
|
|
||||||
# Depending on what key we press, the agent will move in that direction
|
|
||||||
# DISCRETION : The only keys that are available are arrow keys
|
|
||||||
# DISCRETION : is_valid_move is a new brand function that now plays a critical role in movement of our Agent (It is NOT just the "check up" function anymore)
|
|
||||||
if keys[pygame.K_RIGHT]:
|
|
||||||
target_row, target_column = minefield.agent.go_right()
|
|
||||||
minefield.is_valid_move(target_row, target_column)
|
|
||||||
|
|
||||||
elif keys[pygame.K_LEFT]:
|
|
||||||
target_row, target_column = minefield.agent.go_left()
|
|
||||||
minefield.is_valid_move(target_row, target_column)
|
|
||||||
|
|
||||||
elif keys[pygame.K_UP]:
|
|
||||||
target_row, target_column = minefield.agent.go_up()
|
|
||||||
minefield.is_valid_move(target_row, target_column)
|
|
||||||
|
|
||||||
elif keys[pygame.K_DOWN]:
|
|
||||||
target_row, target_column = minefield.agent.go_down()
|
|
||||||
minefield.is_valid_move(target_row, target_column)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
@ -42,6 +44,14 @@ class Direction(Enum):
|
|||||||
DOWN = 2
|
DOWN = 2
|
||||||
LEFT = 3
|
LEFT = 3
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
v = (self.value + 1) % 4
|
||||||
|
return Direction(v)
|
||||||
|
|
||||||
|
def previous (self):
|
||||||
|
v = (self.value - 1) % 4
|
||||||
|
return Direction(v)
|
||||||
|
|
||||||
|
|
||||||
class Action(Enum):
|
class Action(Enum):
|
||||||
ROTATE_LEFT = 0
|
ROTATE_LEFT = 0
|
||||||
|
@ -2,9 +2,10 @@ from __future__ import annotations
|
|||||||
from typing import List, Set
|
from typing import List, Set
|
||||||
|
|
||||||
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 = (2, 2)
|
||||||
|
|
||||||
|
|
||||||
class State:
|
class State:
|
||||||
@ -13,6 +14,12 @@ class State:
|
|||||||
self.column = column
|
self.column = column
|
||||||
self.direction = direction
|
self.direction = direction
|
||||||
|
|
||||||
|
# def __eq__(self, other):
|
||||||
|
# if not isinstance(other, State):
|
||||||
|
# # don't attempt to compare against unrelated types
|
||||||
|
# return NotImplemented
|
||||||
|
# return self.row == other.row and self.column == other.column and self.direction == other.direction
|
||||||
|
|
||||||
|
|
||||||
class Node:
|
class Node:
|
||||||
def __init__(self, state: State, parent: Node = None, action: Action = None):
|
def __init__(self, state: State, parent: Node = None, action: Action = None):
|
||||||
@ -20,6 +27,12 @@ class Node:
|
|||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.action = action
|
self.action = action
|
||||||
|
|
||||||
|
# def __eq__(self, other):
|
||||||
|
# if not isinstance(other, Node):
|
||||||
|
# # don't attempt to compare against unrelated types
|
||||||
|
# return NotImplemented
|
||||||
|
# return self.state == other.state and self.parent == other.parent and self.action == other.action
|
||||||
|
|
||||||
|
|
||||||
def goal_test(state: State):
|
def goal_test(state: State):
|
||||||
if (state.row, state.column) == GOAL:
|
if (state.row, state.column) == GOAL:
|
||||||
@ -27,26 +40,32 @@ 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()
|
||||||
|
|
||||||
|
# root Node
|
||||||
fringe.append(Node(initial_state))
|
fringe.append(Node(initial_state))
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@ -54,11 +73,12 @@ def graphsearch(fringe: List[Node], explored: Set[Node], initial_state: State):
|
|||||||
if not len(fringe):
|
if not len(fringe):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# get first element from fringe
|
||||||
element = fringe.pop(0)
|
element = fringe.pop(0)
|
||||||
|
|
||||||
# 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 +87,41 @@ 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)
|
||||||
|
|
||||||
for successor in get_successors(element.state):
|
# loop through every possible next action
|
||||||
|
for successor in get_successors(element.state, minefield):
|
||||||
# either me or the pseudocode is dumb
|
# either me or the pseudocode is dumb
|
||||||
# somebody has to verify it
|
# somebody has to verify it
|
||||||
fringe_states = [el.state for el in fringe]
|
fringe_states = [el.state for el in fringe]
|
||||||
explored_states = [el.state for el in explored]
|
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:
|
if successor[1] not in fringe_states and \
|
||||||
|
successor[1] not in explored_states:
|
||||||
|
|
||||||
new_node = Node(state=successor.state,
|
# 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)
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
||||||
|
Loading…
Reference in New Issue
Block a user