diff --git a/.github/workflows/python-autopep8-enforcement.yml b/.github/workflows/python-autopep8-enforcement.yml new file mode 100644 index 00000000..a0ae705b --- /dev/null +++ b/.github/workflows/python-autopep8-enforcement.yml @@ -0,0 +1,24 @@ +name: autopep8 +on: pull_request +jobs: + autopep8: + # Check if the PR is not from a fork + if: github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + ref: ${{ github.head_ref }} + - name: autopep8 + id: autopep8 + uses: peter-evans/autopep8@v1 + with: + args: --exit-code --recursive --in-place --aggressive --aggressive . + - name: Commit autopep8 changes + if: steps.autopep8.outputs.exit-code == 2 + run: | + git config --global user.name 'Github Actions' + git config --global user.email 'action@github.com' + git commit -am "Automated autopep8 fixes" + git push diff --git a/game/common/door.py b/game/common/door.py index 9415f747..837df477 100644 --- a/game/common/door.py +++ b/game/common/door.py @@ -4,19 +4,23 @@ class Door(MapObject): - def __init__(self, hitbox, health = GameStats.default_wall_health, open_speed = GameStats.door_opening_speed): - super().__init__(health,hitbox, collidable = True ) + def __init__( + self, + hitbox, + health=GameStats.default_wall_health, + open_speed=GameStats.door_opening_speed): + super().__init__(health, hitbox, collidable=True) self.opening_speed = open_speed - self.open_state = False + self.open_state = False self.object_type = ObjectType.door - + def to_json(self): data = super().to_json() data['opening_speed'] = self.opening_speed data['open_state'] = self.open_state return data - + def from_json(self, data): super().from_json(data) self.opening_speed = data['opening_speed'] - self.open_state = data['open_state'] \ No newline at end of file + self.open_state = data['open_state'] diff --git a/game/common/enums.py b/game/common/enums.py index 499a9069..2b420eef 100644 --- a/game/common/enums.py +++ b/game/common/enums.py @@ -22,20 +22,20 @@ class ObjectType: door = 13 upgrade = 14 consumable = 15 - + class Upgrades: none = 0 gun_upgrades = 1 movement_upgrades = 2 sight_upgrades = 3 - - + + class DamagingType: none = 0 - #note that bullet object has not been added yet + # note that bullet object has not been added yet bullet = 1 - grenade = 2 + grenade = 2 class GunType: @@ -45,14 +45,14 @@ class GunType: shotgun = 3 sniper = 4 - + class GunLevel: level_zero = 0 level_one = 1 level_two = 2 level_three = 3 - + class ShotPattern: none = 0 single = 1 @@ -64,4 +64,4 @@ class Consumables: none = 0 speed_boost = 1 health_pack = 2 - armor_pack = 3 \ No newline at end of file + armor_pack = 3 diff --git a/game/common/game_board.py b/game/common/game_board.py index bf89b65b..baf9503b 100644 --- a/game/common/game_board.py +++ b/game/common/game_board.py @@ -5,11 +5,13 @@ class GameBoard(GameObject): - # the width and height parameters have default values to allow them to be set for unit testing purposes - def __init__(self, width=GameStats.game_board_width, height=GameStats.game_board_height): + # the width and height parameters have default values to allow them to be + # set for unit testing purposes + def __init__(self, width=GameStats.game_board_width, + height=GameStats.game_board_height): super().__init__() self.object_type = ObjectType.game_board - + # pull width and height values from GameStats self.width = width self.height = height @@ -22,7 +24,8 @@ def __init__(self, width=GameStats.game_board_width, height=GameStats.game_board self.lethal_list = [] # this calculates starting radius to totally encompass the map at start - self.circle_radius = math.sqrt( ( self.width / 2 ) ** 2 + ( self.height / 2 ) ** 2 ) + self.circle_radius = math.sqrt( + (self.width / 2) ** 2 + (self.height / 2) ** 2) # set turn counter to 0, not sure the use for this yet self.turn = 0 @@ -53,7 +56,7 @@ def to_json(self): def from_json(self, data): super().from_json(data) - self.width = data['width'] + self.width = data['width'] self.height = data['height'] self.player_list = data['player_list'] @@ -63,5 +66,5 @@ def from_json(self, data): self.lethal_list = data['lethal_list'] self.circle_radius = data['circle_radius'] - - self.turn = data['turn'] \ No newline at end of file + + self.turn = data['turn'] diff --git a/game/common/hitbox.py b/game/common/hitbox.py index 927140b7..43c210a4 100644 --- a/game/common/hitbox.py +++ b/game/common/hitbox.py @@ -38,12 +38,18 @@ def bottomLeft(self): @property def bottomRight(self): - return (self.position[0] + self.width, self.position[1] +self.height) + return (self.position[0] + self.width, self.position[1] + self.height) @property def middle(self): - return (self.position[0] + self.width / 2, self.position[1] +self.height / 2) - + return ( + self.position[0] + + self.width / + 2, + self.position[1] + + self.height / + 2) + # set height between 0 and max @height.setter def height(self, val): @@ -51,29 +57,31 @@ def height(self, val): self.__height = val else: raise ValueError("Tried to set an invalid height for hitbox") - + # Set width for hitbox between 0 and max @width.setter def width(self, val): if val > 0: self.__width = val - else: + else: raise ValueError("Tried to set an invalid width for hitbox") # set x between 0 and max game board width @position.setter def position(self, val): - if (0 <= val[0] <= GameStats.game_board_width) and (0 <= val[1] <= GameStats.game_board_height): + if (0 <= val[0] <= GameStats.game_board_width) and ( + 0 <= val[1] <= GameStats.game_board_height): self.__position = val else: - raise ValueError("Tried to set an invalid xy position tuple for hitbox") - + raise ValueError( + "Tried to set an invalid xy position tuple for hitbox") + def to_json(self): data = super().to_json() data['width'] = self.width data['height'] = self.height data['position'] = self.position - + return data def from_json(self, data): @@ -83,7 +91,7 @@ def from_json(self, data): self.position = data['position'] def __str__(self): - return f""" + return f""" Height: {self.height} Width: {self.width} X: {self.position} diff --git a/game/common/items/consumable.py b/game/common/items/consumable.py index e0d68633..429496e1 100644 --- a/game/common/items/consumable.py +++ b/game/common/items/consumable.py @@ -3,21 +3,28 @@ class Consumable(Item): - def __init__(self, hitbox, health, count, speed_enum = None, health_enum = None, armor_enum = None): + def __init__( + self, + hitbox, + health, + count, + speed_enum=None, + health_enum=None, + armor_enum=None): super().__init__(hitbox, health, count) self.object_type = ObjectType.consumable self.speed_enum = speed_enum self.health_enum = health_enum self.armor_enum = armor_enum - + def to_json(self): data = super().to_json() data['speed_enum'] = self.speed_enum data['health_enum'] = self.health_enum data['armor_enum'] = self.armor_enum - + def from_json(self, data): super().from_json(data) self.speed_enum = data['speed_enum'] self.health_enum = data['health_enum'] - self.armor_enum = data['armor_enum'] \ No newline at end of file + self.armor_enum = data['armor_enum'] diff --git a/game/common/items/gun.py b/game/common/items/gun.py index 5d1fdc9f..ea999d82 100644 --- a/game/common/items/gun.py +++ b/game/common/items/gun.py @@ -12,25 +12,27 @@ def __init__(self, gun_type, level, coordinates=None, hitbox=None): # Leveling subject to change self.level = level self.pattern = stats.GameStats.gun_stats[gun_type]['pattern'] - self.damage = (round(stats.GameStats.gun_stats[gun_type]['damage'] - * (stats.GameStats.gun_stats[gun_type]['level_mod'] ** self.level), 1) - if self.level > GunLevel.level_zero else 0) + self.damage = ( + round( + stats.GameStats.gun_stats[gun_type]['damage'] * ( + stats.GameStats.gun_stats[gun_type]['level_mod'] ** self.level), + 1) if self.level > GunLevel.level_zero else 0) self.fire_rate = (round(stats.GameStats.gun_stats[gun_type]['fire_rate'] - * (stats.GameStats.gun_stats[gun_type]['level_mod'] ** self.level)) - if self.level > GunLevel.level_zero else 0) + * (stats.GameStats.gun_stats[gun_type]['level_mod'] ** self.level)) + if self.level > GunLevel.level_zero else 0) self.range = (round(stats.GameStats.gun_stats[gun_type]['range'] - * (stats.GameStats.gun_stats[gun_type]['level_mod'] ** self.level)) - if self.level > GunLevel.level_zero else 0) + * (stats.GameStats.gun_stats[gun_type]['level_mod'] ** self.level)) + if self.level > GunLevel.level_zero else 0) self.mag_size = (round(stats.GameStats.gun_stats[gun_type]['mag_size'] - * (stats.GameStats.gun_stats[gun_type]['level_mod'] ** self.level)) - if self.level > GunLevel.level_zero else 0) + * (stats.GameStats.gun_stats[gun_type]['level_mod'] ** self.level)) + if self.level > GunLevel.level_zero else 0) self.reload_speed = (round(stats.GameStats.gun_stats[gun_type]['reload_speed'] - * (stats.GameStats.gun_stats[gun_type]['level_mod'] ** self.level)) - if self.level > GunLevel.level_zero else 0) + * (stats.GameStats.gun_stats[gun_type]['level_mod'] ** self.level)) + if self.level > GunLevel.level_zero else 0) if self.level > GunLevel.level_zero: self.cooldown = stats.GameStats.gun_stats[gun_type]['cooldown'] - self.cooldown['max'] = round(self.cooldown['max'] - * (stats.GameStats.gun_stats[gun_type]['level_mod'] ** self.level)) + self.cooldown['max'] = round( + self.cooldown['max'] * (stats.GameStats.gun_stats[gun_type]['level_mod'] ** self.level)) else: self.cooldown = {'max': 0, 'rate': 0} diff --git a/game/common/items/item.py b/game/common/items/item.py index 4f99ddc3..8ffd6aeb 100644 --- a/game/common/items/item.py +++ b/game/common/items/item.py @@ -1,12 +1,13 @@ from game.common.map_object import MapObject from game.common.enums import ObjectType + class Item(MapObject): - def __init__(self, hitbox, health=None, count = 1): + def __init__(self, hitbox, health=None, count=1): super().__init__(health, hitbox, True) self.object_type = ObjectType.item self.count = count - + def to_json(self): data = super().to_json() data['count'] = self.count diff --git a/game/common/items/upgrade.py b/game/common/items/upgrade.py index eeb1f4c9..9e82b370 100644 --- a/game/common/items/upgrade.py +++ b/game/common/items/upgrade.py @@ -4,21 +4,28 @@ class Upgrade(Item): - - def __init__ (self, hitbox, health, count, upgrade_enum = None, movement_enum = None, sight_enum = None ): + + def __init__( + self, + hitbox, + health, + count, + upgrade_enum=None, + movement_enum=None, + sight_enum=None): super().__init__(hitbox, health, count) self.object_type = ObjectType.upgrade self.upgrade_enum = upgrade_enum self.movement_enum = movement_enum self.sight_enum = sight_enum - + def to_json(self): data = super().to_json() data['upgrade_enum'] = self.upgrade_enum data['movement_enum'] = self.movement_enum data['sight_enum'] = self.sight_enum return data - + def from_json(self, data): super().from_json(data) self.upgrade_enum = data['upgrade_enum'] diff --git a/game/common/map_object.py b/game/common/map_object.py index 2ce4caeb..3fe4d8e8 100644 --- a/game/common/map_object.py +++ b/game/common/map_object.py @@ -9,7 +9,7 @@ def __init__(self, health=None, hitbox=None, collidable=None): self.health = health self.hitbox = hitbox self.collidable = collidable - + def to_json(self): data = super().to_json() data['health'] = self.health @@ -27,7 +27,7 @@ def from_json(self, data): self.collidable = data['collidable'] def __str__(self): - return f""" + return f""" Health: {self.health} Coordinates: {self.coordinates} Hitbox: {self.hitbox} diff --git a/game/common/moving/damaging/damaging_object.py b/game/common/moving/damaging/damaging_object.py index cb784d6a..d8a39ab3 100644 --- a/game/common/moving/damaging/damaging_object.py +++ b/game/common/moving/damaging/damaging_object.py @@ -4,15 +4,14 @@ from game.common.enums import * - class DamagingObject(MovingObject): - def __init__(self, range=0, damage=0, heading = None, speed = None, - health=None, hitbox=None, collidable=None): + def __init__(self, range=0, damage=0, heading=None, speed=None, + health=None, hitbox=None, collidable=None): super().__init__(heading, speed, health, hitbox, collidable) self.range = range self.damage = damage self.object_type = ObjectType.damaging_object - + @property def range(self): return self.__range @@ -23,11 +22,11 @@ def range(self, value): self.__range = value else: raise Exception("Range value outside bounds, Not set") - + @property def damage(self): return self.__damage - + @damage.setter def damage(self, value): if value >= 0 and value <= GameStats.damaging_object_stats['max_damage']: @@ -35,16 +34,14 @@ def damage(self, value): else: raise Exception("Damage value outside bounds, Not set") - def to_json(self): data = super().to_json() data['range'] = self.range data['damage'] = self.damage return data - + def from_json(self, data): super().from_json(data) self.range = data['range'] self.damage = data['damage'] - \ No newline at end of file diff --git a/game/common/moving/damaging/grenade.py b/game/common/moving/damaging/grenade.py index e792ed2d..d4f7a992 100644 --- a/game/common/moving/damaging/grenade.py +++ b/game/common/moving/damaging/grenade.py @@ -4,24 +4,31 @@ class Grenade(DamagingObject): - def __init__(self, fuse_time = GameStats.grenade_stats['min_fuse_time'], range= None, damage= None, - heading = None, speed = None, health=None, hitbox=None, collidable=None): + def __init__( + self, + fuse_time=GameStats.grenade_stats['min_fuse_time'], + range=None, + damage=None, + heading=None, + speed=None, + health=None, + hitbox=None, + collidable=None): super().__init__(range, damage, heading, speed, health, hitbox, collidable) self.fuse_time = fuse_time self.object_type = ObjectType.grenade - - @property + + @property def fuse_time(self): return self.__fuse_time - + @fuse_time.setter def fuse_time(self, val): if val >= GameStats.grenade_stats['min_fuse_time'] and val <= GameStats.grenade_stats['max_fuse_time']: - self.__fuse_time = val + self.__fuse_time = val else: raise Exception("fuse time value outside bounds, Not set") - - + def to_json(self): data = super().to_json() data['fuse_time'] = self.fuse_time diff --git a/game/common/moving/moving_object.py b/game/common/moving/moving_object.py index 0603a43d..70c0a867 100644 --- a/game/common/moving/moving_object.py +++ b/game/common/moving/moving_object.py @@ -6,7 +6,13 @@ # Inherits MapObject class MovingObject(MapObject): - def __init__(self, heading=0, speed=0, health=None, hitbox=None, collidable=None): + def __init__( + self, + heading=0, + speed=0, + health=None, + hitbox=None, + collidable=None): super().__init__(health, hitbox, collidable) self.heading = heading self.speed = speed @@ -19,7 +25,7 @@ def heading(self): @property def speed(self): return self.__speed - + # setter for heading. Should be degrees between 0 and 360 inclusive @heading.setter def heading(self, val): @@ -27,13 +33,13 @@ def heading(self, val): self.__heading = val else: raise Exception("Heading value outside bounds, Not set") - + # Set speed must be greater than 0 @speed.setter def speed(self, val): if val >= 0 and val <= GameStats.moving_object_stats['max_speed']: self.__speed = val - else: + else: raise Exception("Speed value outside bounds, Not set") # To_json creates a dictionary representation of the object. @@ -51,4 +57,4 @@ def to_json(self): def from_json(self, data): super().from_json(data) self.heading = data['heading'] - self.speed = data['speed'] \ No newline at end of file + self.speed = data['speed'] diff --git a/game/common/moving/shooter.py b/game/common/moving/shooter.py index f277fd5c..86813825 100644 --- a/game/common/moving/shooter.py +++ b/game/common/moving/shooter.py @@ -9,7 +9,12 @@ class Shooter(MovingObject): """The main player within the game logic""" - def __init__(self, heading=0, speed=0, coordinates=GameStats.player_stats['starting_coordinates'][0]): + + def __init__( + self, + heading=0, + speed=0, + coordinates=GameStats.player_stats['starting_coordinates'][0]): super().__init__( heading, speed, @@ -28,16 +33,19 @@ def __init__(self, heading=0, speed=0, coordinates=GameStats.player_stats['start # To add new slots, add them to stats, they will be dynamically added to the shooter object on instantiation # Because of the way this is set up, it is VERY important that each shooter is only instantiated once per run # - # this statement grabs the slot_type as a string, the object type as a Type, and puts it into a list of tuples + # this statement grabs the slot_type as a string, the object type as a + # Type, and puts it into a list of tuples self.slot_obj_types = [ - (slot_type, slot_stats['type']) for slot_type, slot_stats in GameStats.inventory_stats.items() - ] - # this generates an empty inventory, with number of slots for each slot type taken from game stats + (slot_type, + slot_stats['type']) for slot_type, + slot_stats in GameStats.inventory_stats.items()] + # this generates an empty inventory, with number of slots for each slot + # type taken from game stats self.__inventory = { - slot_type: - [None for _ in range(GameStats.inventory_stats[slot_type]['slots'])] - for slot_type, slot_obj_type in self.slot_obj_types - } + slot_type: [ + None for _ in range( + GameStats.inventory_stats[slot_type]['slots'])] for slot_type, + slot_obj_type in self.slot_obj_types} # set initial primary gun to be none self.__primary_pointer = 0 @@ -56,25 +64,34 @@ def has_empty_slot(self, slot_type): def append_inventory(self, value): """Add object to inventory""" - if not isinstance(value, tuple(slot_type[1] for slot_type in self.slot_obj_types)): - raise TypeError(f"Value appended must be of type " - f"{[obj_type[1] for obj_type in self.slot_obj_types]} " - f"not {type(value)}") + if not isinstance( + value, tuple( + slot_type[1] for slot_type in self.slot_obj_types)): + raise TypeError( + f"Value appended must be of type " + f"{[obj_type[1] for obj_type in self.slot_obj_types]} " + f"not {type(value)}") for slot_type, slot_obj_type in self.slot_obj_types: - if isinstance(value, slot_obj_type) and self.has_empty_slot(slot_type): - self.__inventory[slot_type][self.__inventory[slot_type].index(None)] = value + if isinstance( + value, + slot_obj_type) and self.has_empty_slot(slot_type): + self.__inventory[slot_type][self.__inventory[slot_type].index( + None)] = value return None raise InventoryFullError(f"Inventory full for type {type(value)}") def remove_from_inventory(self, obj): """Remove object from inventory""" for slot_type in self.__inventory: - # this try except block checks to make sure you're only checking the correct slot type + # this try except block checks to make sure you're only checking + # the correct slot type try: - self.__inventory[slot_type][self.__inventory[slot_type].index(obj)] = None + self.__inventory[slot_type][self.__inventory[slot_type].index( + obj)] = None except ValueError: continue - # if a gun is removed and it's the primary one, cycle to the next one + # if a gun is removed and it's the primary one, cycle to the next + # one if isinstance(obj, Gun) and obj == self.primary_gun: self.cycle_primary() return obj @@ -97,7 +114,8 @@ def cycle(): cycle() # if the next gun is None, cycle until you find one that isn't if self.primary_gun is None: - # use a for loop here because you don't want infinite loop scenarios if they're all None + # use a for loop here because you don't want infinite loop + # scenarios if they're all None for gun in self.__inventory['guns']: if gun is None: cycle() @@ -105,14 +123,16 @@ def cycle(): break return self.primary_gun - # set the heading and direction in a controlled way, might need to add distance attribute later + # set the heading and direction in a controlled way, might need to add + # distance attribute later def move(self, heading, speed): """Set heading and speed to handle moving""" super().heading = heading if speed < GameStats.player_stats['move_speed']: super().speed = speed self.moving = True - raise ValueError("Speed must be less than max move speed for the player") + raise ValueError( + "Speed must be less than max move speed for the player") def stop(self): """Define stop movement""" diff --git a/game/common/player.py b/game/common/player.py index 1a531462..33c94b59 100644 --- a/game/common/player.py +++ b/game/common/player.py @@ -9,7 +9,7 @@ class Player(GameObject): def __init__(self, code=None, team_name=None, action=None): super().__init__() self.object_type = ObjectType.player - + self.functional = True self.error = None self.team_name = team_name @@ -22,18 +22,20 @@ def to_json(self): data['functional'] = self.functional data['error'] = self.error data['team_name'] = self.team_name - data['action'] = self.action.to_json() if self.action is not None else None + data['action'] = self.action.to_json( + ) if self.action is not None else None return data def from_json(self, data): super().from_json(data) - + self.functional = data['functional'] self.error = data['error'] self.team_name = data['team_name'] act = Action() - self.action = act.from_json(data['action']) if data['action'] is not None else None + self.action = act.from_json( + data['action']) if data['action'] is not None else None def __str__(self): p = f"""ID: {self.id} diff --git a/game/common/stats.py b/game/common/stats.py index 1c6c2b75..fbed4c80 100644 --- a/game/common/stats.py +++ b/game/common/stats.py @@ -36,17 +36,18 @@ class GameStats: } moving_object_stats = { - # max speed value is arbitrary at this time and will most likely be changed + # max speed value is arbitrary at this time and will most likely be + # changed 'max_speed': 500 } damaging_object_stats = { - # This is assuming the player is at the very edge of board and the object - # only stops once it hits an object. + # This is assuming the player is at the very edge of board and the object + # only stops once it hits an object. 'max_range': 500, - # This determines the max damage an object instance to do, value - # is arbitrary for now and will be changed when necessary + # This determines the max damage an object instance to do, value + # is arbitrary for now and will be changed when necessary 'max_damage': 100 } @@ -57,22 +58,61 @@ class GameStats: # Placeholder stats, stats may be created for all gun levels gun_stats = { - GunType.none: {'pattern': ShotPattern.none, 'damage': 0, - 'fire_rate': 0, 'range': 0, 'mag_size': 0, 'reload_speed': 0, - 'cooldown': {'max': 0, 'rate': 0}, 'level_mod': 1}, - GunType.handgun: {'pattern': ShotPattern.single, 'damage': 1, - 'fire_rate': 2, 'range': 30, 'mag_size': 13, 'reload_speed': 3, - 'cooldown': {'max': 8, 'rate': 2}, 'level_mod': 1.25}, - GunType.assault_rifle: {'pattern': ShotPattern.multi, 'damage': 1, - 'fire_rate': 5, 'range': 50, 'mag_size': 30, 'reload_speed': 6, - 'cooldown': {'max': 15, 'rate': 5}, 'level_mod': 1.25}, - GunType.shotgun: {'pattern': ShotPattern.spread, 'damage': 8, - 'fire_rate': 1, 'range': 10, 'mag_size': 2, 'reload_speed': 8, - 'cooldown': {'max': 1, 'rate': 1}, 'level_mod': 1.25}, - GunType.sniper: {'pattern': ShotPattern.single, 'damage': 9, - 'fire_rate': 1, 'range': 100, 'mag_size': 1, 'reload_speed': 8, - 'cooldown': {'max': 1, 'rate': 1}, 'level_mod': 1.25} - } + GunType.none: { + 'pattern': ShotPattern.none, + 'damage': 0, + 'fire_rate': 0, + 'range': 0, + 'mag_size': 0, + 'reload_speed': 0, + 'cooldown': { + 'max': 0, + 'rate': 0}, + 'level_mod': 1}, + GunType.handgun: { + 'pattern': ShotPattern.single, + 'damage': 1, + 'fire_rate': 2, + 'range': 30, + 'mag_size': 13, + 'reload_speed': 3, + 'cooldown': { + 'max': 8, + 'rate': 2}, + 'level_mod': 1.25}, + GunType.assault_rifle: { + 'pattern': ShotPattern.multi, + 'damage': 1, + 'fire_rate': 5, + 'range': 50, + 'mag_size': 30, + 'reload_speed': 6, + 'cooldown': { + 'max': 15, + 'rate': 5}, + 'level_mod': 1.25}, + GunType.shotgun: { + 'pattern': ShotPattern.spread, + 'damage': 8, + 'fire_rate': 1, + 'range': 10, + 'mag_size': 2, + 'reload_speed': 8, + 'cooldown': { + 'max': 1, + 'rate': 1}, + 'level_mod': 1.25}, + GunType.sniper: { + 'pattern': ShotPattern.single, + 'damage': 9, + 'fire_rate': 1, + 'range': 100, + 'mag_size': 1, + 'reload_speed': 8, + 'cooldown': { + 'max': 1, + 'rate': 1}, + 'level_mod': 1.25}} grenade_stats = { 'min_fuse_time': 10, @@ -80,7 +120,7 @@ class GameStats: } door_opening_speed = 1 - - Upgrades.gun_upgrades = 20 #Could potentially incease bullet speed? - Upgrades.movement_upgrades = 20 #May be used to make the player go faster? - Upgrades.sight_upgrades = 20 #Increase how far player can see? + + Upgrades.gun_upgrades = 20 # Could potentially incease bullet speed? + Upgrades.movement_upgrades = 20 # May be used to make the player go faster? + Upgrades.sight_upgrades = 20 # Increase how far player can see? diff --git a/game/common/wall.py b/game/common/wall.py index 19cd2200..0ab02ae9 100644 --- a/game/common/wall.py +++ b/game/common/wall.py @@ -4,17 +4,21 @@ class Wall(MapObject): - def __init__(self, hitbox, health = GameStats.default_wall_health, destructible = False): - super().__init__(health, hitbox, collidable = True ) + def __init__( + self, + hitbox, + health=GameStats.default_wall_health, + destructible=False): + super().__init__(health, hitbox, collidable=True) self.destructible = destructible self.object_type = ObjectType.wall self.destructible = destructible - + def to_json(self): data = super().to_json() data['destructible'] = self.destructible return data - + def from_json(self, data): super().from_json(data) - self.destructible = data['destructible'] \ No newline at end of file + self.destructible = data['destructible'] diff --git a/game/config.py b/game/config.py index 47e8d412..04e41fa2 100644 --- a/game/config.py +++ b/game/config.py @@ -2,41 +2,64 @@ from game.common.enums import * -# Runtime settings / Restrictions -------------------------------------------------------------------------------------- +# Runtime settings / Restrictions ---------------------------------------- # The engine requires these to operate -MAX_TICKS = 500 # max number of ticks the server will run regardless of game state +# max number of ticks the server will run regardless of game state +MAX_TICKS = 500 TQDM_BAR_FORMAT = "Game running at {rate_fmt} " # how TQDM displays the bar TQDM_UNITS = " turns" # units TQDM takes in the bar -MAX_SECONDS_PER_TURN = 0.1 # max number of basic operations clients have for their turns +# max number of basic operations clients have for their turns +MAX_SECONDS_PER_TURN = 0.1 -MIN_CLIENTS_START = None # minimum number of clients required to start running the game; should be None when SET_NUMBER_OF_CLIENTS is used -MAX_CLIENTS_START = None # maximum number of clients required to start running the game; should be None when SET_NUMBER_OF_CLIENTS is used -SET_NUMBER_OF_CLIENTS_START = 2 # required number of clients to start running the game; should be None when MIN_CLIENTS or MAX_CLIENTS are used -CLIENT_KEYWORD = "client" # string required to be in the name of every client file, not found otherwise -CLIENT_DIRECTORY = "./" # location where client code will be found +# minimum number of clients required to start running the game; should be +# None when SET_NUMBER_OF_CLIENTS is used +MIN_CLIENTS_START = None +# maximum number of clients required to start running the game; should be +# None when SET_NUMBER_OF_CLIENTS is used +MAX_CLIENTS_START = None +# required number of clients to start running the game; should be None +# when MIN_CLIENTS or MAX_CLIENTS are used +SET_NUMBER_OF_CLIENTS_START = 2 +# string required to be in the name of every client file, not found otherwise +CLIENT_KEYWORD = "client" +# location where client code will be found +CLIENT_DIRECTORY = "./" -MIN_CLIENTS_CONTINUE = None # minimum number of clients required to continue running the game; should be None when SET_NUMBER_OF_CLIENTS is used -MAX_CLIENTS_CONTINUE = None # maximum number of clients required to continue running the game; should be None when SET_NUMBER_OF_CLIENTS is used -SET_NUMBER_OF_CLIENTS_CONTINUE = 2 # required number of clients to continue running the game; should be None when MIN_CLIENTS or MAX_CLIENTS are used +# minimum number of clients required to continue running the game; should +# be None when SET_NUMBER_OF_CLIENTS is used +MIN_CLIENTS_CONTINUE = None +# maximum number of clients required to continue running the game; should +# be None when SET_NUMBER_OF_CLIENTS is used +MAX_CLIENTS_CONTINUE = None +# required number of clients to continue running the game; should be None +# when MIN_CLIENTS or MAX_CLIENTS are used +SET_NUMBER_OF_CLIENTS_CONTINUE = 2 ALLOWED_MODULES = ["game.client.user_client", # modules that clients are specifically allowed to access "game.common.enums"] -RESULTS_FILE_NAME = "results.json" # Name and extension of results file -RESULTS_DIR = os.path.join(os.getcwd(), "logs") # Location of the results file -RESULTS_FILE = os.path.join(RESULTS_DIR, RESULTS_FILE_NAME) # Results directory combined with file name +# Name and extension of results file +RESULTS_FILE_NAME = "results.json" +# Location of the results file +RESULTS_DIR = os.path.join(os.getcwd(), "logs") +# Results directory combined with file name +RESULTS_FILE = os.path.join(RESULTS_DIR, RESULTS_FILE_NAME) LOGS_FILE_NAME = 'turn_logs.json' -LOGS_DIR = os.path.join(os.getcwd(), "logs") # Directory for game log files +# Directory for game log files +LOGS_DIR = os.path.join(os.getcwd(), "logs") LOGS_FILE = os.path.join(LOGS_DIR, LOGS_FILE_NAME) -GAME_MAP_FILE_NAME = "game_map.json" # Name and extension of game file that holds generated world -GAME_MAP_DIR = os.path.join(os.getcwd(), "logs") # Location of game map file -GAME_MAP_FILE = os.path.join(GAME_MAP_DIR, GAME_MAP_FILE_NAME) # Filepath for game map file +# Name and extension of game file that holds generated world +GAME_MAP_FILE_NAME = "game_map.json" +# Location of game map file +GAME_MAP_DIR = os.path.join(os.getcwd(), "logs") +# Filepath for game map file +GAME_MAP_FILE = os.path.join(GAME_MAP_DIR, GAME_MAP_FILE_NAME) class Debug: # Keeps track of the current debug level of the game level = DebugLevel.none -# Other Settings Here -------------------------------------------------------------------------------------------------- +# Other Settings Here ---------------------------------------------------- diff --git a/game/controllers/master_controller.py b/game/controllers/master_controller.py index b97a03b7..a45f26f5 100644 --- a/game/controllers/master_controller.py +++ b/game/controllers/master_controller.py @@ -17,12 +17,14 @@ def __init__(self): self.turn = None self.current_world_data = None - # Receives all clients for the purpose of giving them the objects they will control + # Receives all clients for the purpose of giving them the objects they + # will control def give_clients_objects(self, clients): pass # 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 + # the state of the world, returns the key that will give the appropriate + # world information def game_loop_logic(self, start=1): self.turn = start @@ -33,11 +35,13 @@ def game_loop_logic(self, start=1): # Increment the turn counter by 1 self.turn += 1 - # Receives world data from the generated game log and is responsible for interpreting it + # Receives world data from the generated game log and is responsible for + # interpreting it def interpret_current_turn_data(self, clients, world, turn): self.current_world_data = world - # Receive a specific client and send them what they get per turn. Also obfuscates necessary objects. + # Receive a specific client and send them what they get per turn. Also + # obfuscates necessary objects. def client_turn_arguments(self, client, turn): actions = Action() client.action = actions diff --git a/game/engine.py b/game/engine.py index 6850dfd4..fd4e1268 100644 --- a/game/engine.py +++ b/game/engine.py @@ -27,7 +27,8 @@ def __init__(self, quiet_mode=False): self.quiet_mode = quiet_mode - # Starting point of the engine. Runs other methods then sits on top of a basic game loop until over + # Starting point of the engine. Runs other methods then sits on top of a + # basic game loop until over def loop(self): # If quiet mode is activated, replace stdout with devnull f = sys.stdout @@ -38,10 +39,11 @@ def loop(self): self.boot() self.load() - for self.current_world_key in tqdm(self.master_controller.game_loop_logic(), - bar_format=TQDM_BAR_FORMAT, - unit=TQDM_UNITS, - file=f): + for self.current_world_key in tqdm( + self.master_controller.game_loop_logic(), + bar_format=TQDM_BAR_FORMAT, + unit=TQDM_UNITS, + file=f): self.pre_tick() self.tick() self.post_tick() @@ -52,7 +54,8 @@ def loop(self): # Finds, checks, and instantiates clients def boot(self): - # Insert path of where clients are expected to be inside where python will look + # Insert path of where clients are expected to be inside where python + # will look current_dir = os.getcwd() sys.path.insert(0, current_dir) sys.path.insert(0, f'{current_dir}/{CLIENT_DIRECTORY}') @@ -61,7 +64,8 @@ def boot(self): for filename in os.listdir(CLIENT_DIRECTORY): filename = filename.replace('.py', '') - # Filter out files that do not contain CLIENT_KEYWORD in their filename (located in config) + # Filter out files that do not contain CLIENT_KEYWORD in their + # filename (located in config) if CLIENT_KEYWORD.upper() not in filename.upper(): continue @@ -77,11 +81,13 @@ def boot(self): imports, opening = verify_code(filename + '.py') if len(imports) != 0: player.functional = False - player.error = ImportError(f'Player has attempted illegal imports: {imports}') + player.error = ImportError( + f'Player has attempted illegal imports: {imports}') if opening: player.functional = False - player.error = PermissionError(f'Player is using "open" which is forbidden.') + player.error = PermissionError( + f'Player is using "open" which is forbidden.') # Import client's code im = importlib.import_module(f'{filename}', CLIENT_DIRECTORY) @@ -103,7 +109,8 @@ def boot(self): if thr.is_alive(): player.functional = False - player.error = TimeoutError('Client failed to provide a team name in time.') + player.error = TimeoutError( + 'Client failed to provide a team name in time.') if thr.error is not None: player.functional = False @@ -121,7 +128,8 @@ def boot(self): if client_num_correct is not None: self.shutdown(source='Client_error') - # Finally, request master controller to establish clients with basic objects + # Finally, request master controller to establish clients with basic + # objects if SET_NUMBER_OF_CLIENTS_START == 1: self.master_controller.give_clients_objects(self.clients[0]) else: @@ -146,23 +154,28 @@ def load(self): world = json.load(json_file) self.world = world - # Sits on top of all actions that need to happen before the player takes their turn + # Sits on top of all actions that need to happen before the player takes + # their turn 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.') + 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], current_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, current_world, self.tick_number) - # Does actions like lets the player take their turn and asks master controller to perform game logic + # Does actions like lets the player take their turn and asks master + # controller to perform game logic def tick(self): # Create list of threads to run client's code threads = list() @@ -172,7 +185,8 @@ def tick(self): continue # Retrieve list of arguments to pass - arguments = self.master_controller.client_turn_arguments(client, self.tick_number) + arguments = self.master_controller.client_turn_arguments( + client, self.tick_number) # Create the thread, pass the arguments thr = Thread(func=client.code.take_turn, args=arguments) @@ -201,10 +215,12 @@ def tick(self): # Go through each thread and check if they are still alive for client, thr in zip(self.clients, threads): - # If thread is no longer alive, mark it as non-functional, preventing it from receiving future turns + # If thread is no longer alive, mark it as non-functional, + # preventing it from receiving future turns if thr.is_alive(): client.functional = False - client.error = TimeoutError(f'{client.id} failed to reply in time and has been dropped.') + client.error = TimeoutError( + f'{client.id} failed to reply in time and has been dropped.') print(client.error) # Also check to see if the client had created an error and save it @@ -224,18 +240,22 @@ def tick(self): # Finally, consult master controller for game logic if SET_NUMBER_OF_CLIENTS_START == 1: - self.master_controller.turn_logic(self.clients[0], self.tick_number) + self.master_controller.turn_logic( + self.clients[0], self.tick_number) else: self.master_controller.turn_logic(self.clients, self.tick_number) - # Does any actions that need to happen after the game logic, then creates the game log for the turn + # Does any actions that need to happen after the game logic, then creates + # the game log for the turn def post_tick(self): # Add logs to logs list data = None if SET_NUMBER_OF_CLIENTS_START == 1: - data = self.master_controller.create_turn_log(self.clients[0], self.tick_number) + data = self.master_controller.create_turn_log( + self.clients[0], self.tick_number) else: - data = self.master_controller.create_turn_log(self.clients, self.tick_number) + data = self.master_controller.create_turn_log( + self.clients, self.tick_number) self.game_logs[self.tick_number] = data @@ -251,9 +271,11 @@ def shutdown(self, source=None): # Retrieve and write results information results_information = None if SET_NUMBER_OF_CLIENTS_START == 1: - results_information = self.master_controller.return_final_results(self.clients[0], self.tick_number) + results_information = self.master_controller.return_final_results( + self.clients[0], self.tick_number) else: - results_information = self.master_controller.return_final_results(self.clients, self.tick_number) + results_information = self.master_controller.return_final_results( + self.clients, self.tick_number) if source: results_information['reason'] = source diff --git a/game/test_suite/runner.py b/game/test_suite/runner.py index 5d4e7b6c..d37b35d2 100644 --- a/game/test_suite/runner.py +++ b/game/test_suite/runner.py @@ -2,6 +2,7 @@ import game.test_suite.tests import sys + def main(): loader = unittest.TestLoader() suite = unittest.TestSuite() @@ -11,8 +12,11 @@ def main(): sys.exit(not runner.run(suite).wasSuccessful()) + if __name__ == '__main__': main() # To run the test suite, make sure your terminal is in the root directory of the project (the 'byte_le_royale_2022 folder) -# Then, in your terminal, run 'python -m game.test_suite.runner'. This runs this file as a module of the entire project, allowing imports to function properly \ No newline at end of file +# Then, in your terminal, run 'python -m game.test_suite.runner'. This +# runs this file as a module of the entire project, allowing imports to +# function properly diff --git a/game/test_suite/tests/__init__.py b/game/test_suite/tests/__init__.py index 35683e52..12a6633d 100644 --- a/game/test_suite/tests/__init__.py +++ b/game/test_suite/tests/__init__.py @@ -1,5 +1,6 @@ # When you create a new test file, make sure to add it here. -# Simply import the class from your file, and then add that class to the '__all__' array. +# Simply import the class from your file, and then add that class to the +# '__all__' array. from game.test_suite.tests.objects.test_game_board import TestGameBoard from game.test_suite.tests.objects.test_moving_object import TestMovingObject @@ -17,4 +18,4 @@ 'TestGrenade', 'TestInit', 'TestHitboxObject' -] \ No newline at end of file +] diff --git a/game/test_suite/tests/objects/test_damaging_object.py b/game/test_suite/tests/objects/test_damaging_object.py index c620bd61..948b6bc3 100644 --- a/game/test_suite/tests/objects/test_damaging_object.py +++ b/game/test_suite/tests/objects/test_damaging_object.py @@ -1,4 +1,4 @@ -import unittest +import unittest from game.common.moving.damaging import damaging_object from game.common.moving.damaging.damaging_object import DamagingObject from game.common.stats import GameStats @@ -7,8 +7,10 @@ class TestDamagingObject(unittest.TestCase): def setUp(self): - self.dmgObj = DamagingObject(10, 10, heading= 1, speed= 1, hitbox= Hitbox(5,5 ,(5,5)), collidable=True) - + self.dmgObj = DamagingObject( + 10, 10, heading=1, speed=1, hitbox=Hitbox( + 5, 5, (5, 5)), collidable=True) + def test_set_get_range_valid(self): self.dmgObj.range = 50 self.assertEqual(self.dmgObj.range, 50) @@ -17,51 +19,63 @@ def test_set_get_damage_valid(self): self.dmgObj.damage = 50 self.assertEqual(self.dmgObj.damage, 50) - def test_set_get_range_invalid_low(self): self.assertRaises(Exception, self.setRange, (-10)) - + def test_set_get_range_invalid_high(self): - self.assertRaises(Exception, self.setRange, (GameStats.damaging_object_stats['max_range'] + 1)) + self.assertRaises( + Exception, + self.setRange, + (GameStats.damaging_object_stats['max_range'] + 1)) def test_set_get_damage_invalid_low(self): self.assertRaises(Exception, self.setDamage, (-10)) - + def test_set_get_damage_invalid_high(self): - self.assertRaises(Exception, self.setDamage, GameStats.damaging_object_stats['max_damage'] + 1) - + self.assertRaises( + Exception, + self.setDamage, + GameStats.damaging_object_stats['max_damage'] + + 1) + def test_set_get_range_boundary_low(self): self.dmgObj.range = 0 self.assertEqual(self.dmgObj.range, 0) # for now I have the lower boundary be zero but can be subject to change - def test_set_get_damage_boundary_low(self): + def test_set_get_damage_boundary_low(self): self.dmgObj.damage = 0 self.assertEqual(self.dmgObj.damage, 0) - def test_set_get_range_boundary_high(self): + def test_set_get_range_boundary_high(self): self.dmgObj.range = GameStats.damaging_object_stats['max_range'] - self.assertEqual(self.dmgObj.range, GameStats.damaging_object_stats['max_range']) + self.assertEqual( + self.dmgObj.range, + GameStats.damaging_object_stats['max_range']) - def test_set_get_damage_boundary_high(self): + def test_set_get_damage_boundary_high(self): self.dmgObj.damage = GameStats.damaging_object_stats['max_damage'] - self.assertEqual(self.dmgObj.damage, GameStats.damaging_object_stats['max_damage']) + self.assertEqual( + self.dmgObj.damage, + GameStats.damaging_object_stats['max_damage']) def test_damaging_obj_parent_params(self): - testDmg = DamagingObject(range = 10, damage = 10, heading = 1, speed = 10, health = 1, hitbox= Hitbox(5,5,(5,5)), collidable=True) - - + testDmg = DamagingObject( + range=10, damage=10, heading=1, speed=10, health=1, hitbox=Hitbox( + 5, 5, (5, 5)), collidable=True) + self.assertIsNotNone(testDmg.heading) self.assertIsNotNone(testDmg.speed) self.assertIsNotNone(testDmg.hitbox.position) self.assertIsNotNone(testDmg.hitbox) self.assertIsNotNone(testDmg.collidable) - + def setRange(self, newRange): self.dmgObj.range = newRange - + def setDamage(self, newDamage): self.dmgObj.damage = newDamage - + + if __name__ == '__main__': - unittest.main \ No newline at end of file + unittest.main diff --git a/game/test_suite/tests/objects/test_example.py b/game/test_suite/tests/objects/test_example.py index 8e5249ba..443c6fc7 100644 --- a/game/test_suite/tests/objects/test_example.py +++ b/game/test_suite/tests/objects/test_example.py @@ -4,21 +4,30 @@ import unittest -class TestExample(unittest.TestCase): # Your test class is a subclass of unittest.Testcase, this is important - - def setUp(self): # This method is used to set up anything you wish to test prior to every test method below. - self.d = { # Here I'm just setting up a quick dictionary for example. - "string" : "Hello World!", # Any changes made to anything built in setUp DO NOT carry over to later test methods - "array" : [1, 2, 3, 4, 5], - "integer" : 42, - "bool" : False - } - - def test_dict_array(self): # Test methods should always start with the word 'test' + +class TestExample( + unittest.TestCase): # Your test class is a subclass of unittest.Testcase, this is important + + # This method is used to set up anything you wish to test prior to every + # test method below. + def setUp(self): + self.d = { # Here I'm just setting up a quick dictionary for example. + # Any changes made to anything built in setUp DO NOT carry over to + # later test methods + "string": "Hello World!", + "array": [1, 2, 3, 4, 5], + "integer": 42, + "bool": False + } + + def test_dict_array(self): # Test methods should always start with the word 'test' a = self.d["array"] - self.assertEqual(a, [1, 2, 3, 4, 5]) # The heart of a test method are assertions - self.assertEqual(a[2], 3) # These methods take two arguments and compare them to one another - self.assertIn(5, a) # There are loads of them, and they're all very useful + # The heart of a test method are assertions + self.assertEqual(a, [1, 2, 3, 4, 5]) + # These methods take two arguments and compare them to one another + self.assertEqual(a[2], 3) + # There are loads of them, and they're all very useful + self.assertIn(5, a) def test_dict_string(self): s = self.d["string"] @@ -28,7 +37,8 @@ def test_dict_string(self): def test_dict_integer(self): i = self.d["integer"] self.assertGreater(50, i) - self.assertAlmostEqual(i, 42.00000001) # Checks within 7 decimal points + # Checks within 7 decimal points + self.assertAlmostEqual(i, 42.00000001) def test_dict_bool(self): b = self.d["bool"] diff --git a/game/test_suite/tests/objects/test_game_board.py b/game/test_suite/tests/objects/test_game_board.py index 43428fde..ea38a87d 100644 --- a/game/test_suite/tests/objects/test_game_board.py +++ b/game/test_suite/tests/objects/test_game_board.py @@ -7,20 +7,27 @@ class TestGameBoard(unittest.TestCase): # square board test def test_circle_square(self): game_board1 = GameBoard(10, 10) - self.assertGreaterEqual(game_board1.circle_radius, .5 * math.sqrt(200)) # should succeed - self.assertAlmostEqual(game_board1.circle_radius, .5 * math.sqrt(200)) # if the first test fails, but this one succeeds, then there might be rounding errors + self.assertGreaterEqual( + game_board1.circle_radius, .5 * math.sqrt(200)) # should succeed + # if the first test fails, but this one succeeds, then there might be + # rounding errors + self.assertAlmostEqual(game_board1.circle_radius, .5 * math.sqrt(200)) # rectangular board test, width greater than height def test_circle_rect_width(self): game_board2 = GameBoard(15, 10) - self.assertGreaterEqual(game_board2.circle_radius, .5 * math.sqrt(325)) # should succeed - self.assertAlmostEqual(game_board2.circle_radius, .5 * math.sqrt(325)) # shows possible rounding errors + self.assertGreaterEqual( + game_board2.circle_radius, .5 * math.sqrt(325)) # should succeed + # shows possible rounding errors + self.assertAlmostEqual(game_board2.circle_radius, .5 * math.sqrt(325)) # rectangular board test, height greater than width def test_circle_rect_height(self): game_board3 = GameBoard(10, 15) - self.assertGreaterEqual(game_board3.circle_radius, .5 * math.sqrt(325)) # should succeed - self.assertAlmostEqual(game_board3.circle_radius, .5 * math.sqrt(325)) # shows possible rounding errors + self.assertGreaterEqual( + game_board3.circle_radius, .5 * math.sqrt(325)) # should succeed + # shows possible rounding errors + self.assertAlmostEqual(game_board3.circle_radius, .5 * math.sqrt(325)) # check each corner's location, and if y value of corner is >= y value of the circle at that x, # then that corner must be inside the circle @@ -39,6 +46,7 @@ def check_corner(corner_x, corner_y, radius): self.assertTrue( check_corner(width / 2, height / 2, radius) and # QI check_corner(-1 * (width / 2), height / 2, radius) and # QII - check_corner(-1 * (width / 2), -1 * (height / 2), radius) and # QIII + # QIII + check_corner(-1 * (width / 2), -1 * (height / 2), radius) and check_corner(width / 2, -1 * (height / 2), radius) # QIV - ) \ No newline at end of file + ) diff --git a/game/test_suite/tests/objects/test_grenade.py b/game/test_suite/tests/objects/test_grenade.py index 8bb58034..2c3cbaef 100644 --- a/game/test_suite/tests/objects/test_grenade.py +++ b/game/test_suite/tests/objects/test_grenade.py @@ -1,39 +1,53 @@ from game.common.hitbox import Hitbox -import unittest +import unittest from game.common.moving.damaging import grenade from game.common.moving.damaging.grenade import Grenade from game.common.stats import GameStats + class TestGrenade(unittest.TestCase): def setUp(self): - self.grnObj = Grenade(damage= 10, heading=1, speed=1, range= 1) - + self.grnObj = Grenade(damage=10, heading=1, speed=1, range=1) + def test_set_get_fuse_time_valid(self): self.grnObj.fuse_time = 20 self.assertEqual(self.grnObj.fuse_time, 20) - def test_set_get_fuse_time_invalid_low(self): - self.assertRaises(Exception, self.setFuse, (0)) + self.assertRaises(Exception, self.setFuse, (0)) def test_set_get_fuse_time_invalid_high(self): - self.assertRaises(Exception, self.setFuse, (100)) + self.assertRaises(Exception, self.setFuse, (100)) def test_set_get_fuse_time_boundary_low(self): self.grnObj.fuse_time = GameStats.grenade_stats['min_fuse_time'] - self.assertEqual(self.grnObj.fuse_time, GameStats.grenade_stats['min_fuse_time']) - + self.assertEqual( + self.grnObj.fuse_time, + GameStats.grenade_stats['min_fuse_time']) - def test_set_get_fuse_time_boundary_high(self): + def test_set_get_fuse_time_boundary_high(self): self.grnObj.fuse_time = GameStats.grenade_stats['max_fuse_time'] - self.assertEqual(self.grnObj.fuse_time, GameStats.grenade_stats['max_fuse_time']) - + self.assertEqual( + self.grnObj.fuse_time, + GameStats.grenade_stats['max_fuse_time']) def test_grenade_obj_parent_params(self): - - testGrn = Grenade(fuse_time = 20, range = 10, damage = 10, heading = 1, speed = 10, health = 1, hitbox=Hitbox(10,10,(10,10)), collidable=True) - + + testGrn = Grenade( + fuse_time=20, + range=10, + damage=10, + heading=1, + speed=10, + health=1, + hitbox=Hitbox( + 10, + 10, + (10, + 10)), + collidable=True) + self.assertIsNotNone(testGrn.range) self.assertIsNotNone(testGrn.damage) self.assertIsNotNone(testGrn.heading) @@ -44,6 +58,7 @@ def test_grenade_obj_parent_params(self): def setFuse(self, newTime): self.grnObj.fuse_time = newTime - + + if __name__ == '__main__': - unittest.main \ No newline at end of file + unittest.main diff --git a/game/test_suite/tests/objects/test_hitbox_object.py b/game/test_suite/tests/objects/test_hitbox_object.py index 6fa546cb..b26fe983 100644 --- a/game/test_suite/tests/objects/test_hitbox_object.py +++ b/game/test_suite/tests/objects/test_hitbox_object.py @@ -1,4 +1,4 @@ -import unittest +import unittest from game.common.hitbox import Hitbox from game.common.moving.damaging.damaging_object import DamagingObject from game.common.stats import GameStats @@ -7,8 +7,8 @@ class TestHitboxObject(unittest.TestCase): def setUp(self): - self.hitbox = Hitbox(2,2,(0,0)) - + self.hitbox = Hitbox(2, 2, (0, 0)) + def test_set_get_heigth_valid(self): self.hitbox.height = 10 self.assertEqual(self.hitbox.height, 10) @@ -18,72 +18,75 @@ def test_set_get_heigth_valid(self): self.assertEqual(self.hitbox.height, 7) def test_set_get_tuple_x_valid(self): - self.hitbox.position = (50,10) - self.assertEqual(self.hitbox.position, (50,10)) - + self.hitbox.position = (50, 10) + self.assertEqual(self.hitbox.position, (50, 10)) + def test_set_get_tuple_y_valid(self): - self.hitbox.position = (10,50) - self.assertEqual(self.hitbox.position, (10,50)) + self.hitbox.position = (10, 50) + self.assertEqual(self.hitbox.position, (10, 50)) def test_set_get_tuple_y_boundary_low(self): - self.hitbox.position = (10,0) - self.assertEqual(self.hitbox.position, (10,0)) + self.hitbox.position = (10, 0) + self.assertEqual(self.hitbox.position, (10, 0)) def test_set_get_tuple_y_boundary_high(self): self.hitbox.position = (10, GameStats.game_board_height) - self.assertEqual(self.hitbox.position, (10, GameStats.game_board_height)) - + self.assertEqual(self.hitbox.position, + (10, GameStats.game_board_height)) + def test_set_get_tuple_x_boundary_high(self): - self.hitbox.position = (GameStats.game_board_width,10) - self.assertEqual(self.hitbox.position, (GameStats.game_board_width,10)) + self.hitbox.position = (GameStats.game_board_width, 10) + self.assertEqual(self.hitbox.position, + (GameStats.game_board_width, 10)) def test_set_get_tuple_X_invalid_high(self): - self.assertRaises(ValueError, self.setPosition, (GameStats.game_board_width + 1,10)) + self.assertRaises(ValueError, self.setPosition, + (GameStats.game_board_width + 1, 10)) def test_set_get_tuple_y_invalid_high(self): - self.assertRaises(ValueError, self.setPosition, (10, GameStats.game_board_height + 1)) - + self.assertRaises(ValueError, self.setPosition, + (10, GameStats.game_board_height + 1)) + def test_set_get_tuple_x_boundary_low(self): self.assertRaises(ValueError, self.setPosition, ((-1, 10))) - + def test_set_get_tuple_y_boundary_low(self): self.assertRaises(ValueError, self.setPosition, ((10, -1))) def test_topLeft_corner(self): - self.assertEqual(self.hitbox.topLeft, (0,0)) + self.assertEqual(self.hitbox.topLeft, (0, 0)) def test_topRight_corner(self): self.assertEqual(self.hitbox.topRight, (2, 0)) def test_bottomLeft_corner(self): - self.assertEqual(self.hitbox.bottomLeft, (0,2)) + self.assertEqual(self.hitbox.bottomLeft, (0, 2)) def test_bottomRight_corner(self): - self.assertEqual(self.hitbox.bottomRight, (2,2)) + self.assertEqual(self.hitbox.bottomRight, (2, 2)) - def test_middle(self): - self.assertEqual(self.hitbox.middle, (1,1)) + self.assertEqual(self.hitbox.middle, (1, 1)) def test_topLeft_corner_alt(self): - self.hitbox.position = (10,10) - self.assertEqual(self.hitbox.topLeft, (10,10)) + self.hitbox.position = (10, 10) + self.assertEqual(self.hitbox.topLeft, (10, 10)) def test_topRight_corner_alt(self): - self.hitbox.position = (10,10) - self.assertEqual(self.hitbox.topRight, (12,10)) + self.hitbox.position = (10, 10) + self.assertEqual(self.hitbox.topRight, (12, 10)) def test_bottomLeft_corner_alt(self): - self.hitbox.position = (10,10) - self.assertEqual(self.hitbox.bottomLeft, (10,12)) + self.hitbox.position = (10, 10) + self.assertEqual(self.hitbox.bottomLeft, (10, 12)) def test_bottomRight_corner_alt(self): - self.hitbox.position = (10,10) - self.assertEqual(self.hitbox.bottomRight, (12,12)) + self.hitbox.position = (10, 10) + self.assertEqual(self.hitbox.bottomRight, (12, 12)) def test_middle_alt(self): - self.hitbox.position = (10,10) - self.assertEqual(self.hitbox.middle, (11,11)) + self.hitbox.position = (10, 10) + self.assertEqual(self.hitbox.middle, (11, 11)) def test_damaging_obj_parent_params(self): self.assertIsNotNone(self.hitbox.id) @@ -94,15 +97,16 @@ def test_set_get_height_invalid_low(self): def test_set_get_width_invalid_low(self): self.assertRaises(ValueError, self.setWidth, (-1)) - + def setPosition(self, newPos): self.hitbox.position = newPos - + def setHeight(self, newHeight): self.hitbox.height = newHeight - + def setWidth(self, newWidth): self.hitbox.width = newWidth - + + if __name__ == '__main__': - unittest.main \ No newline at end of file + unittest.main diff --git a/game/test_suite/tests/objects/test_initialization.py b/game/test_suite/tests/objects/test_initialization.py index d987c0b1..57f4bae0 100644 --- a/game/test_suite/tests/objects/test_initialization.py +++ b/game/test_suite/tests/objects/test_initialization.py @@ -23,12 +23,18 @@ from game.common.enums import ObjectType, GunLevel, GunType -class TestInit(unittest.TestCase): # Your test class is a subclass of unittest.Testcase, this is important +class TestInit( + unittest.TestCase): # Your test class is a subclass of unittest.Testcase, this is important - def setUp(self): # This method is used to set up anything you wish to test prior to every test method below. - self.gun = Gun(gun_type=GunType.assault_rifle, level= GunLevel.level_one) - self.item = Item(hitbox=Hitbox(10,10,(10,10))) - self.damaging = DamagingObject(hitbox=Hitbox(10,10,(10,10)), heading=1, speed=10 ) + # This method is used to set up anything you wish to test prior to every + # test method below. + def setUp(self): + self.gun = Gun( + gun_type=GunType.assault_rifle, + level=GunLevel.level_one) + self.item = Item(hitbox=Hitbox(10, 10, (10, 10))) + self.damaging = DamagingObject(hitbox=Hitbox( + 10, 10, (10, 10)), heading=1, speed=10) self.movObj = MovingObject(1, 10) self.shooter = Shooter() self.action = Action() @@ -36,12 +42,15 @@ def setUp(self): # This method is used to set up anything you wish to test prio self.gameObj = GameObject() self.map = MapObject() self.player = Player() - self.wall = Wall(hitbox=Hitbox(10,10,(10,10))) + self.wall = Wall(hitbox=Hitbox(10, 10, (10, 10))) self.grnObj = Grenade(heading=1, speed=1, range=10, damage=10) - self.consumable = Consumable(hitbox= Hitbox(10,10,(10,10)), health=10, count=1) - self.upgrade = Upgrade(hitbox= Hitbox(10,10,(10,10)), health=10, count=1) - self.door = Door(hitbox= Hitbox(10,10,(10,10)) ) - + self.consumable = Consumable(hitbox=Hitbox( + 10, 10, (10, 10)), health=10, count=1) + self.upgrade = Upgrade( + hitbox=Hitbox( + 10, 10, (10, 10)), health=10, count=1) + self.door = Door(hitbox=Hitbox(10, 10, (10, 10))) + def testObjectInit(self): self.assertEqual(self.gun.object_type, ObjectType.gun) self.assertEqual(self.item.object_type, ObjectType.item) @@ -57,13 +66,8 @@ def testObjectInit(self): self.assertEqual(self.wall.object_type, ObjectType.wall) self.assertEqual(self.consumable.object_type, ObjectType.consumable) self.assertEqual(self.upgrade.object_type, ObjectType.upgrade) - - - # This is just the very basics of how to set up a test file # For more info: https://docs.python.org/3/library/unittest.html - - if __name__ == '__main__': unittest.main diff --git a/game/test_suite/tests/objects/test_moving_object.py b/game/test_suite/tests/objects/test_moving_object.py index 5d7469aa..f321b91e 100644 --- a/game/test_suite/tests/objects/test_moving_object.py +++ b/game/test_suite/tests/objects/test_moving_object.py @@ -10,16 +10,19 @@ import math -class TestMovingObject(unittest.TestCase): # Your test class is a subclass of unittest.Testcase, this is important +class TestMovingObject( + unittest.TestCase): # Your test class is a subclass of unittest.Testcase, this is important - def setUp(self): # This method is used to set up anything you wish to test prior to every test method below. + # This method is used to set up anything you wish to test prior to every + # test method below. + def setUp(self): self.movObj = MovingObject(1, 10) - + # Test if a valid heading set works def test_set_get_heading_valid(self): self.movObj.heading = math.pi self.assertEqual(self.movObj.heading, math.pi) - + # Test if a valid speed set works def test_set_get_speed_valid(self): self.movObj.speed = 100 @@ -33,19 +36,24 @@ def test_set_get_speed_invalid_low(self): self.assertRaises(Exception, self.setSpeed, -1) def test_set_get_heading_invalid_high(self): - self.assertRaises(Exception, self.setHeading, (math.pi*3)) - + self.assertRaises(Exception, self.setHeading, (math.pi * 3)) + def test_set_get_speed_invalid_high(self): - self.assertRaises(Exception, self.setSpeed, (GameStats.moving_object_stats['max_speed'] + 1)) + self.assertRaises( + Exception, + self.setSpeed, + (GameStats.moving_object_stats['max_speed'] + 1)) # Check if boundary sets do work def test_set_get_heading_boundary_high(self): - self.movObj.heading = math.pi*2 - self.assertEqual(self.movObj.heading, math.pi*2) + self.movObj.heading = math.pi * 2 + self.assertEqual(self.movObj.heading, math.pi * 2) def test_set_get_speed_boundary_high(self): self.movObj.speed = GameStats.moving_object_stats['max_speed'] - self.assertEqual(self.movObj.speed, GameStats.moving_object_stats['max_speed']) + self.assertEqual( + self.movObj.speed, + GameStats.moving_object_stats['max_speed']) def test_set_get_heading_boundary_low(self): self.movObj.heading = 0 @@ -56,16 +64,18 @@ def test_set_get_speed_boundary_low(self): self.assertEqual(self.movObj.speed, 0) def test_moving_obj_parent_params(self): - test_mov = MovingObject(1, 10, health=1, hitbox= Hitbox(10,10,(10,10)), collidable=True) + test_mov = MovingObject( + 1, 10, health=1, hitbox=Hitbox( + 10, 10, (10, 10)), collidable=True) self.assertIsNotNone(test_mov.hitbox.position) self.assertIsNotNone(test_mov.hitbox) self.assertIsNotNone(test_mov.collidable) self.assertIsNone(self.movObj.hitbox) self.assertIsNone(self.movObj.collidable) - + def setHeading(self, newHeading): self.movObj.heading = newHeading - + def setSpeed(self, newSpeed): self.movObj.speed = newSpeed diff --git a/game/test_suite/tests/objects/test_shooter.py b/game/test_suite/tests/objects/test_shooter.py index 79944606..a1815300 100644 --- a/game/test_suite/tests/objects/test_shooter.py +++ b/game/test_suite/tests/objects/test_shooter.py @@ -21,7 +21,9 @@ def test_inventory_guns(self): for slot in self.shooter.inventory['guns']: self.shooter.append_inventory(test_gun) self.assertFalse(self.shooter.has_empty_slot('guns')) - self.assertEqual(test_gun, self.shooter.remove_from_inventory(test_gun)) + self.assertEqual( + test_gun, + self.shooter.remove_from_inventory(test_gun)) self.assertTrue(self.shooter.has_empty_slot('guns')) def test_inventory_upgrades(self): @@ -38,20 +40,31 @@ def test_inventory_upgrades(self): def test_inventory_consumables(self): self.assertTrue(self.shooter.has_empty_slot('consumables')) - test_consumable = Consumable(Hitbox(10,10,(10,10)), 20, 1, None, None, None) + test_consumable = Consumable( + Hitbox(10, 10, (10, 10)), 20, 1, None, None, None) for slot in self.shooter.inventory['consumables']: self.shooter.append_inventory(test_consumable) self.assertFalse(self.shooter.has_empty_slot('consumables')) - self.assertEqual(test_consumable, self.shooter.remove_from_inventory(test_consumable)) + self.assertEqual( + test_consumable, + self.shooter.remove_from_inventory(test_consumable)) self.assertTrue(self.shooter.has_empty_slot('consumables')) def test__append_inventory__wrong_inventory_type_raises_TypeError(self): - self.assertRaises(TypeError, self.shooter.append_inventory, (Item(None, None))) + self.assertRaises( + TypeError, + self.shooter.append_inventory, + (Item( + None, + None))) - def test__append_inventory__correct_type_inventory_full__raises_InventoryFullError(self): + def test__append_inventory__correct_type_inventory_full__raises_InventoryFullError( + self): test_gun = Gun(GunType.shotgun, 1) for slot in self.shooter.inventory['guns']: self.shooter.append_inventory(test_gun) - self.assertRaises(InventoryFullError, self.shooter.append_inventory, (test_gun)) - + self.assertRaises( + InventoryFullError, + self.shooter.append_inventory, + (test_gun)) diff --git a/game/utils/thread.py b/game/utils/thread.py index ac663254..49035366 100644 --- a/game/utils/thread.py +++ b/game/utils/thread.py @@ -33,9 +33,9 @@ def run(self): except Exception: self.error = traceback.format_exc() - if self.type is not None and not isinstance(self.safeObject.value, self.type): + if self.type is not None and not isinstance( + self.safeObject.value, self.type): self.safeObject.value = None def retrieve_value(self): return self.safeObject.value - diff --git a/game/utils/validation.py b/game/utils/validation.py index 7059f74d..75c437ef 100644 --- a/game/utils/validation.py +++ b/game/utils/validation.py @@ -44,12 +44,18 @@ def verify_num_clients(clients, set_clients, min_clients, max_clients): # Verify correct number of clients if set_clients is not None and len(clients) != set_clients: res = ValueError("Number of clients is not the set value.\n" - "Number of clients: " + str(len(clients)) + " | Set number: " + str(set_clients)) + "Number of clients: " + + str(len(clients)) + + " | Set number: " + + str(set_clients)) elif min_clients is not None and len(clients) < min_clients: res = ValueError("Number of clients is less than the minimum required.\n" "Number of clients: " + str(len(clients)) + " | Minimum: " + str(min_clients)) elif max_clients is not None and len(clients) > max_clients: res = ValueError("Number of clients exceeds the maximum allowed.\n" - "Number of clients: " + str(len(clients)) + " | Maximum: " + str(max_clients)) + "Number of clients: " + + str(len(clients)) + + " | Maximum: " + + str(max_clients)) return res diff --git a/sphinx/conf.py b/sphinx/conf.py index b1124087..0927e595 100644 --- a/sphinx/conf.py +++ b/sphinx/conf.py @@ -42,7 +42,7 @@ # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = [ '.rst', '.md' ] +source_suffix = ['.rst', '.md'] # The master toctree document. master_doc = 'index' @@ -178,13 +178,15 @@ # At the bottom of conf.py github_doc_root = "https://royale.ndacm.org/GameURL/" + + def setup(app): app.add_config_value('recommonmark_config', { - 'url_resolver': lambda url: github_doc_root + url, - 'enable_auto_toc_tree': True, - 'enable_eval_rst': True, - 'enable_auto_doc_ref': False, - }, True) + 'url_resolver': lambda url: github_doc_root + url, + 'enable_auto_toc_tree': True, + 'enable_eval_rst': True, + 'enable_auto_doc_ref': False, + }, True) app.add_transform(AutoStructify) app.add_stylesheet('accordion.css') diff --git a/wrapper/__main__.py b/wrapper/__main__.py index 3bbd6ab4..da4fcbb7 100644 --- a/wrapper/__main__.py +++ b/wrapper/__main__.py @@ -13,28 +13,41 @@ spar = par.add_subparsers(title="Commands", dest="command") # Generate Subparser - gen_subpar = spar.add_parser('generate', aliases=['g'], help='Generates a new random game map') - + gen_subpar = spar.add_parser( + 'generate', + aliases=['g'], + help='Generates a new random game map') + # Run Subparser and optionals - run_subpar = spar.add_parser('run', aliases=['r'], - help='Runs your bot against the last generated map! "r -h" shows more options') + run_subpar = spar.add_parser( + 'run', + aliases=['r'], + help='Runs your bot against the last generated map! "r -h" shows more options') + + run_subpar.add_argument( + '-debug', + '-d', + action='store', + type=int, + nargs='?', + const=-1, + default=None, + dest='debug', + help='Allows for debugging when running your code') - run_subpar.add_argument('-debug', '-d', action='store', type=int, nargs='?', const=-1, - default=None, dest='debug', help='Allows for debugging when running your code') - run_subpar.add_argument('-quiet', '-q', action='store_true', default=False, dest='q_bool', help='Runs your AI... quietly :)') # Parse Command Line par_args = par.parse_args() - + # Main Action variable action = par_args.command # Generate game options if action in ['generate', 'g']: generate() - + # Run game options elif action in ['run', 'r']: # Additional args @@ -45,7 +58,7 @@ game.config.Debug.level = par_args.debug else: print('Valid debug input not found, using default value') - + if par_args.q_bool: quiet = True