【博弈】叉圈棋永远都是平局
【博弈】叉圈棋永远都是平局
- 叉圈棋的规则
- 棋盘状态的表示
- 棋盘状态的转移
- 必胜/必败状态的确定
- 采用的最优策略
- 无法到达的状态
- 深度优先搜索(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++的代码块配色这么丑呢??!)
【博弈】叉圈棋永远都是平局相关推荐
- 迅雷CEO邹胜龙:国外公司在中国永远都是维权面孔
"就诉讼本身,我们觉得不是第一次,也不会是最后一次,昨天发生在百度身上,今天发生在迅雷,明天还会发生在其他人身上."2月20日,刚刚抵达上海的P2P(点对点)下载服务商深圳迅雷网络 ...
- 干货 | 成为一名推荐系统工程师永远都不晚
作者 | 陈开江 责编 | 何永灿 推荐系统工程师技能树 掌握核心原理的技能 数学:微积分,统计学,线性代数 周边学科:信息论基础 推荐算法:CF,LR,SVM,FM,FTRL,GBDT,RF,SVD ...
- ⑨①-成功者的路永远都是相通的
老男孩语录⑨①-成功者的路永远都是相通的 作为国内互联网公司优秀企业家的代表,马云说: 觉得自己做得到和做不到,其实只在一念之间.自己要先看得起自己,别人才会看得起你.一切伟大的行动和思想,都有一个微 ...
- 学习方法之04提取练习,永远都不会忘的记忆方法
学习方法之04提取练习,永远都不会忘的记忆方法 前言 最近在复习准备秋招,总觉得效率不高,可能学习方式哪里出了问题,思考了一下,决定先学习正确的学习方式(是否真的正确还有待).在网上找了个学习方法教程 ...
- 三国历史的教训读后感_历史上伟大的创新者的教训,你永远都不会忘记
三国历史的教训读后感 by Adam Naor 亚当·纳尔(Adam Naor) 历史上伟大的创新者的教训,你永远都不会忘记 (Lessons from history's great innovat ...
- 【转】成为一名推荐系统工程师永远都不晚
原文链接:<干货 | 成为一名推荐系统工程师永远都不晚> 推荐系统工程师技能树 掌握核心原理的技能 数学:微积分,统计学,线性代数 周边学科:信息论基础 推荐算法:CF,LR,SVM,FM ...
- 不记得撞得有多痛了,可是,那个电线杆,永远都在
蓝色,你喜欢的颜色,后来才知道,你早就不喜欢蓝色了. 你总是不断在变,其实,我没有真正了解过你! 很多事情,恨的太多. 事情过去就好了. 其实折磨人最深的是希望. 总是对你抱有希望,总是压抑这心中的恨 ...
- 事情永远都没有想象中那么好
今天开始用Bugzilla了,在里面建了现在需要维护的产品,让一个同事把前一段测到的问题提交进去.(其实建这个系统就是为了方便这次维护的) 转眼间提交完毕了,我找了半天没找到,最后发现,他是在一个测试 ...
- 《我要飞,永远都不会累 》---伤感留言
转自:http://bbs.astro.qq.com/t-209191-1.htm 就要分东西,从此不在有关系,留在这里的记忆在也抹不去.想说再见,却回首从前,想挥一挥衣袖,作别这里的云彩,无奈手未举 ...
最新文章
- PHp批量推送数据太慢,PHP非阻塞批量推送数据-php教程
- python学习之 字符串前'r'的用法
- Java代码简化之朗母达表达式(Lambda Express)
- day29 socket编程TCP和UDP
- 在powerpoint中默认的视图是_专升本计算机《Word、Excel、Powerpoint》知识点
- Qt界面UI之QML初见(学习笔记四)
- .net core 应用程序“default web site”中的服务器错误_Net程序员讲JAVA系列——Spring Boot“科普篇”...
- 阿里云ECS服务器怎么安装宝塔面板?
- 系统架构设计:平滑发布和 ABTesting,你都会吗?
- TVS ESD 二极管介绍与应用
- 任鑫:提前布局,不做轻公司
- 外篇 评相对论
- 2016,我有些明白了
- python-set
- 由浅入深玩转华为WLAN—12安全认证配置(5)Portal认证,外置Protal服务器TSM对接
- windows mysql 开启非3306端口
- 一只特立独行的“猿”
- java的 内省机制_Java内省机制
- MFC 画笔功能实现
- 2021-08-14 《 生活大爆炸版石头剪刀布》P1328
热门文章
- SWIG和MapGuide Web API
- PostMessage,SendMessage,GetMessage,PeekMessage,TranslateMessage,DispatchMessage的用法集合
- 图解http(七)-web的攻击技术
- base64编码类源代码(C#)
- Blender着色器节点教程 —— AO
- Cookie | Cookie的理论基础、Cookie中常用的方法
- 我找到的一些google搜索技巧
- 一种基于物理信息极限学习机的PDE求解方法
- MTK如何配置长按关机
- JS通过List列表生成树结构