目录

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实现)相关推荐

  1. python二维游戏示例_Python实现的井字棋(Tic Tac Toe)游戏示例

    本文实例讲述了Python实现的井字棋(Tic Tac Toe)游戏.分享给大家供大家参考,具体如下: 说明 用python实现了井字棋,整个框架是本人自己构思的,自认为比较满意.另外,90%+的代码 ...

  2. python井字棋ai,python 井字棋(Tic Tac Toe)

    说明 用python实现了井字棋,整个框架是本人自己构思的,自认为比较满意.另外,90%+的代码也是本人逐字逐句敲的. minimax算法还没完全理解,所以参考了这里的代码,并作了修改. 特点 可以选 ...

  3. python井字棋游戏代码_Python实现的井字棋(Tic Tac Toe)游戏示例

    Python实现的井字棋(Tic Tac Toe)游戏示例 来源:中文源码网    浏览: 次    日期:2018年9月2日 [下载文档:  Python实现的井字棋(Tic Tac Toe)游戏示 ...

  4. 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 ...

  5. python游戏代码运行不了_无法使我的tic tac toe游戏在python中正确运行

    转不到"玩家1"的原因是你的支票中缺少一个空格.你也没有正确地检查一个玩家何时获胜,这就是为什么你会有这种奇怪的行为.你需要检查每个位置,而不仅仅是最后一个.我还添加了对用户输入的 ...

  6. C++ 很有趣:编写一个井字游戏 (Tic Tac Toe)

    英文原文:C++ is fun: Writing a Tic Tac Toe Game 这个有趣的C++系列打算展示一下使用C++写代码可以和其他主流语言一样高效而有趣.在第二部分,我将向你展示使用C ...

  7. 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 ...

  8. amazon.设计1. tic tac toe

    //不觉中 已经全力找工作好久好久了.大概有1年半了.身心疲惫,不要放弃.曙光快来了. 1.tic tac toe //http://www.ntu.edu.sg/home/ehchua/progra ...

  9. python井字棋_python 井字棋(Tic Tac Toe)

    说明 用python实现了井字棋,整个框架是本人自己构思的,自认为比较满意.另外,90%+的代码也是本人逐字逐句敲的. minimax算法还没完全理解,所以参考了这里的代码,并作了修改. 特点 可以选 ...

最新文章

  1. 158行Python代码复现:DeepMind提图像生成的递归神经网络DRAW
  2. 对抗性攻击轻松愚弄人工智能
  3. Mol Cell Proteomics. |胡丹丹| 雷公藤红素通过SIRT1-FXR 信号通路保护胆汁淤积性肝损伤...
  4. Neo4j【环境部署 01】图形数据库(简介+下载地址+安装+配置+demo源码+学习教程地址)
  5. '800a0005' 图片上传出现写入文件失败的错误 -- 修改pload_5xsoft.inc
  6. 如何有效开展小组教学_新型教学方法,小组合作教学,有效的提升了学生的合作技能...
  7. HTML(一):HTML基本元素标签
  8. Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收
  9. 移动app设计公司流程—APP设计需求分析规范
  10. 豆瓣电影爬虫Ⅱ 豆瓣电影数据的整理
  11. 做了三年前端开发后,我选择回家创业
  12. Java EJB到底是什么?
  13. 学习在Unity中制作基础的节点编辑器
  14. 矩阵的特征值、特征向量、特征子空间
  15. 翻转课堂十大精彩案例
  16. 《环境科学概论》考试复习资料
  17. 润物无声因挚爱,育人无痕待花开
  18. ubuntu 软件管理
  19. CSS实现中英双语导航栏——利用块级元素隐藏实现
  20. 【论文笔记】Image Manipulation Detection by Multi-View Multi-Scale Supervision

热门文章

  1. 英伟达把P图软件GAN了
  2. jdk1.8新特性 Lambda表达式和Stream集合操作(详细)
  3. 中文维基百科语料上的Word2Vec实验
  4. 程序数据集散地:数据库(1)
  5. 053试题 193 - recover 命令
  6. php三行情书,文案得看看这些三行情书
  7. IDEA莫名出现there's not enought memory to perform the requrested operation
  8. mini-imagenet数据处理过程_从头开始训练
  9. 面向接口编程实施模块化/组件化解耦,以友盟、极光等统计分析为例
  10. 还记得诺基亚手机上贪吃蛇小游戏吗?