Python井字棋小程序(基于《Python编程快速上手》例题改编)

'''
改编自《python编程快速上手》,原代码仅能实现井字棋棋盘的打印、落子的记录
在此基础上增加了双人与人机对战模式、判断胜负、电脑下棋AI
判断胜负时,联想到三阶幻方各行、列、斜线之和均为15,因此将原棋盘的落子位置转化为用三阶幻方的数字表示,从而轻松地实现胜负地判断
电脑下棋AI采用alpha-beta剪枝法,得到最优策略
感觉写得很凌乱,将来掌握多一点了再回头修改
2019.06
'''

import itertools
import random

def printBoard(board, rounds):
	# 打印棋盘
	print('\ntop  ' + board['top-L'] + '|' + board['top-M'] + '|' + board['top-R'])
	print('     -+-+-')
	print('mid  ' + board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R'])
	print('     -+-+-')
	print('low  ' + board['low-L'] + '|' + board['low-M'] + '|' + board['low-R'])
	print('\n     L M R\n')
	if (rounds % 2) == 0:
		print('-' * 60)
		print(f'ROUND {int(rounds/2)+1}\n')
	if rounds == -1:
		print('-' * 60)

def chooseMode():
	# 选择模式:1.双人;2.人机
	mode = input('\nEnter 1 to play with your friend, 2 to play with computer: ')
	while mode not in ['1', '2']:
		print('\nInvalid input. Do again.')
		mode = input('\nEnter 1 to play with your friend, 2 to play with computer: ')
	return int(mode)

def choosePieces():
	# 选择棋子
	player1 = input('\nEnter pieces you(player1) like (X or O): ')
	while player1 not in ['X', 'O']:
		print('\nInvalid input. Do again.')
		player1 = input('\nEnter pieces you(player1) like (X or O): ')
	player2 = 'O' if player1 == 'X' else 'X'
	return player1, player2

def chooseInitiaties():
	# 选择先手方
	turn = random.choice(['X', 'O'])
	print('\n' + turn + ' goes first!')
	return turn

def playerMove(correctInput, turn):
	# 记录落子
	move = input('Turn for ' + turn + '. Move on which space?(e.g.mid-M): ')
	while move not in correctInput: # 检查输入是否正确,或者将要落子的位置是否已经有了棋子
		print('\nInvalid input. Do again.')
		move = input('\nTurn for ' + turn + '. Move on which space?(e.g.mid-M): ')
	correctInput.remove(move)
	return move
	
def board2magic(board):
	# 将棋盘位置转换为用三阶幻方同位置上数字表示
	tempBoard = board.copy()
	magic3 = [4, 9, 2, 3, 5, 7, 8, 1, 6] # 利用三阶幻方各行列及斜线之和均为15,简单地判断是否获胜
	j = 0
	for i in list(tempBoard.keys()):
		tempBoard[str(magic3[j])] = tempBoard.pop(i)
		j += 1
	return tempBoard
	
def checkWin_sub(pieces):
	# 判断是否获胜的子程序,返回判断结果
	comb = list(itertools.combinations(pieces, 3))
	isWin = True if 15 in [sum(i) for i in comb] else False
	return isWin
	
def checkWin(board):
	# 判断是否有获胜方
	tempBoard = board2magic(board)
	Xpieces = [int(x[0]) for x in tempBoard.items() if 'X' in x[1]]
	Opieces = [int(x[0]) for x in tempBoard.items() if 'O' in x[1]]
	Xwin = checkWin_sub(Xpieces)
	Owin = checkWin_sub(Opieces)
	winner = 'N'
	if Xwin == True:
		winner = 'X'
	elif Owin == True:
		winner = 'O'
	return winner

def abValuation(board, player1, player2, computerTurn, alpha, beta):
	# alpha-beta剪枝法
	tempBoard = board.copy()
	tempCorrectInput = [x for x in tempBoard.keys() if tempBoard[x] == ' ']
	winner = checkWin(tempBoard)
	if winner == computerTurn: # 电脑获胜
		return 1
	elif winner == 'N':
		if not tempCorrectInput: # 平局
			return 0
	else: # 玩家获胜
		return -1
	for move in tempCorrectInput:
		tempBoard[move] = player1
		tempVal = abValuation(tempBoard, player2, player1, computerTurn, alpha, beta)
		tempBoard[move] = ' '
		if player1 == computerTurn: # 当前玩家是电脑,即Max节点
			if tempVal > alpha:
				alpha = tempVal
			if alpha >= beta:
				return beta
		else: # 当前玩家是Min节点
			if tempVal < beta:
				beta = tempVal
			if beta <= alpha:
				return alpha
	if player1 == computerTurn:
		value = alpha
	else:
		value = beta
	return value

def computerMove(board, turn, correctInput, computerTurn):
	# 电脑落子
	print("Computer's turn. Computer decides to move on: ", end = '')
	best = -2
	strategy = []
	player1 = computerTurn
	player2 = 'O' if player1 == 'X' else 'X'
	for possibleMove in correctInput:
		board[possibleMove] = player1
		val = abValuation(board, player2, player1, computerTurn, -2, 2) #深度优先
		board[possibleMove] = ' '
		if val > best:
			best = val
			strategy = [possibleMove]
		if val == best:
			strategy.append(possibleMove)
	move = random.choice(strategy)
	correctInput.remove(move)
	print(move)
	return move

def main():			
	while True:
		theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ',
					'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ',
					'low-L': ' ', 'low-M': ' ', 'low-R': ' '}
		correctInput = list(theBoard.keys())
		mode = chooseMode()
		player1, player2 = choosePieces()
		turn = chooseInitiaties()
		for rounds in range(9):
			printBoard(theBoard, rounds)
			if mode == 1:
				move = playerMove(correctInput, turn)
			else:
				if turn == player1:
					move = playerMove(correctInput, turn)
				else:
					move = computerMove(theBoard, turn, correctInput, player2)
			theBoard[move] = turn
			turn = 'O' if turn == 'X' else 'X'
			winner = checkWin(theBoard)
			if winner == 'N':
				if rounds == 8:
					print('\nDraw!')
			else:
				print("\n'" + winner + "'wins!")
				break
		printBoard(theBoard, -1)
		if input('Enter y to start a new game. Others to quit.') != 'y':
			break

if __name__ == '__main__':
	main()

 

你可能感兴趣的:(Python井字棋小程序(基于《Python编程快速上手》例题改编))