def random_data(tile_collection: TileCollection, random: random.Random) -> Tuple[int, int]: """ Simulates a randomly swiping user and returns the score and the number of made valid moves. :param tile_collection: :param random: :return: """ game_field = GameField(tile_collection) game_controller = GameController(game_field, tile_collection) game_controller.initialize() moves = 0 actions = [ game_controller.swipe_north_action, game_controller.swipe_east_action, game_controller.swipe_south_action, game_controller.swipe_west_action ] while True: try: # do anything action = random.choice(actions) action() moves += 1 except InvalidActionError as _: # if the action was invalid, ignore and keep going pass except GameLostError as e: # if the game is lost, break out of the loop if isinstance(e, GameLostError): break # print score return game_controller.score, moves
def random_data( tile_collection: TileCollection, random: random.Random ) -> Tuple[int, int]: """ Simulates a randomly swiping user and returns the score and the number of made valid moves. :param tile_collection: :param random: :return: """ game_field = GameField(tile_collection) game_controller = GameController(game_field, tile_collection) game_controller.initialize() moves = 0 actions = [ game_controller.swipe_north_action, game_controller.swipe_east_action, game_controller.swipe_south_action, game_controller.swipe_west_action ] while True: try: # do anything action = random.choice(actions) action() moves += 1 except InvalidActionError as _: # if the action was invalid, ignore and keep going pass except GameLostError as e: # if the game is lost, break out of the loop if isinstance(e, GameLostError): break # print score return game_controller.score, moves
from controller.game_controller import GameController from exceptions import InvalidActionError, GameLostError from gamefield.gamefield import GameField from gamefield.tilecollection import TileCollection import random """ This script simulates a player who randomly swipes the game until they lose. Afterwards, the number of valid swipes and the reached score are displayed. """ tile_collection = TileCollection() game_field = GameField(tile_collection) game_controller = GameController(game_field, tile_collection) game_controller.initialize() random = random.Random() moves = 0 actions = [ game_controller.swipe_north_action, game_controller.swipe_east_action, game_controller.swipe_south_action, game_controller.swipe_west_action ] while True: try: # do anything action = random.choice(actions) action() moves += 1 except InvalidActionError as _: # if the action was invalid, ignore and keep going pass except GameLostError as e:
from gamefield.gamefield import GameField from gamefield.tilecollection import TileCollection from exceptions import GameLostError, InvalidActionError, \ GameNotInitializedError tile_collection = TileCollection() game_field = GameField.basic_field(tile_collection) game_controller = GameController(game_field, tile_collection) # If the game was not initialized yet, the score is not accessible try: game_controller.score except GameNotInitializedError as e: print(e) game_controller.initialize() # score is returned after each action and each action can raise an # InvalidActionError if the called action can't be executed: try: score = game_controller.swipe_north_action() score = game_controller.swipe_east_action() score = game_controller.swipe_south_action() score = game_controller.swipe_west_action() except InvalidActionError as e: print(e) # score can be accessed at any time: score = game_controller.score # when there is no move left, a GameLostError is raised: try:
class GameControllerTestCase(unittest.TestCase): def setUp(self): self.tile_collection = TileCollection() self.game_field = GameField(self.tile_collection) self.game_controller = GameController(self.game_field, self.tile_collection) self.game_controller._random.seed(1337) def test_initialize(self): """ Tests that initialization places two random Tiles on the GameField. """ self.game_controller.initialize() # The spaces which the random tiles occupy are based on the random gene- # rator seed and thus are always equal in tests. self.assertEqual( self.game_field.field_data[2][1].tile, self.tile_collection.get_tile('value', value=2) ) self.assertEqual( self.game_field.field_data[2][3].tile, self.tile_collection.get_tile('value', value=4) ) def test_swipeNorth(self): """ Test that issueing a swipeNorthAction uses the north-ward iterator. """ self.game_field = create_autospec(GameField) self.game_field.field_data = {} self.game_controller = GameController(self.game_field, self.tile_collection) self.game_controller._random.seed(1337) self.game_controller._swipe = MagicMock() self.game_controller.swipe_north_action() self.game_field.get_north_iterator.assert_any_call() self.game_controller._swipe.assert_called_with(self.game_field.get_north_iterator()) def test_swipeEast(self): """ Test that issueing a swipeNorthAction uses the east-ward iterator. """ self.game_field = create_autospec(GameField) self.game_field.field_data = {} self.game_controller = GameController(self.game_field, self.tile_collection) self.game_controller._random.seed(1337) self.game_controller._swipe = MagicMock() self.game_controller.swipe_east_action() self.game_field.get_east_iterator.assert_any_call() self.game_controller._swipe.assert_called_with(self.game_field.get_east_iterator()) def test_swipeSouth(self): """ Test that issueing a swipeNorthAction uses the south-ward iterator. """ self.game_field = create_autospec(GameField) self.game_field.field_data = {} self.game_controller = GameController(self.game_field, self.tile_collection) self.game_controller._random.seed(1337) self.game_controller._swipe = MagicMock() self.game_controller.swipe_south_action() self.game_field.get_south_iterator.assert_any_call() self.game_controller._swipe.assert_called_with(self.game_field.get_south_iterator()) def test_swipeWest(self): """ Test that issueing a swipeNorthAction uses the west-ward iterator. """ self.game_field = create_autospec(GameField) self.game_field.field_data = {} self.game_controller = GameController(self.game_field, self.tile_collection) self.game_controller._random.seed(1337) self.game_controller._swipe = MagicMock() self.game_controller.swipe_west_action() self.game_field.get_west_iterator.assert_any_call() self.game_controller._swipe.assert_called_with(self.game_field.get_west_iterator()) def test_swipe(self): """ Functional test that a swipe action correctly traverses the created iterator. The field is layed out like this: 2 x x 4 2 4 8 4 4 4 2 4 32 16 2 4 The result should be this: (northward swipe) 4 8 8 8 4 16 4 8 32 x x x x x x x """ # set up field: self.game_field.field_data[0][0].tile = self.tile_collection.get_tile('value', value=2) self.game_field.field_data[3][0].tile = self.tile_collection.get_tile('value', value=4) self.game_field.field_data[0][1].tile = self.tile_collection.get_tile('value', value=2) self.game_field.field_data[1][1].tile = self.tile_collection.get_tile('value', value=4) self.game_field.field_data[2][1].tile = self.tile_collection.get_tile('value', value=8) self.game_field.field_data[3][1].tile = self.tile_collection.get_tile('value', value=4) self.game_field.field_data[0][2].tile = self.tile_collection.get_tile('value', value=4) self.game_field.field_data[1][2].tile = self.tile_collection.get_tile('value', value=4) self.game_field.field_data[2][2].tile = self.tile_collection.get_tile('value', value=2) self.game_field.field_data[3][2].tile = self.tile_collection.get_tile('value', value=4) self.game_field.field_data[0][3].tile = self.tile_collection.get_tile('value', value=32) self.game_field.field_data[1][3].tile = self.tile_collection.get_tile('value', value=16) self.game_field.field_data[2][3].tile = self.tile_collection.get_tile('value', value=2) self.game_field.field_data[3][3].tile = self.tile_collection.get_tile('value', value=4) self.game_controller.swipe_north_action() self.assertEqual( self.tile_collection.get_tile('value', value=4), self.game_field.field_data[0][0]._tile ) self.assertEqual( self.tile_collection.get_tile('value', value=8), self.game_field.field_data[1][0]._tile ) self.assertEqual( self.tile_collection.get_tile('value', value=8), self.game_field.field_data[2][0]._tile ) self.assertEqual( self.tile_collection.get_tile('value', value=8), self.game_field.field_data[3][0]._tile ) self.assertEqual( self.tile_collection.get_tile('value', value=4), self.game_field.field_data[0][1]._tile ) self.assertEqual( self.tile_collection.get_tile('value', value=16), self.game_field.field_data[1][1]._tile ) self.assertEqual( self.tile_collection.get_tile('value', value=4), self.game_field.field_data[2][1]._tile ) self.assertEqual( self.tile_collection.get_tile('value', value=8), self.game_field.field_data[3][1]._tile ) self.assertEqual( self.tile_collection.get_tile('value', value=32), self.game_field.field_data[0][2]._tile ) # One Tile is randomly inserted after swiping self.assertEqual( self.tile_collection.get_tile('value', value=4), self.game_field.field_data[2][3].tile ) def test_scorekeeping(self) -> None: """ Tests, that swipes return the resulting score and score is accessible. The Score numbers are based on the random seed and thus are equal every time the Test is run. """ with self.assertRaises(GameNotInitializedError): score = self.game_controller.score self.game_controller.initialize() self.assertEqual( 0, self.game_controller.swipe_east_action() ) self.assertEqual( 4, self.game_controller.swipe_south_action() ) self.assertEqual( 12, self.game_controller.swipe_south_action() ) self.assertEqual( 16, self.game_controller.swipe_south_action() ) self.assertEqual( 16, self.game_controller.swipe_south_action() ) self.assertEqual( 20, self.game_controller.swipe_south_action() ) self.assertEqual(20, self.game_controller.score) def test_initialization_enables_score(self): """ Tests, that calling GameController.initialize() allows to acces GameCon- troller.score afterwards. Before, it raises a GameNotInitializedError. """ self.game_field = GameField.basic_field(self.tile_collection) self.game_controller = GameController( self.game_field, self.tile_collection ) with self.assertRaises(GameNotInitializedError): score = self.game_controller.score self.game_controller.initialize() self.assertEqual(0, self.game_controller.score) def test_invalid_action_error(self): """ Tests that an InvalidActionError is raised when an action is issued that can't be executed. This test is very rough but should work. """ self.game_controller.initialize() with self.assertRaises(InvalidActionError): for i in range(100): self.game_controller.swipe_east_action() def test_game_lost_error(self): """ Tests that a GameLostError is raised when an action is issued but no action can be executed anymore. This test is very rough but should work. """ self.game_controller.initialize() # fill the GameField in a checkers mannern with value twos/fours, so # that they can't be fused with each other. for x in range(4): for y in range(4): if x % 2 == y % 2: self.game_field.field_data[x][y].tile = \ self.tile_collection.get_tile('value', value=2) else: self.game_field.field_data[x][y].tile = \ self.tile_collection.get_tile('value', value=4) with self.assertRaises(GameLostError): self.game_controller.swipe_north_action()
class App(object): """ The App administrates the game. It instantiates a GameField and a GameCon- troller and makes them interact with the user. """ def __init__( self, input_stream: ConsoleInput, output_stream: ConsoleOutput ): self.input = input_stream self.output = output_stream self.tile_collection = TileCollection() self.game_field = GameField.basic_field(self.tile_collection) self.game_controller = GameController( self.game_field, self.tile_collection ) self.game_controller.initialize() self.renderer = ConsoleRenderer(output_stream) # type: Renderer self.prompt_counter = 0 @staticmethod def input_invalid(user_input: str) -> bool: """ Checks if a given user input is valid. Allowed inputs are one charachter directions or 'q' to end the application. :param user_input: """ return user_input not in ['n', 'e', 's', 'w', 'q'] def run(self, max_prompts: int = -1): """ Runs the mainloop for a maximum of max_prompts times. :param max_prompts: """ run_indefinitely = max_prompts == -1 run_limit_not_reached_yet = max_prompts > self.prompt_counter # render once before everything starts, so the initial field can be seen self.renderer.render(self.game_field, self.game_controller.score) while run_indefinitely or run_limit_not_reached_yet: user_input = self.input.getline( 'Wohin swipen? n/e/s/w | q for exit\n' ) if self.input_invalid(user_input): self.output.write('Ungültiger Input, bitte wiederholen.') continue else: try: if user_input == 'n': self.output.write("swiping north") self.game_controller.swipe_north_action() elif user_input == 'e': self.output.write("swiping east") self.game_controller.swipe_east_action() elif user_input == 's': self.output.write("swiping south") self.game_controller.swipe_south_action() elif user_input == 'w': self.output.write("swiping west") self.game_controller.swipe_west_action() else: exit() except (GameLostError, InvalidActionError) as e: if isinstance(e, GameLostError): print("sorry, you lost the game!") exit() else: print("that move was invalid. try again!") # render again after input and calculation self.renderer.render(self.game_field, self.game_controller.score) self.prompt_counter += 1 run_limit_not_reached_yet = max_prompts > self.prompt_counter