【问题】
现有如下一款游戏,游戏的目的是通过”左,右,上,下”滑动来移动红,绿,蓝色的小球,每操作一次所有小球最多只能移动一步(与2048不同),其中灰色区域块为禁止区域,小球不能移动到该位置。若所有有色小球停留在对应的色区块下,则游戏结束。那么对于该游戏关卡,最少需要多少步才能完成。
【输入】
输入只由一组测试样例组成。该样例由两部分组成,第一部分为3×3的矩阵,矩阵每一行占据一列,每个数之间以Tab键隔开;其中0表示该单元未被小球和灰色壁垒占据,-1表示该单元被灰色壁垒占据,1表示被红色小球占据,2表示被绿色小球占据,3表示被蓝色小球占据;第二部分表示红,绿,蓝色块的位置,第一行表示红色色块的位置,第二行表示绿色色块的位置,第三行表示蓝色色块的位置。数字之间以Tab键隔开。
【输出】
对于每一次输出样例,输出最小的操作数。
【示例输入】
1 0 -1
3 2 0
-1 -1 0
1 2
0 1
0 0
--------------------------------------------------------------------------------------------------------------------------------------------------
【解答】
该题目与上一道题目类似,都是利用宽度优先搜索。该示例代码未按照指定格式进行输出,输出了最短操作步骤,可以直接按照输出步骤完成该游戏。
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:上上下下ABAB
// 程序描述:搜索
// IDE版本:Visual Studio 2013
// 作者:Arthur Lee
//------------------------------------------------------------------------------------------------
//【1】头文件
#include <fstream>
#include <ctime>
#include <list>
#include <functional>//包含less<>等仿函数
#include <algorithm>
#include <deque>//包含deque类
using namespace std;
#define TIMER
//【2】函数声明
void InitialData();
bool BreadthFirstSearch();
//【3】定义枚举体,在几种方法中切换
enum Method
{
BreadthFirst
};
enum Action{
Left,Right,
Up,Down
};
enum Color{
Red=1,Green,Blue
};
class Point {
public:
int x;
int y;
Point(){
x = 0;
y = 0;
}
Point(int x0, int y0) :x(x0), y(y0){}
//Point(Point& p) :x(p.x), y(p.y){}
bool operator ==(Point pos){
return (x == pos.x&&y == pos.y);
}
bool operator !=(Point pos){
return !(*this == pos);
}
Point& operator = (const Point& p){
this->x = p.x;
this->y = p.y;
return *this;
}
};
Point PosTemp[3];//全局Point变量,类实现需要放在这之前
//定义的判断准则
bool CompareWithX_IndexIncrease(const int& x1, const int& x2){
return less<int>()(PosTemp[x1].x, PosTemp[x2].x);
}
bool CompareWithX_IndexDecrease(const int& x1, const int& x2){
return greater<int>()(PosTemp[x1].x, PosTemp[x2].x);
}
bool CompareWithY_IndexIncrease(const int& x1, const int& x2){
return less<int>()(PosTemp[x1].y, PosTemp[x2].y);
}
bool CompareWithY_IndexDecrease(const int& x1, const int& x2){
return greater<int>()(PosTemp[x1].y, PosTemp[x2].y);
}
class State{
public:
static Point FinalPoint[3];
int Board[3][3];//游戏面板,0表示无占据,Red,Green,Blue表示有点占据。-1表示障碍物占据
Point InitialPoint[3];//R,G,B
list<Action> Routine;
State& operator =(const State& s){
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
this->Board[i][j] = s.Board[i][j];
for (int i = 0; i < 3; ++i){
this->InitialPoint[i] = s.InitialPoint[i];
}
this->Routine = s.Routine;
return *this;
}
bool IsFinalState(){
int i = 0;
for (; i < 3; ++i){
if (InitialPoint[i] != FinalPoint[i])
break;
}
if (i < 3)
return false;
else
return true;
}
bool operator == (State s){
int i = 0;
for (; i < 3; ++i){
if (InitialPoint[i] != s.InitialPoint[i])
break;
}
if (i < 3)
return false;
else
return true;
}
bool MoveOneStep(Action act, State& result){//NOTE:为保证修改形参Result,该函数必须以State&作为参数~~!!
int Order[3] = { 0, 1, 2 };//0 - Red,1-Green,2-Blue;表示三者排序指标
for (int i = 0; i < 3; ++i)
PosTemp[i] = InitialPoint[i];
result = *this;//result 储存转换后的最终的结果
bool flag = false;//表示MoveOneStep 是否改变了状态。
switch (act)
{
case Left:
sort(Order, Order + 3, CompareWithY_IndexIncrease);
for (int i = 0; i < 3; ++i){
if (InitialPoint[Order[i]].y >= 1 &&
result.Board[InitialPoint[Order[i]].x][InitialPoint[Order[i]].y - 1] == 0)
{
result.Board[InitialPoint[Order[i]].x][InitialPoint[Order[i]].y] = 0;
result.InitialPoint[Order[i]].y -= 1;
result.Board[InitialPoint[Order[i]].x][InitialPoint[Order[i]].y - 1] = (Order[i] + 1);
flag = true;
}
}
break;
case Right:
sort(Order, Order + 3, CompareWithY_IndexDecrease);
for (int i = 0; i < 3; ++i){
if (InitialPoint[Order[i]].y<2 &&
result.Board[InitialPoint[Order[i]].x][InitialPoint[Order[i]].y + 1] == 0)
{
result.Board[InitialPoint[Order[i]].x][InitialPoint[Order[i]].y] = 0;
result.InitialPoint[Order[i]].y += 1;
result.Board[InitialPoint[Order[i]].x][InitialPoint[Order[i]].y + 1] = (Order[i] + 1);
flag = true;
}
}
break;
case Up:
sort(Order, Order + 3, CompareWithX_IndexIncrease);
for (int i = 0; i < 3; ++i){
if (InitialPoint[Order[i]].x >= 1 &&
result.Board[InitialPoint[Order[i]].x - 1][InitialPoint[Order[i]].y] == 0)
{
result.Board[InitialPoint[Order[i]].x][InitialPoint[Order[i]].y] = 0;
result.InitialPoint[Order[i]].x -= 1;
result.Board[InitialPoint[Order[i]].x - 1][InitialPoint[Order[i]].y] = (Order[i] + 1);
flag = true;
}
}
break;
case Down:
sort(Order, Order + 3, CompareWithX_IndexDecrease);
for (int i = 0; i < 3; ++i){
if (InitialPoint[Order[i]].x <2 &&
result.Board[InitialPoint[Order[i]].x + 1][InitialPoint[Order[i]].y] == 0)
{
result.Board[InitialPoint[Order[i]].x][InitialPoint[Order[i]].y] = 0;
result.InitialPoint[Order[i]].x += 1;
result.Board[InitialPoint[Order[i]].x + 1][InitialPoint[Order[i]].y] = (Order[i] + 1);
flag = true;
}
}
break;
default:
break;
}
return flag;
}
};
Point State::FinalPoint[3] = {};
//【4】变量声明
bool IsExistInHashTable(State);
deque<State> HashTable;//充当hashtable 的功能
State InitialState;
State Result;//存放最终的结果
int main(){
#ifdef TIMER
clock_t start = clock();
#endif // TIMER
ifstream fin("in.txt");
if (fin.fail())
return 1;
ofstream fout("out.txt");
Method method = Method::BreadthFirst;
bool flag = false;
while (!fin.eof())
{
InitialData();
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j){
fin >> InitialState.Board[i][j];
switch (InitialState.Board[i][j])
{
case 1://红色
InitialState.InitialPoint[0].x = i;
InitialState.InitialPoint[0].y = j;
break;
case 2://绿色
InitialState.InitialPoint[1].x = i;
InitialState.InitialPoint[1].y = j;
break;
case 3:
InitialState.InitialPoint[2].x = i;
InitialState.InitialPoint[2].y = j;
break;
default:
break;
}
}
fin >> State::FinalPoint[0].x >> State::FinalPoint[0].y
>> State::FinalPoint[1].x >> State::FinalPoint[1].y
>> State::FinalPoint[2].x >> State::FinalPoint[2].y;
switch (method)
{
case BreadthFirst:
flag = BreadthFirstSearch();
break;
default:
break;
}
if (flag)//输出
{
fout << "the smallest steps to achieve the goal is " << Result.Routine.size() << "\n";
while (!Result.Routine.empty())
{
switch (Result.Routine.front())
{
case Left:
fout << "left" << "\t";
break;
case Right:
fout << "right" << "\t";
break;
case Up:
fout << "up" << "\t";
break;
case Down:
fout << "down" << "\t";
break;
default:
break;
}
Result.Routine.pop_front();
}
}
else
fout << "there is no answer!" << "\n";
fout << "\n";
}
#ifdef TIMER
clock_t end = clock();
double duration = (double)(end - start);
fout << "runtime : " << duration << "ms" << endl;
#endif // TIMER
fout.close();
return 0;
}
//【5】函数实现
void InitialData(){
HashTable.clear();
}
bool BreadthFirstSearch(){
list<State> list_temp;
State temp;
list_temp.push_back(InitialState);
HashTable.push_back(InitialState);
while (!list_temp.empty()){
temp = list_temp.front();
list_temp.pop_front();
for (int i = 0; i < 4; ++i){
if (temp.MoveOneStep((Action)i, Result)){
if (!IsExistInHashTable(Result)){
Result.Routine.push_back((Action)i);
list_temp.push_back(Result);
HashTable.push_back(Result);
if (Result.IsFinalState())
return true;
}
}
}
}
return false;
}
bool IsExistInHashTable(State s){
for (int i = 0; i < HashTable.size(); ++i){
if (HashTable[i] == s)
{
return true;
}
}
return false;
}