Tic-Tac-Toe人机对弈程序(python实现)
目录
1. 前言
2. 处理流程
3. 代码
4. 代码说明
4.1 棋盘显示
4.2 初始化
4.3 人类棋手的下一步
4.4 AI棋手的下一步
4.5 终局及胜负判断
5. 棋局示例
1. 前言
前面几篇博客(以循序渐进的方式)实现了Tic-Tac-Toe游戏的棋局搜索、遍历以及所有可能棋局数和盘面状态数的计算,参见:
Tic-Tac-Toe可能棋局搜索的实现(python)
Tic-Tac-Toe可能棋局遍历的实现(python)
Tic-Tac-Toe有多少种不同棋局和盘面状态(python实现)
本文先实现一个简单的Tic-Tac-Toe人机对弈程序,为下一步实现基于minimax算法的Tic-Tac-Toe人机对弈程序做一个准备。
2. 处理流程
3. 代码
# Tic Tac Toe
# Created by chenxy in 2017-06-23, with only drawBoard() copied from <<inventwithpython>>
# 2023-01-04 refined
import random
import sysdef drawBoard(board, initFlag = 0):# This function prints out the board that it was passed.brd_copy = board.copy()if initFlag:brd_copy = ['0','1','2','3','4','5','6','7','8','9']# "board" is a list of 10 strings representing the board (ignore index 0)print('=============')# print(' | |')print(' ' + brd_copy[7] + ' | ' + brd_copy[8] + ' | ' + brd_copy[9])# print(' | |')print('-----------')# print(' | |')print(' ' + brd_copy[4] + ' | ' + brd_copy[5] + ' | ' + brd_copy[6])# print(' | |')print('-----------')# print(' | |')print(' ' + brd_copy[1] + ' | ' + brd_copy[2] + ' | ' + brd_copy[3])# print(' | |')print('=============')print()def askGameStart():# Ask human start a game or not;print('Do you want to start a game? Y or y to start; Others to exit');inputWord = input().lower();if inputWord.startswith('y'):startNewGame = True;else:startNewGame = False;return(startNewGame); # Decide whether the number human input for the next move has been already used or not.
# It can be decided by whether the corrsponding element is empty or not.
def isValidInput(board, humanNextMove):isValid = 1;if humanNextMove == 0:print('Please input 1~9, 0 is not an valid input for the next move!');isValid = 0;elif board[humanNextMove] != ' ':print('The space has already been used! Please select an empty space for the next move');isValid = 0; return(isValid); # Ask the human player for the next move.
def askNextMove(board):while True:print('Please input the next move!');c = input()if not c.isdigit():print('Invalid input! Please input [1-9]!');continuenextMove = int(c);if board[nextMove] == ' ':break;else:continue;isValid = isValidInput(board, nextMove)return isValid,nextMovedef gameRsltDisplay(winner): if 'A' == winner:print('AI win!');elif 'H' == winner:print('Human win!');else: print('A tie game!'); # Decide AI's next move.
# Decide whether the three input are all the same
def isTripleGoalReachedNext(board,idx1, idx2, idx3, role):in1 = board[idx1];in2 = board[idx2];in3 = board[idx3];if in1 == ' ' and in2 == in3 and in2 == role:return idx1;elif in2 == ' ' and in1 == in3 and in3 == role:return idx2;elif in3 == ' ' and in1 == in2 and in1 == role:return idx3;else:return 0; # Invalid space index.def isGoalReachedNext(board, role):nextMove = 0;nextMove = isTripleGoalReachedNext(board, 1, 4, 7, role);if nextMove > 0:return True, nextMovenextMove = isTripleGoalReachedNext(board, 1, 2, 3, role);if nextMove > 0:return True, nextMovenextMove = isTripleGoalReachedNext(board, 1, 5, 9, role);if nextMove > 0:return True, nextMovenextMove = isTripleGoalReachedNext(board, 2, 5, 8, role);if nextMove > 0:return True, nextMovenextMove = isTripleGoalReachedNext(board, 3, 5, 7, role);if nextMove > 0:return True, nextMovenextMove = isTripleGoalReachedNext(board, 3, 6, 9, role);if nextMove > 0:return True, nextMovenextMove = isTripleGoalReachedNext(board, 4, 5, 6, role);if nextMove > 0:return True, nextMovenextMove = isTripleGoalReachedNext(board, 7, 8, 9, role);if nextMove > 0:return True, nextMovereturn False, nextMove;def aiNextMove(board, gameRole):# Temporarily, select the first empty space.# 1. First, check whether AI will reach the goal in the next step.# gameRole[0] represents AI's role.goalReachedNext, nextMove = isGoalReachedNext(board, gameRole[0]);if goalReachedNext == True:return nextMove;# 2. Secondly, check whether Human will reach the goal in the next step.# gameRole[1] represents Human's role.# Of course, AI should take the next move to blocking Human player to reach the goal.goalReachedNext, nextMove = isGoalReachedNext(board, gameRole[1]);if goalReachedNext == True:return nextMove;# Randomly selected from the left spaces for the next move.spaces = []for k in range(1,10): if board[k] == ' ':spaces.append(k)else:continue;nextMove = random.choice(spaces)return(nextMove);# Decide whether the three input are all the same
def isTripleSame(in1, in2, in3):if in1 == ' ' or in2 == ' ' or in3 == ' ':return Falseelif in1 == in2 and in1 == in3:return Trueelse:return Falsedef gameJudge(board):if isTripleSame(board[1],board[4],board[7]):gameOver = True; winner = board[1];elif isTripleSame(board[1],board[2],board[3]): gameOver = True; winner = board[1];elif isTripleSame(board[1],board[5],board[9]): gameOver = True; winner = board[1];elif isTripleSame(board[2],board[5],board[8]): gameOver = True; winner = board[2];elif isTripleSame(board[3],board[5],board[7]): gameOver = True; winner = board[3];elif isTripleSame(board[3],board[6],board[9]): gameOver = True; winner = board[3];elif isTripleSame(board[4],board[5],board[6]): gameOver = True; winner = board[4];elif isTripleSame(board[7],board[8],board[9]): gameOver = True; winner = board[7];elif ' ' in board[1:9]: gameOver = False; winner = ' ';else:gameOver = True; winner = ' ';return gameOver, winnerwhoseTurn = 0; # 0 : AI's turn; 1: Human's turn.
gameRole = ['A','H']; # [0]: AI's role; [1]: Human's role;
board = [' ']*10; # Note: '*' for string means concatenation.drawBoard(board,1); # Draw the initial board with numberingif not askGameStart():print('Bye-Bye! See you next time!');sys.exit();while True:# Initialization.gameOver = 0;board = [' ',' ',' ',' ',' ',' ',' ',' ',' ',' '];# Decide who, either human or AI, play first.# 0: AI; 1: human.role = random.randint(0,1);if role == 0:whoseTurn = 0;elif role == 1:whoseTurn = 1;while(not gameOver): if whoseTurn == 0:print('AI\'s turn')nextMove = aiNextMove(board,gameRole);board[nextMove] = gameRole[0];whoseTurn = 1;else:print('Human\'s turn')isValid = 0;while(not isValid):isValid, nextMove = askNextMove(board);board[nextMove] = gameRole[1];whoseTurn = 0;drawBoard(board); gameOver,winner = gameJudge(board); gameRsltDisplay(winner);#startNewGame = askGameStart();if not askGameStart():print('Bye-Bye! See you next time!');sys.exit();
4. 代码说明
4.1 棋盘显示
为了方便操作,棋盘的格点位置与(人类棋手下棋时输入的)数字的对应关系设计成和计算机键盘右边的小键盘相同,如下图所示。这样的话,比如说棋手输入7的话就表示在棋盘左上角落子,输入3的话表示在棋盘右下角落子,余者类推。
代码中用一个包含10个元素的(字符:“H”,“A”)数组表示棋盘board,其中board[0]不使用。人类棋手用字母“H”(Human)表示;AI棋手用字母“A”(Artificial Intelligence)表示。比如说,人类棋手输入7的话,表示在左上角落子,则将board[7]赋值为“H”;AI棋手输入1的话,表示在左下角落子,则将board[1]赋值为“A”。。。
详细参见drawBoard(board, initFlag = 0)函数的实现。
4.2 初始化
初始棋盘显示。游戏开始时的初始棋盘显示中,显示的是上图所示棋盘各个位置对应的数字,方便玩家参考。在游戏过程中,各棋盘格子中显示的是“H”或者“A”或者空格(还没有落子的格子)。
猜先。调用askGameStart()开始游戏并进行猜先。
4.3 人类棋手的下一步
askNextMove ():询问人类棋手的下一步。应该输入1~9中的一个数字
isValidInput():用于判断棋手输入的合法性。如果输入0或者非数字的话,程序会要求棋手再次输入。
4.4 AI棋手的下一步
本程序中目前只实现了一个傻傻的AI,只比完全随机落子聪明一点点。
AI决定落子时,首先检查是否有能够终结棋局的下一手,如果有的话就选择那一手(如果有多个下一手可以终结棋局的话则选择找到的第一手);如果没有能够终结棋局的下一手时就从余下的空格中随机选择一手。很显然,将来优化这个AI时就应该从此处着手。
aiNextMove(board, gameRole):AI agent。决定AI的下一手。
isGoalReachedNext(board, role):AI决定下一手时首先遍历空的棋格看是否存在能够终结棋局的下一手。
isTripleGoalReachedNext(board,idx1, idx2, idx3, role):用于确定指定的三个棋格(在再下一手的条件下)是否满足终结棋局的条件。
4.5 终局及胜负判断
gameJudge():
终局及胜负判断。如果已经出现排成一条直线的三个棋格相同的终结棋局的局面,则判定棋局结束且判定胜者为谁;如果棋盘已满但是没有出现“排成一条直线的三个棋格相同”的情况,则判定平局;否则,棋局仍将继续。
isTripleSame():
用于确定指定的三个棋格是否满足终结棋局的条件。注意它与isTripleGoalReachedNext()的区别。
5. 棋局示例
以下为一局棋的运行过程示例。
(base) E:\TicTacToe>python tictactoe.py
=============
7 | 8 | 9
-----------
4 | 5 | 6
-----------
1 | 2 | 3
=============Do you want to start a game? Y or y to start; Others to exit
y
Human's turn
Please input the next move!
7
=============
H | |
-----------
| |
-----------
| |
=============AI's turn
=============
H | |
-----------
| |
-----------
A | |
=============Human's turn
Please input the next move!
3
=============
H | |
-----------
| |
-----------
A | | H
=============AI's turn
=============
H | |
-----------
| A |
-----------
A | | H
=============Human's turn
Please input the next move!
9
=============
H | | H
-----------
| A |
-----------
A | | H
=============AI's turn
=============
H | | H
-----------
| A | A
-----------
A | | H
=============Human's turn
Please input the next move!
8
=============
H | H | H
-----------
| A | A
-----------
A | | H
=============Human win!
Do you want to start a game? Y or y to start; Others to exit
Next Step:
实现基于完全minimax的unbeatable TicTacToe AI
实现TicTacToe GUI
。。。
后记(2023-01-05):调研学习alphaGo论文中,想先写一个Tic-Tac-Toe的游戏程序,以此为基础学习minimax,alphabeta,MCTS等算法概念。然后翻了翻计算机中的文件发现自己居然在2017年就写过一个,完全没有印象了^-^。整理了一下先发出来以免自己再次忘记。
基于minimax算法的tic-tac-toe AI agent实现参见:
https://chenxiaoyuan.blog.csdn.net/article/details/128591542https://chenxiaoyuan.blog.csdn.net/article/details/128591542
参考文献:
AL SWEIGART, Invent Your Own Computer Games with Python(4th)
Tic-Tac-Toe人机对弈程序(python实现)相关推荐
- python二维游戏示例_Python实现的井字棋(Tic Tac Toe)游戏示例
本文实例讲述了Python实现的井字棋(Tic Tac Toe)游戏.分享给大家供大家参考,具体如下: 说明 用python实现了井字棋,整个框架是本人自己构思的,自认为比较满意.另外,90%+的代码 ...
- python井字棋ai,python 井字棋(Tic Tac Toe)
说明 用python实现了井字棋,整个框架是本人自己构思的,自认为比较满意.另外,90%+的代码也是本人逐字逐句敲的. minimax算法还没完全理解,所以参考了这里的代码,并作了修改. 特点 可以选 ...
- python井字棋游戏代码_Python实现的井字棋(Tic Tac Toe)游戏示例
Python实现的井字棋(Tic Tac Toe)游戏示例 来源:中文源码网 浏览: 次 日期:2018年9月2日 [下载文档: Python实现的井字棋(Tic Tac Toe)游戏示 ...
- Principle of Computing (Python)学习笔记(7) DFS Search + Tic Tac Toe use MiniMax Stratedy
1. Trees Tree is a recursive structure. 1.1 math nodes https://class.coursera.org/principlescomputin ...
- python游戏代码运行不了_无法使我的tic tac toe游戏在python中正确运行
转不到"玩家1"的原因是你的支票中缺少一个空格.你也没有正确地检查一个玩家何时获胜,这就是为什么你会有这种奇怪的行为.你需要检查每个位置,而不仅仅是最后一个.我还添加了对用户输入的 ...
- C++ 很有趣:编写一个井字游戏 (Tic Tac Toe)
英文原文:C++ is fun: Writing a Tic Tac Toe Game 这个有趣的C++系列打算展示一下使用C++写代码可以和其他主流语言一样高效而有趣.在第二部分,我将向你展示使用C ...
- react中使用构建缓存_通过在React中构建Tic Tac Toe来学习ReasonML
react中使用构建缓存 3. 7. 2018: UPDATED to ReasonReact v0.4.2 3. 7. 2018:更新为ReasonReact v0.4.2 You may have ...
- amazon.设计1. tic tac toe
//不觉中 已经全力找工作好久好久了.大概有1年半了.身心疲惫,不要放弃.曙光快来了. 1.tic tac toe //http://www.ntu.edu.sg/home/ehchua/progra ...
- python井字棋_python 井字棋(Tic Tac Toe)
说明 用python实现了井字棋,整个框架是本人自己构思的,自认为比较满意.另外,90%+的代码也是本人逐字逐句敲的. minimax算法还没完全理解,所以参考了这里的代码,并作了修改. 特点 可以选 ...
最新文章
- 158行Python代码复现:DeepMind提图像生成的递归神经网络DRAW
- 对抗性攻击轻松愚弄人工智能
- Mol Cell Proteomics. |胡丹丹| 雷公藤红素通过SIRT1-FXR 信号通路保护胆汁淤积性肝损伤...
- Neo4j【环境部署 01】图形数据库(简介+下载地址+安装+配置+demo源码+学习教程地址)
- '800a0005' 图片上传出现写入文件失败的错误 -- 修改pload_5xsoft.inc
- 如何有效开展小组教学_新型教学方法,小组合作教学,有效的提升了学生的合作技能...
- HTML(一):HTML基本元素标签
- Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收
- 移动app设计公司流程—APP设计需求分析规范
- 豆瓣电影爬虫Ⅱ 豆瓣电影数据的整理
- 做了三年前端开发后,我选择回家创业
- Java EJB到底是什么?
- 学习在Unity中制作基础的节点编辑器
- 矩阵的特征值、特征向量、特征子空间
- 翻转课堂十大精彩案例
- 《环境科学概论》考试复习资料
- 润物无声因挚爱,育人无痕待花开
- ubuntu 软件管理
- CSS实现中英双语导航栏——利用块级元素隐藏实现
- 【论文笔记】Image Manipulation Detection by Multi-View Multi-Scale Supervision
热门文章
- 英伟达把P图软件GAN了
- jdk1.8新特性 Lambda表达式和Stream集合操作(详细)
- 中文维基百科语料上的Word2Vec实验
- 程序数据集散地:数据库(1)
- 053试题 193 - recover 命令
- php三行情书,文案得看看这些三行情书
- IDEA莫名出现there's not enought memory to perform the requrested operation
- mini-imagenet数据处理过程_从头开始训练
- 面向接口编程实施模块化/组件化解耦,以友盟、极光等统计分析为例
- 还记得诺基亚手机上贪吃蛇小游戏吗?