2023-03-20 01:14:48 +01:00
|
|
|
from enum import Enum
|
2023-03-28 19:36:57 +02:00
|
|
|
import random
|
2023-03-20 01:14:48 +01:00
|
|
|
from typing import List
|
2023-03-12 16:22:51 +01:00
|
|
|
from Interface.grid_draw import GridDraw, Colors
|
2023-03-12 18:11:31 +01:00
|
|
|
import sys
|
|
|
|
import pygame
|
2023-03-23 00:54:05 +01:00
|
|
|
from Interface.movement import movement_key_press
|
2023-03-11 19:31:43 +01:00
|
|
|
|
2023-03-16 20:33:22 +01:00
|
|
|
|
2023-03-19 22:00:10 +01:00
|
|
|
# window_dimensions says how many pixels window have
|
2023-03-22 20:48:02 +01:00
|
|
|
# board_size says how many lines board have in one row
|
2023-03-19 22:00:10 +01:00
|
|
|
def initial_draw(window_dimensions, board_size):
|
2023-03-16 21:38:42 +01:00
|
|
|
# window name
|
|
|
|
pygame.display.set_caption("AI Vacuum Cleaner")
|
|
|
|
|
2023-03-22 20:48:02 +01:00
|
|
|
# define additional variables
|
2023-03-22 23:11:13 +01:00
|
|
|
tile_size = window_dimensions / board_size
|
2023-03-22 20:48:02 +01:00
|
|
|
|
|
|
|
# initialize board array
|
2023-03-28 19:36:57 +02:00
|
|
|
newGrid = Grid(board_size, window_dimensions=window_dimensions, board_size=board_size)
|
2023-03-22 23:11:13 +01:00
|
|
|
newGrid.add(objectOnTile(1, 1, acceptedType.PLAYER))
|
2023-03-28 19:36:57 +02:00
|
|
|
newGrid.add(objectOnTile(7, 8, acceptedType.ANIMAL))
|
2023-03-28 21:32:07 +02:00
|
|
|
newGrid.add(objectOnTile(2, 8, acceptedType.PLANT1))
|
|
|
|
newGrid.add(objectOnTile(4, 1, acceptedType.PLANT1))
|
|
|
|
newGrid.add(objectOnTile(3, 4, acceptedType.PLANT2))
|
|
|
|
newGrid.add(objectOnTile(8, 8, acceptedType.PLANT2))
|
|
|
|
newGrid.add(objectOnTile(9, 3, acceptedType.PLANT3))
|
|
|
|
|
|
|
|
|
2023-03-23 00:54:05 +01:00
|
|
|
player = newGrid.findFirst(acceptedType.PLAYER)
|
|
|
|
newGrid.move(1, 1, 1, 2)
|
|
|
|
newGrid.move(1, 2, 1, 1)
|
2023-03-22 20:48:02 +01:00
|
|
|
|
2023-03-16 21:38:42 +01:00
|
|
|
# set window dimension
|
2023-03-19 22:00:10 +01:00
|
|
|
window_width = window_dimensions
|
|
|
|
window_height = window_dimensions
|
2023-03-16 21:38:42 +01:00
|
|
|
|
2023-03-23 00:54:05 +01:00
|
|
|
# initialize drawer
|
|
|
|
drawer = GridDraw(window_width, window_height)
|
2023-03-16 20:33:22 +01:00
|
|
|
|
|
|
|
# rendering loop
|
2023-03-12 16:22:51 +01:00
|
|
|
while True:
|
2023-03-23 00:54:05 +01:00
|
|
|
drawer.start_draw()
|
|
|
|
drawer.board(board_size, board_size)
|
2023-03-22 23:11:13 +01:00
|
|
|
|
2023-03-23 00:54:05 +01:00
|
|
|
player = newGrid.findFirst(acceptedType.PLAYER)
|
2023-03-22 23:11:13 +01:00
|
|
|
|
2023-03-23 00:54:05 +01:00
|
|
|
(x, y) = movement_key_press(board_size, player.position_x, player.position_y)
|
|
|
|
|
|
|
|
newGrid.move(player.position_x, player.position_y, x, y)
|
|
|
|
|
2023-03-28 19:36:57 +02:00
|
|
|
newGrid.render(drawer, newGrid=newGrid)
|
2023-03-23 00:54:05 +01:00
|
|
|
drawer.end_draw()
|
2023-03-22 23:11:13 +01:00
|
|
|
pygame.time.delay(30)
|
2023-03-20 01:14:48 +01:00
|
|
|
|
|
|
|
|
|
|
|
# TODO wrap it all to another file that handles array rendering
|
|
|
|
class acceptedType(Enum):
|
|
|
|
EMPTY = "empty"
|
|
|
|
PLAYER = "player"
|
|
|
|
RUBBISH = "rubbish"
|
2023-03-28 21:32:07 +02:00
|
|
|
PLANT1 = "plant1"
|
|
|
|
PLANT2 = "plant2"
|
|
|
|
PLANT3 = "plant3"
|
2023-03-20 01:14:48 +01:00
|
|
|
ANIMAL = "animal"
|
|
|
|
|
|
|
|
|
|
|
|
class objectOnTile:
|
|
|
|
def __init__(
|
|
|
|
self, position_x: int, position_y: int, type: acceptedType = acceptedType.EMPTY
|
|
|
|
):
|
|
|
|
self.position_x = position_x
|
|
|
|
self.position_y = position_y
|
|
|
|
self.type = type
|
|
|
|
|
|
|
|
|
2023-03-22 20:48:02 +01:00
|
|
|
# calculate position from array position to window position eg.: array_position = 0 => window_position = 50 (px)
|
2023-03-22 23:11:13 +01:00
|
|
|
def _translate_array_to_window_position(array_position, tile_size_window) -> int:
|
2023-03-22 20:48:02 +01:00
|
|
|
return array_position * tile_size_window + tile_size_window / 2
|
2023-03-20 01:14:48 +01:00
|
|
|
|
|
|
|
|
|
|
|
class Grid:
|
2023-03-28 19:36:57 +02:00
|
|
|
|
|
|
|
def __init__(self, size_array, window_dimensions, board_size):
|
2023-03-20 01:14:48 +01:00
|
|
|
self.array = [
|
|
|
|
[objectOnTile(i, j) for j in range(size_array)] for i in range(size_array)
|
|
|
|
]
|
|
|
|
self.list: List[objectOnTile] = []
|
|
|
|
|
2023-03-28 19:36:57 +02:00
|
|
|
self.tile_size = window_dimensions / board_size
|
2023-03-28 21:32:07 +02:00
|
|
|
self.board_size = board_size
|
2023-03-28 19:36:57 +02:00
|
|
|
|
|
|
|
self.cat_last_tick = pygame.time.get_ticks()
|
|
|
|
self.cat_cooldown = 1000
|
|
|
|
self.cat_velocity = 1
|
|
|
|
self.cat_busy = False
|
|
|
|
|
|
|
|
#region images
|
|
|
|
self.cat_front_image = pygame.transform.scale(pygame.image.load("Interface/images/cat/standing_front.png"), (self.tile_size, self.tile_size))
|
|
|
|
self.cat_back_image = pygame.transform.scale(pygame.image.load("Interface/images/cat/standing_back.png"), (self.tile_size, self.tile_size))
|
|
|
|
self.cat_left_image = pygame.transform.scale(pygame.image.load("Interface/images/cat/standing_left.png"), (self.tile_size, self.tile_size))
|
|
|
|
self.cat_right_image = pygame.transform.scale(pygame.image.load("Interface/images/cat/standing_right.png"), (self.tile_size, self.tile_size))
|
|
|
|
self.cat_current_image = self.cat_front_image
|
2023-03-28 21:32:07 +02:00
|
|
|
self.plant1 = pygame.transform.scale(pygame.image.load("Interface/images/plants/plant1.png"), (self.tile_size + self.tile_size/4, self.tile_size + self.tile_size/4))
|
|
|
|
self.plant2 = pygame.transform.scale(pygame.image.load("Interface/images/plants/plant2.png"), (self.tile_size + self.tile_size/4, self.tile_size + self.tile_size/4))
|
|
|
|
self.plant3 = pygame.transform.scale(pygame.image.load("Interface/images/plants/plant3.png"), (self.tile_size + self.tile_size/4, self.tile_size + self.tile_size/4))
|
2023-03-28 19:36:57 +02:00
|
|
|
#endregion
|
|
|
|
|
2023-03-20 01:14:48 +01:00
|
|
|
# render the array
|
2023-03-28 19:36:57 +02:00
|
|
|
def render(self, drawer: GridDraw, newGrid):
|
|
|
|
#tile_size = window_dimensions / board_size
|
2023-03-22 23:11:13 +01:00
|
|
|
|
2023-03-20 01:14:48 +01:00
|
|
|
# render object with respect to type
|
|
|
|
for item in self.list:
|
|
|
|
if item.type == acceptedType.PLAYER:
|
|
|
|
# constants for player
|
|
|
|
PLAYER_RADIUS_RATIO = 3
|
|
|
|
PLAYER_COLOR = Colors.RED
|
|
|
|
|
2023-03-22 20:48:02 +01:00
|
|
|
# position on screen
|
2023-03-20 01:14:48 +01:00
|
|
|
render_x = _translate_array_to_window_position(
|
2023-03-28 19:36:57 +02:00
|
|
|
item.position_x, self.tile_size
|
2023-03-20 01:14:48 +01:00
|
|
|
)
|
|
|
|
render_y = _translate_array_to_window_position(
|
2023-03-28 19:36:57 +02:00
|
|
|
item.position_y, self.tile_size
|
2023-03-20 01:14:48 +01:00
|
|
|
)
|
2023-03-22 20:48:02 +01:00
|
|
|
|
|
|
|
# image rendering function
|
2023-03-23 00:54:05 +01:00
|
|
|
drawer.circle(
|
2023-03-20 01:14:48 +01:00
|
|
|
render_x,
|
|
|
|
render_y,
|
2023-03-28 19:36:57 +02:00
|
|
|
self.tile_size / PLAYER_RADIUS_RATIO,
|
2023-03-20 01:14:48 +01:00
|
|
|
color=PLAYER_COLOR,
|
|
|
|
)
|
2023-03-28 19:36:57 +02:00
|
|
|
if item.type == acceptedType.ANIMAL:
|
|
|
|
now = pygame.time.get_ticks()
|
|
|
|
#region cat random movement
|
|
|
|
if now - self.cat_last_tick >= self.cat_cooldown:
|
2023-03-28 21:32:07 +02:00
|
|
|
|
2023-03-28 19:36:57 +02:00
|
|
|
if self.cat_busy == False:
|
2023-03-28 21:32:07 +02:00
|
|
|
while True:
|
|
|
|
self.cat_direction = random.randint(0,3)
|
|
|
|
if not((self.cat_direction == 0 and item.position_y == 0) or (self.cat_direction == 1 and item.position_x == self.board_size - 1) or (self.cat_direction == 2 and item.position_y == self.board_size - 1) or (self.cat_direction == 3 and item.position_x == 0)):
|
|
|
|
break
|
2023-03-28 19:36:57 +02:00
|
|
|
|
|
|
|
if self.cat_direction == 0: #up
|
|
|
|
if self.cat_current_image == self.cat_back_image:
|
|
|
|
newGrid.move(item.position_x, item.position_y, item.position_x, item.position_y - 1)
|
|
|
|
self.cat_busy = False
|
|
|
|
else:
|
|
|
|
self.cat_busy = True
|
|
|
|
self.cat_current_image = self.cat_back_image
|
|
|
|
if self.cat_direction == 1: #right
|
|
|
|
if self.cat_current_image == self.cat_right_image:
|
|
|
|
newGrid.move(item.position_x, item.position_y, item.position_x + 1, item.position_y)
|
|
|
|
self.cat_busy = False
|
|
|
|
else:
|
|
|
|
self.cat_busy = True
|
|
|
|
self.cat_current_image = self.cat_right_image
|
|
|
|
if self.cat_direction == 2: #down
|
|
|
|
if self.cat_current_image == self.cat_front_image:
|
|
|
|
newGrid.move(item.position_x, item.position_y, item.position_x, item.position_y + 1)
|
|
|
|
self.cat_busy = False
|
|
|
|
else:
|
|
|
|
self.cat_busy = True
|
|
|
|
self.cat_current_image = self.cat_front_image
|
|
|
|
if self.cat_direction == 3: #left
|
|
|
|
if self.cat_current_image == self.cat_left_image:
|
|
|
|
newGrid.move(item.position_x, item.position_y, item.position_x - 1, item.position_y)
|
|
|
|
self.cat_busy = False
|
|
|
|
else:
|
|
|
|
self.cat_busy = True
|
|
|
|
self.cat_current_image = self.cat_left_image
|
|
|
|
self.cat_last_tick = pygame.time.get_ticks()
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
render_x = item.position_x * self.tile_size
|
|
|
|
render_y = item.position_y * self.tile_size
|
|
|
|
|
|
|
|
drawer.image(render_x, render_y, self.cat_current_image)
|
|
|
|
|
2023-03-28 21:32:07 +02:00
|
|
|
if item.type == acceptedType.PLANT1:
|
|
|
|
drawer.image((item.position_x - 0.1) * self.tile_size, (item.position_y - 0.25) * self.tile_size, self.plant1)
|
|
|
|
if item.type == acceptedType.PLANT2:
|
|
|
|
drawer.image((item.position_x - 0.1) * self.tile_size, (item.position_y - 0.25) * self.tile_size, self.plant2)
|
|
|
|
if item.type == acceptedType.PLANT3:
|
|
|
|
drawer.image((item.position_x - 0.1) * self.tile_size, (item.position_y - 0.25) * self.tile_size, self.plant3)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# TODO act accordingly to other options(rubbish)
|
2023-03-20 01:14:48 +01:00
|
|
|
|
|
|
|
# add new object on grid
|
|
|
|
def add(self, newObject: objectOnTile):
|
|
|
|
if (
|
|
|
|
self.array[newObject.position_x][newObject.position_y].type
|
|
|
|
!= acceptedType.EMPTY
|
|
|
|
):
|
|
|
|
print(
|
|
|
|
f"Cannot add object at ({newObject.position_x}, {newObject.position_y}): position already occupied"
|
|
|
|
)
|
|
|
|
return
|
|
|
|
|
|
|
|
self.array[newObject.position_x][newObject.position_y] = newObject
|
|
|
|
self.list.append(newObject)
|
|
|
|
|
2023-03-23 00:54:05 +01:00
|
|
|
# deletes object from game
|
|
|
|
# untested, potentially not working
|
|
|
|
def delete(self, position_x: int, position_y: int):
|
2023-03-20 01:14:48 +01:00
|
|
|
# Find the object with the given position in the list
|
|
|
|
for obj in self.list:
|
|
|
|
if obj.position_x == position_x and obj.position_y == position_y:
|
|
|
|
break
|
|
|
|
|
|
|
|
else: # No object found with the given position
|
|
|
|
print(f"No object found at ({position_x}, {position_y})")
|
|
|
|
return
|
|
|
|
|
|
|
|
# Remove the object from both the array and the list
|
|
|
|
self.array[position_x][position_y] = objectOnTile(position_x, position_y)
|
|
|
|
self.list.remove(obj)
|
|
|
|
|
2023-03-23 00:54:05 +01:00
|
|
|
# move: update position from (start_x, start_y) to (end_x, end_y)
|
|
|
|
def move(self, start_x: int, start_y: int, end_x: int, end_y: int):
|
|
|
|
# no change
|
|
|
|
if start_x == end_x and start_y == end_y:
|
|
|
|
return
|
|
|
|
|
2023-03-28 21:32:07 +02:00
|
|
|
#check if object moves beyond border
|
|
|
|
if end_x > self.board_size - 1 or end_y > self.board_size - 1 or end_x < 0 or end_y < 0:
|
|
|
|
print(
|
|
|
|
f"Cannot move object beyond board"
|
|
|
|
)
|
|
|
|
return
|
|
|
|
|
2023-03-22 20:48:02 +01:00
|
|
|
# check if obj exist at starting position
|
|
|
|
if self.array[start_x][start_y].type == acceptedType.EMPTY:
|
|
|
|
print(
|
|
|
|
f"Cannot move object at ({start_x}, {start_y}): no object on position"
|
|
|
|
)
|
|
|
|
return
|
2023-03-23 00:54:05 +01:00
|
|
|
|
2023-03-22 20:48:02 +01:00
|
|
|
# check if destination is empty
|
|
|
|
if self.array[end_x][end_y].type != acceptedType.EMPTY:
|
|
|
|
print(
|
|
|
|
f"Cannot move object to ({end_x}, {end_y}): position already occupied"
|
|
|
|
)
|
|
|
|
return
|
2023-03-28 21:32:07 +02:00
|
|
|
|
|
|
|
|
2023-03-23 00:54:05 +01:00
|
|
|
|
2023-03-22 20:48:02 +01:00
|
|
|
# all OK
|
2023-03-23 00:54:05 +01:00
|
|
|
# change position attribute in array
|
|
|
|
self.array[start_x][start_y].position_x = end_x
|
|
|
|
self.array[start_x][start_y].position_y = end_y
|
2023-03-22 20:48:02 +01:00
|
|
|
|
2023-03-23 00:54:05 +01:00
|
|
|
# change position in array
|
|
|
|
self.array[end_x][end_y] = self.array[start_x][start_y]
|
|
|
|
self.array[start_x][start_y] = objectOnTile(start_x, start_y)
|
|
|
|
|
|
|
|
def findFirst(self, find_type: acceptedType) -> objectOnTile:
|
|
|
|
for item in self.list:
|
|
|
|
if item.type == find_type:
|
|
|
|
return item
|
|
|
|
else:
|
|
|
|
print(f"Cannot find object of type: ({find_type})!")
|