예제 #1
0
 def test_2normalize(self):
     logger.info("test_2normalize")
     rows = [1, 0, 3, 2, 1]
     gs = GameState(rows)
     self.assertEqual(gs.get_rows(), rows)
     self.assertEqual(str(gs), "[10321]")
     self.assertFalse(gs.is_normalized())
     p = gs.normalize()
     self.assertTrue(gs.is_normalized())
     self.assertEqual(gs.get_rows(), [0, 1, 1, 2, 3])
     gs.denormalize(p)
     self.assertEqual(gs.get_rows(), rows)
예제 #2
0
def solve(game_state: GameState, level: int) -> (GameMove or None, int):
    """Compute the next move.
    :param game_state: a valid game_state
    :param level: the smartness level, must be in 0..2.
    :return: result[0] the game-move
             result[1] game continues, int in [-1, 0, 1, 2, 3]
                       -1 : "You won". Occurs when input game_state contains exactly 1 match.
                            In this case, result[0] == None. In all other cases result[0] != None.
                        0 : "I won". Occurs when game_state after making the move specified by result[0]
                            contains exactly 1 match.
                        1 : game continues -- no further information
                        2 : game continues -- you have a safe strategy to win.
                        3 : game continues -- your opponent (i.e. I) has a safe strategy to win
    :raise: Error, if level invalid.
    """
    Error.check(0 <= level <= 2, "level must be an integer in 0..2")
    rows = game_state.get_rows()

    # sub functions

    def random_move() -> GameMove:
        """Choose randomly one of the possible moves."""
        non_zeros = [k for k in range(5)
                     if rows[k] > 0]  # all indices with value > 0
        row_index = rand.choice(non_zeros)  # choose such index
        max_n = min(
            3,
            rows[row_index])  # max number of matches to be taken at this index
        if len(
                non_zeros
        ) == 1:  # special case: only this row has matches --> must not make_move all
            max_n = min(max_n, rows[row_index] - 1)
        match_count = rand.randint(
            1, max_n)  # choose number of matches at this index
        return GameMove(row_index, match_count)

    def most_first() -> GameMove:
        """Choose a row with the most matches and take as many matches as possible."""
        p = game_state.normalize()
        sorted_rows = game_state.get_rows()
        match_count = min(3, sorted_rows[4])  # max number of matches
        if sorted_rows[
                3] == 0:  # special case: only this row has matches --> must not take all
            match_count = min(match_count, sorted_rows[4] - 1)
        row_index = p(4)
        return GameMove(row_index, match_count)

    def best_move() -> (GameMove, int):
        """Choose best possible move, if several exist, choose one randomly.
        Return also the winning flag of the resulting node.
        """
        p = game_state.normalize()
        node = current_tree().find(game_state)
        _game_move, _winning = node.select_move()
        _game_move.row_index = p(_game_move.row_index)
        return _game_move, _winning

    # todo: new intermediate level between 1 and 2: start randomly, switch to best when more than half of
    # the matches have been taken.

    # main body continued

    # init to "you won"
    game_move = None
    game_continues = -1
    # not "you won"
    if sum(rows) > 1:
        # choose an algorithm
        winning = 0
        if level == 0:
            game_move = random_move()
        elif level == 1:
            game_move = most_first()
        else:
            game_move, winning = best_move()
        assert 1 <= game_move.match_count <= min(3, rows[game_move.row_index])
        # check whether I won or game continues
        assert sum(rows) - game_move.match_count > 0
        if sum(rows) - game_move.match_count > 1:
            game_continues = 1
            if winning == 1:
                game_continues = 2
            elif winning == -1:
                game_continues = 3
        else:  # I won
            game_continues = 0
    # you won
    else:
        assert sum(rows) == 1
    return game_move, game_continues