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

tests for station & test fixes #31

Merged
merged 5 commits into from
May 6, 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
2 changes: 1 addition & 1 deletion base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def team_name(self):
return 'Team Name'

# This is where your AI will decide what to do
def take_turn(self, turn, actions, world):
def take_turn(self, turn, actions, world, avatar):
"""
This is where your AI will decide what to do.
:param turn: The current turn of the game.
Expand Down
2 changes: 1 addition & 1 deletion base_client_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def team_name(self):
return 'Team Name'

# This is where your AI will decide what to do
def take_turn(self, turn, actions, world):
def take_turn(self, turn, actions, world, avatar):
"""
This is where your AI will decide what to do.
:param turn: The current turn of the game.
Expand Down
4 changes: 2 additions & 2 deletions game/client/user_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

class UserClient:
def __init__(self):
self.debug_level = DebugLevel.client
self.debug_level = DebugLevel.CLIENT
self.debug = True

def print(self, *args):
Expand All @@ -15,5 +15,5 @@ def print(self, *args):
def team_name(self):
return "No_Team_Name_Available"

def take_turn(self, turn, actions, world):
def take_turn(self, turn, actions, world, avatar):
raise NotImplementedError("Implement this in subclass")
6 changes: 3 additions & 3 deletions game/common/avatar.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,10 @@ def from_json(self, data: dict) -> Self:
self.held_item = None
return self

match held_item['object_type']:
match ObjectType(held_item['object_type']):
case ObjectType.ITEM:
self.held_item = Item().from_json(data['held_item'])
self.held_item = Item().from_json(held_item)
case _:
raise ValueError(f'{self.__class__.__name__}.held_item needs to be an item.')
raise ValueError(f'held_item needs to be an item, not {held_item}.')

return self
3 changes: 3 additions & 0 deletions game/common/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class ObjectType(Enum):
OCCUPIABLE = auto()
STATION = auto()
OCCUPIABLE_STATION = auto()
STATION_EXAMPLE = auto()
STATION_RECEIVER_EXAMPLE = auto()
OCCUPIABLE_STATION_EXAMPLE = auto()


class ActionType(Enum):
Expand Down
4 changes: 2 additions & 2 deletions game/common/game_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ def to_json(self) -> dict:
data = dict()

data['id'] = self.id
data['object_type'] = self.object_type
data['object_type'] = self.object_type.value

return data

def from_json(self, data: dict) -> Self:
# It is recommended call this using super() in child implementations
self.id = data['id']
self.object_type = data['object_type']
self.object_type = ObjectType(data['object_type'])
return self

def obfuscate(self):
Expand Down
10 changes: 5 additions & 5 deletions game/common/items/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class Item(GameObject):
*** Refer to avatar.py for a more in-depth explanation of how picking up items work with examples. ***
"""

def __init__(self, value: int = 1, durability: int | None = 100, quantity: int = 1, stack_size: int = 1):
def __init__(self, value: int = 1, durability: int | None = None, quantity: int = 1, stack_size: int = 1):
super().__init__()
self.__quantity = None # This is here to prevent an error
self.__durability = None # This is here to prevent an error
Expand All @@ -87,7 +87,7 @@ def stack_size(self) -> int:
return self.__stack_size

@durability.setter
def durability(self, durability: int | None):
def durability(self, durability: int | None) -> None:
if durability is not None and not isinstance(durability, int):
raise ValueError(f'{self.__class__.__name__}.durability must be an int or None.')
if durability is not None and self.stack_size != 1:
Expand Down Expand Up @@ -145,16 +145,16 @@ def pick_up(self, item: Self) -> Self | None:

def to_json(self) -> dict:
data: dict = super().to_json()
data['stack_size'] = self.stack_size
data['durability'] = self.durability
data['value'] = self.value
data['quantity'] = self.quantity
data['stack_size'] = self.stack_size
return data

def from_json(self, data: dict) -> Self:
super().from_json(data)
self.durability: int | None = data['durability']
self.value: int = data['value']
self.quantity: int = data['quantity']
self.stack_size: int = data['stack_size']
self.quantity: int = data['quantity']
self.value: int = data['value']
return self
7 changes: 4 additions & 3 deletions game/common/map/game_board.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ def generate_event(self, start: int, end: int) -> None:
self.event_active = random.randint(start, end)

def __from_json_helper(self, data: dict) -> GameObject:
match data['object_type']:
temp:ObjectType = ObjectType(data['object_type'])
match temp:
case ObjectType.WALL:
return Wall().from_json(data)
case ObjectType.OCCUPIABLE_STATION:
Expand All @@ -287,6 +288,6 @@ def from_json(self, data: dict) -> Self:
zip(data["location_vectors"], data["location_objects"])} if data["location_vectors"] is not None else None
self.walled: bool = data["walled"]
self.event_active: int = data['event_active']
self.game_map: list[list[Tile]] = list(
list(map(lambda tile: Tile().from_json(tile), y)) for y in temp) if temp is not None else None
self.game_map: list[list[Tile]] = [
[Tile().from_json(tile) for tile in y] for y in temp] if temp is not None else None
return self
14 changes: 7 additions & 7 deletions game/common/map/tile.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,20 @@ def __init__(self, occupied_by: GameObject = None):

def from_json(self, data: dict) -> Self:
super().from_json(data)
occupied_by: dict = data['occupied_by']
occupied_by: dict | None = data['occupied_by']
if occupied_by is None:
self.occupied_by = None
return self
# Add all possible game objects that can occupy a tile here (requires python 3.10)
match occupied_by['object_type']:
match ObjectType(occupied_by['object_type']):
case ObjectType.AVATAR:
self.occupied_by: Avatar = Avatar().from_json(data['occupied_by'])
self.occupied_by: Avatar = Avatar().from_json(occupied_by)
case ObjectType.OCCUPIABLE_STATION:
self.occupied_by: OccupiableStation = OccupiableStation().from_json(data['occupied_by'])
self.occupied_by: OccupiableStation = OccupiableStation().from_json(occupied_by)
case ObjectType.STATION:
self.occupied_by: Station = Station().from_json(data['occupied_by'])
self.occupied_by: Station = Station().from_json(occupied_by)
case ObjectType.WALL:
self.occupied_by: Wall = Wall().from_json(data['occupied_by'])
self.occupied_by: Wall = Wall().from_json(occupied_by)
case _:
raise Exception(f'Could not parse occupied_by: {self.occupied_by}')
raise Exception(f'Could not parse occupied_by: {occupied_by}')
return self
10 changes: 5 additions & 5 deletions game/common/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def __init__(self, code: object | None = None, team_name: str | None = None, act
self.team_name: str | None = team_name
self.code: object = code
# self.action: Action = action
self.actions: list[ActionType] | list = actions
self.actions: list[ActionType] = actions
self.avatar: Avatar | None = avatar

@property
Expand Down Expand Up @@ -69,7 +69,7 @@ def avatar(self, avatar: Avatar) -> None:

@property
def object_type(self) -> ObjectType:
return self.object_type
return self.__object_type

@object_type.setter
def object_type(self, object_type: ObjectType) -> None:
Expand All @@ -83,7 +83,7 @@ def to_json(self):
data['functional'] = self.functional
# data['error'] = self.error # .to_json() if self.error is not None else None
data['team_name'] = self.team_name
data['actions'] = self.actions
data['actions'] = [act.value for act in self.actions]
data['avatar'] = self.avatar.to_json() if self.avatar is not None else None

return data
Expand All @@ -95,7 +95,7 @@ def from_json(self, data):
# self.error = data['error'] # .from_json(data['action']) if data['action'] is not None else None
self.team_name = data['team_name']

self.actions: list[ActionType] | list = data['actions']
self.actions: list[ActionType] = [ObjectType(action) for action in data['actions']]
avatar: Avatar | None = data['avatar']
if avatar is None:
self.avatar = None
Expand All @@ -110,7 +110,7 @@ def from_json(self, data):
# raise Exception(f'Could not parse action: {self.action}')

# match case for avatar
match avatar['object_type']:
match ObjectType(avatar['object_type']):
case ObjectType.AVATAR:
self.avatar = Avatar().from_json(data['avatar'])
case None:
Expand Down
10 changes: 5 additions & 5 deletions game/common/stations/occupiable_station.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ def from_json(self, data: dict) -> Self:
self.occupied_by = None
return self
# Add all possible game objects that can occupy a tile here (requires python 3.10)
match occupied_by['object_type']:
match ObjectType(occupied_by['object_type']):
case ObjectType.AVATAR:
self.occupied_by: Avatar = Avatar().from_json(data['occupied_by'])
self.occupied_by: Avatar = Avatar().from_json(occupied_by)
case ObjectType.OCCUPIABLE_STATION:
self.occupied_by: OccupiableStation = OccupiableStation().from_json(data['occupied_by'])
self.occupied_by: OccupiableStation = OccupiableStation().from_json(occupied_by)
case ObjectType.STATION:
self.occupied_by: Station = Station().from_json(data['occupied_by'])
self.occupied_by: Station = Station().from_json(occupied_by)
case _:
raise Exception(f'Could not parse occupied_by: {self.occupied_by}')
raise Exception(f'Could not parse occupied_by: {occupied_by}')
return self
13 changes: 13 additions & 0 deletions game/common/stations/occupiable_station_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from game.common.avatar import Avatar
from game.common.enums import ObjectType
from game.common.items.item import Item
from game.common.stations.occupiable_station import OccupiableStation

# create example of occupiable_station that gives item
class OccupiableStationExample(OccupiableStation):
def __init__(self, held_item: Item | None = None):
super().__init__(held_item=held_item)
self.object_type = ObjectType.STATION_EXAMPLE

def take_action(self, avatar: Avatar) -> Item | None:
avatar.pick_up(self.held_item)
10 changes: 5 additions & 5 deletions game/common/stations/station.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ def held_item(self, held_item: Item) -> None:
raise ValueError(f'{self.__class__.__name__}.held_item must be an Item or None, not {held_item}.')
self.__item = held_item

# take action method
# base of take action method, defined in classes that extend Station (StationExample demonstrates this)
def take_action(self, avatar: Avatar) -> Item | None:
return self.held_item
pass

# json methods
def to_json(self) -> dict:
Expand All @@ -47,9 +47,9 @@ def from_json(self, data: dict) -> Self:
return self

# framework match case for from json, can add more object types that can be item
match held_item['object_type']:
match ObjectType(held_item['object_type']):
case ObjectType.ITEM:
self.held_item = Item().from_json(data['held_item'])
self.held_item = Item().from_json(held_item)
case _:
raise Exception(f'Could not parse held_item: {self.held_item}')
raise Exception(f'Could not parse held_item: {held_item}')
return self
13 changes: 13 additions & 0 deletions game/common/stations/station_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from game.common.avatar import Avatar
from game.common.enums import ObjectType
from game.common.items.item import Item
from game.common.stations.station import Station

# create example of station that gives item to avatar
class StationExample(Station):
def __init__(self, held_item: Item | None = None):
super().__init__(held_item=held_item)
self.object_type = ObjectType.STATION_EXAMPLE

def take_action(self, avatar: Avatar) -> Item | None:
avatar.pick_up(self.held_item)
15 changes: 15 additions & 0 deletions game/common/stations/station_receiver_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from game.common.avatar import Avatar
from game.common.enums import ObjectType
from game.common.items.item import Item
from game.common.stations.station import Station

# create example of station that takes held_item from avatar at inventory slot 0
class StationReceiverExample(Station):
def __init__(self, held_item: Item | None = None):
super().__init__(held_item=held_item)
self.object_type = ObjectType.STATION_RECEIVER_EXAMPLE

def take_action(self, avatar: Avatar) -> None:
self.held_item = avatar.held_item
# assuming held_item is stored at index 0 in inventory
avatar.inventory.pop(0)
19 changes: 15 additions & 4 deletions game/controllers/master_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from game.controllers.interact_controller import InteractController
from game.common.map.game_board import GameBoard
from game.config import MAX_NUMBER_OF_ACTIONS_PER_TURN
from game.utils.vector import Vector


class MasterController(Controller):
Expand Down Expand Up @@ -65,8 +66,12 @@ def __init__(self):
# Receives all clients for the purpose of giving them the objects they will control
def give_clients_objects(self, clients: list[Player], world: dict):
# starting_positions = [[3, 3], [3, 9]] # would be done in generate game
for index, client in enumerate(clients):
client.avatar = Avatar(position=world[index])
gb: GameBoard = world['game_board']
avatars: list[Avatar] = gb.get_objects(ObjectType.AVATAR)
for avatar, client in zip(avatars,clients):
avatar.position = Vector(1,1)
client.avatar = avatar


# Generator function. Given a key:value pair where the key is the identifier for the current world and the value is
# the state of the world, returns the key that will give the appropriate world information
Expand Down Expand Up @@ -108,8 +113,14 @@ def client_turn_arguments(self, client: Player, turn):
def turn_logic(self, clients: list[Player], turn):
for client in clients:
for i in range(MAX_NUMBER_OF_ACTIONS_PER_TURN):
self.movement_controller.handle_actions(client.actions[i], client, self.current_world_data["game_board"])
self.interact_controller.handle_actions(client.actions[i], client, self.current_world_data["game_board"])
try:
self.movement_controller.handle_actions(client.actions[i], client, self.current_world_data["game_board"])
except IndexError:
pass
try:
self.interact_controller.handle_actions(client.actions[i], client, self.current_world_data["game_board"])
except IndexError:
pass
# checks event logic at the end of round
# self.handle_events(clients)

Expand Down
9 changes: 2 additions & 7 deletions game/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,16 +177,11 @@ def pre_tick(self):
# Increment the tick
self.tick_number += 1

# Retrieve current world info
if self.current_world_key not in self.world:
raise KeyError('Given generated world key does not exist inside the world.')
current_world = self.world[self.current_world_key]

# Send current world information to master controller for purposes
if SET_NUMBER_OF_CLIENTS_START == 1:
self.master_controller.interpret_current_turn_data(self.clients[0], current_world, self.tick_number)
self.master_controller.interpret_current_turn_data(self.clients[0], self.world, self.tick_number)
else:
self.master_controller.interpret_current_turn_data(self.clients, current_world, self.tick_number)
self.master_controller.interpret_current_turn_data(self.clients, self.world, self.tick_number)

# Does actions like lets the player take their turn and asks master controller to perform game logic
def tick(self):
Expand Down
Loading