拼图游戏的步骤求解

前两天突然想做一个android拼图游戏的小程序玩一下,csdn博客上发现已经有人写过相关的程序,大致看了一下发现程序写的挺好的,我截取了其中的主要的代码试了一下,程序的界面如下:android程序http://pan.baidu.com/s/1kT5fA2j直接下载。

玩了一下被虐了,走了一会发现并不是想象那么好拼。擦,要不让计算机帮我算吧,算出最短的步骤给我,嘿嘿。

先把计算机算出来的结果,贴出来,待会给出程序。

1、result=31132441332424113242(1 2 3 4 代表左右上下)

2、翻译过来为:上左左上右 下下左上上 右下右下左 左上右下右

操作一下:

结果对了。

下面贴出程序:计算的工程是在PC上算的,计算量比较大,android要等好久,先贴Java程序:

1. AnswerUtil.java

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;


public class AnswerUtil {
	private int deltax[]={-1,1,0,0};
	private int deltay[]={0,0,-1,1};
	private String aimStr="123456780";
	private String orangeData;
	private int lineItems;
	private DataItem dataItem;
	private List<DataItem> queue =new ArrayList<DataItem>();
	
	public AnswerUtil(String list,int n) {
		orangeData=list;
		lineItems=n;
		queue.clear();
		queue.add(new DataItem(orangeData, null,0,0));
	}
	public void getAnswer()
	{
		
		int queueindex=0;
		while (queueindex<queue.size()) 
		{
			dataItem=queue.get(queueindex);
			if(queueindex%1000==0)
				System.out.println("queueindex="+queueindex);
			int zero_xy=dataItem.getData().indexOf("0");
			if(zero_xy==8)
			{
				if(dataItem.getData().equals(aimStr))
				{
					//find the answer
					System.out.println("the ans pos="+queueindex);
					printPath(queueindex);
					break;
				}
			}
			int zero_x=zero_xy%lineItems;
			int zero_y=zero_xy/lineItems;
			int new_x,new_y;
			for(int i=0;i<4;i++)
			{
				new_x=zero_x+deltax[i];
				new_y=zero_y+deltay[i];
				if(new_x>=0&&new_x<lineItems&&new_y>=0&&new_y<lineItems)
				{
					String str=swap(dataItem.getData(), zero_xy, new_y*lineItems+new_x);
					if(!isExist(str))
					{
						DataItem item=new DataItem(str, dataItem.getData(), i+1,queueindex);
						queue.add(item);
					}
				}
			}
			queueindex++;
		}
	}
	public String swap(String data,int old_xy,int new_xy)
	{
		String str="";
		char[] array=data.toCharArray();
		char tmp=array[old_xy];
		array[old_xy]=array[new_xy];
		array[new_xy]=tmp;
		for(int i=0;i<array.length;i++)
			str+=array[i];
		return str;
	}
	public int getZeroXY(String str)
	{
		return str.indexOf("0");
	}
	
	private void printPath(int pos)
	{
		if(pos==0)
			return ;
		printPath(queue.get(pos).getParentPos());
		System.out.print(queue.get(pos).getPtoC());
	}
	private boolean isExist(String str)
	{
		for(int i=0;i<queue.size();i++)
		{
			if(queue.get(i).getData().equals(str))
				return true;
		}
		return false;
	}
	public void test()
	{
		String str=swap(orangeData, orangeData.indexOf("0"), orangeData.indexOf("2"));
		
	}
	public class DataItem
	{
		private int mParentPos;
		private int mPtoC;//1 2 3 4 代表左右上下
		private String mParent;
		private String mData;
		public DataItem(String data,String parent,int ptoc,int ppos) {
			mData=data;
			mParent=parent;
			mPtoC=ptoc;
			mParentPos=ppos;
		}
		public int getPtoC() {
			return mPtoC;
		}
		public void setPtoC(int mPtoC) {
			this.mPtoC = mPtoC;
		}
		public String getParent() {
			return mParent;
		}
		public void setParent(String mParent) {
			this.mParent = mParent;
		}
		public String getData() {
			return mData;
		}
		public void setData(String mData) {
			this.mData = mData;
		}
		public int getParentPos() {
			return mParentPos;
		}
		public void setParentPos(int mParentPos) {
			this.mParentPos = mParentPos;
		}
	}
}
2、Puzzle.java

public class Puzzle {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String str="573146820";
		AnswerUtil answer=new AnswerUtil(str, 3);
		answer.getAnswer();
	}

}

将原图分成9块,分别编号为1234567890,所以一个打乱的编号比573146820,只要按照一定规则变换到原始的有序顺序就解决了问题。


主要的思想不是很难,主要是利用9宫格的状态图变换来进行计算的,具体的算法步奏如下:

1、将第一初始的状态push进队列queue,这里用List不用queue的目的是为了找到目标后可以递归回退回来找到路径,就是为了模拟queue但是数据不出队用的。

2、循环从队列取数据,先判断如果是目标状态就打印路径并返回,如果不是就从这个状态能变换到的状态都压入队列。

3、队列指针向后移动,知道队列为空。

计算的结果的速度可能要等一会,计算量有点大。下面再贴一下C++的代码,本来想用C++来提高计算速度的,结果不随人愿啊,比Java还慢受不了,可能还是代码有点问题,希望懂C++的可以看一下,具体的问题,有能提高效率的地方,大家可以积极留言。

#include <list>
#include <string>
#include <iostream>
using namespace std;

class DataItem
{
	public:
		 int mPtoC;//1 2 3 4 代表左右上下
		 list<DataItem>::iterator *mParent;
		 string mData;
		 DataItem(string data,list<DataItem>::iterator *parent,int ptoc) 
		{
			mData=data;
			mParent=parent;
			mPtoC=ptoc;
		}	
};
list<DataItem> datas;
string swap(string str,int x,int y);
int isExist(string str);
void printPath(list<DataItem>::iterator *idx);
int main()
{
	int deltax[]={-1,1,0,0};
	int deltay[]={0,0,-1,1};
	string originalstr="573146820";
	string aimstr="123456780";
	DataItem item(originalstr,NULL,0);
	list<DataItem>::iterator idx;
	int lineItems=3;
	int count=0;
	datas.clear();
	datas.push_back(item);
	idx=datas.begin();
	cout<<"calulator the result.please waiting ..."<<endl;
	while(idx!=datas.end())
	{
		int zero_xy=idx->mData.find('0');
		if(count++%1000==0)
			cout<<count<<endl;
		if(zero_xy==8)
		{
			if(idx->mData==aimstr)
			{
				//find the answer
				cout<<"the ans pos="<<idx->mParent;
				printPath(&idx);
				break;
			}
		}
		int zero_x=zero_xy%lineItems;
		int zero_y=zero_xy/lineItems;
		int new_x,new_y;
		for(int i=0;i<4;i++)
		{
			new_x=zero_x+deltax[i];
			new_y=zero_y+deltay[i];
			if(new_x>=0&&new_x<lineItems&&new_y>=0&&new_y<lineItems)
			{
				string str=swap(idx->mData,zero_xy, new_y*lineItems+new_x);;
				if(!isExist(str))
				{
					DataItem tmp(str,&idx,i+1);
					datas.push_back(tmp);
				}
			}
		}
		idx++;
	}

	//cout<<aimstr[1]<<endl;
	return 0;
}

string swap(string str,int x,int y)
{
	string str1=str;
	char tmp=str1[x];
	str1[x]=str1[y];
	str1[y]=tmp;
	return str1;
}

int isExist(string str)
{
	list<DataItem>::iterator i;
	for(i=datas.begin();i!=datas.end();i++)
	{
		if(i->mData==str)
			return 1;
	}
	return 0;
}

void printPath(list<DataItem>::iterator *idx)
{
	if(*idx==datas.begin())
		return;
	cout<<(*idx)->mPtoC;
	printPath((*idx)->mParent);
}
代码有点乱,仓促之间写的,还望海涵。估计是用了STL造成的,估计直接用数组去改进一下,可能能提高速度。




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值