Python实现的井字棋(Tic Tac Toe)游戏示例


Posted in Python onJanuary 31, 2018

本文实例讲述了Python实现的井字棋(Tic Tac Toe)游戏。分享给大家供大家参考,具体如下:

说明

用python实现了井字棋,整个框架是本人自己构思的,自认为比较满意。另外,90%+的代码也是本人逐字逐句敲的。

minimax算法还没完全理解,所以参考了这里的代码,并作了修改。

特点

可以选择人人、人机、机人、机机四种对战模式之一
电脑玩家的AI使用了minimax算法,带apha-beta剪枝
电脑玩家在思考时,时时刻刻都有一个“假想敌”。以便使得minimax算法运转起来

代码

#作者:hhh5460
#时间:2017年6月26日
# 棋盘
class Board(object):
 def __init__(self):
  #self._board = '-'*9 # 坑!!
  self._board = ['-' for _ in range(9)]
  self._history = [] # 棋谱
 # 按指定动作,放入棋子
 def _move(self, action, take):
  if self._board[action] == '-':
   self._board[action] = take
   self._history.append((action, take)) # 加入棋谱
 # 撤销动作,拿走棋子
 def _unmove(self, action):
  self._board[action] = '-'
  self._history.pop()
 # 棋盘快照
 def get_board_snapshot(self):
  return self._board[:]
 # 取棋盘上的合法走法
 def get_legal_actions(self):
  actions = []
  for i in range(9):
   if self._board[i] == '-':
    actions.append(i)
  return actions
 # 判断走法是否合法
 def is_legal_action(self, action):
  return self._board[action] == '-'
 # 终止检测
 def teminate(self):
  board = self._board
  lines = [board[0:3], board[3:6], board[6:9], board[0::3], board[1::3], board[2::3], board[0::4], board[2:7:2]]
  if ['X']*3 in lines or ['O']*3 in lines or '-' not in board:
   return True
  else:
   return False
 # 胜负检查
 def get_winner(self):
  board = self._board
  lines = [board[0:3], board[3:6], board[6:9], board[0::3], board[1::3], board[2::3], board[0::4], board[2:7:2]]
  if ['X']*3 in lines:
   return 0
  elif ['O']*3 in lines:
   return 1
  else:
   return 2
 # 打印棋盘
 def print_b(self):
  board = self._board
  for i in range(len(board)):
   print(board[i], end='')
   if (i+1)%3 == 0:
    print()
 # 打印棋谱
 def print_history(self):
  print(self._history)
# 玩家
class Player(object):
 '''
 玩家只做两件事:思考、落子
  1. 思考 --> 得到走法
  2. 落子 --> 执行走法,改变棋盘
 '''
 def __init__(self, take='X'): # 默认执的棋子为 take = 'X'
  self.take=take
 def think(self, board):
  pass
 def move(self, board, action):
  board._move(action, self.take)
# 人类玩家
class HumanPlayer(Player):
 def __init__(self, take):
  super().__init__(take)
 def think(self, board):
  while True:
   action = input('Please input a num in 0-8:')
   if len(action)==1 and action in '012345678' and board.is_legal_action(int(action)):
    return int(action)
# 电脑玩家
class AIPlayer(Player):
 def __init__(self, take):
  super().__init__(take)
 def think(self, board):
  print('AI is thinking ...')
  take = ['X','O'][self.take=='X']
  player = AIPlayer(take)  # 假想敌!!!
  _, action = self.minimax(board, player)
  #print('OK')
  return action
 # 极大极小法搜索,α-β剪枝
 def minimax(self, board, player, depth=0) :
  '''参考:https://stackoverflow.com/questions/44089757/minimax-algorithm-for-tic-tac-toe-python'''
  if self.take == "O":
   bestVal = -10
  else:
   bestVal = 10
  if board.teminate() :
   if board.get_winner() == 0 :
    return -10 + depth, None
   elif board.get_winner() == 1 :
    return 10 - depth, None
   elif board.get_winner() == 2 :
    return 0, None
  for action in board.get_legal_actions() : # 遍历合法走法
   board._move(action, self.take)
   val, _ = player.minimax(board, self, depth+1) # 切换到 假想敌!!!
   board._unmove(action) # 撤销走法,回溯
   if self.take == "O" :
    if val > bestVal:
     bestVal, bestAction = val, action
   else :
    if val < bestVal:
     bestVal, bestAction = val, action
  return bestVal, bestAction
# 游戏
class Game(object):
 def __init__(self):
  self.board = Board()
  self.current_player = None
 # 生成玩家
 def mk_player(self, p, take='X'): # p in [0,1]
  if p==0:
   return HumanPlayer(take)
  else:
   return AIPlayer(take)
 # 切换玩家
 def switch_player(self, player1, player2):
  if self.current_player is None:
   return player1
  else:
   return [player1, player2][self.current_player == player1]
 # 打印赢家
 def print_winner(self, winner): # winner in [0,1,2]
  print(['Winner is player1','Winner is player2','Draw'][winner])
 # 运行游戏
 def run(self):
  ps = input("Please select two player's type:\n\t0.Human\n\t1.AI\nSuch as:0 0\n")
  p1, p2 = [int(p) for p in ps.split(' ')]
  player1, player2 = self.mk_player(p1, 'X'), self.mk_player(p2, 'O') # 先手执X,后手执O
  print('\nGame start!\n')
  self.board.print_b() # 显示棋盘
  while True:
   self.current_player = self.switch_player(player1, player2) # 切换当前玩家
   action = self.current_player.think(self.board) # 当前玩家对棋盘进行思考后,得到招法
   self.current_player.move(self.board, action) # 当前玩家执行招法,改变棋盘
   self.board.print_b() # 显示当前棋盘
   if self.board.teminate(): # 根据当前棋盘,判断棋局是否终止
    winner = self.board.get_winner() # 得到赢家 0,1,2
    break
  self.print_winner(winner)
  print('Game over!')
  self.board.print_history()
if __name__ == '__main__':
 Game().run()

下图是人人对战的结果

Python实现的井字棋(Tic Tac Toe)游戏示例

更多关于Python相关内容可查看本站专题:《Python游戏开发技巧总结》、《Python数据结构与算法教程》、《Python Socket编程技巧总结》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
Python中的choice()方法使用详解
May 15 Python
Python计算一个文件里字数的方法
Jun 15 Python
Python遍历numpy数组的实例
Apr 04 Python
python使用tcp实现局域网内文件传输
Mar 20 Python
Random 在 Python 中的使用方法
Aug 09 Python
python实现年会抽奖程序
Jan 22 Python
使用Python轻松完成垃圾分类(基于图像识别)
Jul 09 Python
解决python 虚拟环境删除包无法加载的问题
Jul 13 Python
Python爬虫实例——scrapy框架爬取拉勾网招聘信息
Jul 14 Python
如何解决flask修改静态资源后缓存文件不能及时更改问题
Aug 02 Python
通俗易懂了解Python装饰器原理
Sep 17 Python
Python函数对象与闭包函数
Apr 13 Python
使用Python制作微信跳一跳辅助
Jan 31 #Python
python模块之paramiko实例代码
Jan 31 #Python
Python进度条实时显示处理进度的示例代码
Jan 30 #Python
Python3生成手写体数字方法
Jan 30 #Python
python字符串的方法与操作大全
Jan 30 #Python
Python实现带参数与不带参数的多重继承示例
Jan 30 #Python
Python实现的随机森林算法与简单总结
Jan 30 #Python
You might like
用PHP和ACCESS写聊天室(三)
2006/10/09 PHP
php+mysqli实现批量替换数据库表前缀的方法
2014/12/29 PHP
PHP获取POST数据的几种方法汇总
2015/03/03 PHP
php编写简单的文章发布程序
2015/06/18 PHP
php抽奖概率算法(刮刮卡,大转盘)
2020/04/17 PHP
常用PHP数组排序函数归纳
2016/08/08 PHP
Laravel框架控制器的middleware中间件用法分析
2019/09/30 PHP
js正确获取元素样式详解
2009/08/07 Javascript
js各种验证文本框输入格式(正则表达式)
2010/10/22 Javascript
js循环改变div颜色具体方法
2013/06/25 Javascript
jQuery中slideUp 和 slideDown 的点击事件
2015/02/26 Javascript
JavaScript使用Max函数返回两个数字中较大数的方法
2015/04/06 Javascript
javascript实现tab切换的两个实例
2015/11/05 Javascript
微信小程序实战之顶部导航栏(选项卡)(1)
2020/06/19 Javascript
JavaScript限定范围拖拽及自定义滚动条应用(3)
2017/05/17 Javascript
详解vue中computed 和 watch的异同
2017/06/30 Javascript
关于vue单文件中引用路径的处理方法
2018/01/08 Javascript
详解如何在React组件“外”使用父组件的Props
2018/01/12 Javascript
jQuery实现获取选中复选框的值实例详解
2018/06/28 jQuery
使用express来代理服务的方法
2019/06/21 Javascript
在vue中使用Base64转码的案例
2020/08/07 Javascript
python编程开发之日期操作实例分析
2015/11/13 Python
Python聚类算法之凝聚层次聚类实例分析
2015/11/20 Python
Python从文件中读取数据的方法讲解
2019/02/14 Python
在Pandas中处理NaN值的方法
2019/06/25 Python
python GUI库图形界面开发之PyQt5滚动条控件QScrollBar详细使用方法与实例
2020/03/06 Python
python对指定字符串逆序的6种方法(小结)
2020/04/02 Python
CSS3制作翻转效果_动力节点Java学院整理
2017/07/11 HTML / CSS
传统HTML页面实现模块化加载的方法
2018/10/15 HTML / CSS
html5-websocket基于远程方法调用的数据交互实现
2012/12/04 HTML / CSS
详解HTML5中CSS外观属性
2020/09/10 HTML / CSS
简述进程的启动、终止的方式以及如何进行进程的查看
2013/07/12 面试题
中秋节礼品促销方案
2014/02/02 职场文书
产品质量承诺书
2014/03/27 职场文书
学习作风建设心得体会
2014/10/22 职场文书
mysql性能优化以及配置连接参数设置
2022/05/06 MySQL