refactoring code and add functionality to the tractor like harvesting, irrigating, etc.

This commit is contained in:
Dominik Cupał 2021-03-30 11:24:50 +02:00
parent 815f85c78f
commit d92c015daa
9 changed files with 301 additions and 107 deletions

View File

@ -4,7 +4,7 @@ import pygame
from config import *
from app.board import Board
from app.agent import Agent
from app.tractor import Tractor
class App:
@ -13,7 +13,7 @@ class App:
self.__screen = None
self.__clock = None
self.__board = Board()
self.__agent = Agent()
self.__tractor = Tractor(self.__board)
def initialize(self):
pygame.init()
@ -28,19 +28,36 @@ class App:
def loop_handler(self):
self.__board.draw(self.__screen)
self.__agent.draw(self.__screen)
self.__tractor.draw(self.__screen)
def keys_pressed_handler(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
self.__agent.move_up()
self.__tractor.move_up()
print(self.__tractor)
if keys[pygame.K_DOWN]:
self.__agent.move_down()
self.__tractor.move_down()
print(self.__tractor)
if keys[pygame.K_LEFT]:
self.__agent.move_left()
self.__tractor.move_left()
print(self.__tractor)
if keys[pygame.K_RIGHT]:
self.__agent.move_right()
self.__tractor.move_right()
print(self.__tractor)
if keys[pygame.K_h]:
self.__tractor.harvest()
if keys[pygame.K_v]:
self.__tractor.sow()
if keys[pygame.K_n]:
self.__tractor.hydrate()
if keys[pygame.K_f]:
self.__tractor.fertilize()
def update_screen(self):
pygame.display.flip()

View File

@ -1,32 +0,0 @@
#!/usr/bin/python3
from images import *
from config import *
class Agent:
def __init__(self):
self.__pos_x = (int(HORIZONTAL_NUM_OF_FIELDS/2)-1)*FIELD_SIZE
self.__pos_y = (int(VERTICAL_NUM_OF_FIELDS/2)-1)*FIELD_SIZE
self.__move = FIELD_SIZE
def draw(self, screen: pygame.Surface):
tractorrect.size = (FIELD_SIZE, FIELD_SIZE)
tractorrect.center = (self.__pos_x + FIELD_SIZE/2, self.__pos_y + FIELD_SIZE/2)
screen.blit(tractor, tractorrect)
def move_up(self):
if self.__pos_y - self.__move >= 0:
self.__pos_y -= self.__move
def move_down(self):
if self.__pos_y + self.__move + FIELD_SIZE <= HEIGHT:
self.__pos_y += self.__move
def move_left(self):
if self.__pos_x - self.__move >= 0:
self.__pos_x -= self.__move
def move_right(self):
if self.__pos_x + self.__move + FIELD_SIZE <= WIDTH:
self.__pos_x += self.__move

20
app/base_field.py Normal file
View File

@ -0,0 +1,20 @@
import pygame
from config import *
class BaseField:
def __init__(self, img_path: str):
self._img_path = img_path
def draw_field(self, screen: pygame.Surface, pos_x: int, pos_y: int, is_centered: bool = False, size: tuple = None):
img = pygame.image.load(self._img_path)
scale = pygame.transform.scale(img, (FIELD_SIZE, FIELD_SIZE))
rect = img.get_rect()
if is_centered:
rect.center = (pos_x, pos_y)
else:
rect.topleft = (pos_x, pos_y)
if size is not None:
rect.size = (FIELD_SIZE, FIELD_SIZE)
screen.blit(scale, rect)

View File

@ -1,50 +1,44 @@
#!/usr/bin/python3
import pygame
import random
from images import *
from config import *
from app.fields import *
from app.utils import get_class
class Board:
def __init__(self):
self.__fields = []
self.generate_board()
self.create_board()
self.fill()
self.generate_board()
# print(self.__fields)
def generate_board(self):
def get_fields(self):
return self.__fields
def create_board(self):
for i in range(HORIZONTAL_NUM_OF_FIELDS):
self.__fields.append([])
for j in range(VERTICAL_NUM_OF_FIELDS):
self.__fields[i].append(None)
def fill(self):
# colors = [C_RED, C_GREEN, C_BLUE]
for i in range(len(self.__fields)):
for j in range(len(self.__fields[i])):
self.__fields[i][j] = random.choice(soilType)
self.__fields[i][j] = random.choice(FIELD_TYPES).capitalize()
def generate_board(self):
for x in range(len(self.__fields)):
for y in range(len(self.__fields[x])):
field_type = self.__fields[x][y]
c = get_class("app.fields", field_type)
field = c()
self.__fields[x][y] = field
def draw(self, screen: pygame.Surface):
for x in range(len(self.__fields)):
for y in range(len(self.__fields[x])):
obj = self.__fields[x][y]
pos_x = x * FIELD_SIZE + FIELD_SIZE//2
pos_y = y * FIELD_SIZE + FIELD_SIZE//2
if obj == 'grass':
grassrect.center = (pos_x, pos_y)
screen.blit(grass, grassrect)
if obj == 'corn':
cornrect.center = (pos_x, pos_y)
screen.blit(corn, cornrect)
if obj == 'sunflower':
sunflowerrect.center = (pos_x, pos_y)
screen.blit(sunflower, sunflowerrect)
if obj == 'sand':
sandrect.center = (pos_x, pos_y)
screen.blit(sand, sandrect)
if obj == 'clay':
clayrect.center = (pos_x , pos_y)
screen.blit(clay, clayrect)
field = self.__fields[x][y]
pos_x = x * FIELD_SIZE
pos_y = y * FIELD_SIZE
field.draw_field(screen, pos_x, pos_y)

61
app/fields.py Normal file
View File

@ -0,0 +1,61 @@
#!/usr/bin/python3
import os
from app.base_field import BaseField
from config import *
class Soil(BaseField):
def __init__(self, img_path: str):
super().__init__(img_path)
class Crops(BaseField):
price = 0
def __init__(self, img_path: str):
super().__init__(img_path)
self.weight = 1.0
class Plant(BaseField):
def __init__(self, img_path: str):
super().__init__(img_path)
self.is_hydrated = False
class Clay(Soil):
def __init__(self):
super().__init__(os.path.join(RESOURCE_DIR, f"{CLAY}.{PNG}"))
self.is_fertilized = False
class Sand(Soil):
def __init__(self):
super().__init__(os.path.join(RESOURCE_DIR, f"{SAND}.{PNG}"))
self.is_sowed = False
self.is_hydrated = False
class Grass(Plant):
def __init__(self):
super().__init__(os.path.join(RESOURCE_DIR, f"{GRASS}.{PNG}"))
class Sunflower(Crops):
price = 7.90
def __init__(self):
super().__init__(os.path.join(RESOURCE_DIR, f"{SUNFLOWER}.{PNG}"))
class Corn(Crops):
price = 9.15
def __init__(self):
super().__init__(os.path.join(RESOURCE_DIR, f"{CORN}.{PNG}"))
CROPS = (Sunflower.__name__, Corn.__name__)
PLANTS = (Grass.__name__,)
SOILS = (Clay.__name__, Sand.__name__)

138
app/tractor.py Normal file
View File

@ -0,0 +1,138 @@
#!/usr/bin/python3
import random
import pygame
import os
import time
from threading import Thread
from typing import Union
from app.base_field import BaseField
from app.board import Board
from app.utils import get_class
from app.fields import CROPS, PLANTS, SOILS, Sand, Clay
from config import *
from app.fields import Plant, Soil, Crops
class Tractor(BaseField):
def __init__(self, board: Board):
super().__init__(os.path.join(RESOURCE_DIR, f"{TRACTOR}.{PNG}"))
self.__pos_x = (int(HORIZONTAL_NUM_OF_FIELDS / 2) - 1) * FIELD_SIZE
self.__pos_y = (int(VERTICAL_NUM_OF_FIELDS / 2) - 1) * FIELD_SIZE
self.__move = FIELD_SIZE
self.__board = board
self.__harvested_corps = []
def draw(self, screen: pygame.Surface):
self.draw_field(screen, self.__pos_x + FIELD_SIZE / 2, self.__pos_y + FIELD_SIZE / 2,
is_centered=True, size=(FIELD_SIZE, FIELD_SIZE))
# Key methods handlers
def move_up(self):
if self.__pos_y - self.__move >= 0:
self.__pos_y -= self.__move
def move_down(self):
if self.__pos_y + self.__move + FIELD_SIZE <= HEIGHT:
self.__pos_y += self.__move
def move_left(self):
if self.__pos_x - self.__move >= 0:
self.__pos_x -= self.__move
def move_right(self):
if self.__pos_x + self.__move + FIELD_SIZE <= WIDTH:
self.__pos_x += self.__move
def hydrate(self):
if self.check_field(Sand):
field = self.get_field_from_board()
if not field.is_hydrated and field.is_sowed:
print('Hydrate soil')
self.irrigate_sand(field)
elif self.check_field(Plant):
field = self.get_field_from_board()
if not field.is_hydrated:
print("Hydrate plant")
self.irrigate_plants(field)
def sow(self):
field = self.get_field_from_board()
if self.check_field(Sand) and not field.is_sowed:
print('Sow')
field.is_sowed = True
def harvest(self):
if self.check_field(Crops):
print('Harvest')
field = self.get_field_from_board()
self.harvest_crops(field)
self.get_result_of_harvesting()
def fertilize(self):
if self.check_field(Clay):
print('Fertilize soil')
field = self.get_field_from_board()
self.fertilize_clay(field)
################################################################################
def fertilize_clay(self, field: Clay):
field.is_fertilized = True
self.do_action((Sand.__name__,))
def irrigate_plants(self, field: Plant):
field.is_hydrated = True
self.do_time_action(CROPS)
def irrigate_sand(self, field: Sand):
field.is_hydrated = True
self.do_time_action(PLANTS)
def harvest_crops(self, field: Crops):
self.__harvested_corps.append(type(field).__name__)
self.do_action(SOILS)
def do_action(self, TYPE: tuple):
choosen_type = random.choice(TYPE)
obj = get_class("app.fields", choosen_type)
x, y = self.get_position()
self.__board.get_fields()[x][y] = obj()
def do_time_action(self, TYPE: tuple):
thread = Thread(target=self.do_time_action_handler, args=(TYPE,), daemon=True)
thread.start()
def do_time_action_handler(self, TYPE: tuple):
time.sleep(TIME_OF_GROWING)
self.do_action(TYPE)
def check_field(self, class_name: Union[type(Plant), type(Crops), type(Soil)]):
if isinstance(self.get_field_from_board(), class_name):
return True
return False
def get_field_from_board(self):
x, y = self.get_position()
return self.__board.get_fields()[x][y]
def get_position(self):
x = self.__pos_x // FIELD_SIZE
y = self.__pos_y // FIELD_SIZE
return x, y
def get_result_of_harvesting(self):
crops = set(self.__harvested_corps)
result = 0.0
for crop in crops:
amount = self.__harvested_corps.count(crop)
print(f"{amount} x {crop}")
result += amount * get_class("app.fields", crop).price
print(f"Price for collected crops: {result:.2f}")
def __str__(self):
x, y = self.get_position()
return f"Position: {x}:{y} - {type(self.__board.get_fields()[x][y]).__name__}"

8
app/utils.py Normal file
View File

@ -0,0 +1,8 @@
#!/usr/bin/python3
from importlib import import_module
def get_class(module: str, class_name: str):
m = import_module(module)
c = getattr(m, class_name)
return c

View File

@ -1,25 +1,44 @@
#!/usr/bin/python3
import os
__all__ = (
'WIDTH', 'HEIGHT', 'FIELD_SIZE',
'VERTICAL_NUM_OF_FIELDS', 'HORIZONTAL_NUM_OF_FIELDS',
'C_RED', 'C_GREEN', 'C_BLUE', 'C_BLACK',
'FPS','CAPTION'
'FPS', 'CAPTION', 'RESOURCE_DIR', 'TRACTOR', 'PNG',
'SAND', 'CLAY', 'GRASS', 'CORN', 'SUNFLOWER',
'FIELD_TYPES','TIME_OF_GROWING'
)
# Board settings:
VERTICAL_NUM_OF_FIELDS = 6
HORIZONTAL_NUM_OF_FIELDS = 6
VERTICAL_NUM_OF_FIELDS = 9
HORIZONTAL_NUM_OF_FIELDS = 12
FIELD_SIZE = 60
WIDTH = HORIZONTAL_NUM_OF_FIELDS * FIELD_SIZE
HEIGHT = VERTICAL_NUM_OF_FIELDS * FIELD_SIZE
# Colors of Fields
C_RED = (255, 0, 0)
C_GREEN = (0, 255, 0)
C_BLUE = (0, 0, 255)
C_BLACK = (0, 0, 0)
# Other settings
FPS = 10
CAPTION = 'Tractor'
# Path
BASE_DIR = os.path.dirname(__file__)
RESOURCE_DIR = os.path.join(BASE_DIR, 'resources')
# Picture format
PNG = "png"
# Tractor settings
TRACTOR = 'tractor'
# Types of Fields
SAND = 'sand'
CLAY = 'clay'
GRASS = 'grass'
CORN = 'corn'
SUNFLOWER = 'sunflower'
FIELD_TYPES = (SAND, CLAY, GRASS, CORN, SUNFLOWER)
# Times
TIME_OF_GROWING = 2

View File

@ -1,31 +0,0 @@
import pygame
from config import *
soilType = ('sand','clay', 'grass', 'corn', 'sunflower')
tractor_scale = pygame.image.load("resources/tractor.png")
tractor = pygame.transform.scale(tractor_scale, (FIELD_SIZE, FIELD_SIZE))
clay_scale= pygame.image.load("resources/clay.png")
clay = pygame.transform.scale(clay_scale, (FIELD_SIZE, FIELD_SIZE))
sand_scale = pygame.image.load("resources/sand.png")
sand = pygame.transform.scale(sand_scale, (FIELD_SIZE, FIELD_SIZE))
grass_scale = pygame.image.load("resources/grass.png")
grass = pygame.transform.scale(grass_scale, (FIELD_SIZE, FIELD_SIZE))
corn_scale = pygame.image.load("resources/corn.png")
corn = pygame.transform.scale(corn_scale, (FIELD_SIZE, FIELD_SIZE))
sunflower_scale = pygame.image.load("resources/sunflower.png")
sunflower = pygame.transform.scale(sunflower_scale, (FIELD_SIZE, FIELD_SIZE))
tractorrect = tractor.get_rect()
clayrect = clay.get_rect()
sandrect = sand.get_rect()
grassrect = grass.get_rect()
cornrect = corn.get_rect()
sunflowerrect = sunflower.get_rect()