连连看(图)
[问题描述]
建立一个10*20的矩形方格图,其中有10种不同的图案,每种图案个数为偶数,填满矩形方格图。
[基本要求]
(1)随机产生原始数据;
(2)输入两个位置,如果两者图案相同,并且可以用小于等于3条直线相连,即可消除该两个图案。
解题思路:
1、我们首先要做的是构建方格图。这里我们用A到J(对应数字1到10)这10个大写字母来表示10种不同的图案。因为要求每种图案的个数都为偶数,所以我们要先确定每种图案的个数(确保都是偶数,且总和为200)。然后再依次遍历每一格,对每一格,我们从尚有剩余的图案中通过随机数来随机选定一个图案填上去。
2、之后就是 play game 的阶段了。我们首先要明确游戏规则:(1)能消去的图案必须相同。(2)两个图案可以用小于等于3条直线相连。这里解释一下,将两个图案连接在一起的直线可以视为一个路径。路径必须是可以到达(即通过空的位置连接),在最开始图案全满的时候,只能消除相邻的两个图案或位于同一边缘的两个图案。另外,小于等于3条直线,意味着路径最多包含三条直线(即最多只能拐弯两次)。这里,我们可以使用DFS,从一点出发去搜索另一个点,并时刻统计拐弯的次数,若拐弯次数大于2,则终止这一条路径的搜索。若最后,有拐弯次数小于等于2的到达路径,则说明可以成功消去。
注意:为了提高程序的鲁棒性,要进行输入检查。输入必须满足两个位置不能越界且都有图案存在。至于能不能成功消去,要看两个图案是否相等且能否找到两个图案之间的通路。对已经消去的图案,我们用 * (对应数字0)来填补,主要是便于后面消去时确定位置。另外,由于位于同一边缘的两个图案也可以消去,所以我们在开数组空间时,要在原来方格图的大小进行适当扩充。
程序代码:
# include <iostream>
# include <random>
# include <time.h>
# define LONG 20
# define WIDTH 10
# define SIZE 200
# define NUM 10
using namespace std;
//随机生成图案
void Create();
//打印图案
void Print();
//输入判断
bool Judge(int a, int b, int c, int d);
//搜索路径
void DFS(int x, int y, int x2, int y2, int d, int k);
bool Find(int x1, int y1, int x2, int y2);
//玩游戏
void PlayGame();
int g[WIDTH + 2][LONG + 2] = { {0} }; //图像
int way[4][2] = { {0,1},{0,-1},{1,0},{-1,0} }; //前进方式
int visit[WIDTH + 2][LONG + 2] = { {0} }; //标记走过的地方
bool temp; //是否存在路径
int main()
{
Create();
cout << "原图:" << endl;
Print();
PlayGame();
return 0;
}
//随机生成图案
void Create()
{
int n, sum = 0;
int num[NUM + 1]; //每种图案的个数
srand((unsigned int)time(0)); //修改种子
for (int i = 1; i < NUM; i++) {
//确定每种图案的个数
n = rand() % SIZE + 1;
if (n % 2 == 0 && sum + n < SIZE) {
sum += n;
num[i] = n;
}
}
num[NUM] = SIZE - sum; //直接求最后一种图案的个数
for (int i = 1; i <= WIDTH; i++) {
for (int j = 1; j <= LONG; j++) {
n = rand() % NUM + 1; //随机选取一种图案
while (!num[n]) {
//如果这种图案已放置完,跳到下一个
n = (n + 1) % NUM;
if (n == 0) {
n = 10;
}
}
g[i][j] = n;
num[n]--;
}
}
}
//打印图案
void Print()
{
char c;
for (int i = 1; i <= WIDTH; i++) {
for (int j = 1; j <= LONG; j++) {
if (g[i][j]) {
c = 64 + g[i][j];
cout << c;
}
else {
//已消去的地方用*补齐
cout << "*";
}
}
cout << endl;
}
}
//输入判断
bool Judge(int a, int b, int c, int d)
{
//越界检查
if (a<1 || a>WIDTH || c<1 || c>WIDTH) {
return false;
}
if (b<1 || b>LONG || d<1 || d>LONG) {
return false;
}
//检查对应位置是否存在图案
if (!g[a][b] || !g[c][d]) {
return false;
}
return true;
}
//搜索路径
//(x,y)当前位置
//d是上一次的前进方向(0,1,2,3)
//k是已拐弯的次数
void DFS(int x, int y, int x2, int y2, int d, int k)
{
if (x == x2 && y == y2 && k <= 2) {
//到达终点,且拐弯次数小于等于2,可以成功消去
temp = true;
return;
}
if (k > 2) {
return;
}
for (int i = 0; i < 4; i++) {
int p1 = x + way[i][0];
int p2 = y + way[i][1];
if (visit[p1][p2] || p1<0 || p1>WIDTH + 1 || p2<0 || p2>LONG + 1) {
//走过或越界的路淘汰
continue;
}
if (g[p1][p2] && (p1 != x2 || p2 != y2)) {
//不是终点,但有图案的路淘汰
continue;
}
if (i == d || d == -1) {
//没有拐弯
visit[p1][p2] = 1;
DFS(p1, p2, x2, y2, i, k);
}
else {
//拐弯
visit[p1][p2] = 1;
DFS(p1, p2, x2, y2, i, k + 1);
}
//数据恢复
visit[p1][p2] = 0;
}
}
bool Find(int x1, int y1, int x2, int y2)
{
temp = false;
for (int i = 0; i <= WIDTH + 1; i++) {
for (int j = 0; j <= LONG + 1; j++) {
visit[i][j] = 0;
}
}
DFS(x1, y1, x2, y2, -1, 0);
return temp;
}
//玩游戏
void PlayGame()
{
bool t;
int x1, y1, x2, y2; //位置坐标(x1,y1),(x2,y2)
cout << "\n游戏开始!(提示:输入0游戏结束)\n";
cout << "请输入两个位置:";
cin >> x1;
while (x1) {
cin >> y1 >> x2 >> y2;
if (!Judge(x1, y1, x2, y2)) {
cout << "坐标错误,请重新输入:";
}
else {
if (g[x1][y1] != g[x2][y2]) {
cout << "消去失败" << endl;
}
else {
t = Find(x1, y1, x2, y2);
if (t) {
//符合消去要求
g[x1][y1] = 0;
g[x2][y2] = 0;
cout << endl;
Print();
}
else {
cout << "消去失败" << endl;
}
}
cout << "请输入两个位置:";
}
cin >> x1;
}
}
运行结果:
原图:
CEHDEFFIAAGJBDJHBFGH
DBHACEEHGHGDFEJIJHFD
CBEAGDFHDCEJEFGHIJJG
IDHFDFHGIDFJJBECEGGA
HHIBBJADHCCEDDAABIIH
CCDAFHFEDGHAEDGIDEFI
BHECGADHDDGABGCADGDC
DDBICDABDFBAACAABBHE
AGEDHEHIGCBBIGACCEEG
FGDBACCDGAADBAACIABA
游戏开始!(提示:输入0游戏结束)
请输入两个位置:1 2 1 5
C*HD*FFIAAGJBDJHBFGH
DBHACEEHGHGDFEJIJHFD
CBEAGDFHDCEJEFGHIJJG
IDHFDFHGIDFJJBECEGGA
HHIBBJADHCCEDDAABIIH
CCDAFHFEDGHAEDGIDEFI
BHECGADHDDGABGCADGDC
DDBICDABDFBAACAABBHE
AGEDHEHIGCBBIGACCEEG
FGDBACCDGAADBAACIABA
请输入两个位置:1 1 2 5
**HD*FFIAAGJBDJHBFGH
DBHA*EEHGHGDFEJIJHFD
CBEAGDFHDCEJEFGHIJJG
IDHFDFHGIDFJJBECEGGA
HHIBBJADHCCEDDAABIIH
CCDAFHFEDGHAEDGIDEFI
BHECGADHDDGABGCADGDC
DDBICDABDFBAACAABBHE
AGEDHEHIGCBBIGACCEEG
FGDBACCDGAADBAACIABA
请输入两个位置:0
以上便是我对这道题的看法,很高兴与大家分享。