消消乐是个比较经典的游戏;这个过程的操作用计算机来模拟也比较简单,深度遍历即可。一般都能找到很好的解,下面通过穷举法寻找最优解。相关说明如下:
消消乐攻略;
1,对于5种颜色初始分别用1,2,3,4,5表示出来,这里用int和String都是一样,例子用int;当该块中的单元格被消除则该格消失。
两个出发点,<1>根据格的属性出发,每个格看做是唯一的;一个个的进行周边匹配;遍历过程后。
<2>常规解答---就是我们人工消消乐的解答过程
2,解答思路;
对于这样的一个二维矩阵;
Class——Node生成一个类记录单元格Node
单元格
格属性:颜色,位置,是否被占有;
Class——Pile我们生成一个类专门来存储块[上下左右],分为5中颜色的各个位置的块,不能分的记为
块属性:Zip()的编号,首次遍历的位置[m,n],当前块的颜色[数字‘’],当前块的个数,消除后的得分块数的平方;块编号
当前块的个数>1 称为有效块;
个数 = 1 称为无效块
Class——Zip对应的是界面的变化View类;补充:后面用View代替了,功能和思想没变;
对于每一步的消除都会重新产生一个界面,称之为簇<由块形成>;
簇属性:当前步数,当前分数,当前界面矩阵,已经点击过的消除块[,]集合
----------------------<类定义说明完毕>--------------
访问路线:
首先访问每个单元格;对应单元格的类进行上下左右的匹配进行分块,横向遍历,上下左右匹配,直到上下左右界都是别的颜色为止。记录出块Zip;
若该单元格已被块占有,则跳过继续进行访问产生新的zip直到访问单元格从00->NN结束;
----------------------<Pile生成完毕>------------------
3,解答过程
消除攻略
遍历法,对每个zip进行访问,当对应编号的zip进行消除时,挪动;产生新的团。再进行分Pile生成new Zip继续
直到有效块的个数为0结束。
-------------穷举解答完毕----------------------------
程序流程
<1>---个体_包------生成三个类----------
<2>-----操作_包 ----操作类-------
分块方法<计算机识别,穷举>
消除方法:<消除之后进入下个状态>zip1 -> zip2
afterClick<zip, int(pile的编号)> == new Zip->setElectedPiles ArrayList<Pile > ---
若size>0继续细分;否则-|return;
//中间对Zip进行分块是否有有效块,就是有效块的个数>0;
<Pile 的位置和得分记录下来>---------每次进行迭代遍历的时候,预计点击哪一个块的时候,记录其Pile.local,个数;局数;返回各个状态下的得分
---------<优化前>-------------
对每一个待消除块进行访问,若被消除,则上面的下移即可。
----------<消除过程优化>------------
当要消除一堆时;解决思路;就是对格中的纵轴进行访问;若格的下方还有格的话<列相同>,一起消;用集合来表示;
<3>---最后一个Test类——————————
生成Pile类的方法;
其中Node
int value;//颜色,对应的数值
int local;//位置,用代号表示;0-99
boolean used;//主要是在下一列的遍历中捕捉有没有被占用过
Pile
Zip zip;//传递个View进来;zip_num==开始了几次消除==这是单局中的第几次视图==初始可以设为0;往后++
ArrayList<Node> pileLocalAl;//块里面存储的位置集合
int local_;//块的位置;即在遍历过程中块的代表位置,例如一排选取第一个;
int count; //块的个数;------->对应块的个数的平方为分数
int num_pile;//块的编号
//ps这里块的个数 == 块的编号 == 块的pileLocalAl.size()+1
View
int[][] arr2;
ArrayList<Pile> pile;
int num;
Zip ___本来设置了,但是仔细想了下,没必要,所以用View代替了;还方面输出结果
int num_zip = 0;//初始为0,当进行了操作,消除操作,自动重新set++;
ArrayList<Node> view;//后续处理中所有的view都是zip的view
int grade = 0;
ArrayList<Integer> al_local;//已经点击过得local集合
基本类处理的程序;Sheel类;对对象进行相应的处理便于后期的操作;
package com.xiaoxiaole.Name;
/**
* 消消看 <生成阵>
* -------------工具类----------------
*/
import java.util.ArrayList;
import java.util.HashMap;
import com.xiaoxiaole.Test.Data;
//建立一个sheel,对每一个数字建立一个新的Node/sheel
//Note,当调用一个setNode的时候,其他的几个也要同时调用,这是一个界面需要的全部数据的操作
public class Sheel {
static int val;
public static boolean flag = true;
//对于每一个视图都有一个sheel阵;阵里面包含所有的初始信息;zip[0]
public static ArrayList<Node> setNode() {
int[][] array2 = Data.setArray2(10);
ArrayList<Node> al = new ArrayList<>();
for (int i = 0; i < array2.length; i++) {
for (int j = 0; j < array2.length; j++) {
Node node = new Node();
node.setValue(array2[i][j]);
node.setUsed(false);
node.setLocal(10*i + j);
al.add(node);
}
}
return al;
}
//重新建立一个HashSet能够根据local控制对象的变化。
public static HashMap<Integer, Node> getHsNode(ArrayList<Node> al2){
HashMap<Integer,Node> hm = new HashMap<>();
for (Node node : al2) {
hm.put(node.getLocal(), node);
}
return hm;
}
//遍历每一个Node阵;分出我们想要的块出来,,,这个Pile是个小Pile;仅仅作用于当前的zip下《这里也可以传进来一个Zip》
public static ArrayList<Pile> setPiles(ArrayList<Node> view){
System.out.println("====开始建立View下的Piles集合====");
ArrayList<Pile> alp = new ArrayList<>();
int jj = 0;
for (int i = 0; i < 100; i++) {
ArrayList<Node> al_demo = new ArrayList<Node>();//需要用到和需要返回
Pile pile = new Pile();
setPile(pile, al_demo,i, view,true);
if(!flag){//判断是否为有效块;若是,则添加到块集合Piles中,flag =false,表示最少有2个一起的
pile.setNum_pile(jj);
alp.add(pile);
jj++;
}
al_demo = null;//初始化全局变量,便于函数再次引用
flag = true;
}
return alp;
}
public static void setPile(Pile pile,ArrayList<Node> al_demo,int local_, ArrayList<Node> view, boolean flag2){
Node node = view.get(local_);
if(node.used == true) return;
al_demo.add(node);//在Pile原本为空的node集合中添加Node;
node.setUsed(true);
if (flag2) {
val = node.value;
pile.setLocal_(local_);
}
int i = node.local/10;
int j = node.local%10;
int[] local_ar1 = set4cell(i, j);
for (int k = 0; k < local_ar1.length; k++) {
if (isUsual(local_ar1[k])) {
if(val == view.get(local_ar1[k]).value && !view.get(local_ar1[k]).used){
flag = false;
setPile(pile, al_demo,local_ar1[k], view, false);
}
}
}
pile.setPileLocalAl(al_demo);
}
//判断下标是在界内,专门为Pile的遍历下标预备的————这里的9是对应10*10的9;
public static boolean isUsual(int k){
if (k>=0 && k<=99) return true;
return false;
}
public static int[] set4cell(int i,int j){
int[] arr1 = new int[4];
arr1[0] = 10*(i-1) + j;
arr1[1] = 10*(i+1) + j;
arr1[2] = 10*i + j-1;
arr1[3] = 10*i + j+1;
return arr1;
}
//setView建立View函数;
public static ArrayList<Node> setView(int[][] array2){
ArrayList<Node> view = new ArrayList<>();
for (int i = 0; i < array2.length; i++) {
for (int j = 0; j < array2.length; j++) {
Node node = new Node();
node.setValue(array2[i][j]);
node.setUsed(false);
node.setLocal(10*i + j);
view.add(node);
}
}
return view;
}
}
关于工具类的处理方法:
这里有待优化,正在努力中。一般通过看程序内容就能知道具体编译的类是什么结构;所以不详述,需要优化的结构有很多,同样对于程序,我们可以不尝试用Np用其他遍历方法或者经典想法的方案也不错。
package com.xiaoxiaole.Opreate;
import java.util.ArrayList;
import com.xiaoxiaole.Name.Node;
import com.xiaoxiaole.Name.Pile;
import com.xiaoxiaole.Name.Sheel;
import com.xiaoxiaole.Name.View;
import com.xiaoxiaole.Name.Zip;
import com.xiaoxiaole.Test.Test;
public class Tool {
public static ArrayList<Pile> piles;
//传递进来的是块local_,也就是可以对应点击的local,现在改local_对应的Pile要消失了
public static View xiaochu(View view,int num){
View view2 = new View();
ArrayList<Node> nodes = exchangeView(Sheel.setView(view.getArr2()), view.getPile().get(num));
view2.setNum(view.getNum()+1);
view2.setArr2(ExchangeNodeToArray.exchangeNodeToArray(nodes));
view2.setPile(Sheel.setPiles(nodes));
return view2;
}
//传进来的是一个pile对象和前视图;Pile为View的一个取个元素
public static ArrayList<Node> exchangeView(ArrayList<Node> view1, Pile pile){
int[] arr = new int[10];//10列;0-9,数组值为块中对应列的待消除数
int[] hang_mins = new int[10];
for (int i = 0; i < hang_mins.length; i++) {
hang_mins[i] = 10;//初始化hang最下值
}
ArrayList<Node> al = pile.getPileLocalAl();
for (Node node : al) {//在这里多遍历了集合,应该发现一个,就删除一个
int hang = node.getLocal()/10;
int lie = node.getValue()%10;
for (int i = 0; i < arr.length; i++) {
if(hang <= hang_mins[i]){
hang_mins[i] = hang;
}
if(i==lie){
arr[lie] = arr[lie] + 1;
}
}
}
for (int i = 0; i < hang_mins.length; i++) {
lieXiaoChu(view1,i, arr[i], hang_mins[i]);
}
System.out.println("消除了一个Pile,产生新的视图");
return view1;
}
//传递进来Node视图,列lie,列中行的个数arr[lie];最小行min_hang
public static void lieXiaoChu(ArrayList<Node> view,int lie, int lie_count, int min_hang){
//消除lie_count列;所以把上方的下移 hang+lie_count -1 个单位,再把本身Node的value置为0;
for(int hang = 0; hang< min_hang ;hang++){
view.get(10*hang + lie + 10*lie_count).setValue(view.get(hang).getValue());
}
for (int hang = 0; hang < lie_count; hang++) {
view.get(10*hang + lie).setValue(0);
}
}
//传进来的是一个pile对象和前视图;还可以优化做其他的操作;
public static ArrayList<Node> exchangeView1(ArrayList<Node> view1, Pile pile){
int[] arr = new int[10];//10列;0-9,数组值为块中对应列的待消除数
for (int i = 0; i < arr.length; i++) {
int min_hang = 100;
int lie = 0;
for (Node node : pile.getPileLocalAl()) {
lie = node.getLocal()%10;
int hang = node.getLocal()/10;
arr[lie] = arr[lie] + 1;
if (hang <= min_hang) {
min_hang = hang;
}
}
lieXiaoChu(view1, lie, arr[lie], min_hang);
}
System.out.println("消除了一个Pile,产生新的视图");
return view1;
}
}
Data类;10X10消消乐随机建成;setArray2(10);附带提供一个打印二维数组的小方法。
public static int[][] setArray2(int n){
//生成5个特征元素组成的数组;
int[][] arr2 = new int[n][];
for (int i = 0; i < n; i++) {
arr2[i] = new int[n];
for (int j = 0; j < n; j++) {
double k = Math.random();
arr2[i][j] = (int)( 5* k) + 1;
}
}
return arr2;
}
public static void printArray2(int[][] arr2){
System.out.print("打印型号 "+arr2.length +"X"+ arr2.length +" 的二维数组");
for (int i = 0; i < arr2.length; i++) {
System.out.println();
for (int j = 0; j < arr2.length; j++) {
System.out.print(arr2[i][j]);
if (j<arr2.length - 1) {
System.out.print(",");
}
}
}
}
纯属娱乐;后期有优化再更新!