目录

一,圈叉棋(Tic-Tac-Toe)

二,套娃圈叉棋

1,规则

2,解空间分析

1,节点

2,解空间结构

3,复杂度分析

1,总节点数目

2,思路一——关键节点

3,思路二——对称性

4,数据结构

1,颜色

2,数目

5,编码实现

1,有效颜色状态

2,有效数目状态

三,嵌套圈叉棋

四,九个井字棋


一,圈叉棋(Tic-Tac-Toe)

圈叉棋是一种游戏,3*3的9个方格子,先下者画圈,后下者画叉,每人可以在任意没有对方棋子的封闭方格里下一次,看谁先连成一行(一列,斜线)3个就判胜。由于圈叉棋规则简单,在任何地方都可以玩,所以是打发时间的有效的休闲游戏。现在几乎全球人都了解圈叉棋。


之前一直不知道为什么圈叉棋竟然可以风靡全球,因为对于2个智商足够高的人来说,结局肯定是平局(即双方均有不败策略)而且平局总共也就只有321种不同的情况。

今天把所有情况都列了出来,发现还是有点意思的。

(按照上面的图来编号,我所说的321种不同的情况是指,通过翻转、旋转之后不能重合的下法。)

(然而,我列出的321种只是一种上界,所有的平局都能通过翻转、旋转之后变成这321种中的一种,但是这321种之间,应该还是有些可以通过翻转、旋转重合的)

首先,第一个回合,不同的平局只有15,21,25,28,51这5种!

其次,可以得出后手的不败策略:

第一步,先手下5就下1,否则(另外的8种情况)就下5。

第二步,比第一步简单地多,但是已经不好总结了,就不总结了。总之已经基本上已经不会输了。

当然了,也可以得出先手的不败策略,不过先手基本上都不会输。。。

所以我总结一下先手和一个还不知道不败策略的人下棋的时候的方法:

如果下2的话,后手不管下哪儿都还可能是平局。

如果下5的话,看后手怎么下,如果下2就干掉他,如果下1的话,很可能就是平局了。

如果下1的话,后手很可能下5,然后就很可能平局,如果后手不下5,当然可以直接干掉他了。

总之,和一个第一次玩圈叉棋的人一样,第一步还是下5合理一些,除非你对后手有一定的了解,那当然另当别论了。

讨论一下圈叉棋的平局到底有多少种情况(仅限双方都不犯错的情况)

第一个回合即前2步,有15,21,25,28,51这5种情况。

然后分别讨论,看前6步有多少种情况,可以枚举出来,有138种情况。

最后,还有3步。

这138种情况中,有77种情况,最后3步只有1种情况,还有61种情况,最后3步有4种情况。

所以一共是77+61*4=321种情况。

最后,附上圈叉棋321种不同的下法

(长度为9的序列是棋子落子的顺序,比如152374689就是先手下1,然后后手下5,然后先手下2。。。。。。)

(?*4就是说,最后3步有4种情况,不是简单地为了简写,而是为了表达出这4种情况之间的共性)

(15开头的有9+4*4=25种)

152374689、152374698、153284697、153286479、156823749、156374*4、156289*4、156287394、156974*4、156923748、156932874、156983742、156982*4

(21开头的有34+30*4=154种)

214593786、214596*4、214635978、214635987、214637*4、214638*4、214658379、214658937、214685973、14695*4、214697*4、21469357、21469375、21469537、215846*4、215864739、215873*4、215893*4、215894736、215896*4、215897463、217598*4、217835*4、217853*4、217845936、217845963、217843*4、217846*4、217863*4、217864*4、217865934、217893456、217893465、217893546、217893564、217895*4、217896*4、219478*4、219536478、219536487、219543786、219546*4、219563784、219578*4、219745368、219746*4、219836*4、219841*4、219845*4、219846357、219846375、219846537、219846573、219863*4、219854736、219857463、219853*4、219856*4、219873456、219873465、219873546、219873564、219875*4、219876*4

(25开头的有11+5*4=31种)

251374689、251374698、254193786、254196*4、254371986、257198*4、257469138、257463*4、257641983、257314689、257314698、257389146、257341986、257398*4、257361984、257364*4

(28开头的有21+19*4=97种)

281359746、281374*4、281395746、284156*4、284165*4、284173*4、284175936、284175963、284176*4、284193*4、284195*4、284196357、284196375、284196537、284196573、284356917、284365719、284371*4、284391*4、284395716、287135964、287143*4、287145936、287145963、287146*4、287153*4、287163*4、287165934、287193456、287193465、287193546、287193564、287195*4、287196*4、287314*4、287341*4、287351*4、287354*4、287356914、287359641

(51开头的2+3*4=14种)

512846*4、512864739、513746*4、516473289、519328*4

二,套娃圈叉棋

1,规则

在圈叉棋的基础上,加上套娃的规则:

每人有9个棋子,3大3中3小,较大的可以把较小的套住。

接下来我将分析这个博弈游戏的胜负规律。

2,解空间分析

1,节点

节点包含的信息有:

  • 9个格子的状态,每个格子有7种状态(空白、双方的大中小棋子)
  • 轮到谁下
  • 双方手里剩下的棋子数量

双方手里剩下的棋子数量可以推算出轮到谁下。

2,解空间结构

这是一个无环的有向图,开局作为起点,到任意节点都有唯一路径存在。

如果去掉方向,那么得到的无向图就有圈了。

3,复杂度分析

1,总节点数目

9个格子的状态有7^9=40353607种,双方手里剩下的棋子数量有(4*4*4)^ 2 = 4096种情况,一共有40353607*4096=1653亿种情况。

考虑到双方手里剩下的大棋子的数量其实也可以推算出来,那么就只有40353607*16*16=103亿种情况。

数目还是有点大,动态规划的备忘录存103亿种状态,需要的内存太大。

2,思路一——关键节点

所有局面最终都会走向三种局面:

  • 胜负已分,但是还有空格。
  • 所有棋子都用完了,平局,但是还有空格。
  • 没有空格。

其中,前两种局面应该是很少的,关键是第三种,没有空格的局面。

没有空格的局面,方手里剩下的小棋子就没用了,所有只有6^9 * 4 * 4 = 1.6亿种情况。

如果每种情况用4字节来表示,那么一共需要不到1G的内存。

我们可以先把所有的关键状态的胜负全部求出来,然后以此为基础再求其他状态的胜负。

3,思路二——对称性

还是从所有状态着手,但是利用对称性进行去重,降低数据量。

4,数据结构

1,颜色

用1个整数表示棋盘上的9个格子的棋子颜色

int color = 0; //18位,低18位是9个颜色,0空1先手2后手
inline int GetColor(int color, int n)//n是0-8
{return (color >> (n + n)) & 3;
}
inline int SetColor(int color, int n, int c)//n是0-8,c是0-2
{return color ^ (color & (3 << (n + n))) ^ (c << (n + n));
}

2,数目

用1个整数表示棋盘上的9个格子的棋子大小、先后手手里的棋子数、先手还是后手会赢。

int num = 0;//6位,低2位、接下来2位、接下来2位分别是手里小中大棋子的数目,0-3
int nums = 0;//32位,低18位是9个数目,0-3,接下来6位是先手num1,接下来6位是后手num2//接下来2位是轮到先手下时,先手的胜负ret,0平1胜2负
int GetNums(int nums)
{return nums & 262143;//2^18-1=262143
}
int GetNum1(int nums)
{return (nums >> 18) & 63;//2^6-1
}
int GetNum2(int nums)
{return (nums >> 24) & 63;
}
int GetRet(int nums)
{return (nums >> 30) & 3;//2^2-1
}

5,编码实现

1,有效颜色状态

颜色的组合有3^9=19683种,但是其中一些是无效状态。

如何判断哪些状态是有可能达到的呢?

有两种方法,第一种思路是用搜索算法去枚举所有可能的情况,

第二种思路是只看是否同时存在双方的三子连线。

如果双方都存在三子连线,那肯定是无效状态,如果双方都不存在,那一定是有效状态,如果只有一方存在,那可能有效也可能无效,但是把其中的无效状态视为有效状态不会影响DFS算法的正确性

所以我们认为,只要不是双方都有三子连线,那就是有效的颜色状态。

2,有效数目状态

在某个颜色状态条件下,哪些数目状态是有效的呢?

首先,任意一个格子的颜色和数目一定同时为0或者同时不为0。

其次,双方大中小的棋子都需要满足数量上限。

三,嵌套圈叉棋

taptap小游戏(嵌套井字棋)

1.双方,回合制。每次落子的范围应是某个特定的小九宫格。如果这个特定的小九宫格无位置了或是开局第一手,则落子的范围是整个大九宫格。

2.大九宫格由九个小九宫格组成。每次落子的这一个特定的小九宫格,相对于大九宫格的位置;正对应着对方上一次落子的格子,相对小九宫格的位置。

3.占领小格:每个小九宫格满足井字棋规则。一旦某次落子后,出现某个小九宫格三子一线,这个小九宫格被成线方占领,变成一个大棋子。

4.胜利:大九宫格满足井字棋规则。一旦某次落子后,某三个占领的小九宫格均三子一线(同色),则达成者胜利。

四,九个井字棋

在线play

9个井字棋组成的井字棋游戏。

规则:每一步都可以在81个格子中任意一个格子落子,除非当一个井字有结果(赢或输或者被填满),那么这个井字就不能再下了。游戏最后以输赢的个数比较决定输赢或者平局。

理论上,双方都有不败策略,要想赢,只能找对方的漏洞了。

AI漏洞示例:

我是先手蓝色圈圈,到这一步,我已经有必胜策略了。

圈叉棋、套娃圈叉棋、嵌套圈叉棋、九个井字棋相关推荐

  1. 井字棋--课后程序(Python程序开发案例教程-黑马程序员编著-第7章-课后作业)

    实例2:井字棋 井字棋是一种在3 * 3格子上进行的连珠游戏,又称井字游戏.井字棋的游戏有两名玩家,其中一个玩家画圈,另一个玩家画叉,轮流在3 * 3格子上画上自己的符号,最先在横向.纵向.或斜线方向 ...

  2. matlab实验报告井字棋,一字棋实验报告

    一. 实验目的: 1. 理解和掌握博弈树的启发式搜索过程 2. 学习极大极小搜索α –β剪枝 3. 能够用选定的编程语言设计简单的博弈游戏 二. 实验环境及工具 1. 硬件环境:网络环境中的微型计算机 ...

  3. 组合游戏系列5: 井字棋、五子棋AlphaGo Zero 算法实战

    来源 | MyEncyclopedia 上一篇我们从原理层面解析了AlphaGo Zero如何改进MCTS算法,通过不断自我对弈,最终实现从零棋力开始训练直至能够打败任何高手.在本篇中,我们在已有的N ...

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

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

  5. python井字棋_python实现简单井字棋游戏

    井字棋,英文名叫Tic-Tac-Toe,是一种在3*3格子上进行的连珠游戏,和五子棋类似,由于棋盘一般不画边框,格线排成井字故得名.游戏需要的工具仅为纸和笔,然后由分别代表O和X的两个游戏者轮流在格子 ...

  6. python写井字棋_python实现简单井字棋游戏

    #!/usr/bin/env python3 # -*- coding:utf-8 -*- u''' Created on 2019年4月13日 @author: wuluo ''' author = ...

  7. python学习之井字棋游戏

    井字棋,英文名叫Tic-Tac-Toe,是一种在3*3格子上进行的连珠游戏,和五子棋类似,由于棋盘一般不画边框,格线排成井字故得名.游戏需要的工具仅为纸和笔,然后由分别代表O和X的两个游戏者轮流在格子 ...

  8. [C++] 井字棋游戏源码

    TicTac.h 1 #define EX 1 //该点左鼠标 2 #define OH 2 //该点右鼠标 3 4 class CMyApp : public CWinApp 5 { 6 publi ...

  9. python井字棋ai_[Python100行系列]-井字棋游戏

    博客:Hzy的博客 | Hzy Blog​hzeyuan.cn一些学习python的小项目,小游戏.python小项目​github.com 话不多说,今天尝试用turtle库来写一个井字棋游戏.1. ...

最新文章

  1. Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用
  2. [数据结构]快速排序
  3. lamp自动部署工具_salt实现lamp自动化部署
  4. exit()函数_complete函数
  5. ezcad旋转轴标刻参数_激光打标机软件ezcad中菜单下的多文档标刻功能介绍及其操作设置...
  6. XTUOJ-1281-Cute String
  7. AddressSanitizer: heap-buffer-overflow on address 0x602000000534 at pc 0x00000040699d bp 0x7ffce0afd
  8. 计算机操作系统之设备管理思维导图
  9. python古诗代码案例_用python实现古诗词横板竖版显示 【二维列表的使用】
  10. 红芯宣布获得2.5亿元C轮系列融资,要做1亿人的安全工作入口
  11. 瑞科生物港交所上市:市值121亿港元 9个月期内亏损5.2亿
  12. 薄膜温室贵不贵,一亩地温室大棚需要花多少钱?
  13. 求1-1/2+1/3-1/4+...+1/99-1/100。
  14. 移动电影院2.0发布及垂直社交等功能体验
  15. PS学习记录6--html5 canvas+js实现ps钢笔抠图
  16. 那些年我们追过的C#奇葩关键字——忐忑
  17. 月份加日期前面用on还是in_英语当中,年月日前加哪个介词on还是in;月日/年月的话呢?...
  18. 阿里云OSS服务端签名前端JS直传(php)示例
  19. android版微信什么时候更新版本的,微信6.6版本安卓系统更新时间
  20. chromeOS安装WineHQ

热门文章

  1. 【智慧医院小程序】智慧医疗系统方便你我他
  2. php字符串处理函数大全--有时候我们只需要知道名字。
  3. STM32CubeMX实现串口DMA中断通信
  4. 深圳第一职业技术学校计算机分数线,2018年深圳第一职业技术学校第一批中招录取分数线:382分...
  5. p39 8.由以下三个集合,集合成员分别是会Python、C、Java的人员。
  6. 自媒体免费编辑工具竞品分析 135编辑器乐观号媒号通三大功能优劣报告
  7. win8.1怎样打开计算机名,Win8怎么打开cmd命令窗口_Win8.1打开命令提示符的方法-192路由网...
  8. 小程序赚钱快,对不起我只能告诉你这么多!
  9. 如何以编程方式执行Unwind segue?
  10. 2021-07-08图书借阅管理系统