alpha-beta剪枝

井字棋

井字棋(tic-tac-toe)

经过旋转,翻转操作进行去重后,
有91个局面X赢
有44个局面O赢
有3个局面平局

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
from copy import deepcopy

HEIGHT = 3
WIDTH = 3
X_CHESS = 1
O_CHESS = -1
EMPTY_CHESS = 0

board = [[EMPTY_CHESS for _ in range(WIDTH)] for _ in range(HEIGHT)]


def print_board(board):
    print('*' * 20)
    for i in range(HEIGHT):
        for j in range(WIDTH):
            if X_CHESS == board[i][j]:
                print('X', end='')
            elif O_CHESS == board[i][j]:
                print('O', end='')
            else:
                print('_', end='')
        print()
    print('*' * 20)


def check_win(board, player):
    # row
    for i in range(HEIGHT):
        cnt = 0
        for j in range(WIDTH):
            cnt += (player == board[i][j])
        if 3 == cnt:
            return True
    # col
    for j in range(WIDTH):
        cnt = 0
        for i in range(HEIGHT):
            cnt += (player == board[i][j])
        if 3 == cnt:
            return True
    main_diagonal_cnt, sub_diagonal_cnt = 0, 0
    for i in range(HEIGHT):
        main_diagonal_cnt += (player == board[i][i])
        sub_diagonal_cnt += (player == board[i][WIDTH - i - 1])
    return 3 == main_diagonal_cnt or 3 == sub_diagonal_cnt


def get_state(board):
    state = 0
    for i in range(HEIGHT):
        for j in range(WIDTH):
            cur = board[i][j]
            if O_CHESS == board[i][j]:
                cur = 2
            state += cur * (3 ** (i * WIDTH + j))
    return state


def transpose(board):
    temp = deepcopy(board)
    # transpose
    for i in range(HEIGHT):
        for j in range(i):
            temp[i][j], temp[j][i] = temp[j][i], temp[i][j]
    return temp


def horizontal_flip(board):
    temp = deepcopy(board)
    for i in range(HEIGHT):
        j, k = 0, WIDTH - 1
        while j < k:
            temp[i][j], temp[i][k] = temp[i][k], temp[i][j]
            j += 1
            k -= 1
    return temp


def vertical_flip(board):
    temp = deepcopy(board)
    for j in range(WIDTH):
        i, k = 0, HEIGHT - 1
        while i < k:
            temp[i][j], temp[k][j] = temp[k][j], temp[i][j]
            i += 1
            k -= 1
    return temp


def rotate90(board):
    temp = deepcopy(board)
    return horizontal_flip(transpose(temp))


states = set()

x_win_cnt = 0
o_win_cnt = 0
draw = 0
open_cnt = 0


def get_equivalent_state(board):
    cur_state = get_state(board)
    temp = deepcopy(board)
    result = {cur_state}
    for _ in range(3):
        temp = rotate90(temp)
        result.add(get_state(temp))
    temp = horizontal_flip(temp)
    result.add(get_state(temp))
    for _ in range(3):
        temp = rotate90(temp)
        result.add(get_state(temp))
    return result


def traverse(board, cur_player, depth, states):
    # x_win_cnt=626, o_win_cnt=316, draw=16, open_cnt=4536
    # x_win_cnt=91, o_win_cnt=44, draw=3, open_cnt=630
    global open_cnt
    open_cnt += 1

    moves = []
    for i in range(HEIGHT):
        for j in range(WIDTH):
            if EMPTY_CHESS == board[i][j]:
                moves.append((i, j))
    if 0 == len(moves):
        print_board(board)
        global draw
        draw += 1
        return
    for i, j in moves:
        board[i][j] = cur_player
        cur_state = get_state(board)
        flag = cur_state not in states
        if flag:
            states.update(get_equivalent_state(board))
        else:
            board[i][j] = EMPTY_CHESS
            continue
        states.add(cur_state)
        if check_win(board, cur_player):
            print_board(board)
            board[i][j] = EMPTY_CHESS
            if cur_player == X_CHESS:
                global x_win_cnt
                x_win_cnt += 1
            else:
                global o_win_cnt
                o_win_cnt += 1
            continue
        traverse(board, -cur_player, depth + 1, states)

        board[i][j] = EMPTY_CHESS



if __name__ == '__main__':
    traverse(board, X_CHESS, 0, set())
    print(x_win_cnt, o_win_cnt, draw, open_cnt)

Min-Max算法/Negamax算法

假设这是一个零和博弈

自己总是回选择最好的局面,但是对手总是会选择最不利于我们的局面
然后利用回溯,找到下一步最好的局面
如下图(来自wiki)
alpha-beta剪枝_第1张图片
伪代码如下(来自wiki)

function  minimax( node, depth, maximizingPlayer ) is
    if depth = 0 or node is a terminal node then
        return the heuristic value of node
    if maximizingPlayer then
        value := −∞
        for each child of node do
            value := max(value, minimax(child, depth − 1, FALSE))
        return value
    else (* minimizing player *)
        value := +for each child of node do
            value := min( value, minimax( child, depth − 1, TRUE ) )
        return value

当然这样比较麻烦,可以化简一下

function  negamax( node, depth, maximizingPlayer ) is
    if depth = 0 or node is a terminal node then
        return the heuristic value of node
    value := −∞
    for each child of node do
        value := max(value, -minimax(child, depth − 1, not maximizingPlayer))
    return value

可以大概感受一下
alpha-beta剪枝_第2张图片
这里胜利局面返回的 11 − d e p t h 11-depth 11depth,简单来说,越快赢,分数越大,平局返回0,输了返回 − ( 11 − d e p t h ) -\left(11-depth\right) (11depth) (因为判断赢写在了下一层,所以 1 ≤ d e p t h ≤ 10 1\le depth\le 10 1depth10为了保证正数,所以写了 11 11 11)

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
from copy import deepcopy

HEIGHT = 3
WIDTH = 3
X_CHESS = 1
O_CHESS = -1
EMPTY_CHESS = 0
INF = 0x7fffffff


def print_board(board):
    print('*' * 20)
    for i in range(HEIGHT):
        for j in range(WIDTH):
            if X_CHESS == board[i][j]:
                print('X', end='')
            elif O_CHESS == board[i][j]:
                print('O', end='')
            else:
                print('_', end='')
        print()
    print('*' * 20)


def check_win(board, player):
    # row
    for i in range(HEIGHT):
        cnt = 0
        for j in range(WIDTH):
            cnt += (player == board[i][j])
        if 3 == cnt:
            return True
    # col
    for j in range(WIDTH):
        cnt = 0
        for i in range(HEIGHT):
            cnt += (player == board[i][j])
        if 3 == cnt:
            return True
    main_diagonal_cnt, sub_diagonal_cnt = 0, 0
    for i in range(HEIGHT):
        main_diagonal_cnt += (player == board[i][i])
        sub_diagonal_cnt += (player == board[i][WIDTH - i - 1])
    return 3 == main_diagonal_cnt or 3 == sub_diagonal_cnt


def get_state(board):
    state = 0
    for i in range(HEIGHT):
        for j in range(WIDTH):
            cur = board[i][j]
            if O_CHESS == board[i][j]:
                cur = 2
            state += cur * (3 ** (i * WIDTH + j))
    return state


def transpose(board):
    temp = deepcopy(board)
    # transpose
    for i in range(HEIGHT):
        for j in range(i):
            temp[i][j], temp[j][i] = temp[j][i], temp[i][j]
    return temp


def horizontal_flip(board):
    temp = deepcopy(board)
    for i in range(HEIGHT):
        j, k = 0, WIDTH - 1
        while j < k:
            temp[i][j], temp[i][k] = temp[i][k], temp[i][j]
            j += 1
            k -= 1
    return temp


def vertical_flip(board):
    temp = deepcopy(board)
    for j in range(WIDTH):
        i, k = 0, HEIGHT - 1
        while i < k:
            temp[i][j], temp[k][j] = temp[k][j], temp[i][j]
            i += 1
            k -= 1
    return temp


def rotate90(board):
    temp = deepcopy(board)
    return horizontal_flip(transpose(temp))


x_win_cnt = 0
o_win_cnt = 0
draw = 0
open_cnt = 0


def get_equivalent_state(board):
    cur_state = get_state(board)
    temp = deepcopy(board)
    result = {cur_state}
    for _ in range(3):
        temp = rotate90(temp)
        result.add(get_state(temp))
    temp = horizontal_flip(temp)
    result.add(get_state(temp))
    for _ in range(3):
        temp = rotate90(temp)
        result.add(get_state(temp))
    return result


def traverse(board, cur_player, depth, states):
    # x_win_cnt=626, o_win_cnt=316, draw=16, open_cnt=4536
    # x_win_cnt=91, o_win_cnt=44, draw=3, open_cnt=630
    global open_cnt
    open_cnt += 1

    moves = []
    for i in range(HEIGHT):
        for j in range(WIDTH):
            if EMPTY_CHESS == board[i][j]:
                moves.append((i, j))
    if 0 == len(moves):
        print_board(board)
        global draw
        draw += 1
        return
    for i, j in moves:
        board[i][j] = cur_player
        cur_state = get_state(board)
        flag = cur_state not in states
        if flag:
            states.update(get_equivalent_state(board))
        else:
            board[i][j] = EMPTY_CHESS
            continue
        states.add(cur_state)
        if check_win(board, cur_player):
            print_board(board)
            board[i][j] = EMPTY_CHESS
            if cur_player == X_CHESS:
                global x_win_cnt
                x_win_cnt += 1
            else:
                global o_win_cnt
                o_win_cnt += 1
            continue
        traverse(board, -cur_player, depth + 1, states)

        board[i][j] = EMPTY_CHESS


def min_max(board, cur_player, depth, states):
    if check_win(board, -cur_player):
        # return -INF + 1, None, None
        return -(HEIGHT * WIDTH + 2 - depth), None, None
    moves = []
    for i in range(HEIGHT):
        for j in range(WIDTH):
            if EMPTY_CHESS == board[i][j]:
                moves.append((i, j))
    if 0 == len(moves):
        return 0, None, None
    best_val, best_i, best_j = -INF, -1, -1
    for i, j in moves:
        board[i][j] = cur_player
        cur_state = get_state(board)
        flag = cur_state not in states
        if flag:
            result = -min_max(board, -cur_player, depth + 1, states)[0]
            for equivalent_state in get_equivalent_state(board):
                states[equivalent_state] = -result
        else:
            result = -states[cur_state]
        board[i][j] = EMPTY_CHESS
        if result > best_val:
            best_val, best_i, best_j = result, i, j

    return best_val, best_i, best_j


def get_input(board):
    while True:
        try:
            i, j = map(int, input('position: (split by space)').strip().split())
            if 0 <= i < HEIGHT and 0 <= j < WIDTH and EMPTY_CHESS == board[i][j]:
                return i, j
            else:
                print('illegal input')
        except:
            print('illegal input')


def pvp():
    board = [[EMPTY_CHESS for _ in range(WIDTH)] for _ in range(HEIGHT)]
    cur_player = X_CHESS
    print_board(board)
    for _ in range(HEIGHT * WIDTH):
        print('*' * 20)
        if X_CHESS == cur_player:
            print('X turn')
        else:
            print('O turn')
        i, j = get_input(board)
        board[i][j] = cur_player
        print_board(board)
        if check_win(board, cur_player):
            if X_CHESS == cur_player:
                print('X win')
            else:
                print('O win')
            return
        else:
            cur_player = -cur_player
    print('draw')


def pve():
    a = input('choose X or O').strip()
    player = X_CHESS
    while True:
        if 'X' == a.upper():
            break
        elif 'O' == a.upper():
            player = O_CHESS
            break
        else:
            a = input('choose X or O').strip()
    board = [[EMPTY_CHESS for _ in range(WIDTH)] for _ in range(HEIGHT)]
    cur_player = X_CHESS
    print_board(board)
    for _ in range(HEIGHT * WIDTH):
        if X_CHESS == cur_player:
            print('X turn')
        else:
            print('O turn')
        if player == cur_player:
            i, j = get_input(board)
        else:
            _, i, j = min_max(board, cur_player, 0, {})
        board[i][j] = cur_player
        print_board(board)
        if check_win(board, cur_player):
            if X_CHESS == cur_player:
                print('X win')
            else:
                print('O win')
            return
        else:
            cur_player = -cur_player
    print('draw')


def traverse_ai(board, cur_player, ai_player, depth):
    moves = []
    for i in range(HEIGHT):
        for j in range(WIDTH):
            if EMPTY_CHESS == board[i][j]:
                moves.append((i, j))
    if 0 == len(moves):
        print_board(board)
        global draw
        draw += 1
        return
    for i, j in moves:
        if cur_player == ai_player:
            _, i, j = min_max(board, cur_player, 0, {})
        board[i][j] = cur_player
        if check_win(board, cur_player):
            print_board(board)
            board[i][j] = EMPTY_CHESS
            if cur_player == X_CHESS:
                global x_win_cnt
                x_win_cnt += 1
            else:
                global o_win_cnt
                o_win_cnt += 1
            continue
        traverse_ai(board, -cur_player, ai_player, depth + 1)

        board[i][j] = EMPTY_CHESS


if __name__ == '__main__':
    # board = [
    #     [-1, 0, 1],
    #     [0, 1, 0],
    #     [0, 0, 0]
    # ]
    # print_board(board)
    # min_max(board, O_CHESS, 0, {})
    # print_board(board)
    # board = [[EMPTY_CHESS for _ in range(WIDTH)] for _ in range(HEIGHT)]
    # traverse_ai(board, X_CHESS, X_CHESS, 0)
    # print(f"x_win_cnt={x_win_cnt}, o_win_cnt={o_win_cnt}, draw={draw}")
    # traverse_ai(board, X_CHESS, O_CHESS, 0)
    # print(f"x_win_cnt={x_win_cnt}, o_win_cnt={o_win_cnt}, draw={draw}")
    # x_win_cnt=72765, o_win_cnt=0, draw=1890
    # x_win_cnt=41895, o_win_cnt=0, draw=1890
    # x_win_cnt = 0, o_win_cnt = 165888, draw = 70272
    # x_win_cnt = 0, o_win_cnt = 112128, draw = 70272

    a = input('pvp or pve').strip()
    pvp_flag = True
    while True:
        if 'pvp' == a:
            break
        elif 'pve' == a:
            pvp_flag = False
            break
        else:
            a = input('pvp or pve').strip()
    if pvp_flag:
        pvp()
    else:
        pve()

alpha-beta剪枝

alpha-beta剪枝(alpha-beta pruning)
α \alpha α为max方(自己)能取到的最大值,初始值为 − ∞ -\infty
β \beta β为min方(对手)能取到最小值 + ∞ +\infty +
在max的时候,是要更新 α \alpha α的,但是当 α ≥ β \alpha\ge\beta αβ时,这个分支就可以剪掉了
在min的时候,是要更新 β \beta β的,但是当 α ≥ β \alpha\ge\beta αβ时,这个分支就可以剪掉了

alpha-beta剪枝_第3张图片
比如这个图(来自wiki),第2层的第3个结点,从叶子返回了5,但是 5 ≤ 6 = α 5\le 6=\alpha 56=α,第1层(max)有更好的选择(第2层第2个是6),他一定不会选择这个5;又因为第2层是min,后续的节点要想返回,只能比5小,但是同时也 ≤ α \le \alpha α,所以后续的分支不用看了
alpha-beta剪枝_第4张图片
同理(来自csdn),比如访问完K的时候,从叶子节点返回4,但是 4 ≥ 3 = β 4\ge 3=\beta 43=β,而B有更好的选择(D),所以他一定不会选择这个4;又因为第3层是max,后续节点想返回,只能比4大,但是同时也 ≥ β \ge \beta β,所以后续的分支不用看了

伪代码(来自wiki)

function alphabeta(node, depth, α, β, maximizingPlayer) is
    if depth = 0 or node is a terminal node then
        return the heuristic value of node
    if maximizingPlayer then
        value := −∞
        for each child of node do
            value := max(value, alphabeta(child, depth − 1, α, β, FALSE))
            if value ≥ β then
                break (* β cutoff *)
            α := max(α, value)
        return value
    else
        value := +for each child of node do
            value := min(value, alphabeta(child, depth − 1, α, β, TRUE))
            if value ≤ α then
                break (* α cutoff *)
            β := min(β, value)
        return value

也可以化简一下

function negamax(node, depth, α, β, maximizingPlayer) is
    if depth = 0 or node is a terminal node then
        return the heuristic value of node
    value := −∞
    for each child of node do
        value := -max(value, alphabeta(child, depth − 1, -β, α, not maximizingPlayer))
        if value ≥ β then
            break (* β cutoff *)
        α := max(α, value)
    return value

这里与min-max不同,去重只去重一层,因为可能因为剪枝导致某个局面返回的值不对
比如说有一个局面,有下一步就赢的策略,但是由于alpha-beta剪枝,导致返回了一个输了局面

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
from copy import deepcopy

HEIGHT = 3
WIDTH = 3
X_CHESS = 1
O_CHESS = -1
EMPTY_CHESS = 0
INF = 0x7fffffff


def print_board(board):
    print('*' * 20)
    for i in range(HEIGHT):
        for j in range(WIDTH):
            if X_CHESS == board[i][j]:
                print('X', end='')
            elif O_CHESS == board[i][j]:
                print('O', end='')
            else:
                print('_', end='')
        print()
    print('*' * 20)


def check_win(board, player):
    # row
    for i in range(HEIGHT):
        cnt = 0
        for j in range(WIDTH):
            cnt += (player == board[i][j])
        if 3 == cnt:
            return True
    # col
    for j in range(WIDTH):
        cnt = 0
        for i in range(HEIGHT):
            cnt += (player == board[i][j])
        if 3 == cnt:
            return True
    main_diagonal_cnt, sub_diagonal_cnt = 0, 0
    for i in range(HEIGHT):
        main_diagonal_cnt += (player == board[i][i])
        sub_diagonal_cnt += (player == board[i][WIDTH - i - 1])
    return 3 == main_diagonal_cnt or 3 == sub_diagonal_cnt


def get_state(board):
    state = 0
    for i in range(HEIGHT):
        for j in range(WIDTH):
            cur = board[i][j]
            if O_CHESS == board[i][j]:
                cur = 2
            state += cur * (3 ** (i * WIDTH + j))
    return state


def state2board(state):
    board = [[EMPTY_CHESS for _ in range(WIDTH)] for _ in range(HEIGHT)]

    pos = HEIGHT * WIDTH - 1
    weight = 3 ** pos
    while weight > 0:
        i, j = pos // WIDTH, pos % WIDTH
        chess = state // weight
        if 2 == chess:
            board[i][j] = O_CHESS
        else:
            board[i][j] = chess
        pos -= 1
        weight //= 3
    return board


def transpose(board):
    temp = deepcopy(board)
    # transpose
    for i in range(HEIGHT):
        for j in range(i):
            temp[i][j], temp[j][i] = temp[j][i], temp[i][j]
    return temp


def horizontal_flip(board):
    temp = deepcopy(board)
    for i in range(HEIGHT):
        j, k = 0, WIDTH - 1
        while j < k:
            temp[i][j], temp[i][k] = temp[i][k], temp[i][j]
            j += 1
            k -= 1
    return temp


def vertical_flip(board):
    temp = deepcopy(board)
    for j in range(WIDTH):
        i, k = 0, HEIGHT - 1
        while i < k:
            temp[i][j], temp[k][j] = temp[k][j], temp[i][j]
            i += 1
            k -= 1
    return temp


def rotate90(board):
    temp = deepcopy(board)
    return horizontal_flip(transpose(temp))


x_win_cnt = 0
o_win_cnt = 0
draw = 0
open_cnt = 0


def get_equivalent_state(board):
    cur_state = get_state(board)
    temp = deepcopy(board)
    result = {cur_state}
    for _ in range(3):
        temp = rotate90(temp)
        result.add(get_state(temp))
    temp = horizontal_flip(temp)
    result.add(get_state(temp))
    for _ in range(3):
        temp = rotate90(temp)
        result.add(get_state(temp))
    return result


def traverse(board, cur_player, depth, states):
    # x_win_cnt=626, o_win_cnt=316, draw=16, open_cnt=4536
    # x_win_cnt=91, o_win_cnt=44, draw=3, open_cnt=630
    global open_cnt
    open_cnt += 1

    moves = []
    for i in range(HEIGHT):
        for j in range(WIDTH):
            if EMPTY_CHESS == board[i][j]:
                moves.append((i, j))
    if 0 == len(moves):
        print_board(board)
        global draw
        draw += 1
        return
    for i, j in moves:
        board[i][j] = cur_player
        cur_state = get_state(board)
        flag = cur_state not in states
        if flag:
            states.update(get_equivalent_state(board))
        else:
            board[i][j] = EMPTY_CHESS
            continue
        states.add(cur_state)
        if check_win(board, cur_player):
            print_board(board)
            board[i][j] = EMPTY_CHESS
            if cur_player == X_CHESS:
                global x_win_cnt
                x_win_cnt += 1
            else:
                global o_win_cnt
                o_win_cnt += 1
            continue
        traverse(board, -cur_player, depth + 1, states)

        board[i][j] = EMPTY_CHESS


def alpha_beta_pruning(board, cur_player, depth, alpha, beta, states):
    if check_win(board, -cur_player):
        # return -INF + 1, None, None
        return -(HEIGHT * WIDTH + 2 - depth), None, None
    moves = []
    for i in range(HEIGHT):
        for j in range(WIDTH):
            if EMPTY_CHESS == board[i][j]:
                moves.append((i, j))
    if 0 == len(moves):
        return 0, None, None
    best_val, best_i, best_j = -INF, -1, -1
    for i, j in moves:
        board[i][j] = cur_player
        cur_state = get_state(board)
        flag = cur_state not in states
        if flag:
            result = -alpha_beta_pruning(board, -cur_player, depth + 1, -beta, -alpha, {})[0]
            for equivalent_state in get_equivalent_state(board):
                states[equivalent_state] = -result
        else:
            result = -states[cur_state]
        if result > best_val:
            best_val, best_i, best_j = result, i, j
        board[i][j] = EMPTY_CHESS
        if result >= beta:
            break
        alpha = max(alpha, result)

    return best_val, best_i, best_j


def get_input(board):
    while True:
        try:
            i, j = map(int, input('position: (split by space)').strip().split())
            if 0 <= i < HEIGHT and 0 <= j < WIDTH and EMPTY_CHESS == board[i][j]:
                return i, j
            else:
                print('illegal input')
        except:
            print('illegal input')


def pvp():
    board = [[EMPTY_CHESS for _ in range(WIDTH)] for _ in range(HEIGHT)]
    cur_player = X_CHESS
    print_board(board)
    for _ in range(HEIGHT * WIDTH):
        print('*' * 20)
        if X_CHESS == cur_player:
            print('X turn')
        else:
            print('O turn')
        i, j = get_input(board)
        board[i][j] = cur_player
        print_board(board)
        if check_win(board, cur_player):
            if X_CHESS == cur_player:
                print('X win')
            else:
                print('O win')
            return
        else:
            cur_player = -cur_player
    print('draw')


def pve():
    a = input('choose X or O').strip()
    player = X_CHESS
    while True:
        if 'X' == a.upper():
            break
        elif 'O' == a.upper():
            player = O_CHESS
            break
        else:
            a = input('choose X or O').strip()
    board = [[EMPTY_CHESS for _ in range(WIDTH)] for _ in range(HEIGHT)]
    cur_player = X_CHESS
    print_board(board)
    for _ in range(HEIGHT * WIDTH):
        if X_CHESS == cur_player:
            print('X turn')
        else:
            print('O turn')
        if player == cur_player:
            i, j = get_input(board)
        else:
            _, i, j = alpha_beta_pruning(board, cur_player, 0, -INF, INF, {})
        board[i][j] = cur_player
        print_board(board)
        if check_win(board, cur_player):
            if X_CHESS == cur_player:
                print('X win')
            else:
                print('O win')
            return
        else:
            cur_player = -cur_player
    print('draw')


order = []


def traverse_ai(board, cur_player, ai_player, depth):
    moves = []
    for i in range(HEIGHT):
        for j in range(WIDTH):
            if EMPTY_CHESS == board[i][j]:
                moves.append((i, j))
    if 0 == len(moves):
        print_board(board)
        global draw
        draw += 1
        return
    for i, j in moves:
        if cur_player == ai_player:
            _, i, j = alpha_beta_pruning(board, cur_player, 0, -INF, INF, {})
        board[i][j] = cur_player
        order.append((i, j))
        if check_win(board, cur_player):
            print_board(board)
            board[i][j] = EMPTY_CHESS
            if cur_player == X_CHESS:
                global x_win_cnt
                x_win_cnt += 1
            else:
                global o_win_cnt
                o_win_cnt += 1
            if cur_player != ai_player:
                print(order)
                raise Exception('faQ')
            order.pop()
            continue
        traverse_ai(board, -cur_player, ai_player, depth + 1)

        board[i][j] = EMPTY_CHESS
        order.pop()


if __name__ == '__main__':
    # board = [
    #     [1, 0, 0],
    #     [0, 0, 0],
    #     [0, 0, 0]
    # ]
    # print_board(board)
    # _, i, j = alpha_beta_pruning(board, O_CHESS, 0, -INF, INF, {})
    # board[i][j] = O_CHESS
    # print_board(board)
    # board = [[EMPTY_CHESS for _ in range(WIDTH)] for _ in range(HEIGHT)]
    # traverse_ai(board, X_CHESS, X_CHESS, 0)
    # print(f"x_win_cnt={x_win_cnt}, o_win_cnt={o_win_cnt}, draw={draw}")
    # traverse_ai(board, X_CHESS, O_CHESS, 0)
    # print(f"x_win_cnt={x_win_cnt}, o_win_cnt={o_win_cnt}, draw={draw}")
    # x_win_cnt=72765, o_win_cnt=0, draw=1890
    # x_win_cnt=41895, o_win_cnt=0, draw=1890
    # x_win_cnt=41895, o_win_cnt=0, draw=1890
    # x_win_cnt=41895, o_win_cnt=0, draw=1890
    # x_win_cnt= 0, o_win_cnt=165888, draw=70272
    # x_win_cnt= 0, o_win_cnt=112128, draw=70272
    # x_win_cnt=0, o_win_cnt=112128, draw=70272

    a = input('pvp or pve').strip()
    pvp_flag = True
    while True:
        if 'pvp' == a:
            break
        elif 'pve' == a:
            pvp_flag = False
            break
        else:
            a = input('pvp or pve').strip()
    if pvp_flag:
        pvp()
    else:
        pve()

你可能感兴趣的:(数据结构与算法,剪枝,python,算法)