From 00e64d19f4b56c5585c77a89795e8bf9cfa6e26a Mon Sep 17 00:00:00 2001 From: Brady James Garvin <bgarvin@cse.unl.edu> Date: Tue, 27 Feb 2018 09:53:25 -0600 Subject: [PATCH] Began readying codebase for the 2018 assignment. --- ants_vs_some_bees.py | 73 ++++++++++++++++++++++---------------------- main.py | 2 +- tower.kv | 32 +++++++++---------- 3 files changed, 53 insertions(+), 54 deletions(-) diff --git a/ants_vs_some_bees.py b/ants_vs_some_bees.py index 5713af3..7b68dbe 100644 --- a/ants_vs_some_bees.py +++ b/ants_vs_some_bees.py @@ -136,7 +136,7 @@ class UnitType(Enum): possible for fundamentally different Insects to have the same UnitType. Any changes to this Enum should be accompanied by corresponding changes to - the frontend in main.py. + the frontend in main.py and tower.kv. """ BEE = 'BEE' HARVESTER = 'HARVESTER' @@ -259,19 +259,6 @@ class Harvester(Ant): self.production = production -class Wall(Ant): - """ - A Wall is an Ant with no attack, but lots of health for holding off - attacking Bees. - """ - - def __init__(self, unit_type): - """ - Create a Wall with the given type. - """ - super(Wall, self).__init__(unit_type, 4, 4) - - class Thrower(Ant): """ A Thrower throws a leaf each turn at the nearest Bee in its range. @@ -400,7 +387,7 @@ class GameState(object): Construct a world from the given places, designating one place as the Bee's target, offer the player the given archetypes, and provide the player with the given amount of starting food. The places may be (and - usually are) prepopulated with insects. + usually should be) prepopulated with insects. """ self.ant_archetypes = ant_archetypes self.places = places @@ -473,7 +460,7 @@ STANDARD_ANT_ARCHETYPES = ( Thrower(UnitType.THROWER, food_cost=7, health=1, damage=1), Thrower(UnitType.LONG_THROWER, food_cost=3, health=1, damage=1, minimum_range=4), - Wall(UnitType.WALL), + Ant(UnitType.WALL, food_cost=4, health=4), ) @@ -497,36 +484,50 @@ def make_standard_hive(center_x, center_y, radius, wave_count=4, wave_size=2, return hive -def make_standard_game(row_count=3, column_count=8, wave_count=4, wave_size=2, +def make_standard_game(minimum_row_count=2, maximum_row_count=4, + column_count=9, wave_count=4, wave_size=2, wave_growth=1, wave_interval=5, bee_health=4, bee_damage=1, ant_archetypes=STANDARD_ANT_ARCHETYPES, food=4): """ Construct the GameState for the beginning of a standard game, which has the - ant queen and the Bee's hive separated by several equal-length rows of - ColonyPlaces and Bee's attacking in waves of increasing size. Most of the - specifics of this setup can be varied by specifying non-default arguments. + ant queen and the Bee's hive separated by tunnels of ColonyPlaces and Bee's + attacking in waves of increasing size. Most of the specifics of this setup + can be varied by specifying non-default arguments. """ + assert minimum_row_count > 0, 'Cannot create a game with no rows' + assert maximum_row_count >= minimum_row_count, \ + 'The maximum row count must be at least the minimum row count' + assert column_count > 0, 'Cannot create a game with no columns' - center_y = (row_count + 1) / 2 + center_y = (maximum_row_count + 1) / 2 queen_place = Place(1, center_y) - hive_center_x = column_count + 6 + multiplier = maximum_row_count - minimum_row_count + 1 + heights = [int(minimum_row_count + multiplier * column / column_count) + for column in range(column_count)] + + hive_center_x = 6 + column_count + heights[-1] - minimum_row_count hive = make_standard_hive(hive_center_x, center_y, 2, wave_count, wave_size, wave_growth, wave_interval, bee_health, bee_damage) - places = [queen_place] + hive - for row in range(row_count): - destination = queen_place - for column in range(column_count): - place = Respite(column + 3, row + 1) \ - if (column + 2 * row) % 5 == 1 else \ - ColonyPlace(column + 3, row + 1) - place.connect_to(destination) - destination = place - places.append(place) - for hive_place in hive: - hive_place.connect_to(destination) - - return GameState(places, queen_place, ant_archetypes, food) + tunnels = {} + for column in range(column_count): + height = heights[column] + x = 3 + column + height - minimum_row_count + for row in range(height): + y = center_y + row - (height - 1) / 2 + place = Respite(x, y) if (column + 2 * row) % 5 == 1 else ColonyPlace(x, y) + if column == 0: + place.connect_to(queen_place) + elif height == heights[column - 1]: + place.connect_to(tunnels[column - 1, row]) + else: + for other_row in range(heights[column - 1]): + place.connect_to(tunnels[column - 1, other_row]) + if column == column_count - 1: + for hive_place in hive: + hive_place.connect_to(place) + tunnels[column, row] = place + return GameState([queen_place] + hive + list(tunnels.values()), queen_place, ant_archetypes, food) diff --git a/main.py b/main.py index dbf572f..1038f92 100644 --- a/main.py +++ b/main.py @@ -388,6 +388,6 @@ class TowerApp(App): self.end_game() -if __name__ == "__main__": +if __name__ == '__main__': app = TowerApp() app.run() diff --git a/tower.kv b/tower.kv index 75d789a..e9caec3 100644 --- a/tower.kv +++ b/tower.kv @@ -1,9 +1,7 @@ -#:import ants_vs_some_bees ants_vs_some_bees - -#:set SPRITE_WIDTH 93 -#:set SPRITE_HEIGHT 98 -#:set UNIT_NAMES {'HARVESTER': 'Harvester Ant', 'SHORT_THROWER': 'Short-Range Leaf Thrower', 'THROWER': 'All-Range Leaf Thrower', 'LONG_THROWER': 'Long-Range Leaf Thrower', 'WALL': 'Wall Ant'} - +#:import Game main.Game +#:import UnitType ants_vs_some_bees.UnitType +#:set SPRITE_SIZE (Game.SPRITE_WIDTH, Game.SPRITE_HEIGHT) +#:set UNIT_NAMES {UnitType.HARVESTER: 'Harvester Ant', UnitType.SHORT_THROWER: 'Short-Range Leaf Thrower', UnitType.THROWER: 'All-Range Leaf Thrower', UnitType.LONG_THROWER: 'Long-Range Leaf Thrower', UnitType.WALL: 'Wall Ant'} ScreenManager: Screen: @@ -132,7 +130,7 @@ ScreenManager: id: harvester_image source: 'assets/ant_harvester.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'A harvester ant costs 3 food units to deploy, but produces 2 food units per turn.' text_size: (self.width, None) @@ -149,7 +147,7 @@ ScreenManager: id: short_thrower_image source: 'assets/ant_short_thrower.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'A short-range leaf thrower costs 3 food units to deploy and can throw leaves at bees it sees up to two spaces away.' text_size: (self.width, None) @@ -166,7 +164,7 @@ ScreenManager: id: thrower_image source: 'assets/ant_thrower.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'An all-range thrower costs 7 food units to deploy and can throw leaves at any range.' text_size: (self.width, None) @@ -183,7 +181,7 @@ ScreenManager: id: long_thrower_image source: 'assets/ant_long_thrower.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'A long-range thrower costs 3 food units to deploy and can throw leaves at bees it sees from at least four spaces away.' text_size: (self.width, None) @@ -200,7 +198,7 @@ ScreenManager: id: wall_image source: 'assets/ant_wall.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'A wall ant costs 4 food units to deploy and has no attack, but it can withstand 4 stings before dying.' text_size: (self.width, None) @@ -233,7 +231,7 @@ ScreenManager: id: wall_image source: 'assets/bee.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'A bee can either fly forward or sting each turn. It normally takes 4 leaves to kill a bee.' text_size: (self.width, None) @@ -264,7 +262,7 @@ ScreenManager: size: self.size source: 'assets/tunnel.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'Every time a bee reaches a red-shaded space in the tunnel, its health increases by one point.' text_size: (self.width, None) @@ -318,7 +316,7 @@ ScreenManager: height: 24 Label: id: selection - text: '{unit} ({food_cost} food)'.format(unit=UNIT_NAMES[root.selection.unit_type.value], food_cost=getattr(root.selection, 'food_cost', 0)) if root.selection is not None else 'Sacrifice Ant' + text: '{unit} ({food_cost} food)'.format(unit=UNIT_NAMES[root.selection.unit_type], food_cost=getattr(root.selection, 'food_cost', 0)) if root.selection is not None else 'Sacrifice Ant' size_hint: (1, None) height: 24 Label: @@ -363,7 +361,7 @@ ScreenManager: pos: self.pos size: self.size size_hint: (None, None) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE <Sprite>: @@ -373,6 +371,6 @@ ScreenManager: Rectangle: pos: self.pos size: self.size - pos: (SPRITE_WIDTH * self.world_x, SPRITE_HEIGHT * self.world_y) + pos: (Game.SPRITE_WIDTH * self.world_x, Game.SPRITE_HEIGHT * self.world_y) size_hint: (None, None) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE -- GitLab