improving a_star algorithm
This commit is contained in:
parent
b46ebc9b3e
commit
7e61c61116
Binary file not shown.
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 16 KiB |
Binary file not shown.
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 17 KiB |
@ -22,10 +22,13 @@ for name, val in {
|
|||||||
'grass_02_mineAT_01': 1,
|
'grass_02_mineAT_01': 1,
|
||||||
'grass_02_mineAP_02': 1,
|
'grass_02_mineAP_02': 1,
|
||||||
'grass_02_mineAP_03': 1,
|
'grass_02_mineAP_03': 1,
|
||||||
|
'mud_01':0,
|
||||||
|
'mud_02':1
|
||||||
}.items():
|
}.items():
|
||||||
IMAGES.append(
|
IMAGES.append(
|
||||||
Image(
|
Image(
|
||||||
val,
|
val,
|
||||||
|
name,
|
||||||
pg.image.load(
|
pg.image.load(
|
||||||
main_path + '/images/Tiles/' + name + ".png"
|
main_path + '/images/Tiles/' + name + ".png"
|
||||||
),
|
),
|
||||||
|
@ -8,7 +8,7 @@ from tilesFactory import TilesFactory
|
|||||||
def generate_field() -> List[List[Tile]]:
|
def generate_field() -> List[List[Tile]]:
|
||||||
tiles_factory = TilesFactory()
|
tiles_factory = TilesFactory()
|
||||||
tiles_list = tiles_factory.get_tiles_list()
|
tiles_list = tiles_factory.get_tiles_list()
|
||||||
return [choices(tiles_list, weights=[10, 10, 4, 4, 4, 4, 4, 4, 4, 4, 4], k=10) for _ in range(10)]
|
return [choices(tiles_list, weights=[10, 10, 4, 4, 4, 4, 4, 4, 4, 4, 4,2,2], k=12) for _ in range(12)]
|
||||||
|
|
||||||
|
|
||||||
class Environment:
|
class Environment:
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
|
import string
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from pygame import image
|
from pygame import image
|
||||||
|
|
||||||
|
|
||||||
class Image:
|
class Image:
|
||||||
def __init__(self, parent: int, img: image, mine_type: Union[str, None]):
|
def __init__(self, parent: int, name: string, img: image, mine_type: Union[str, None]):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.img = img
|
self.img = img
|
||||||
self.mine_type = mine_type
|
self.mine_type = mine_type
|
||||||
|
self.name = name
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from typing import Tuple
|
||||||
|
|
||||||
import pygame as pg
|
import pygame as pg
|
||||||
|
|
||||||
from agent import Agent
|
from agent import Agent
|
||||||
@ -5,6 +7,7 @@ from game_ui import GameUi
|
|||||||
from const import ICON, IMAGES
|
from const import ICON, IMAGES
|
||||||
from environment import Environment
|
from environment import Environment
|
||||||
from search_algoritms.BFS import breadth_first_search
|
from search_algoritms.BFS import breadth_first_search
|
||||||
|
from src.search_algoritms.a_star import a_star, nearest_bomb
|
||||||
from tilesFactory import TilesFactory
|
from tilesFactory import TilesFactory
|
||||||
|
|
||||||
|
|
||||||
@ -64,6 +67,8 @@ def main():
|
|||||||
while env.mine_count:
|
while env.mine_count:
|
||||||
print('-'*20)
|
print('-'*20)
|
||||||
path, actions = breadth_first_search(env.field, agent.x, agent.y, agent.direction)
|
path, actions = breadth_first_search(env.field, agent.x, agent.y, agent.direction)
|
||||||
|
#xd: Tuple[int,int] = Tuple[agent.x, agent.y]
|
||||||
|
# path, actions = a_star(env.field, agent.x, agent.y, agent.direction, nearest_bomb((agent.x, agent.y), env.field))
|
||||||
if not path and not env.field[agent.y][agent.x].mine:
|
if not path and not env.field[agent.y][agent.x].mine:
|
||||||
print('Unable to find path, rocks are in the way')
|
print('Unable to find path, rocks are in the way')
|
||||||
break
|
break
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import queue
|
import queue
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from node import Node
|
from src.node import Node
|
||||||
from tile import Tile
|
from src.tile import Tile
|
||||||
from .helpers import successor, get_path_actions
|
from .helpers import successor, get_path_actions
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
from node import Node
|
from src.node import Node
|
||||||
from tile import Tile
|
from src.tile import Tile
|
||||||
from .helpers import successor, get_path_actions
|
from .helpers import successor, get_path_actions, calculate_priority
|
||||||
|
from ..mine import Mine
|
||||||
|
|
||||||
|
|
||||||
def a_star(field: List[List[Tile]], start_x: int, start_y: int, start_direction: int, goal: Tuple[int, int]):
|
def a_star(field: List[List[Tile]], start_x: int, start_y: int, start_direction: int, goal: Tuple[int, int]):
|
||||||
explored = []
|
explored = []
|
||||||
node_queue: List[Tuple[int, Node]] = [(1, Node(start_x, start_y, start_direction))]
|
node_queue: List[Tuple[int, Node]] = [(field[start_x][start_y].weight, Node(start_x, start_y, start_direction))]
|
||||||
# do kolejki dodawać krotke (priorytet, obiekt)
|
# do kolejki dodawać krotke (priorytet, obiekt)
|
||||||
|
|
||||||
while node_queue:
|
while node_queue:
|
||||||
@ -21,14 +22,36 @@ def a_star(field: List[List[Tile]], start_x: int, start_y: int, start_direction:
|
|||||||
explored.append(node)
|
explored.append(node)
|
||||||
for x, y, direction, action in successor(field, node.x, node.y, node.direction):
|
for x, y, direction, action in successor(field, node.x, node.y, node.direction):
|
||||||
neighbour_node = Node(x, y, direction, node, action)
|
neighbour_node = Node(x, y, direction, node, action)
|
||||||
neighbour_priority = calculate_priority(node, goal)
|
neighbour_priority = calculate_priority(field, node, goal)
|
||||||
if neighbour_node not in explored and all(neighbour_node not in queue_tuple for queue_tuple in node_queue):
|
if neighbour_node not in explored and all(neighbour_node not in queue_tuple for queue_tuple in node_queue):
|
||||||
node_queue.append((neighbour_priority, neighbour_node))
|
node_queue.append((neighbour_priority, neighbour_node))
|
||||||
node_queue = sorted(node_queue, key=itemgetter(0))
|
node_queue = sorted(node_queue, key=itemgetter(0))
|
||||||
elif (index := [
|
elif (index := [
|
||||||
index for index, queue_tuple in enumerate(node_queue) if neighbour_priority > queue_tuple[0]
|
index for index, queue_tuple in enumerate(node_queue) if neighbour_priority > queue_tuple[0] and neighbour_node == queue_tuple[1]
|
||||||
][0]):
|
]):
|
||||||
node_queue[index] = (neighbour_priority, neighbour_node)
|
print(index)
|
||||||
|
node_queue[index[0]] = (neighbour_priority, neighbour_node)
|
||||||
node_queue = sorted(node_queue, key=itemgetter(0))
|
node_queue = sorted(node_queue, key=itemgetter(0))
|
||||||
|
|
||||||
return False, False
|
return False, False
|
||||||
|
|
||||||
|
|
||||||
|
def heuristic(a: Tuple[int, int], b: Tuple[int, int]):
|
||||||
|
(x1,y1) = a
|
||||||
|
(x2,y2) = b
|
||||||
|
return abs(x1 - x2) + abs(y1 - y2)
|
||||||
|
|
||||||
|
|
||||||
|
def nearest_bomb(a: Tuple[int, int],field: List[List[Tile]]):
|
||||||
|
min = 20
|
||||||
|
min_x = 0
|
||||||
|
min_y = 0
|
||||||
|
for x in range(10):
|
||||||
|
for y in range(10):
|
||||||
|
if issubclass(Mine,field[x][y].mine.__class__):
|
||||||
|
distance = abs(a[0] - x) + abs(a[1] - y)
|
||||||
|
if distance < min:
|
||||||
|
min = distance
|
||||||
|
min_x = x
|
||||||
|
min_y = y
|
||||||
|
return (min_x, min_y)
|
@ -1,9 +1,31 @@
|
|||||||
from typing import List
|
from typing import List, Tuple
|
||||||
|
|
||||||
import pygame as pg
|
import pygame as pg
|
||||||
|
|
||||||
from tile import Tile
|
from src.node import Node
|
||||||
from node import Node
|
from src.tile import Tile
|
||||||
|
|
||||||
|
|
||||||
|
def successor(field: List[List[Tile]], x: int, y: int, direction: int):
|
||||||
|
"""
|
||||||
|
kody klawiszy:
|
||||||
|
:a -> 97
|
||||||
|
:d -> 100
|
||||||
|
:w -> 119
|
||||||
|
"""
|
||||||
|
neighbours = []
|
||||||
|
coord = 'x' if direction in (1, 3) else 'y'
|
||||||
|
shift = -1 if direction in (0, 3) else 1
|
||||||
|
|
||||||
|
neighbours.append((x, y, (direction - 1) % 4, pg.K_a))
|
||||||
|
neighbours.append((x, y, (direction + 1) % 4, pg.K_d))
|
||||||
|
|
||||||
|
if coord == 'x' and 0 <= x + shift <= 9 and field[y][x + shift].number not in (2, 3):
|
||||||
|
neighbours.append((x + shift, y, direction, pg.K_w))
|
||||||
|
elif coord == 'y' and 0 <= y + shift <= 9 and field[y + shift][x].number not in (2, 3):
|
||||||
|
neighbours.append((x, y + shift, direction, pg.K_w))
|
||||||
|
|
||||||
|
return neighbours
|
||||||
|
|
||||||
|
|
||||||
def successor(field: List[List[Tile]], x: int, y: int, direction: int):
|
def successor(field: List[List[Tile]], x: int, y: int, direction: int):
|
||||||
@ -36,3 +58,37 @@ def get_path_actions(node: Node):
|
|||||||
actions.append(node.action)
|
actions.append(node.action)
|
||||||
node = node.parent
|
node = node.parent
|
||||||
return path[::-1], actions[::-1]
|
return path[::-1], actions[::-1]
|
||||||
|
|
||||||
|
|
||||||
|
def successor_priority(field: List[List[Tile]], x: int, y: int, direction: int):
|
||||||
|
"""
|
||||||
|
kody klawiszy:
|
||||||
|
:a -> 97
|
||||||
|
:d -> 100
|
||||||
|
:w -> 119
|
||||||
|
"""
|
||||||
|
neighbours = []
|
||||||
|
coord = 'x' if direction in (1, 3) else 'y'
|
||||||
|
shift = -1 if direction in (0, 3) else 1
|
||||||
|
|
||||||
|
neighbours.append((x, y, (direction - 1) % 4, pg.K_a))
|
||||||
|
neighbours.append((x, y, (direction + 1) % 4, pg.K_d))
|
||||||
|
|
||||||
|
if coord == 'x' and 0 <= x + shift <= 9 and field[y][x + shift].number not in (2, 3):
|
||||||
|
neighbours.append((x + shift, y, direction, pg.K_w))
|
||||||
|
elif coord == 'y' and 0 <= y + shift <= 9 and field[y + shift][x].number not in (2, 3):
|
||||||
|
neighbours.append((x, y + shift, direction, pg.K_w))
|
||||||
|
|
||||||
|
return neighbours
|
||||||
|
|
||||||
|
|
||||||
|
def cost(field: List[List[Tile]], node):
|
||||||
|
return field[node.x][node.y].weight
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_priority(field: List[List[Tile]], node, goaltest: Tuple[int, int]):
|
||||||
|
return cost(field, node) + heuristic(node, goaltest)
|
||||||
|
|
||||||
|
|
||||||
|
def heuristic(a, b):
|
||||||
|
return abs(a.x - b[0]) + abs(a.y - b[1])
|
||||||
|
@ -5,6 +5,7 @@ from at_mine import ATMine
|
|||||||
|
|
||||||
|
|
||||||
class Tile:
|
class Tile:
|
||||||
def __init__(self, number: int, mine: Union[None, APMine, ATMine] = None):
|
def __init__(self, number: int,weight: int, mine: Union[None, APMine, ATMine] = None):
|
||||||
self.number = number
|
self.number = number
|
||||||
self.mine = mine
|
self.mine = mine
|
||||||
|
self.weight = weight
|
||||||
|
@ -10,9 +10,9 @@ class TilesFactory:
|
|||||||
img = IMAGES[number]
|
img = IMAGES[number]
|
||||||
if img.mine_type:
|
if img.mine_type:
|
||||||
module = import_module(f'{img.mine_type.lower()}_mine')
|
module = import_module(f'{img.mine_type.lower()}_mine')
|
||||||
return Tile(number, getattr(module, f'{img.mine_type}Mine'))
|
return Tile(number, 1, getattr(module, f'{img.mine_type}Mine'))
|
||||||
else:
|
else:
|
||||||
return Tile(number, None)
|
return Tile(number, 1, None) if img.name.find('grass') else Tile(number,3, None)
|
||||||
|
|
||||||
def get_tiles_list(self) -> List[Tile]:
|
def get_tiles_list(self) -> List[Tile]:
|
||||||
return [self.create_tile(i) for i in range(11)]
|
return [self.create_tile(i) for i in range(13)]
|
||||||
|
Loading…
Reference in New Issue
Block a user