Changing bfs into astar using 'Field' class #11

Merged
s473556 merged 1 commits from Astar into main 2023-05-15 13:32:52 +02:00
5 changed files with 75 additions and 22 deletions
Showing only changes of commit 477c0b552a - Show all commits

14
main.py
View File

@ -2,10 +2,10 @@ import pygame
import sys
import random
from settings import screen_height, screen_width, SIZE, SPECIES, block_size, tile, road_coords, directions
from src.map import drawRoads, seedForFirstTime
from src.map import drawRoads, seedForFirstTime, return_fields_list
from src.Tractor import Tractor
from src.Plant import Plant
from src.bfs import BFS
from src.bfs import Astar
# pygame initialization
pygame.init()
@ -33,18 +33,20 @@ tractor_group.add(tractor)
#PLANTS
plant_group = pygame.sprite.Group()
plant_group = seedForFirstTime()
fields = return_fields_list()
#
tractor_move = pygame.USEREVENT + 1
pygame.time.set_timer(tractor_move, 800)
moves = []
goal_bfs = BFS()
goal_astar = Astar()
destination = (random.randrange(0, 936, 36), random.randrange(0, 900, 36))
print("Destination: ", destination)
moves = goal_bfs.search(
moves = goal_astar.search(
[tractor.rect.x, tractor.rect.y, directions[tractor.rotation]], destination)
if __name__ == "__main__":
running = True
@ -61,7 +63,9 @@ if __name__ == "__main__":
running = False
if event.type == tractor_move:
if len(moves) != 0:
step = moves.pop()
moves_list = list(moves) # convert to list
step = moves_list.pop() # pop the last element
moves = tuple(moves_list) # convert back to tuple
tractor.movement(step[0])

View File

@ -1,13 +1,13 @@
from pygame.sprite import Sprite
class Field(Sprite):
def __init__(self, type, row_id, col_id, image, cost, hydration_level , soil,
def __init__(self, type, x, y, image, cost, hydration_level , soil,
fertilizer_degree, development_degree, plant_type, fertilizer_type, to_water):
super().__init__()
self.type = type
self.row_id = row_id
self.col_id = col_id
self.position = (row_id, col_id)
self.x = x
self.y = y
self.position = (x, y)
self.image = image
self.cost = cost

View File

@ -36,7 +36,7 @@ class Tractor(pygame.sprite.Sprite):
self.movement('F')
#waits between moves to avoid moving to fast
pygame.time.wait(100)
pygame.time.wait(30)
def move_forward(self):
if self.rect.y > 0 and self.rotation == 0:

View File

@ -1,14 +1,25 @@
import heapq
from settings import block_size, screen_width, directions
import copy
from src.map import get_cost_by_type, get_type_by_position, return_fields_list
fields = return_fields_list()
class Node:
def __init__(self, state, parent=None, action=None):
def __init__(self, state, parent=None, action=None, g=0, h=0):
self.state = state
self.parent = parent
self.action = action
self.g = g
self.h = h
class BFS:
def f(self):
return self.g + self.h
def __lt__(self, other):
return self.f() < other.f()
class Astar:
def __init__(self):
self.fringe = []
self.explored = []
@ -16,6 +27,7 @@ class BFS:
def successor(self, state):
pos_x, pos_y, rotation = state
options = []
cost = get_cost_by_type(get_type_by_position(fields, pos_x, pos_y))
if rotation == directions[0]:
states = [(pos_x, pos_y - block_size, directions[0]), (pos_x, pos_y, directions[270]), (pos_x, pos_y, directions[90])]
@ -32,7 +44,7 @@ class BFS:
for s, a in zip(states, actions):
if self.valid_state(s):
options.append((a, s))
options.append((a, s, cost))
return options
@ -42,6 +54,9 @@ class BFS:
return False
return True
def heuristic(self, state, goal):
return abs(state[0] - goal[0]) + abs(state[1] - goal[1])
def goal_path(self, elem):
path = []
@ -49,27 +64,30 @@ class BFS:
path.append([elem.action, elem.state[0], elem.state[1]])
elem = elem.parent
path = path[::-1]
return path
def search(self, istate, goaltest):
x, y, rotation = istate
start_node = Node((x, y, rotation))
start_node = Node((x, y, rotation), None, None, 0, self.heuristic(istate, goaltest))
self.fringe.append(start_node)
heapq.heappush(self.fringe, (start_node.f(), start_node))
while True:
if len(self.fringe) == 0:
return False
elem = self.fringe.pop(0)
_, elem = heapq.heappop(self.fringe)
if elem.state[0] == goaltest[0] and elem.state[1] == goaltest[1]:
return self.goal_path(elem)
self.explored.append(elem.state)
for (action, state) in self.successor(elem.state):
for (action, state, cost) in self.successor(elem.state):
if state not in self.explored:
x = Node(state, elem, action)
self.fringe.append(x)
g = elem.g + cost # cost to move from parent node to current node is based on the field type.
h = self.heuristic(state, goaltest) # manhattan distance cost
x = Node(state, elem, action, g, h) #creating the node and pushing it into fringe
heapq.heappush(self.fringe, (x.f(), x))

View File

@ -3,8 +3,33 @@ import pygame
from settings import screen_height, screen_width, SIZE, SPECIES, block_size, tile, road_coords, fields_amount, field_size, field_height, field_width
from src.Plant import Plant
import random
from src.Field import Field
def get_type_by_position(fields, x, y):
for field in fields:
if field.x == x and field.y == y:
return field.plant_type
return None
def get_cost_by_type(plant_type):
#plant_type == None, when field is empty.
if plant_type == None:
return 200
elif plant_type == 'carrot':
return 300
elif plant_type == 'potato':
return 500
elif plant_type == 'beetroot':
return 500
elif plant_type == 'wheat':
return 1000
#else, means that field is type of road.
else:
return 100
fields = pygame.sprite.Group()
def drawRoads(screen):
#drawing roads:
road = pygame.image.load("assets/road.jpeg")
@ -12,9 +37,11 @@ def drawRoads(screen):
for x in road_coords:
for block in range(26):
screen.blit(road, (x*block_size, block * 36))
fields.add(Field('road', x*block_size, block * 36, None, get_cost_by_type('road'), None, None, None, None, 'road', None, None))
for y in road_coords:
for block in range(26):
screen.blit(road, (block * 36, y*block_size))
fields.add(Field('road', block * 36, y*block_size, None, get_cost_by_type('road'), None, None, None, None, 'road', None, None))
barn_img = pygame.image.load('assets/barn.png')
barn = pygame.transform.scale(barn_img, tile)
@ -33,8 +60,12 @@ def seedForFirstTime():
new_plant = Plant(plant,0, x, y)
blocks_seeded_in_field = blocks_seeded_in_field + 1
plant_group.add(new_plant)
fields.add(Field('field', x-18, y-18, None, get_cost_by_type(plant), None, None, None, None, plant, None, None))
return plant_group
def return_fields_list():
return fields
# to-be-done with minecraft farmland graphic xD
# maybe this function should be in drawRoads (ofc with changed name), not separated