文章目录
内容介绍
井字棋 / 一字棋游戏
西安电子科技大学
人工智能概论大作业1
问题规约方法之博弈与博弈树
用最大最小算法 Max-Min博弈树的一阶展开形式
后面附有具体的算法(Python代码 附有详细的注释)
该算法的难点在于估值函数的定义,这个函数不好写。
问题规约法
博弈与博弈树
一字棋的估价函数定义
代码部分
import random
import sys
import math
import copy
import time
class TicTacToe(object):
"""一字棋游戏的类:"""
def __init__(self):
"""初始化类属性:"""
self.begin()
self.rule()
# 定义棋盘属性:
self.position = {
}
for i in range(1, 10):
self.position[str(i)] = ' '
# 绘制棋盘:
self.board = None
self.update()
# 玩家和电脑的棋子:
self.player, self.computer, self.goFirst = None, None, None
self.choose()
self.whoGoFirst()
def update(self):
"""更新棋盘的函数:"""
self.board = f"{
self.position['1']}|{
self.position['2']}|{
self.position['3']}\n-+-+-\n{
self.position['4']}|{
self.position['5']}|{
self.position['6']}\n-+-+-\n{
self.position['7']}|{
self.position['8']}|{
self.position['9']}"
def printf(self):
"""输出棋盘的函数:"""
self.update()
print(self.board)
@staticmethod
def begin():
"""控制游戏开始:"""
massage = input("输入任选信息开始一字棋游戏,输入 q 退出程序:")
if massage == 'q':
sys.exit()
@staticmethod
def rule():
"""简述游戏规则:"""
print("规则如下:\n输入下棋的位置为对应拨号系统的九字键")
board = """1|2|3\n-+-+-\n4|5|6\n-+-+-\n7|8|9"""
print(board)
def choose(self):
"""选择棋子的函数:"""
chess = input("请输入选择的棋子(X or O):")
while chess != 'X' and chess != 'O' and chess != 'x' and chess != 'o':
chess = input("请选择正确的棋子(X or O):")
if chess == 'X' or chess == 'x':
self.player = 'X'
self.computer = 'O'
else:
self.player = 'O'
self.computer = 'X'
def whoGoFirst(self):
"""判断计算机和玩家谁先走:"""
if random.randint(0, 1) == 0:
self.goFirst = 'computer'
print("本轮计算机先走!")
return
self.goFirst = 'player'
print("本轮玩家先走!")
def playerMove(self):
"""让玩家下棋的函数:"""
self.printf()
while True:
b = 1
position = input("请输入下棋的位置(1~9):")
if position.isdigit():
if int(position) < 1 or int(position) > 9:
print("请输入正确的下棋位置!")
b = 0
elif self.position[position] != ' ':
print("该位置已有棋子,请重新选择!")
b = 0
if b == 1:
self.position[position] = self.player
break
else:
print("请输入正确的下棋位置!")
def computerMove(self):
"""让计算机下棋的函数:"""
# 复制当前棋盘:
position = copy.deepcopy(self.position)
# 用估价函数得到最优的下棋位置:
best = self.ect(position)
# 下棋:
self.position[best] = self.computer
@staticmethod
def fill(position, chess):
"""填充棋盘的函数:"""
p = copy.deepcopy(position)
for i in range(1, 10):
if p[str(i)] == ' ':
p[str(i)] = chess
return p
def ect(self, position):
"""Max-Min搜索的估值函数:"""
# 记录不同位置的 alpha 值:
alpha = {
}
targe = '1'
# 先让计算机模拟下棋:
for i in range(1, 10):
copyComputerPosition = copy.deepcopy(position)
if copyComputerPosition[str(i)] == ' ':
copyComputerPosition[str(i)] = self.computer
# 定义评估值 alpha, beta, 初始值为负无穷和正无穷:
beta = math.inf
# 让玩家模拟下棋:
for j in range(1, 10):
copyPlayerPosition = copy.deepcopy(copyComputerPosition)
if copyPlayerPosition[str(j)] == ' ':
copyPlayerPosition[str(j)] = self.player
# 分别用两种棋子填充该棋盘:
player_position = self.fill(copyPlayerPosition, self.player)
computer_position = self.fill(copyPlayerPosition, self.computer)
"""以下算法计算 beta 的值,并从中确定 alpha:"""
# 该情况玩家获胜的期望值:
Min = 0
if player_position['1'] == self.player and player_position['2'] == self.player and \
player_position['3'] == self.player:
Min += 1
if player_position['1'] == self.player and player_position['4'] == self.player and \
player_position['7'] == self.player:
Min += 1
if player_position['4'] == self.player and player_position['5'] == self.player and \
player_position['6'] == self.player:
Min += 1
if player_position['2'] == self.player and player_position['5'] == self.player and \
player_position['8'] == self.player:
Min += 1
if player_position['7'] == self.player and player_position['8'] == self.player and \
player_position['9'] == self.player:
Min += 1
if player_position['3'] == self.player and player_position['6'] == self.player and \
player_position['9'] == self.player:
Min += 1
if player_position['1'] == self.player and player_position['5'] == self.player and \
player_position['9'] == self.player:
Min += 1
if player_position['3'] == self.player and player_position['5'] == self.player and \
player_position['7'] == self.player:
Min += 1
# 该情况计算机获胜的期望值:
Max = 0
if computer_position['1'] == self.computer and computer_position['2'] == self.computer and \
computer_position['3'] == self.computer:
Max += 1
if computer_position['1'] == self.computer and computer_position['4'] == self.computer and \
computer_position['7'] == self.computer:
Max += 1
if computer_position['4'] == self.computer and computer_position['5'] == self.computer and \
computer_position['6'] == self.computer:
Max += 1
if computer_position['2'] == self.computer and computer_position['5'] == self.computer and \
computer_position['8'] == self.computer:
Max += 1
if computer_position['7'] == self.computer and computer_position['8'] == self.computer and \
computer_position['9'] == self.computer:
Max += 1
if computer_position['3'] == self.computer and computer_position['6'] == self.computer and \
computer_position['9'] == self.computer:
Max += 1
if computer_position['1'] == self.computer and computer_position['5'] == self.computer and \
computer_position['9'] == self.computer:
Max += 1
if computer_position['3'] == self.computer and computer_position['5'] == self.computer and \
computer_position['7'] == self.computer:
Max += 1
# 判断是否需要更换 beta 的值:
exp_beta = Max - Min
if exp_beta < beta:
beta = exp_beta
# 创建模拟计算机下棋的字典记录每个位置的 alpha值 和 下棋的位置:
alpha[str(i)] = beta
# 返回出下棋的位置:(定位到最优解)
max_value = -math.inf
for key, value in alpha.items():
if value > max_value:
max_value = value
targe = key
# 保证计算机不输:
for i in range(1, 10):
position = self.position.copy()
if position[str(i)] == ' ':
position[str(i)] = self.computer
if self.checkWinner(position, self.computer):
targe = str(i)
break
position[str(i)] = self.player
if self.checkWinner(position, self.player):
targe = str(i)
break
return targe
@staticmethod
def checkWinner(position, chess):
"""判断胜负的函数:"""
return (position['1'] == chess and position['2'] == chess and position['3'] == chess) or \
(position['1'] == chess and position['4'] == chess and position['7'] == chess) or \
(position['4'] == chess and position['5'] == chess and position['6'] == chess) or \
(position['2'] == chess and position['5'] == chess and position['8'] == chess) or \
(position['7'] == chess and position['8'] == chess and position['9'] == chess) or \
(position['3'] == chess and position['6'] == chess and position['9'] == chess) or \
(position['1'] == chess and position['5'] == chess and position['9'] == chess) or \
(position['3'] == chess and position['5'] == chess and position['7'] == chess)
def checkDraw(self):
"""判断平局的函数:"""
end = True
for i in range(1, 10):
if self.position[str(i)] == ' ':
end = False
if not self.checkWinner(self.position, self.player) and not self.checkWinner(self.position, self.computer) and end:
return True
return False
def checkBoard(self):
"""检测棋局的函数:"""
if self.checkWinner(self.position, self.player):
self.printf()
print("程序结束,玩家获胜!")
time.sleep(5)
sys.exit()
if self.checkWinner(self.position, self.computer):
self.printf()
print("程序结束,计算机获胜!")
time.sleep(5)
sys.exit()
if self.checkDraw():
self.printf()
print("程序结束,游戏平局!")
time.sleep(5)
sys.exit()
def run(self):
"""启动程序:"""
while True:
if self.goFirst == 'player':
self.playerMove()
self.checkBoard()
self.computerMove()
self.checkBoard()
if self.goFirst == 'computer':
self.computerMove()
self.checkBoard()
self.playerMove()
self.checkBoard()
if __name__ == '__main__':
t = TicTacToe()
t.run()