井字棋(Tic-Tac-Toe)
井字棋介绍:https://en.wikipedia.org/wiki/Tic-tac-toe
井字棋简单,但是获胜策略却和直觉不同,四角比中间重要性要高,而且先手有很大的获胜概率获胜(先手胜:91, 后手胜:44,平局:3),所以当你陷入劣势时,怎么选择打平就是一个不那么简单的事情。不过无聊大抵孤单,没有人一起玩就只能和电脑PK,就写了个弱智AI,没事就偷着乐!
AI的获胜策略也很简单,先遍历检测棋盘副本的空格子看下一步能否获胜,如果有机会获胜,返回格子的下标,然后再棋盘上移动,其次,检测对手能否下一步获胜,提前封堵,如果前面两步都没返回的话,就说明双方都没有一步必胜的招式,这时候就得依次抢占四个角落,中间和剩余的位置。

import random def draw_board(board):
"""board is a 3X3 list containing the moves either ' ' representing
no moves there or 'x' or 'o' representing actual moves"""
for i in range(7):
if i%2 == 0:
print '+'.join(['---']*3)
else:
col = []
for j in range(11):
if j%2 == 0:
col.append(' ')
elif j==3 or j==7:
col.append('|')
else:
col.append(board[i/2][j/4])
print ''.join(col) def who_goes_first():
if random.randint(0, 1):
return 'AI'
else:
return 'P' def play_again():
print "Once Again?(y for Yes, n for No)"
return raw_input().lower().startswith('y') def make_move(board, letter, move):
seq = move-1
board[2-seq/3][seq%3] = letter def is_winner(bo, le):
# Given a board and a player’s letter, this function returns True if that player has won.
# We use bo instead of board and le instead of letter so we don’t have to type as much.
return ((bo[0][0] == le and bo[0][1] == le and bo[0][2] == le) or # across the top
(bo[1][0] == le and bo[1][1] == le and bo[1][2] == le) or # across the middle
(bo[2][0] == le and bo[2][1] == le and bo[2][2] == le) or # across the bottom
(bo[0][0] == le and bo[1][0] == le and bo[2][0] == le) or # down the left side
(bo[0][1] == le and bo[1][1] == le and bo[2][1] == le) or # down the middle
(bo[0][2] == le and bo[1][2] == le and bo[2][2] == le) or # down the right side
(bo[0][0] == le and bo[1][1] == le and bo[2][2] == le) or # diagonal
(bo[0][2] == le and bo[1][1] == le and bo[2][0] == le)) # diagonal def get_board_copy(board):
dup = [[' ']*3 for i in range(3)]
for i in range(3):
for j in range(3):
dup[i][j] = board[i][j]
return dup def is_move_avail(board, move):
seq = move-1
return board[2-seq/3][seq%3] == ' ' def get_P_moves(board):
move = ''
while move not in [1, 2, 3, 4, 5, 6, 7, 8, 9] or not is_move_avail(board, move):
print "Please input your next move('1-9')"
move = input()
return move def is_board_full(board):
for i in range(3):
for j in range(3):
if board[i][j] == ' ':
return False
return True def choose_randomly(board, avail):
possible_moves = []
for i in avail:
if is_move_avail(board, i):
possible_moves.append(i)
if len(possible_moves) != 0:
return random.choice(possible_moves)
else:
return None def get_AI_moves(board, AI, P):
#check if AI can win in the next move
for i in range(1, 10):
copy = get_board_copy(board)
if is_move_avail(board, i):
make_move(copy, AI, i)
if is_winner(copy, AI):
return i #else check if P can win in the next move and block the first found move
for i in range(1, 10):
copy = get_board_copy(board)
if is_move_avail(board, i):
make_move(copy, P, i)
if is_winner(copy, P):
return i #The key to win is to occupy the corners, so move there if available
move = choose_randomly(board, [1, 3, 7, 9])
print move
if move != None:
return move #of second priority is the center element
if is_move_avail(board, 5):
return 5 #Then the rest
return choose_randomly(board, [2, 4, 6, 8]) if __name__ == '__main__': while True:
Board = [[' ']*3 for i in range(3)]
P, AI = 'x', 'o'
turn = who_goes_first()
print "{0} will go first".format(turn)
GameOn = True while GameOn:
if turn == 'P':
move = get_P_moves(Board)
make_move(Board, P, move)
draw_board(Board) if is_winner(Board, P):
draw_board(Board)
print "GameOver You've Won!"
GameOn = False
else:
if is_board_full(Board):
draw_board(Board)
print "Tie"
break
else:
turn = 'AI' else:
move = get_AI_moves(Board, AI, P)
make_move(Board, AI, move)
draw_board(Board) if is_winner(Board, AI):
draw_board(Board)
print "GameOver AI has Won!"
GameOn = False
else:
if is_board_full(Board):
draw_board(Board)
print "Tie"
break
else:
turn = 'P' if not play_again():
break ##---+---+---
## x | o | x
##---+---+---
## o | x | o
##---+---+---
## x | o |
##---+---+---
注:
- python 2.7中input和raw_input的区别,python3中合并了
- 数据结构很简单,3X3的list of lists来表示棋盘。井字棋位置和小键盘一致。
- 参考文献: http://www.guokr.com/article/4754/
井字棋(Tic-Tac-Toe)的更多相关文章
- [CareerCup] 17.2 Tic Tac Toe 井字棋游戏
17.2 Design an algorithm to figure out if someone has won a game oftic-tac-toe. 这道题让我们判断玩家是否能赢井字棋游戏, ...
- python 井字棋(Tic Tac Toe)
说明 用python实现了井字棋,整个框架是本人自己构思的,自认为比较满意.另外,90%+的代码也是本人逐字逐句敲的. minimax算法还没完全理解,所以参考了这里的代码,并作了修改. 特点 可以选 ...
- LeetCode 5275. 找出井字棋的获胜者 Find Winner on a Tic Tac Toe Game
地址 https://www.acwing.com/solution/LeetCode/content/6670/ 题目描述A 和 B 在一个 3 x 3 的网格上玩井字棋. 井字棋游戏的规则如下: ...
- POJ 2361 Tic Tac Toe
题目:给定一个3*3的矩阵,是一个井字过三关游戏.开始为X先走,问你这个是不是一个合法的游戏.也就是,现在这种情况,能不能出现.如果有人赢了,那应该立即停止.那么可以知道X的步数和O的步数应该满足x= ...
- [LeetCode] 348. Design Tic-Tac-Toe 设计井字棋游戏
Design a Tic-tac-toe game that is played between two players on a n x n grid. You may assume the fol ...
- [LeetCode] Design Tic-Tac-Toe 设计井字棋游戏
Design a Tic-tac-toe game that is played between two players on a n x n grid. You may assume the fol ...
- quick cocos2d-x 入门---井字棋
学习quick cocos2d-x 第二天 ,使用quick-x 做了一个井字棋游戏 . 我假设读者已经 http://wiki.quick-x.com/doku.php?id=zh_cn阅读了这个链 ...
- 程序设计入门—Java语言 第五周编程题 2井字棋(5分)
2 井字棋(5分) 题目内容: 嗯,就是视频里说的那个井字棋.视频里说了它的基本思路,现在,需要你把它全部实现出来啦. 你的程序先要读入一个整数n,范围是[3,100],这表示井字棋棋盘的边长.比如n ...
- [C++] 井字棋游戏源码
TicTac.h #define EX 1 //该点左鼠标 #define OH 2 //该点右鼠标 class CMyApp : public CWinApp { public: virtual B ...
- [游戏学习22] MFC 井字棋 双人对战
>_<:太多啦,感觉用英语说的太慢啦,没想到一年做的东西竟然这么多.....接下来要加速啦! >_<:注意这里必须用MFC和前面的Win32不一样啦! >_<:这也 ...
随机推荐
- 获取设备、APP的一些信息
获取设备的一些信息: UIDevice *device = [UIDevice currentDevice]; @property(nonatomic,readonly,strong) NSStrin ...
- Sql Server 2012启动存储过程
可以通过如下步骤创建 1.打开show advanced options reconfigure 2.打开scan for startup procs,使得sql server在启动时扫描需要运行的p ...
- java 短信发送例子 2
package com.google; import java.io.BufferedReader;import java.io.IOException;import java.io.InputStr ...
- Aandroid Error之 新导入工程报Unable to resolve target 'android-18'和R cannot be resolved
有段时间没有写安卓了,今天导入以前的项目,结果看到控制台打印出了这样一句:Unable to resolve target 'android-18', 解决方法: 项目->属性->Andr ...
- USACO 1.4 ariprog 解题报告
这是继虫洞之后又让我为难的一个 剪枝题目,无论如何,做的再快,也只能过6个点,最后三个点也TLE.后来参考了一下标答,大概思路是这样的. 朴素算法就不多说了,枚举a,b然后判断就行,网上说这样优化到位 ...
- [转]activiti5用户任务分配
用户任务分配办理人:1.用户任务可以直接分配给一个用户,这可以通过humanPerformer元素定义. humanPerformer定义需要一个 resourceAssignmentExpressi ...
- 一个完整的SSL连接建立过程
客户端浏览器连接到Web服务器,发出建立安全连接通道的请求. 服务器接受客户端请求,发送服务器证书做为响应. 客户端验证服务器证书的有效性,如果验证通过,则用服务器证书中包含的服务器公钥加密一个会话密 ...
- HD1083 二分图,匈牙利算法
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<stdio.h> #include<stdlib. ...
- SQL Server 解决CPU 高占用的一般step
第一步: 看这些CPU是不是SQL Server用的. 第二步: 确定SQL Server 有没有引发17883\17884错误 第三步: 找出使用CPU最高的语句进行优化.(sys.dm_exec_ ...
- Android_NFC_开发介绍
API概览 Android.nfc 和android.nfc.tech 为android 处理nfc的java 包. 1.Android.nfc package包含顶层类用来与本地NFC适配器交互. ...