Merge pull request 'Changing bfs into astar using 'Field' class' (#11) from Astar into main
Reviewed-on: s473634/TurboTraktor#11
This commit is contained in:
commit
f4b2554c98
16
main.py
16
main.py
@ -2,10 +2,10 @@ import pygame
|
|||||||
import sys
|
import sys
|
||||||
import random
|
import random
|
||||||
from settings import screen_height, screen_width, SIZE, SPECIES, block_size, tile, road_coords, directions
|
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.Tractor import Tractor
|
||||||
from src.Plant import Plant
|
from src.Plant import Plant
|
||||||
from src.bfs import BFS
|
from src.bfs import Astar
|
||||||
|
|
||||||
# pygame initialization
|
# pygame initialization
|
||||||
pygame.init()
|
pygame.init()
|
||||||
@ -33,20 +33,22 @@ tractor_group.add(tractor)
|
|||||||
#PLANTS
|
#PLANTS
|
||||||
plant_group = pygame.sprite.Group()
|
plant_group = pygame.sprite.Group()
|
||||||
plant_group = seedForFirstTime()
|
plant_group = seedForFirstTime()
|
||||||
|
fields = return_fields_list()
|
||||||
|
|
||||||
#
|
#
|
||||||
tractor_move = pygame.USEREVENT + 1
|
tractor_move = pygame.USEREVENT + 1
|
||||||
pygame.time.set_timer(tractor_move, 800)
|
pygame.time.set_timer(tractor_move, 800)
|
||||||
moves = []
|
moves = []
|
||||||
goal_bfs = BFS()
|
goal_astar = Astar()
|
||||||
destination = (random.randrange(0, 936, 36), random.randrange(0, 900, 36))
|
destination = (random.randrange(0, 936, 36), random.randrange(0, 900, 36))
|
||||||
print("Destination: ", destination)
|
print("Destination: ", destination)
|
||||||
moves = goal_bfs.search(
|
moves = goal_astar.search(
|
||||||
[tractor.rect.x, tractor.rect.y, directions[tractor.rotation]], destination)
|
[tractor.rect.x, tractor.rect.y, directions[tractor.rotation]], destination)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
running = True
|
running = True
|
||||||
|
|
||||||
while running:
|
while running:
|
||||||
for event in pygame.event.get():
|
for event in pygame.event.get():
|
||||||
@ -61,7 +63,9 @@ if __name__ == "__main__":
|
|||||||
running = False
|
running = False
|
||||||
if event.type == tractor_move:
|
if event.type == tractor_move:
|
||||||
if len(moves) != 0:
|
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])
|
tractor.movement(step[0])
|
||||||
|
|
||||||
|
|
||||||
|
10
src/Field.py
10
src/Field.py
@ -1,13 +1,13 @@
|
|||||||
from pygame.sprite import Sprite
|
from pygame.sprite import Sprite
|
||||||
|
|
||||||
class Field(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):
|
fertilizer_degree, development_degree, plant_type, fertilizer_type, to_water):
|
||||||
|
super().__init__()
|
||||||
self.type = type
|
self.type = type
|
||||||
self.row_id = row_id
|
self.x = x
|
||||||
self.col_id = col_id
|
self.y = y
|
||||||
self.position = (row_id, col_id)
|
self.position = (x, y)
|
||||||
self.image = image
|
self.image = image
|
||||||
self.cost = cost
|
self.cost = cost
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ class Tractor(pygame.sprite.Sprite):
|
|||||||
self.movement('F')
|
self.movement('F')
|
||||||
|
|
||||||
#waits between moves to avoid moving to fast
|
#waits between moves to avoid moving to fast
|
||||||
pygame.time.wait(100)
|
pygame.time.wait(30)
|
||||||
|
|
||||||
def move_forward(self):
|
def move_forward(self):
|
||||||
if self.rect.y > 0 and self.rotation == 0:
|
if self.rect.y > 0 and self.rotation == 0:
|
||||||
|
38
src/bfs.py
38
src/bfs.py
@ -1,14 +1,25 @@
|
|||||||
|
import heapq
|
||||||
from settings import block_size, screen_width, directions
|
from settings import block_size, screen_width, directions
|
||||||
import copy
|
import copy
|
||||||
|
from src.map import get_cost_by_type, get_type_by_position, return_fields_list
|
||||||
|
|
||||||
|
fields = return_fields_list()
|
||||||
|
|
||||||
class Node:
|
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.state = state
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.action = action
|
self.action = action
|
||||||
|
self.g = g
|
||||||
|
self.h = h
|
||||||
|
|
||||||
|
def f(self):
|
||||||
|
return self.g + self.h
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self.f() < other.f()
|
||||||
|
|
||||||
class BFS:
|
class Astar:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.fringe = []
|
self.fringe = []
|
||||||
self.explored = []
|
self.explored = []
|
||||||
@ -16,6 +27,7 @@ class BFS:
|
|||||||
def successor(self, state):
|
def successor(self, state):
|
||||||
pos_x, pos_y, rotation = state
|
pos_x, pos_y, rotation = state
|
||||||
options = []
|
options = []
|
||||||
|
cost = get_cost_by_type(get_type_by_position(fields, pos_x, pos_y))
|
||||||
|
|
||||||
if rotation == directions[0]:
|
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])]
|
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):
|
for s, a in zip(states, actions):
|
||||||
if self.valid_state(s):
|
if self.valid_state(s):
|
||||||
options.append((a, s))
|
options.append((a, s, cost))
|
||||||
|
|
||||||
return options
|
return options
|
||||||
|
|
||||||
@ -41,6 +53,9 @@ class BFS:
|
|||||||
if pos_x < 0 or pos_x >= screen_width or pos_y < 0 or pos_y >= screen_width:
|
if pos_x < 0 or pos_x >= screen_width or pos_y < 0 or pos_y >= screen_width:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def heuristic(self, state, goal):
|
||||||
|
return abs(state[0] - goal[0]) + abs(state[1] - goal[1])
|
||||||
|
|
||||||
def goal_path(self, elem):
|
def goal_path(self, elem):
|
||||||
path = []
|
path = []
|
||||||
@ -49,27 +64,30 @@ class BFS:
|
|||||||
path.append([elem.action, elem.state[0], elem.state[1]])
|
path.append([elem.action, elem.state[0], elem.state[1]])
|
||||||
elem = elem.parent
|
elem = elem.parent
|
||||||
|
|
||||||
path = path[::-1]
|
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def search(self, istate, goaltest):
|
def search(self, istate, goaltest):
|
||||||
x, y, rotation = istate
|
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:
|
while True:
|
||||||
if len(self.fringe) == 0:
|
if len(self.fringe) == 0:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
elem = self.fringe.pop(0)
|
_, elem = heapq.heappop(self.fringe)
|
||||||
|
|
||||||
if elem.state[0] == goaltest[0] and elem.state[1] == goaltest[1]:
|
if elem.state[0] == goaltest[0] and elem.state[1] == goaltest[1]:
|
||||||
return self.goal_path(elem)
|
return self.goal_path(elem)
|
||||||
|
|
||||||
self.explored.append(elem.state)
|
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:
|
if state not in self.explored:
|
||||||
x = Node(state, elem, action)
|
g = elem.g + cost # cost to move from parent node to current node is based on the field type.
|
||||||
self.fringe.append(x)
|
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))
|
||||||
|
|
||||||
|
|
||||||
|
31
src/map.py
31
src/map.py
@ -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 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
|
from src.Plant import Plant
|
||||||
import random
|
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):
|
def drawRoads(screen):
|
||||||
#drawing roads:
|
#drawing roads:
|
||||||
road = pygame.image.load("assets/road.jpeg")
|
road = pygame.image.load("assets/road.jpeg")
|
||||||
@ -12,9 +37,11 @@ def drawRoads(screen):
|
|||||||
for x in road_coords:
|
for x in road_coords:
|
||||||
for block in range(26):
|
for block in range(26):
|
||||||
screen.blit(road, (x*block_size, block * 36))
|
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 y in road_coords:
|
||||||
for block in range(26):
|
for block in range(26):
|
||||||
screen.blit(road, (block * 36, y*block_size))
|
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_img = pygame.image.load('assets/barn.png')
|
||||||
barn = pygame.transform.scale(barn_img, tile)
|
barn = pygame.transform.scale(barn_img, tile)
|
||||||
@ -33,8 +60,12 @@ def seedForFirstTime():
|
|||||||
new_plant = Plant(plant,0, x, y)
|
new_plant = Plant(plant,0, x, y)
|
||||||
blocks_seeded_in_field = blocks_seeded_in_field + 1
|
blocks_seeded_in_field = blocks_seeded_in_field + 1
|
||||||
plant_group.add(new_plant)
|
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
|
return plant_group
|
||||||
|
|
||||||
|
def return_fields_list():
|
||||||
|
return fields
|
||||||
|
|
||||||
|
|
||||||
# to-be-done with minecraft farmland graphic xD
|
# to-be-done with minecraft farmland graphic xD
|
||||||
# maybe this function should be in drawRoads (ofc with changed name), not separated
|
# maybe this function should be in drawRoads (ofc with changed name), not separated
|
||||||
|
Loading…
Reference in New Issue
Block a user