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

6 篇文章 0 订阅
5 篇文章 0 订阅

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值