消消乐问题的最优策略C++(含代码)
前言:
消消乐是一款逻辑简单,变化复杂的益智游戏,其遵从“同行(列)连续相同个数大于或等于3则消去”的原则。
定义消消乐详细规则如下:
- 游戏中共允许K种对象,分布在大小为M×N的格子布局中。
例:图1中,有K=4(小浣熊、小青蛙、小河马、小鸡)种对象,布局大小为M×N=8×4。
图1:
- 交换两个对象位置,凑够3个或3个以上即可消除,被消除的空格由正上方对象掉落填充。
例:图1中,可交换(3,1)和(3,2)消去[(5,2),(4,2),(3,2)]和[(3,2),(3,3),(3,4)]。消去过程见图2。
图 2:
- 可能出现三种消除方式: 同行(列)三个、同行(列)四个、同行(列)五个。分别 得分1分、4分、10分。注:图2中得分2分。
- 当没有可通过交换消除的对象时,游戏终止。
例:图3将终止游戏。
图3:
目标:
给定K, M, N编写代码计算通过n步操作(交换)可得的最大得分
步骤:
- 构造游戏逻辑部分
(1)生成消消乐地图(使用随机函数)
(2)选定一个方块作为基准块,判断以它构成的待判定消去模块是否有三个或者三个以上的相同方块。
A. 首先定义结构体储存待判定模块
B.水平方向上的判定是否有3个或者有3个以上相同的方块
C.在竖直方向上判断是否有3个或者有3个以上相同的方块
(3)当发生消去操作时,用剩余方块填补空缺位置的行为
(4)每次消去操作执行时,需要计算分值
2、构造游戏基础操作模块
(1)基准块原地判断 bool judgeNotShift((int i,int j,int width,int height)
用法介绍:
i.当没有基准块没有移动时,判断基准块与周围的方块是否组成可消去的方块组,每次生成游戏地图时调用此函数遍历生成的地图,如果生成的地图存在这类方块组,则从新生成地图,以保障地图初始积分为0
ii.当基准块与方块X发生交换后,方块X有可能刚好与周围的方块形成可消去的方块组,启用此函数去判断,避免漏消
(2)基准块左移操作使能判断bool judgeShiftLeft(int i,int j,int width,int height)
作用介绍:
i.将基准块原坐标传进函数,执行左移后,对基准块所在的新坐标进行判断,如果不能产生消去操作则把基准块还原,返回false,否则统计分数,返回true
(3)基准块右移操作使能判断bool judgeShiftLeft(int i,int j,int width,int height),与左移操作类似。
(4)基准块上移操作使能判断bool judgeShiftLeft(int i,int j,int width,int height)
作用介绍:
i.将基准块原坐标传进函数,执行上移后,对基准块所在的新坐标进行判断,如果不能产生消去操作则把基准块还原,返回false,否则统计分数,返回true
(5)基准块下移操作使能判断bool judgeShiftLeft(int i,int j,int width,int height),与上移操作类似。
3、游戏进行核心逻辑
用递归函数实现回溯法遍历消消乐地图。最终返回记录最高得分
本实验最大的难点就在于此,消消乐的游戏规则虽然易懂但由于情况颇多也难以用抽象的递归来实现,最大的难点在于确定递归调用的所需要的参数和如何确保函数已在规定范围内最大限度地遍历消消乐地图。
结果展示:
C++代码:
#include<iostream>
#include<math.h>
#include<string.h>
#include<time.h>
#include <stdlib.h>
#include <fstream>
using namespace std;
#define X 0
int GameMap[10][10];//消消乐地图
//生成游戏地图
int score;
void createGameMap(int width,int height,int k){
srand((unsigned)time(NULL));
for(int i=0;i<height;i++){
for(int j=0;j<width;j++){
GameMap[i][j]=rand()%k+1;
}
}
}
typedef struct {
int same;
int start;
int end;
} Data;
typedef struct{
int direction[4];
}target;
typedef struct{
int map[10][10];
int father;
int a,b;
int grade;
int sonNum;
target tar[10][10];
int son;
}Map;
//在横轴上寻找一样的图案数
Data samePicOfX(int i,int j,int width){
int sLeft,sRight,same;
int index;
//int *data= new int[3];
Data data;
//data.start=data.end=j;
sLeft=sRight=same =0;
index = j;
while(index>=0){
if(GameMap[i][j]==GameMap[i][index]){
sLeft++;
data.start = index;
}
else break;
index--;
}//往左寻找
index=j;
while(index<width){
if(GameMap[i][j]==GameMap[i][index]){
sRight++;
data.end = index;
}
else break;
index++;
}//往右寻找
same = sLeft+sRight-1;
data.same = same;
return data;
}
//在竖轴上寻找一样的图案数
Data samePicOfY(int i,int j,int height){
int sUp,sDown,same;
int index;
sUp=sDown=same =0;
//int *data =new int[3];
Data data;
//data.start=data.end=i;
index=i;
while(index>=0){
if(GameMap[i][j]==GameMap[index][j]){
sUp++;
data.start = index;
}
else break;
index--;
}//往上寻找
index=i;
while(index<height){
if(GameMap[i][j]==GameMap[index][j]){
sDown++;
data.end = index;
}
else break;
index++;
}//往下寻找
same = sUp+sDown-1;
data.same = same;
return data;
}
//返回此步消除分值
int mark(int m){
int Mark;
switch(m){
case 3:
Mark = 1; break;
case 4:
Mark = 4; break;
case 5:
Mark = 10;break;
}
return Mark;
}
void moveDown(int a,int b,int flag){//flag==0,横向消去;flag==纵向消除数,纵向消去
//int index;
if(flag==0){
while(a>0){
GameMap[a][b]=GameMap[a-1][b];
a--;
}
GameMap[0][b]=X;
}
else{
while(a>=flag){
GameMap[a][b]=GameMap[a-flag][b];
a--;
}
while(a>=0){
GameMap[a][b]=X;
a--;
}
}
}
//原地判断
bool judgeNotShift(int i,int j,int width,int height){
Data samePicX,samePicY;
if(GameMap[i][j]==X) return false;
else
{
samePicX = samePicOfX(i,j,width);
samePicY = samePicOfY(i,j,height);
if(samePicX.same<3&&samePicY.same<3){
return false;
}
else if(samePicX.same>=3&&samePicY.same<3)//横向消除
{
score+= mark(samePicX.same);
for(int index=samePicX.start;index<=samePicX.end;index++)
moveDown(i,index,0);
}
else if(samePicX.same<3&&samePicY.same>=3)//竖向消除
{
score+= mark(samePicY.same);
moveDown(samePicY.end,j,samePicY.same);
}
else if(samePicX.same>=3&&samePicY.same>=3){//组合消除
score+= mark(samePicX.same)+mark(samePicY.same);
for(int index=samePicX.start;index<=samePicX.end;index++)
moveDown(i,index,0);
moveDown(samePicY.end,j,samePicY.same-1);
}
}
return true;
}
//左移操作判断
bool judgeShiftLeft(int i,int j,int width,int height){
int pre;//临时变量存储交换时的图案
int left=j-1;//左边图案的横坐标
Data samePicX,samePicY;
if(left < 0) return false;
else if(GameMap[i][j]==X||GameMap[i][left]==X) return false;
else
{
pre = GameMap[i][left];
GameMap[i][left]=GameMap[i][j];
GameMap[i][j] = pre;
samePicX = samePicOfX(i,left,width);
samePicY = samePicOfY(i,left,height);
if(samePicX.same<3&&samePicY.same<3){
pre = GameMap[i][left];
GameMap[i][left]=GameMap[i][j];
GameMap[i][j] = pre;
return false;
}
else if(samePicX.same>=3&&samePicY.same<3)//横向消除
{
score+= mark(samePicX.same);
for(int index=samePicX.start;index<=samePicX.end;index++)
moveDown(i,index,0);
}
else if(samePicX.same<3&&samePicY.same>=3)//竖向消除
{
score+= mark(samePicY.same);
moveDown(samePicY.end,left,samePicY.same);
}
else if(samePicX.same>=3&&samePicY.same>=3){//组合消除
score+= mark(samePicX.same)+mark(samePicY.same);
for(int index=samePicX.start;index<=samePicX.end;index++)
moveDown(i,index,0);
moveDown(samePicY.end,left,samePicY.same-1);
}
}
return true;
}
//右移操作判断
bool judgeShiftRight(int i,int j,int width,int height){
int pre;//临时变量存储交换时的图案
int right=j+1;//右边图案的横坐标
Data samePicX,samePicY;
//存储3个参数,0->消除数量;1->消除起点;2->消除终点
if(right >= width) return false;
else if(GameMap[i][j]==X||GameMap[i][right]==X) return false;
else
{
pre = GameMap[i][right];
GameMap[i][right]=GameMap[i][j];
GameMap[i][j] = pre;
samePicX = samePicOfX(i,right,width);
samePicY = samePicOfY(i,right,height);
if(samePicX.same<3&&samePicY.same<3){
pre = GameMap[i][right];
GameMap[i][right]=GameMap[i][j];
GameMap[i][j] = pre;
return false;
}
else if(samePicX.same>=3&&samePicY.same<3)
{
score+= mark(samePicX.same);
for(int index=samePicX.start;index<=samePicX.end;index++)
moveDown(i,index,0);
}
else if(samePicX.same<3&&samePicY.same>=3)
{
score+= mark(samePicY.same);
moveDown(samePicY.end,right,samePicY.same);
}
else{
score+= mark(samePicX.same)+mark(samePicY.same);
for(int index=samePicX.start;index<=samePicX.end;index++)
moveDown(i,index,0);
moveDown(samePicY.end,right,samePicY.same-1);
}
}
return true;
}
//上移操作判断
bool judgeShiftUp(int i,int j,int width,int height){
int pre;//临时变量存储交换时的图案
int up=i-1;//上边图案的纵坐标
Data samePicX,samePicY;
//存储3个参数,0->消除数量;1->消除起点;2->消除终点
if(up < 0) return false;
else if(GameMap[i][j]==X||GameMap[up][j]==X) return false;
else
{
pre = GameMap[up][j];
GameMap[up][j]=GameMap[i][j];
GameMap[i][j] = pre;
samePicX = samePicOfX(up,j,width);
samePicY = samePicOfY(up,j,height);
if(samePicX.same<3&&samePicY.same<3){
pre = GameMap[up][j];
GameMap[up][j]=GameMap[i][j];
GameMap[i][j] = pre;
return false;
}
else if(samePicX.same>=3&&samePicY.same<3)
{
score+= mark(samePicX.same);
for(int index=samePicX.start;index<=samePicX.end;index++)
moveDown(up,index,0);
}
else if(samePicX.same<3&&samePicY.same>=3)
{
score+= mark(samePicY.same);
moveDown(samePicY.end,j,samePicY.same);
}
else{
score+= mark(samePicX.same)+mark(samePicY.same);
for(int index=samePicX.start;index<=samePicX.end;index++)
moveDown(up,index,0);
moveDown(samePicY.end,j,samePicY.same-1);
}
}
return true;
}
//下移操作判断
bool judgeShiftDown(int i,int j,int width,int height){
int pre;//临时变量存储交换时的图案
int down=i+1;//下边图案的纵坐标
Data samePicX,samePicY;
//存储3个参数,0->消除数量;1->消除起点;2->消除终点
if(down >=height) return false;
else if(GameMap[i][j]==X||GameMap[down][j]==X) return false;
else
{
pre = GameMap[down][j];
GameMap[down][j]=GameMap[i][j];
GameMap[i][j] = pre;
samePicX = samePicOfX(down,j,width);
samePicY = samePicOfY(down,j,height);
if(samePicX.same<3&&samePicY.same<3){
pre = GameMap[down][j];
GameMap[down][j]=GameMap[i][j];
GameMap[i][j] = pre;
return false;
}
else if(samePicX.same>=3&&samePicY.same<3)
{
score+= mark(samePicX.same);
for(int index=samePicX.start;index<=samePicX.end;index++)
moveDown(down,index,0);
}
else if(samePicX.same<3&&samePicY.same>=3)
{
score+= mark(samePicY.same);
moveDown(samePicY.end,j,samePicY.same);
}
else{
score+= mark(samePicX.same)+mark(samePicY.same);
for(int index=samePicX.start;index<=samePicX.end;index++)
moveDown(down,index,0);
moveDown(samePicY.end,j,samePicY.same-1);
}
}
return true;
}
//输出游戏地图
void printGameMap(int width,int height){
for(int i=0;i<height;i++){
for(int j=0;j<width;j++){
cout<<GameMap[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;
}
void mapInit(int width,int height,Map *m,int size){//初始化保存寻找过程中的地图
for(int i=0;i<size;i++){
m[i].grade=0;
m[i].father=-1;
m[i].sonNum=0;
m[i].son=0;
m[i].a=0;
m[i].b=0;
for(int p=0;p<height;p++){
for(int q=0;q<width;q++){
m[i].map[p][q]=-1;
}
}
for(int p=0;p<height;p++){
for(int q=0;q<width;q++){
for(int k=0;k<4;k++){
m[i].tar[p][q].direction[k]=0;
}
}
}
////
}
}
int Index;
int backTrack(int mi,int son,int max,Map *m,int width,int height){
if(m[Index].son>=max) return 0;
int i;
int j;
score = m[mi].grade;
for(int p=0;p<height;p++){ //从map中拷贝需要判断的地图
for(int q=0;q<width;q++){
GameMap[p][q]=m[mi].map[p][q];
}
}
for(i=0;i<height;i++){
for(j=0;j<width;j++){
if(m[mi].tar[i][j].direction[0]==0&&judgeShiftLeft(i,j,width,height)==true){
for(int p=0;p<height;p++){ //对全图进行原地消除使能判断
for(int q=0;q<width;q++){
judgeNotShift(p,q,width,height);
}
}
m[mi].tar[i][j].direction[0]=1;
}
else if(m[mi].tar[i][j].direction[1]==0&&judgeShiftRight(i,j,width,height)==true){
for(int p=0;p<height;p++){ //对全图进行原地消除使能判断
for(int q=0;q<width;q++){
judgeNotShift(p,q,width,height);
}
}
m[mi].tar[i][j].direction[1]=1;
}
else if(m[mi].tar[i][j].direction[2]==0&&judgeShiftUp(i,j,width,height)==true){
for(int p=0;p<height;p++){ //对全图进行原地消除使能判断
for(int q=0;q<width;q++){
judgeNotShift(p,q,width,height);
}
}
m[mi].tar[i][j].direction[2]=1;
}
else if(m[mi].tar[i][j].direction[3]==0&&judgeShiftDown(i,j,width,height)==true){
for(int p=0;p<height;p++){ //对全图进行原地消除使能判断
for(int q=0;q<width;q++){
judgeNotShift(p,q,width,height);
}
}
m[mi].tar[i][j].direction[3]=1;
}
else continue;
if(score!=m[mi].grade){
for(int p=0;p<height;p++){ //
for(int q=0;q<width;q++){
judgeNotShift(p,q,width,height);
}
}
Index++;
// cout<<Index<<" "<<mi<<endl;
// printGameMap(width,height);
m[mi].a=i;
m[mi].b=j;
m[mi].sonNum++;
m[Index].father=mi;
m[Index].grade=score;
m[Index].son=++son;
for(int p=0;p<height;p++){
for(int q=0;q<width;q++){
m[Index].map[p][q]=GameMap[p][q];
}
}
backTrack(Index,m[Index].son,max,m,width,height);
for(int p=0;p<height;p++){ //从map中拷贝需要判断的地图
for(int q=0;q<width;q++){
GameMap[p][q]=m[mi].map[p][q];
}
}
score = m[mi].grade;
// cout<<"backTrack"<<endl;
// cout<<Index<<" "<<mi<<" "<<m[mi].son<<endl;
continue;
}
}
}
// cout<<"end"<<endl;
return 1;
}
int main(){
int M,N,K;
// cout<<"请输入种数K: ";
// cin>>K;
// cout<<"请输入行数M: ";
// cin>>M;
// cout<<"请输入列数N: ";
// cin>>N;
//K=4;
//M=8;
//N=4;
ofstream out("out2.txt");
for(K=2;K<10;K++){
for(M=3;M<10;M++){
for(N=3;N<10;N++){
int mark=0;
double result=0;
int times =20;
while(times--){
Map *m=new Map[M*N*M*N*M*N];
Index =1;
mapInit(N,M,m,M*N*M*N*M*N);
reCreate:
createGameMap(N,M,K);
/* for(int i=0;i<M;i++){
for(int j=0;j<N;j++)
{
if(judgeNotShift(i,j,N,M)==true)
{
score =0;
goto reCreate;
}
}
}
GameMap[0][0]=3;GameMap[0][1]=3;GameMap[0][2]=4;GameMap[0][3]=3;
GameMap[1][0]=3;GameMap[1][1]=2;GameMap[1][2]=3;GameMap[1][3]=3;
GameMap[2][0]=2;GameMap[2][1]=4;GameMap[2][2]=3;GameMap[2][3]=4;
GameMap[3][0]=1;GameMap[3][1]=3;GameMap[3][2]=4;GameMap[3][3]=3;
GameMap[4][0]=3;GameMap[4][1]=3;GameMap[4][2]=1;GameMap[4][3]=1;
GameMap[5][0]=3;GameMap[5][1]=4;GameMap[5][2]=3;GameMap[5][3]=3;
GameMap[6][0]=1;GameMap[6][1]=4;GameMap[6][2]=4;GameMap[6][3]=3;
GameMap[7][0]=1;GameMap[7][1]=2;GameMap[7][2]=3;GameMap[7][3]=2;
*/
// cout<<endl;
// printGameMap(N,M);
// cout<<endl;
for(int p=0;p<M;p++){
for(int q=0;q<N;q++){
m[0].map[p][q]=GameMap[p][q];
}
}
double start,finish;
start = clock();
backTrack(0,0,9,m,N,M);
finish = clock();
result+= double(finish-start);
int max = m[0].grade;
for(int i=0;i<(M*N*M*N*M*N);i++){
if(max<m[i].grade) max = m[i].grade;
}
mark+=max;
// printGameMap(N,M);
if(times==0&&out.is_open()){
out<<K<<","<<M<<","<<N;
out<<","<<(double)mark/20.0<<",";
}
//for(int i=0;i<10;i++){
// delete [][i]
//}
delete []m;
}
if (out.is_open())
out<<result*1000/CLOCKS_PER_SEC/20<<endl;
}
}
}
out.close();
}