Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create schemas #92

Merged
merged 5 commits into from
Oct 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 53 additions & 15 deletions game/common/map/game_board.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import random
from typing import Self
from typing import Self, Callable

from game.common.avatar import Avatar
from game.common.enums import *
Expand Down Expand Up @@ -175,11 +175,11 @@ def locations(self, locations: dict[tuple[Vector]:list[GameObject]] | None) -> N
if locations is not None and not isinstance(locations, dict):
raise ValueError("Locations must be a dict. The key must be a tuple of Vector Objects, and the "
"value a list of GameObject.")
if locations is not None:
for k, v in locations.items():
if len(k) != len(v):
raise ValueError("Cannot set the locations for the game_board. A key has a different "
"length than its key.")
# if locations is not None:
# for k, v in locations.items():
# if len(k) != len(v):
# raise ValueError("Cannot set the locations for the game_board. A key has a different "
# "length than its key.")

self.__locations = locations

Expand Down Expand Up @@ -212,28 +212,66 @@ def generate_map(self) -> None:

def __populate_map(self) -> None:
for k, v in self.locations.items():
if len(k) != len(v) or (len(k) == 0 or len(v) == 0): # Key-Value lengths must be > 0 and equal
raise ValueError("A key-value pair from game_board.locations has mismatching lengths. "
"They must be the same length, regardless of size.")
if len(k) == 0 or len(v) == 0: # Key-Value lengths must be > 0 and equal
raise ValueError("A key-value pair from game_board.locations has a length of 0. ")

# random.sample returns a randomized list which is used in __help_populate()
j = random.sample(k, k=len(k))
self.__help_populate(j, v)

def __help_populate(self, vector_list: list[Vector], v: list[GameObject]) -> None:
for j, i in zip(vector_list, v):
if isinstance(i, Avatar): # If the GameObject is an Avatar, assign it the coordinate position
i.position = j
def __occupied_filter(self, game_object_list: list[GameObject]) -> list[GameObject]:
"""
A helper method that returns a list of game objects that have the 'occupied_by' attribute.
:param game_object_list:
:return: a list of game object
"""
return [game_object for game_object in game_object_list if hasattr(game_object, 'occupied_by')]

temp_tile: GameObject = self.game_map[j.y][j.x]
def __help_populate(self, vector_list: list[Vector], game_object_list: list[GameObject]) -> None:
"""
A helper method that helps populate the game map.
:param vector_list:
:param game_object_list:
:return: None
"""

zipped_list: [tuple[list[Vector], list[GameObject]]] = list(zip(vector_list, game_object_list))
last_vec: Vector = zipped_list[-1][0]

remaining_objects: list[GameObject] | None = self.__occupied_filter(game_object_list[len(zipped_list):]) \
if len(self.__occupied_filter(game_object_list)) > len(zipped_list) \
else None

# Will cap at smallest list when zipping two together
for vector, game_object in zipped_list:
if isinstance(game_object, Avatar): # If the GameObject is an Avatar, assign it the coordinate position
game_object.position = vector

temp_tile: GameObject = self.game_map[vector.y][vector.x]

while hasattr(temp_tile.occupied_by, 'occupied_by'):
temp_tile = temp_tile.occupied_by

if temp_tile is None:
raise ValueError("Last item on the given tile doesn't have the 'occupied_by' attribute.")

temp_tile.occupied_by = i
temp_tile.occupied_by = game_object

if remaining_objects is None:
return

# stack remaining game_objects on last vector
temp_tile: GameObject = self.game_map[last_vec.y][last_vec.x]

while hasattr(temp_tile.occupied_by, 'occupied_by'):
temp_tile = temp_tile.occupied_by

for game_object in remaining_objects:
if temp_tile is None:
raise ValueError("Last item on the given tile doesn't have the 'occupied_by' attribute.")

temp_tile.occupied_by = game_object
temp_tile = temp_tile.occupied_by

def get_objects(self, look_for: ObjectType) -> list[tuple[Vector, list[GameObject]]]:
to_return: list[tuple[Vector, list[GameObject]]] = list()
Expand Down
15 changes: 13 additions & 2 deletions game/test_suite/tests/test_game_board.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ def setUp(self) -> None:
self.locations: dict[tuple[Vector]:list[GameObject]] = {
(Vector(1, 1),): [Station(None)],
(Vector(1, 2), Vector(1, 3)): [OccupiableStation(self.item), Station(None)],
(Vector(2, 2), Vector(2, 3)): [OccupiableStation(self.item), OccupiableStation(self.item), OccupiableStation(self.item), OccupiableStation(self.item)],
(Vector(3, 1), Vector(3, 2), Vector(3, 3)): [OccupiableStation(self.item), Station(None)],
(Vector(5, 5),): [self.avatar],
(Vector(5, 6),): [self.wall]
}
Expand Down Expand Up @@ -69,14 +71,23 @@ def test_walled_fail(self):
def test_get_objects_station(self):
stations: list[tuple[Vector, list[Station]]] = self.game_board.get_objects(ObjectType.STATION)
self.assertTrue(all(map(lambda station: isinstance(station[1][0], Station), stations)))
self.assertEqual(len(stations), 2)
self.assertEqual(len(stations), 3)

# test that get_objects works correctly with occupiable stations
def test_get_objects_occupiable_station(self):
occupiable_stations: list[tuple[Vector, list[OccupiableStation]]] = self.game_board.get_objects(ObjectType.OCCUPIABLE_STATION)
self.assertTrue(
all(map(lambda occupiable_station: isinstance(occupiable_station[1][0], OccupiableStation), occupiable_stations)))
self.assertEqual(len(occupiable_stations), 1)
objects_stacked = [x[1] for x in occupiable_stations]
objects_unstacked = [x for xs in objects_stacked for x in xs]
self.assertEqual(len(objects_unstacked), 6)

def test_get_objects_occupiable_station_2(self):
occupiable_stations: list[tuple[Vector, list[OccupiableStation]]] = self.game_board.get_objects(ObjectType.OCCUPIABLE_STATION)
self.assertTrue(any(map(lambda vec_list: len(vec_list[1]) == 3, occupiable_stations)))
objects_stacked = [x[1] for x in occupiable_stations]
objects_unstacked = [x for xs in objects_stacked for x in xs]
self.assertEqual(len(objects_unstacked), 6)

# test that get_objects works correctly with avatar
def test_get_objects_avatar(self):
Expand Down
12 changes: 0 additions & 12 deletions game/test_suite/tests/test_game_board_no_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,6 @@ def test_locations_fail_type(self):
self.assertEqual(str(e.exception), 'Locations must be a dict. The key must be a tuple of Vector Objects, '
'and the value a list of GameObject.')

def test_locations_fail_len(self):
with self.assertRaises(ValueError) as e:
self.locations = {
(Vector(1, 1),): [],
(Vector(1, 2), Vector(1, 3)): [OccupiableStation(self.item), Station(None)],
(Vector(5, 5),): [Station(None)],
(Vector(5, 6),): [self.wall]
}
self.game_board.locations = self.locations
self.assertEqual(str(e.exception), 'Cannot set the locations for the game_board. A key has a different length '
'than its key.')

# test walled
def test_walled(self):
self.game_board.walled = True
Expand Down
2 changes: 1 addition & 1 deletion server/models/group_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ class GroupRun(Base):
launcher_version: Mapped[str] = mapped_column(String(10), nullable=False)
runs_per_client: Mapped[int] = mapped_column(Integer(), nullable=False)
is_finished: Mapped[bool] = mapped_column(Boolean(), default=False, nullable=False)
runs: Mapped[list[Run]] = relationship()
runs: Mapped[list[Run]] = relationship(back_populates='group_run')
4 changes: 3 additions & 1 deletion server/models/university.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from sqlalchemy import Integer, CheckConstraint, String
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.orm import relationship, Mapped, mapped_column
import team

from .base import Base

Expand All @@ -8,3 +9,4 @@ class University(Base):
__tablename__: str = 'university'
uni_id: Mapped[int] = mapped_column(Integer(), primary_key=True, autoincrement=True)
uni_name: Mapped[str] = mapped_column(String(100), CheckConstraint("uni_name != ''"), nullable=False, unique=True)
teams: Mapped[list[team.Team]] = relationship(back_populates='teams')
18 changes: 18 additions & 0 deletions server/schemas/errors_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from __future__ import annotations
from pydantic import BaseModel
import run_schema, submission_schema


class ErrorsBase(BaseModel):
error_id: int
run_id: int
submission_id: int
error_txt: str

class Config:
from_attributes = True


class ErrorsSchema(ErrorsBase):
runs_id: list[run_schema.RunBase] = []
submission_id: list[submission_schema.SubmissionBase] = []
18 changes: 18 additions & 0 deletions server/schemas/group_run_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from __future__ import annotations
from pydantic import BaseModel
import run_schema


class GroupRunBase(BaseModel):
group_run_id: int
start_run: str
launcher_version: str
runs_per_client: int
is_finished: bool

class Config:
from_attributes = True


class GroupRunSchema(GroupRunBase):
runs: list[run_schema.RunBase] = []
22 changes: 22 additions & 0 deletions server/schemas/run_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from __future__ import annotations
from pydantic import BaseModel
import group_run_schema, errors_schema, turn_table_schema


class RunBase(BaseModel):
run_id: int
group_run_id: int
run_time: str
winner: bool
player_1: int
player_2: int
seed: int

class Config:
from_attributes = True


class RunSchema(RunBase):
group_run: group_run_schema.GroupRunBase
errors: errors_schema.ErrorsBase
turn_tables: list[turn_table_schema.TurnTableBase] = []
18 changes: 18 additions & 0 deletions server/schemas/submission_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from __future__ import annotations
from pydantic import BaseModel
import team_schema, errors_schema


class SubmissionBase(BaseModel):
submission_id: int
team_id_uuid: int
submission_time: str
file_txt: str

class Config:
from_attributes = True


class SubmissionSchema(SubmissionBase):
team_id: list[team_schema.TeamBase] = []
errors: list[errors_schema.ErrorsBase] = []
23 changes: 23 additions & 0 deletions server/schemas/team_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from __future__ import annotations
from pydantic import BaseModel
import university_schema, team_type_schema, submission_schema


class TeamBase(BaseModel):
uni_id: int
team_type_id: int
team_name: str

class Config:
from_attributes = True


class TeamIdSchema(TeamBase):
team_id_uuid: int


# University <-> Team: Many to One
class TeamSchema(TeamBase):
uni_id: int = university_schema.UniversityBase
team_type_id: int = team_type_schema.TeamTypeBase
submissions: list[submission_schema.SubmissionBase] = []
15 changes: 15 additions & 0 deletions server/schemas/team_type_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from __future__ import annotations
from pydantic import BaseModel
import team_schema


class TeamTypeBase(BaseModel):
team_type_id: int
team_type_name: str

class Config:
from_attributes = True


class TeamTypeSchema(TeamTypeBase):
teams: list[team_schema.TeamBase] = []
17 changes: 17 additions & 0 deletions server/schemas/turn_table_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from __future__ import annotations
from pydantic import BaseModel
import run_schema


class TurnTableBase(BaseModel):
turn_id: int
turn_number: int
run_id: int
turn_data: str

class Config:
from_attributes = True


class TurnTableSchema(TurnTableBase):
run: run_schema.RunBase
16 changes: 16 additions & 0 deletions server/schemas/university_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from __future__ import annotations
from pydantic import BaseModel
import team_schema


class UniversityBase(BaseModel):
uni_id: id
uni_name: str

class Config:
from_attributes = True


# University <-> Team: Many to One
class UniversitySchema(UniversityBase):
teams: list[team_schema.TeamBase] = []