Principles of Computing (Part 2) -- week 3 (Tree, Lambda, Minimax)

来源:互联网 发布:java的replace方法 编辑:程序博客网 时间:2024/06/08 05:08

lambda:

Anonymous functions are simplified forms of function definitions.
- they do not have a name.
- the parameter list is not in parentheses.
- the function body is just a single expression, which is implicitly returned.
This simplicity is convenient especially when the function is simply passed as an argument, as in the last example above.

Example:

    data = [1, 3, 6, 9, 18]    # square elements in a list by lambda    data3 = map(lambda x: x ** 2, data)    # filter the even number    data4 = filter(lambda val: val % 2 == 0, data)

Tree

A rooted tree is a hierarchical data structure with applications in many areas of computer science. These applications include searching, sorting, modeling biological processes (such as genealogy), and representing hierarchical programming constructs such as arithmetic expressions.
This distinction between leaf nodes and internal nodes allows us to specify simple recursive definitions for several important structural quantities associated with trees.

  • The number of nodes in a tree satisfies:
    If the root node of the tree is a leaf:        return 1    else:        return 1 + the sum of the number of nodes for each subtree
  • The number of leaves in a tree satisfies:
    If the root node of the tree is a leaf:        return 1    else:        return the sum of the number of leaves for each subtree
  • The height of a tree is the length of the longest sequence of edges from the root to a leaf. The height can be computed recursively via:
    If the root node of the tree is a leaf:        return 0    else:        return 1 + the maximum of the heights of the subtrees

In the case of binary trees, the two subtrees of a node are usually referred to as the left subtree and the right subtree. For binary trees, there are three common types of tree traversals:

  • Pre-order traversals - process root, process left subtree, process right subtree
  • Post-order traversals - process left subtree, process right subtree, process root
  • In-order traversals - process left subtree, process root, process right subtree

ArithmeticExpression class implement uses In-order traversals

Mini Project – TicTacToe with Minimax

  • Use Minimax to return the best move
  • Use Memo_dict to record the score the boards, reduce iteration
  • Use equivalent_boards by mirror & rotation to optimize
  • Use opt_empty_cell to reduce the empty cell search list
    """    Mini-max Tic-Tac-Toe Player    """    import poc_ttt_gui    import poc_ttt_provided as provided    # Set timeout, as mini-max can take a long time    import codeskulptor    codeskulptor.set_timeout(600)    import math    import random    # SCORING VALUES - DO NOT MODIFY    SCORES = {provided.PLAYERX: 1,              provided.DRAW: 0,              provided.PLAYERO: -1}    # helper function    def transpose_board(board):        """        return the transposed board        """        dim = board.get_dim()        tboard = provided.TTTBoard(dim)        for row in range(dim):            for col in range(dim):                if board.square(row, col) != provided.EMPTY:                    tboard.move(col, row, board.square(row, col))                    return tboard                                        def x_mirror_board(board):        """        return the board mirrored by x        """        dim = board.get_dim()        xboard = provided.TTTBoard(dim)        for row in range(dim):            for col in range(dim):                if board.square(row, col) != provided.EMPTY:                    xrow = dim - row - 1                    xboard.move(xrow, col, board.square(row, col))        return xboard                def y_mirror_board(board):        """        return the board mirrored by y        """        dim = board.get_dim()        yboard = provided.TTTBoard(dim)        for row in range(dim):            for col in range(dim):                if board.square(row, col) != provided.EMPTY:                    ycol = dim - col - 1                    yboard.move(row, ycol, board.square(row, col))        return yboard           def rotate_board(board, retation = 90):        """        retate the board by 0, 90, 180, 270 degree        """        dim = board.get_dim()        rboard = provided.TTTBoard(dim)        valid_rotation_list = [0, 90, 180, 270]        if retation not in valid_rotation_list:            return "Invalid retation", retation        for row in range(dim):            for col in range(dim):                if retation == 90:                    rboard.move(dim - col - 1, row, board.square(row, col))                elif retation == 180:                    rboard.move(dim - row - 1, dim - col - 1, board.square(row, col))                elif retation == 270:                    rboard.move(col, dim - row - 1, board.square(row, col))                else:                    rboard.move(row, col, board.square(row, col))        return rboard    def all_equivalent_board(board):        """        return all the equivalent boards        """        all_boards = []        rotation_list = [0, 90, 180, 270]        for rotation in rotation_list:            rboard = rotate_board(board, rotation)            tboard = transpose_board(rboard)            all_boards.append(rboard)            all_boards.append(tboard)        return all_boards    def opt_empty_cell(board):        """        reduce the empty cell according to the board        """        dim = board.get_dim()        all_empty_cells = board.get_empty_squares()        xboard = x_mirror_board(board)        if str(board) == str(xboard):            xrow = int(math.ceil(dim / 2.0))            for row in range(xrow, dim):                for col in range(dim):                    cell = (row, col)                    if cell in all_empty_cells:                        all_empty_cells.remove(cell)        yboard = y_mirror_board(board)        if str(board) == str(yboard):            ycol = int(math.ceil(dim / 2.0))            for row in range(dim):                for col in range(ycol, dim):                    cell = (row, col)                    if cell in all_empty_cells:                        all_empty_cells.remove(cell)        tboard = transpose_board(board)        if str(board) == str(tboard):            xrow = int(math.floor(dim / 2.0))            ycol = int(math.ceil(dim / 2.0))            for row in range(xrow, dim):                for col in range(ycol):                    if row != col:                        cell = (row, col)                        if cell in all_empty_cells:                            all_empty_cells.remove(cell)        return all_empty_cells    def mm_move_helper(board, player, memo_dict):        """        helper function for mm_move for not corrupt origial structure        """        if (str(board)) in memo_dict.keys():            return memo_dict[(str(board))]        # DFS the tree until game finishes        if board.check_win() == None:            cell_dict = {}            # score the next moves            # for cell in board.get_empty_squares():            for cell in opt_empty_cell(board):                board_clone = board.clone()                board_clone.move(cell[0], cell[1], player)                move = mm_move_helper(board_clone, provided.switch_player(player), memo_dict)                # stop DFS search as long as the best solution is found                if move[0] * SCORES[player] == 1:                    # memo the result                    all_boards = all_equivalent_board(board)                    for a_board in all_boards:                        memo_dict[str(a_board)] = (move[0], cell)                                    return move[0], cell                if move[0] * SCORES[player] not in cell_dict.keys():                    cell_dict[move[0] * SCORES[player]] = cell            # return the best score and move            max_score = max(cell_dict.keys())            best_score = max_score * SCORES[player]            best_move = cell_dict[max_score]        else:            # Score the board when game finishes            best_score = SCORES[board.check_win()]            best_move = (-1, -1)        # memo the result        all_boards = all_equivalent_board(board)        for a_board in all_boards:            memo_dict[str(a_board)] = (best_score, best_move)        return best_score, best_move    def mm_move(board, player):        """        Make a move on the board.        Returns a tuple with two elements.  The first element is the score        of the given board and the second element is the desired move as a        tuple, (row, col).        memo_dict is a dictionary that stores previously computed results        """        return mm_move_helper(board, player, {})    def move_wrapper(board, player, trials):        """        Wrapper to allow the use of the same infrastructure that was used        for Monte Carlo Tic-Tac-Toe.        """        move = mm_move(board, player)        assert move[1] != (-1, -1), "returned illegal move (-1, -1)"        return move[1]    # Test game with the console or the GUI.    # Uncomment whichever you prefer.    # Both should be commented out when you submit for    # testing to save time.    #provided.play_game(move_wrapper, 1, False)            poc_ttt_gui.run_gui(3, provided.PLAYERX, move_wrapper, 1, False)
0 0
原创粉丝点击