From d92c015daa1bd14dea5df9663d6a1ace91a9cb44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Cupa=C5=82?= Date: Tue, 30 Mar 2021 11:24:50 +0200 Subject: [PATCH] refactoring code and add functionality to the tractor like harvesting, irrigating, etc. --- app/__init__.py | 31 ++++++++--- app/agent.py | 32 ----------- app/base_field.py | 20 +++++++ app/board.py | 48 +++++++--------- app/fields.py | 61 ++++++++++++++++++++ app/tractor.py | 138 ++++++++++++++++++++++++++++++++++++++++++++++ app/utils.py | 8 +++ config.py | 39 +++++++++---- images.py | 31 ----------- 9 files changed, 301 insertions(+), 107 deletions(-) delete mode 100644 app/agent.py create mode 100644 app/base_field.py create mode 100644 app/fields.py create mode 100644 app/tractor.py create mode 100644 app/utils.py delete mode 100644 images.py diff --git a/app/__init__.py b/app/__init__.py index e72c192..989694d 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -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() diff --git a/app/agent.py b/app/agent.py deleted file mode 100644 index 1347cf8..0000000 --- a/app/agent.py +++ /dev/null @@ -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 diff --git a/app/base_field.py b/app/base_field.py new file mode 100644 index 0000000..21e9a3c --- /dev/null +++ b/app/base_field.py @@ -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) diff --git a/app/board.py b/app/board.py index 19f72ba..ca8ce2e 100644 --- a/app/board.py +++ b/app/board.py @@ -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) diff --git a/app/fields.py b/app/fields.py new file mode 100644 index 0000000..99ab76b --- /dev/null +++ b/app/fields.py @@ -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__) diff --git a/app/tractor.py b/app/tractor.py new file mode 100644 index 0000000..40cc022 --- /dev/null +++ b/app/tractor.py @@ -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__}" diff --git a/app/utils.py b/app/utils.py new file mode 100644 index 0000000..8305d66 --- /dev/null +++ b/app/utils.py @@ -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 diff --git a/config.py b/config.py index 64f8dc2..23eee03 100644 --- a/config.py +++ b/config.py @@ -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 diff --git a/images.py b/images.py deleted file mode 100644 index ccb223a..0000000 --- a/images.py +++ /dev/null @@ -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() - -