Merge pull request 'Route_planning_bfs' (#2) from Route_planning_bfs into master
Reviewed-on: #2
This commit is contained in:
commit
81602fb3cf
BIN
source/__pycache__/bfs.cpython-311.pyc
Normal file
BIN
source/__pycache__/bfs.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -12,6 +12,9 @@ GROUND = ""
|
||||
# path to ground image
|
||||
GREY = (20, 17, 17, 255)
|
||||
|
||||
|
||||
DIRECTION_NORTH = 1
|
||||
DIRECTION_EAST = 2
|
||||
DIRECTION_SOUTH = 3
|
||||
DIRECTION_WEST = 4
|
||||
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
# create a field here : 1: add tiles, 2: place them
|
||||
import pygame
|
||||
import random
|
||||
|
||||
from area.constants import WIDTH,HEIGHT,FIELD_WIDTH,FIELD_HEIGHT,TILE_SIZE,GREY,ROWS,COLS
|
||||
from area.tractor import Tractor
|
||||
from area.constants import WIDTH,FIELD_WIDTH,TILE_SIZE,GREY,ROWS,COLS
|
||||
from tile import Tile
|
||||
from ground import Dirt
|
||||
|
||||
tiles = []
|
||||
tractor = Tractor(0*TILE_SIZE, 0*TILE_SIZE)
|
||||
|
||||
fieldX = (WIDTH-FIELD_WIDTH)/2
|
||||
# in center of the screen
|
||||
fieldY = 100
|
||||
@ -17,16 +18,19 @@ def positionFieldElements():
|
||||
for t in tiles:
|
||||
t.x += fieldX
|
||||
t.y += fieldY
|
||||
tractor.x += fieldX
|
||||
tractor.y += fieldY
|
||||
|
||||
|
||||
def createTiles():
|
||||
for y in range(0, COLS):
|
||||
for x in range(0, ROWS):
|
||||
tile = Tile(x*TILE_SIZE, y*TILE_SIZE)
|
||||
dirt = Dirt(random.randint(1, 100), random.randint(1, 100))
|
||||
dirt.pests_and_weeds()
|
||||
tile.ground = dirt
|
||||
tile.randomizeContent()
|
||||
tiles.append(tile)
|
||||
positionFieldElements()
|
||||
return tiles
|
||||
|
||||
def createField(win):
|
||||
createTiles()
|
||||
@ -35,11 +39,17 @@ def createField(win):
|
||||
image = pygame.transform.scale(image, (TILE_SIZE, TILE_SIZE))
|
||||
win.blit(image, (t.x, t.y))
|
||||
pygame.display.flip()
|
||||
imageTractor = pygame.image.load(tractor.image).convert_alpha()
|
||||
imageTractor = pygame.transform.scale(imageTractor, (TILE_SIZE, TILE_SIZE))
|
||||
win.blit(imageTractor, (tractor.x, tractor.y))
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
def drawWindow(win):
|
||||
win.fill(GREY)
|
||||
createField(win)
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
def get_tile_coordinates(index):
|
||||
if index < len(tiles):
|
||||
tile = tiles[index]
|
||||
return tile.x, tile.y
|
||||
else:
|
||||
return None
|
@ -1,9 +1,14 @@
|
||||
from crop_protection_product import CropProtectionProduct
|
||||
from area.constants import TILE_SIZE, DIRECTION_EAST, DIRECTION_SOUTH, DIRECTION_WEST, DIRECTION_NORTH
|
||||
from area.field import fieldX, fieldY, tiles
|
||||
import pygame
|
||||
import time
|
||||
|
||||
|
||||
class Tractor:
|
||||
x = None
|
||||
y = None
|
||||
direction = None #direction takes values in the range of 1 to 4 (1->North, 2->East etc...)
|
||||
image = None
|
||||
cypermetryna = CropProtectionProduct("pests", "cereal")
|
||||
diflufenikan = CropProtectionProduct("weeds", "cereal")
|
||||
@ -13,10 +18,25 @@ class Tractor:
|
||||
metazachlor = CropProtectionProduct("weeds", "vegetable")
|
||||
# etc
|
||||
|
||||
def __init__(self, x, y):
|
||||
def __init__(self, x, y, direction, tractor_start, tractor_end):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.image = 'resources/images/tractor.png'
|
||||
|
||||
self.rect = pygame.Rect(x, y, TILE_SIZE, TILE_SIZE)
|
||||
|
||||
self.direction = direction
|
||||
self.image = pygame.image.load('resources/images/tractor_right.png').convert_alpha()
|
||||
|
||||
self.tractor_start = tractor_start #important for bfs - prevents from spawning obstacles on these positions
|
||||
self.tractor_end = tractor_end #
|
||||
|
||||
if (self.direction==1):
|
||||
self.image = pygame.image.load('resources/images/tractor_up.png').convert_alpha()
|
||||
elif (self.direction==3):
|
||||
self.image = pygame.image.load('resources/images/tractor_down.png').convert_alpha()
|
||||
elif (self.direction==4):
|
||||
self.image = pygame.image.load('resources/images/tractor_left.png').convert_alpha()
|
||||
|
||||
|
||||
def work_on_field(self, tile, ground, plant1):
|
||||
if plant1 is None:
|
||||
@ -58,3 +78,84 @@ class Tractor:
|
||||
if ground.nutrients_level < plant1.nutrients_requirements:
|
||||
ground.nutrients_level += 20
|
||||
print("Tractor added some nutrients")
|
||||
|
||||
|
||||
|
||||
def move(self):
|
||||
if self.direction == DIRECTION_EAST:
|
||||
self.rect.x += TILE_SIZE
|
||||
|
||||
elif self.direction == DIRECTION_WEST:
|
||||
self.rect.x -= TILE_SIZE
|
||||
|
||||
elif self.direction == DIRECTION_NORTH:
|
||||
self.rect.y -= TILE_SIZE
|
||||
|
||||
elif self.direction == DIRECTION_SOUTH:
|
||||
self.rect.y += TILE_SIZE
|
||||
|
||||
|
||||
def rotate_to_right(self):
|
||||
if self.direction == 4:
|
||||
self.direction = 1
|
||||
else:
|
||||
self.direction += 1
|
||||
self.image = pygame.transform.rotate(self.image, -90)
|
||||
|
||||
|
||||
def rotate_to_left(self):
|
||||
if self.direction == 1:
|
||||
self.direction = 4
|
||||
else:
|
||||
self.direction -= 1
|
||||
self.image = pygame.transform.rotate(self.image, 90)
|
||||
|
||||
#checks if we can move further and if we won't get out of boundaries - for bfs:
|
||||
def can_it_move_node(node):
|
||||
if node.get_direction() == DIRECTION_EAST and node.get_x() + TILE_SIZE < 830: #last tile on the west has y:797
|
||||
return "move east"
|
||||
elif node.get_direction() == DIRECTION_WEST and node.get_x() - TILE_SIZE >=fieldX:
|
||||
return "move west"
|
||||
elif node.get_direction() == DIRECTION_NORTH and node.get_y() - TILE_SIZE >=fieldY:
|
||||
return "move north"
|
||||
elif node.get_direction() == DIRECTION_SOUTH and node.get_y() + TILE_SIZE < 760: #last tile on the south has y:727
|
||||
return "move south"
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
#checks if there's an obstacle on the given coordinates (important for bfs):
|
||||
def is_obstacle(self, x, y):
|
||||
for tile in tiles:
|
||||
if tile.x == x and tile.y == y:
|
||||
ground = tile.ground
|
||||
if ground.obstacle and self.tractor_start != (x, y) and self.tractor_end != (x,y):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def draw_tractor(self, win):
|
||||
|
||||
imageTractor = pygame.transform.scale(self.image, (TILE_SIZE, TILE_SIZE))
|
||||
win.blit(imageTractor, (self.rect.x, self.rect.y))
|
||||
pygame.display.flip()
|
||||
|
||||
#translates move_list generated by bfs into the actual movement:
|
||||
def do_actions(tractor, WIN, move_list):
|
||||
trail = pygame.image.load("resources/images/background.jpg").convert_alpha()
|
||||
trail = pygame.transform.scale(trail, (TILE_SIZE, TILE_SIZE))
|
||||
|
||||
pygame.display.update()
|
||||
for move in move_list:
|
||||
WIN.blit(trail, (tractor.rect.x, tractor.rect.y, TILE_SIZE, TILE_SIZE))
|
||||
if move == "move":
|
||||
tractor.move()
|
||||
elif move == "rotate_right":
|
||||
tractor.rotate_to_right()
|
||||
elif move == "rotate_left":
|
||||
tractor.rotate_to_left()
|
||||
tractor.draw_tractor(WIN)
|
||||
pygame.display.update()
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
|
171
source/bfs.py
Normal file
171
source/bfs.py
Normal file
@ -0,0 +1,171 @@
|
||||
from area.constants import TILE_SIZE
|
||||
import copy
|
||||
from area.tractor import Tractor
|
||||
|
||||
class Istate:
|
||||
|
||||
def __init__(self, x, y, direction ):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.direction = direction
|
||||
|
||||
|
||||
def get_x(self):
|
||||
return self.x
|
||||
|
||||
def set_x(self, _x):
|
||||
self.x = _x
|
||||
|
||||
def get_y(self):
|
||||
return self.y
|
||||
|
||||
def set_y(self, _y):
|
||||
self.y = _y
|
||||
|
||||
def get_direction(self):
|
||||
return self.direction
|
||||
|
||||
def set_direction(self, _direction):
|
||||
self.parent = _direction
|
||||
|
||||
class Node:
|
||||
|
||||
def __init__(self, x, y, direction, parent, action):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.direction = direction
|
||||
self.action = action
|
||||
self.parent = parent
|
||||
|
||||
|
||||
|
||||
#getters and setters:
|
||||
|
||||
def get_parent(self):
|
||||
return self.parent
|
||||
|
||||
def set_parent(self, _parent):
|
||||
self.parent = _parent
|
||||
|
||||
def get_action(self):
|
||||
return self.action
|
||||
|
||||
def set_action(self, _action):
|
||||
self.parent = _action
|
||||
|
||||
def get_x(self):
|
||||
return self.x
|
||||
|
||||
def set_x(self, _x):
|
||||
self.x = _x
|
||||
|
||||
def get_y(self):
|
||||
return self.y
|
||||
|
||||
def set_y(self, _y):
|
||||
self.y = _y
|
||||
|
||||
def get_direction(self):
|
||||
return self.direction
|
||||
|
||||
def set_direction(self, _direction):
|
||||
self.parent = _direction
|
||||
|
||||
def copy(self):
|
||||
return copy.copy(self)
|
||||
|
||||
|
||||
def goal_test(elem, goalstate):
|
||||
if elem.get_x() == goalstate[0] and elem.get_y() == goalstate[1]:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
#State as a tuple (x,y,direction)
|
||||
|
||||
#actions(string): move, rotate_to_left, rotate_to_right
|
||||
|
||||
#main search function:
|
||||
def graphsearch(istate, succ, goaltest, tractor):
|
||||
|
||||
fringe = []
|
||||
explored = []
|
||||
node = Node(istate.get_x(), istate.get_y(), istate.get_direction(), None, None)
|
||||
fringe.append(node)
|
||||
|
||||
while True:
|
||||
|
||||
if not fringe:
|
||||
return False
|
||||
|
||||
elem = fringe.pop(0)
|
||||
temp = copy.copy(elem)
|
||||
if goal_test(elem, goaltest) is True: #jesli True zwroc ciag akcji
|
||||
return get_moves(elem)
|
||||
|
||||
explored.append(elem)
|
||||
|
||||
for (action, state) in succ(temp, tractor): #dla wszystkich mozliwych stanow i akcjach otrzymanych dla danego wierzcholka
|
||||
fringe_tuple = []
|
||||
explored_tuple = []
|
||||
|
||||
for node in fringe:
|
||||
fringe_tuple.append((node.get_x(), node.get_y(), node.get_direction()))
|
||||
for node in explored:
|
||||
explored_tuple.append((node.get_x(), node.get_y(), node.get_direction()))
|
||||
|
||||
|
||||
if state not in fringe_tuple and state not in explored_tuple:
|
||||
x = Node(state[0], state[1], state[2], elem, action)
|
||||
fringe.append(x)
|
||||
|
||||
|
||||
#funkcja nastepnika - jakie akcje sa mozlwie na danym polu i jaki bedzie stan po wykonaniu tych akcji
|
||||
def succ(elem, tractor):
|
||||
actions_states = []
|
||||
temp = copy.copy(elem.get_direction())
|
||||
|
||||
if temp == 1:
|
||||
temp = 4
|
||||
else:
|
||||
temp -= 1
|
||||
actions_states.append(("rotate_left", (elem.get_x(), elem.get_y(), temp)))
|
||||
|
||||
temp = copy.copy(elem.get_direction())
|
||||
if temp == 4:
|
||||
temp = 1
|
||||
else:
|
||||
temp += 1
|
||||
actions_states.append(("rotate_right", (elem.get_x(), elem.get_y(), temp)))
|
||||
|
||||
temp_move_east = elem.get_x() + TILE_SIZE
|
||||
temp_move_west = elem.get_x() - TILE_SIZE
|
||||
temp_move_north = elem.get_y() - TILE_SIZE
|
||||
temp_move_south = elem.get_y() + TILE_SIZE
|
||||
|
||||
if Tractor.can_it_move_node(elem) == "move east" and not Tractor.is_obstacle(tractor, temp_move_east, elem.get_y()):
|
||||
actions_states.append(("move", (temp_move_east, elem.get_y(), elem.get_direction())))
|
||||
|
||||
elif Tractor.can_it_move_node(elem) == "move west" and not Tractor.is_obstacle(tractor, temp_move_west, elem.get_y()):
|
||||
actions_states.append(("move", (temp_move_west, elem.get_y(), elem.get_direction())))
|
||||
|
||||
elif Tractor.can_it_move_node(elem) == "move north" and not Tractor.is_obstacle(tractor,elem.get_x(), temp_move_north):
|
||||
actions_states.append(("move", (elem.get_x(), temp_move_north, elem.get_direction())))
|
||||
|
||||
elif Tractor.can_it_move_node(elem) == "move south" and not Tractor.is_obstacle(tractor, elem.get_x(), temp_move_south):
|
||||
actions_states.append(("move", (elem.get_x(), temp_move_south, elem.get_direction())))
|
||||
|
||||
return actions_states
|
||||
|
||||
|
||||
|
||||
#returns list of actions
|
||||
def get_moves(elem):
|
||||
move_list = []
|
||||
while (elem.get_parent() != None):
|
||||
move_list.append(elem.get_action())
|
||||
elem = elem.get_parent()
|
||||
move_list.reverse()
|
||||
return move_list
|
||||
|
@ -20,7 +20,7 @@ class Dirt:
|
||||
elif i == 4:
|
||||
self.weed = True
|
||||
self.pest = True
|
||||
elif i == 5 or i == 6 or i == 7:
|
||||
elif i == 5:
|
||||
self.obstacle = True
|
||||
|
||||
# add init, getters,setters
|
||||
|
@ -2,12 +2,14 @@ import pygame
|
||||
import time
|
||||
import random
|
||||
|
||||
from area.constants import WIDTH, HEIGHT
|
||||
from area.constants import WIDTH, HEIGHT, TILE_SIZE
|
||||
from area.field import drawWindow
|
||||
from area.tractor import Tractor
|
||||
from area.field import tiles
|
||||
from area.tractor import Tractor, do_actions
|
||||
from area.field import tiles, fieldX, fieldY
|
||||
from area.field import get_tile_coordinates
|
||||
from ground import Dirt
|
||||
from plant import Plant
|
||||
from bfs import graphsearch, Istate, succ
|
||||
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
pygame.display.set_caption('Intelligent tractor')
|
||||
|
||||
@ -16,24 +18,64 @@ def main():
|
||||
run = True
|
||||
window = drawWindow(WIN)
|
||||
pygame.display.update()
|
||||
|
||||
#getting coordinates of our "goal tile":
|
||||
tile_index=127
|
||||
tile_x, tile_y = get_tile_coordinates(tile_index)
|
||||
if tile_x is not None and tile_y is not None:
|
||||
print(f"Coordinates of tile {tile_index} are: ({tile_x}, {tile_y})")
|
||||
else: print("Such tile does not exist")
|
||||
|
||||
#mark the goal tile:
|
||||
tiles[tile_index].image = "resources/images/sampling_goal.png"
|
||||
image = pygame.image.load(tiles[tile_index].image).convert()
|
||||
image = pygame.transform.scale(image, (TILE_SIZE, TILE_SIZE))
|
||||
WIN.blit(image, (tiles[tile_index].x, tiles[tile_index].y))
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
#graphsearch activation:
|
||||
istate = Istate(170, 100, 2) #initial state
|
||||
|
||||
goaltest = []
|
||||
goaltest.append(tile_x) #final state (consists of x and y because direction doesnt matter)
|
||||
goaltest.append(tile_y)
|
||||
|
||||
tractor = Tractor(0*TILE_SIZE, 0*TILE_SIZE, 2, None, None)
|
||||
tractor.rect.x += fieldX
|
||||
tractor.rect.y += fieldY
|
||||
tractor.tractor_start = ((istate.get_x(), istate.get_y()))
|
||||
tractor.tractor_end = ((goaltest[0], goaltest[1]))
|
||||
|
||||
moves = (graphsearch(istate, succ, goaltest, tractor))
|
||||
print(moves)
|
||||
|
||||
|
||||
|
||||
#main loop:
|
||||
while run:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
run = False
|
||||
|
||||
#small test:
|
||||
time.sleep(2)
|
||||
#small test of work_on_field method:
|
||||
time.sleep(1)
|
||||
tile1 = tiles[0]
|
||||
p1 = Plant('wheat', 'cereal', random.randint(1,100), random.randint(1,100), random.randint(1,100))
|
||||
d1 = Dirt(random.randint(1, 100), random.randint(1,100))
|
||||
d1.pests_and_weeds()
|
||||
tile1.ground=d1
|
||||
t1 = Tractor(10, 10)
|
||||
t1.work_on_field(tile1, d1, p1)
|
||||
time.sleep(3)
|
||||
|
||||
#movement based on route-planning (test):
|
||||
|
||||
tractor.draw_tractor(WIN)
|
||||
time.sleep(1)
|
||||
if moves != False:
|
||||
do_actions(tractor, WIN, moves)
|
||||
|
||||
tractor.work_on_field(tile1, d1, p1)
|
||||
time.sleep(30)
|
||||
print("\n")
|
||||
|
||||
|
||||
# in loop move tractor
|
||||
|
||||
main()
|
||||
|
BIN
source/resources/images/rock_dirt.png
Normal file
BIN
source/resources/images/rock_dirt.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 104 KiB |
BIN
source/resources/images/sampling_goal.png
Normal file
BIN
source/resources/images/sampling_goal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 102 KiB |
BIN
source/resources/images/tractor_down.png
Normal file
BIN
source/resources/images/tractor_down.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 191 KiB |
BIN
source/resources/images/tractor_left.png
Normal file
BIN
source/resources/images/tractor_left.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 193 KiB |
BIN
source/resources/images/tractor_right.png
Normal file
BIN
source/resources/images/tractor_right.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 189 KiB |
BIN
source/resources/images/tractor_up.png
Normal file
BIN
source/resources/images/tractor_up.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 191 KiB |
@ -43,5 +43,9 @@ class Tile:
|
||||
else:
|
||||
self.image = "resources/images/dirt.png"
|
||||
self.photo = "resources/images/background.jpg"
|
||||
ground = self.ground
|
||||
if ground.obstacle and self.x != 170 and self.y != 100: #warunek po and do zmiany
|
||||
self.image = "resources/images/rock_dirt.png"
|
||||
|
||||
|
||||
# DISCLAMER check column and choose plant type ("potato","wheat" etc.)
|
||||
|
Loading…
Reference in New Issue
Block a user