拼图游戏(8 puzzle)

如图所示,这是一个九宫格(这倒是让我想起了小时候老师在黑板上教导我们的如何通过一系列的拼凑,将横行,竖行,以及斜行都拼到和相等),格子中有一个格子是空的,另外八个格子分别有数字1--8,我们的任务是将原图通过空格转换为前面八格为1--8,而最后一格为空。
以上的截图来自如下的一款android游戏(当然,由于版本的原因,样式换成了一种木板式的,更贴近于我们在现实中的“八数码游戏”),其名字叫:8--Puzzle,在其软件的启动界面中,有阐述两种游戏的模式:

何者为难?何者为易呢?这里我们有一个可以定量化的衡量标准,也就是说,我们可以以该状态还原为目标状态(这里称为Goal-Status)所需的最小步数为一个凭据。当然,这样比较单纯,我们还可以设计出更“客观”一些的,比如,有些移动是难以想到的,而有些是很容易想到的,为每一个步数赋予一个权值,这就是一个不错的想法。
那么,关键的问题是,我们需要设计出一个AI出来,只要给出初始的状态,我们可以通过我们的AI来得到到目标状态具体需要多少步,甚至,我们可以得到每一步的具体操作过程(这里可以用u,d,l,r分别来代表上下左右)
AI的实现方法很多,比如:裸体的BFS(Bruce Force+BFS),双向BFS+STL,开哈希表之后,更省时间,更牛的一些办法还有楼教主在2005年的百度之星总决赛打出的A*(该算法基于启发式,后来,百度公司在之后的比赛中就以Astar作为百度之星的象征,其来源就是楼天成的A*算法)以及其进一步的IDA*算法。在博客园中,有牛人归纳出了八数码问题的八重境界,我会在最后进行转载的。
有人说过,没有看过该AI的人,人生不完美,也许,该问题真的比较深刻吧!

我们利用X来表示这个8--PUZZLE问题的空格,当然,在Input中,可以将其归为一行(毕竟,大家都知道这是个八数码问题吧!)
Input : 1 2 3 x 4 6 7 5 8
对于输出来说,我们只要输出一个方向就可以了(根据方向,我们可以知道是哪一个方块在动),对于这个Input,我们所得到的Output应该是:lul
Output:lul
而对于最少的次数,我们可以根据输出中的字母的数量得到。
首先,考虑一个问题,我们的状态总数(算上那个空格)一共为9! = 362880 种,于是,即使是最野蛮的暴力+BFS也是可以的(纯粹的暴力的话,果断还是不行的),这里给出的一种方法是暴力+BFS+queue容器+Hash表。
Solve:

2
3 #include <cstdio>
4
5 #include <cstring>
6
7 #include <string>
8
9 #include <algorithm>
10
11 #include <cmath>
12
13 #include <queue>
14
15
16
17 using namespace std;
18
19
20
21 #define MAXN 363000 //9!==326880
22
23
24
25 struct node
26
27 {
28
];//当前状态
30
31 int loc;//'0'的位置,即'x'的位置
32
33 int stat;//康托展开的hash值
34
35 string path;//路径
36
37 };
38
39
40
41 //分别存储1--9的阶乘值
42
,,,,,,,,,};
44
45 //同以前一样,用一个二维数组dir[4][2]来装填方向
46
][]={-,,,,,-,,};
48
49 //存储方向字符,以便在之后表明路径
50
]="udlr";
52
;//123456780对应的hash值
54
55 string path;//路径
56
57 //作为一种标记,遍历已经访问过的状态
58
59 bool vis[MAXN];
60
61 //最初的结点
62
63 node st;
64
65
66
67 //康托展开求序列的hash值
68
69 int cantor(const int *s)
70
71 {
72
;
74
;i<;i++)
76
77 {
78
;
80
;j<i;j++)
82
83 if(s[j]>s[i])
84
85 num++;
86
87 sum+=(num*fac[i]);
88
89 }
90
);
92
93 }
94
95
96
97 //这里利用越界函数来标识是否越界
98
99 bool isok(int x,int y)
{
|| x> || y> || y<)
return false;
return true;
}
bool bfs()
{
//初始化vis数组,将其都标记为0
memset(vis,,sizeof(vis));
//队列容器来装载结点
queue<node>q;
node cur,tmp;
//初始结点进入队列
q.push(st);
vis[st.stat]=;
//如果队列非空,那么就一直重复这个过程
while(!q.empty())
{
//将首结点取出作为当前结点
cur=q.front();
//将队列剥离一个
q.pop();
//得到空白方块的横坐标和纵坐标
,y=cur.loc%;
;i<;i++)
{
//从四个方向对空白位置进行搜索
],ty=y+dir[i][];
//如果越界的话,换一个方向
if(!isok(tx,ty))
continue;
tmp=cur;
tmp.loc=tx*+ty;//'0'移动到该位置
//这里,相当于交换了一个方向
tmp.s[cur.loc]=tmp.s[tmp.loc];
tmp.s[tmp.loc]=;
//获取这个状态的hash值
tmp.stat=cantor(tmp.s);
//如果这个状态没有被遍历过的话
if(!vis[tmp.stat])
{
vis[tmp.stat]=;
//修改路径,字符串可以直接在后面加
tmp.path=cur.path+index[i];
//如果是正解的话
if(tmp.stat==aim)
{
path=tmp.path;
return true;
}
//如果不是最优解的话,继续入队列
q.push(tmp);
}
}
}
;
}
int main()
{
//假设操作的总次数不大于256
];
//利用gets()函数读入一行
while(gets(buf))
{
int len=strlen(buf);
;
;i<len;i++)
{
')
{
st.s[cnt++]=buf[i]-';
}
else if(buf[i]=='x')
{
st.s[cnt]=;
//这里标识空白区域的具体位置
st.loc=cnt++;
}
}
//利用cantor扩展函数得到初始状态
st.stat=cantor(st.s);
//如果一开始就是目标状态的话,那么就输出空气好咯!
if(st.stat==aim)
{
puts("");
continue;
}
//广搜开始
if(bfs())
//输出路径
cout<<path<<endl;
else
//输出不可解
puts("unsolvable");
}
;
}

拼图游戏(8 puzzle)的更多相关文章
- [CareerCup] 8.6 Jigsaw Puzzle 拼图游戏
8.6 Implement a jigsaw puzzle. Design the data structures and explain an algorithm to solve the puzz ...
- 利用Vue.js实现拼图游戏
之前写过一篇<基于Vue.js的表格分页组件>的文章,主要介绍了Vue组件的编写方法,有兴趣的可以访问这里进行阅读:http://www.cnblogs.com/luozhihao/p/5 ...
- JavaScript拼图游戏
今天是2016年最后一天上班了.最近几天都比较休闲,有时间空闲下来写写文档之类的. 2016过得真是快.感觉没做什么就过去了.想到之前想坚持每个月写一写博客都没坚持到.希望2017年可以吧. 无聊之余 ...
- 用Qt图形视图框架开发拼图游戏
用Qt的图形视图框架(Graphics View Framework)做了一个拼图游戏DEMO,演示了: QGraphicsView.QGraphicsScene.QGraphicsItem的基本用法 ...
- Vue.js实现拼图游戏
Vue.js实现拼图游戏 之前写过一篇<基于Vue.js的表格分页组件>的文章,主要介绍了Vue组件的编写方法,有兴趣的可以访问这里进行阅读:http://www.cnblogs.com/ ...
- 程序设计 之 C#实现《拼图游戏》
功能描述: 1.用户自定义上传图片 2.游戏难度选择:简单(3*3).一般(5*5).困难(9*9)三个级别 3.纪录完成步数 模块: 1.拼图类 2.配置类 3.游戏菜单窗口 4.游戏运行窗口 -- ...
- 程序设计 之 C#实现《拼图游戏》 (下) 原理篇
前言:在 http://www.cnblogs.com/labixiaohei/p/6698887.html 程序设计 之 C#实现<拼图游戏>(上),上传了各模块代码,而在本文中将详细剖 ...
- 拼图游戏js
实现算法: 1. JavaScript动态生成拼图:通过生成16个div,且除最后一个div不使用背景图片以外,其他div都设置拼图图片为背景.然后通过调整background-position来实现 ...
- 程序设计 之 C#实现《拼图游戏》 (上)代码篇
原理详解请参考博客中 拼图游戏(下)原理篇 http://www.cnblogs.com/labixiaohei/p/6713761.html 功能描述: 1.用户自定义上传图片 2.游戏难度选择:简 ...
- html+css+js实现网页拼图游戏
代码地址如下:http://www.demodashi.com/demo/14449.html 项目描述 使用 html+js+css 实现一个网页拼图游戏,可支持简单,中等,困难三种难度. 演示效果 ...
随机推荐
- vue 将时间戳转换成日期格式 (一)
(1)创建一个处理时间格式的js,内容如下: ../../utils/formatDate.js export function formatDate(date, fmt) { if (/(y+)/. ...
- unity图片保留周边,中间延伸
1.先把图片切割,类似下面这样的 2.然后在使用的时候(选择图片类型的时候选择sliced)
- Apache常见interview
Apache在Linux系统下的工作模式及特点?如何使Apache使用worker模式? prefork 是一种非线程.与派生的工作模式,用的是进程去处理请求,所以比较容易消耗内存,但是稳定性好,某个 ...
- c# 属性成员
- spark-submit之使用pyspark
在linux下,执行pyspark代码 —— 实测有效:但是并不是所有的包都能够成功,一些很复杂的包或者对C依赖很深的包例如 numpy, pandas, scipy等,无法通过本方法实现:对一些比较 ...
- Kafka 基本知识分享
目录 一.基本术语 二.Kafka 基本命令 三.易混淆概念 四.Kafka的特性 五.Kafka的使用场景 六.Kakfa 的设计思想 七.Kafka 配置文件设置 八.新消费者 九.Kafka该怎 ...
- P2P system: Napster
Napster structure client machines之所以叫peers是因为对于server来说这些machines是平等对待的 当你upload一首歌曲如PennyLane.mp3时, ...
- 用Thymeleaf在实际项目中遇到的坑
最近搭建了基于的springboot的新项目,抛弃了jsp,使用了官方推荐的Thymeleaf(怎么读?[taim][li:f])模板,在实际开发遇到了很多的坑,等项目告一段落,我再一一记录一下,有交 ...
- python 虚拟环境相关命令
1.总是记不住一些关于创建虚拟环境得命令,特在自己得博客里记录一下自己常用得命令: virtualenv -p C:\Python36\python D:\virtual\Envs\AssetScan ...
- 06_Tutorial 6: ViewSets & Routers 视图集与路由器
1.Tutorial 6: ViewSets & Routers 视图集与路由器 0.文档 https://q1mi.github.io/Django-REST-framework-docum ...