【SeedCoder2015年 热身题6 搜索】Move Game (题目)

【问题】


现有如下一款游戏,游戏的目的是通过”左,右,上,下”滑动来移动红,绿,蓝色的小球,每操作一次所有小球最多只能移动一步(与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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值