【博弈】叉圈棋永远都是平局

  • 叉圈棋的规则
  • 棋盘状态的表示
  • 棋盘状态的转移
  • 必胜/必败状态的确定
  • 采用的最优策略
  • 无法到达的状态
  • 深度优先搜索(DFS)

叉圈棋的规则

在一个3x3的棋盘上,先手画“ ◯\bigcirc◯ ”,后手画“ ×\times× ”,如果某方将三个棋子连成一条直线或者斜线就获胜。

棋盘状态的表示

每一个格子都有3种状态,用000表示格子里没有棋子,用111表示格子里有先手画的“ ◯\bigcirc◯ ”,用222表示格子里有后手画的“ ×\times× ”。这样3x3的棋盘状态共有39=196833^{9}=1968339=19683种,我们可以用一个intintint类型的333进制数来表示。
同时,从左上到右下给棋盘里的每个格子编号0−80 - 80−8。

这个状态可以表示为:status=2∗(32)+1∗(34)+1∗(35)=342status = 2*(3^{2})+1*(3^{4})+1*(3^{5})=342status=2∗(32)+1∗(34)+1∗(35)=342

棋盘状态的转移

如果后手在333号位置画了一个“ ×\times× ”,新的状态可以表示为:
status’=status+2∗(33)status’ = status + 2*(3^{3})status’=status+2∗(33)

必胜/必败状态的确定

对于没有平局的博弈问题,我们可以将必胜状态记作PPP状态,必败状态记作NNN状态,两者之间的关系是:
(1) 如果当前状态的后续状态都是PPP局,那么当前状态是NNN状态。(无论如何都会留给对手必胜状态)
(2) 如果当前状态的后续状态存在NNN局,那么当前状态是PPP状态。(在最优策略下可以留给对手必败状态)

叉圈棋是带有平局的博弈问题,我们可以增加一个DDD状态来表示平局状态。(这个名字是随便取的)
这里用sg[status]sg[status]sg[status]表示statusstatusstatus的NNN/DDD/PPP状态。

(*严格来说,这里的sgsgsg值并不是sgsgsg函数,只是借用了这个名字。对于某些特殊的问题,两者是等价的,但是sgsgsg函数实际上还会考虑转移到必败态的步数)

当sg值为0时,表示当前状态是必败状态(NNN)。
当sg值为1时,表示当前状态是平局状态(DDD)。
当sg值为2时,表示当前状态是必胜状态(PPP)。

采用的最优策略

双方都会尽可能留给对手必败状态,如果没有必败状态,也要尽可能保证平局。
也就是在后续状态的sgsgsg值中选择最小值
sg[status′]=2–min(sg[status+type∗(3k)])sg[status']=2 – min( sg[status+type*(3^{k})] )sg[status′]=2–min(sg[status+type∗(3k)])

无法到达的状态

除此之外,受到游戏规则的约束,大部分状态是无法到达的,比如:

可以用−1-1−1来表示这些无法到达状态的sgsgsg值。


深度优先搜索(DFS)

接下来,我们使用深度优先搜索(DFS)的方法确定所有棋盘状态的sgsgsg值。

结果发现:
(1) 无论先手第一步把“ ◯\bigcirc◯ ”画在哪里,后手都有办法到达平局。
(2) 开局要抢占中心点和角落里的格子,如果先手画在中心则后手必须画在角上,如果先手画在角上则后手必须画在中心,然后只要封堵对手的路线上的第三个棋子即可。
(3) 必败状态是对手在两条路线上都已摆好两个棋子,无论如何都只能封堵一条路线。形成必败状态只用3个棋子就足够。
(4) 在所有状态中只有5478种状态可以到达,约占总状态数的27.8%。


最后把打好的NNN/DDD/PPP表交给电脑,顺便写了一个叉圈棋小游戏,从此我和电脑下叉圈棋就再也没赢过。 (๑ १д१)


C/C++代码

#include<stdio.h>
#include<string.h>
const int MAXN=20000; // 棋盘状态上限
int sg[MAXN]; // sg值: 0=必败 1=平手 2=必胜 -1=无法到达的局面
int BASE3[10]; // 存放3的若干次幂
int f[10]; // 存放当前棋盘
void init(){BASE3[0]=1;for(int i=1;i<=9;i++) BASE3[i]=BASE3[i-1]*3;for(int i=0;i<MAXN;i++) sg[i]=-1; // 初始化
}
int getPos(int status,int pos){return (status/BASE3[pos])%3; // 从status状态中提取pos位置
}
int checkGameOver(int status){// 返回值: 0=某方获胜 1=棋盘已满并且无人获胜 -1=棋盘未满并且无人获胜int flag=1;for(int i=0;i<9;i++){f[i]=status%3; status/=3;if(f[i]==0) flag=-1; // 表示棋盘没有满 }for(int i=0;i<3;i++){if(f[i]!=0 && f[i]==f[i+3] && f[i]==f[i+6]) return 0;if(f[3*i]!=0 && f[3*i]==f[3*i+1] && f[3*i]==f[3*i+2]) return 0;}if(f[4]!=0 && f[4]==f[0] && f[4]==f[8]) return 0;if(f[4]!=0 && f[4]==f[2] && f[4]==f[6]) return 0;return flag;
}
int min(int a,int b){return a<=b? a:b; // 最小值函数
}
int DFS(int status,int type){int flag=checkGameOver(status);if(flag!=-1){sg[status]=flag; return flag; // 胜负已定 }flag=3; // 后续状态的sg值一定小于3 for(int i=0;i<9;i++){// 枚举后续状态 if(getPos(status,i)!=0) continue;flag=min(flag,DFS(status+type*BASE3[i],3-type));}sg[status]=2-flag; return sg[status];
}int main()
{init();int cnt=0,res=DFS(0,1);printf("SG[0]=%d\n",res);for(int x=0;x<BASE3[9];x++){if(sg[x]!=-1) cnt+=1;}printf("Number of Status : %d\n",cnt);return 0;
}

(为什么C++的代码块配色这么丑呢??!)

【博弈】叉圈棋永远都是平局相关推荐

  1. 迅雷CEO邹胜龙:国外公司在中国永远都是维权面孔

    "就诉讼本身,我们觉得不是第一次,也不会是最后一次,昨天发生在百度身上,今天发生在迅雷,明天还会发生在其他人身上."2月20日,刚刚抵达上海的P2P(点对点)下载服务商深圳迅雷网络 ...

  2. 干货 | 成为一名推荐系统工程师永远都不晚

    作者 | 陈开江 责编 | 何永灿 推荐系统工程师技能树 掌握核心原理的技能 数学:微积分,统计学,线性代数 周边学科:信息论基础 推荐算法:CF,LR,SVM,FM,FTRL,GBDT,RF,SVD ...

  3. ⑨①-成功者的路永远都是相通的

    老男孩语录⑨①-成功者的路永远都是相通的 作为国内互联网公司优秀企业家的代表,马云说: 觉得自己做得到和做不到,其实只在一念之间.自己要先看得起自己,别人才会看得起你.一切伟大的行动和思想,都有一个微 ...

  4. 学习方法之04提取练习,永远都不会忘的记忆方法

    学习方法之04提取练习,永远都不会忘的记忆方法 前言 最近在复习准备秋招,总觉得效率不高,可能学习方式哪里出了问题,思考了一下,决定先学习正确的学习方式(是否真的正确还有待).在网上找了个学习方法教程 ...

  5. 三国历史的教训读后感_历史上伟大的创新者的教训,你永远都不会忘记

    三国历史的教训读后感 by Adam Naor 亚当·纳尔(Adam Naor) 历史上伟大的创新者的教训,你永远都不会忘记 (Lessons from history's great innovat ...

  6. 【转】成为一名推荐系统工程师永远都不晚

    原文链接:<干货 | 成为一名推荐系统工程师永远都不晚> 推荐系统工程师技能树 掌握核心原理的技能 数学:微积分,统计学,线性代数 周边学科:信息论基础 推荐算法:CF,LR,SVM,FM ...

  7. 不记得撞得有多痛了,可是,那个电线杆,永远都在

    蓝色,你喜欢的颜色,后来才知道,你早就不喜欢蓝色了. 你总是不断在变,其实,我没有真正了解过你! 很多事情,恨的太多. 事情过去就好了. 其实折磨人最深的是希望. 总是对你抱有希望,总是压抑这心中的恨 ...

  8. 事情永远都没有想象中那么好

    今天开始用Bugzilla了,在里面建了现在需要维护的产品,让一个同事把前一段测到的问题提交进去.(其实建这个系统就是为了方便这次维护的) 转眼间提交完毕了,我找了半天没找到,最后发现,他是在一个测试 ...

  9. 《我要飞,永远都不会累 》---伤感留言

    转自:http://bbs.astro.qq.com/t-209191-1.htm 就要分东西,从此不在有关系,留在这里的记忆在也抹不去.想说再见,却回首从前,想挥一挥衣袖,作别这里的云彩,无奈手未举 ...

最新文章

  1. PHp批量推送数据太慢,PHP非阻塞批量推送数据-php教程
  2. python学习之 字符串前'r'的用法
  3. Java代码简化之朗母达表达式(Lambda Express)
  4. day29 socket编程TCP和UDP
  5. 在powerpoint中默认的视图是_专升本计算机《Word、Excel、Powerpoint》知识点
  6. Qt界面UI之QML初见(学习笔记四)
  7. .net core 应用程序“default web site”中的服务器错误_Net程序员讲JAVA系列——Spring Boot“科普篇”...
  8. 阿里云ECS服务器怎么安装宝塔面板?
  9. 系统架构设计:平滑发布和 ABTesting,你都会吗?
  10. TVS ESD 二极管介绍与应用
  11. 任鑫:提前布局,不做轻公司
  12. 外篇 评相对论
  13. 2016,我有些明白了
  14. python-set
  15. 由浅入深玩转华为WLAN—12安全认证配置(5)Portal认证,外置Protal服务器TSM对接
  16. windows mysql 开启非3306端口
  17. 一只特立独行的“猿”
  18. java的 内省机制_Java内省机制
  19. MFC 画笔功能实现
  20. 2021-08-14 《 生活大爆炸版石头剪刀布》P1328

热门文章

  1. SWIG和MapGuide Web API
  2. PostMessage,SendMessage,GetMessage,PeekMessage,TranslateMessage,DispatchMessage的用法集合
  3. 图解http(七)-web的攻击技术
  4. base64编码类源代码(C#)
  5. Blender着色器节点教程 —— AO
  6. Cookie | Cookie的理论基础、Cookie中常用的方法
  7. 我找到的一些google搜索技巧
  8. 一种基于物理信息极限学习机的PDE求解方法
  9. MTK如何配置长按关机
  10. JS通过List列表生成树结构