小游戏五子连珠消除解决方案

序言

五子连珠,顾名思义就是当有五个相同的球在一条直线上,横,竖,斜,总共四个方向呈《米》型的消除规则,达到5个或者5个以上

但是我们的五子连珠不是达到五个就结束,只是连续相同的5个或者5个以上的棋子会被消除同时增加对应的积分;

我们的设计是棋盘上 是 8 * 8 坐标格子,

总共有6总颜色的球,五个独立颜色(色号1-5),一个是彩色叫万能替代球(色号6);

还有一个附加状态是球有爆炸效果

棋子在棋盘上可以沿着四个方向移动,然后移动到需要移动的地方,所以这里采用A*算法来做格子移动;

如果移动棋子没有可以消除的棋子,棋盘上会随机刷出三个新的球;

设计

 先设计基本棋盘代码,完成基础存储功能 

 1 import java.io.Serializable;
 2 
 3 /**
 4  * @author: Troy.Chen(失足程序员 , 15388152619)
 5  * @create: 2020-11-23 22:37
 6  **/
 7 public class Wzlz implements Serializable {
 8 
 9     private static final long serialVersionUID = 1L;
10 
11     /*用于A* 算法的移动寻路导航,*/
12     protected int[][] blockCells;
13     /*棋盘上每个格子状态*/
14     protected Qiu[][] qiuCells;
15 
16     public Wzlz() {
17         blockCells = new int[8][8];
18         qiuCells = new Qiu[8][8];
19         for (int z = 0; z < blockCells.length; z++) {
20             for (int x = 0; x < blockCells[z].length; x++) {
21                 blockCells[z][x] = 0;
22                 qiuCells[z][x] = new Qiu(0, x, z);
23             }
24         }
25     }
26 
27     public class Qiu {
28         /*1-5是五个颜色的球,6是彩色万能球*/
29         private int qiuId;
30         private int x;
31         private int z;
32         private int zhadan;
33 
34         public Qiu() {
35         }
36 
37         public Qiu(int qiuId, int x, int z) {
38             this.qiuId = qiuId;
39             this.x = x;
40             this.z = z;
41         }
42 
43         public int getQiuId() {
44             return qiuId;
45         }
46 
47         public void setQiuId(int qiuId) {
48             this.qiuId = qiuId;
49         }
50 
51         public int getX() {
52             return x;
53         }
54 
55         public void setX(int x) {
56             this.x = x;
57         }
58 
59         public int getZ() {
60             return z;
61         }
62 
63         public void setZ(int z) {
64             this.z = z;
65         }
66 
67         public int getZhadan() {
68             return zhadan;
69         }
70 
71         public void setZhadan(int zhadan) {
72             this.zhadan = zhadan;
73         }
74     }
75 
76     public void print() {
77         StringBuilder stringBuilder = new StringBuilder();
78         stringBuilder.append("==============================================================");
79         stringBuilder.append("
");
80         for (int z = 0; z < qiuCells.length; z++) {
81             for (int x = 0; x < qiuCells[z].length; x++) {
82                 stringBuilder.append(qiuCells[z][x].getQiuId() + "(" + qiuCells[z][x].getZhadan() + ")" + ", ");
83             }
84             stringBuilder.append("
");
85         }
86         stringBuilder.append("==============================================================");
87         System.out.println(stringBuilder.toString());
88     }
89 }

初始化一下类,然后看一下棋盘打印

 1 import java.io.Serializable;
 2 
 3 /**
 4  * @author: Troy.Chen(失足程序员 , 15388152619)
 5  * @create: 2020-11-23 22:59
 6  **/
 7 public class WzlzMain implements Serializable {
 8 
 9     private static final long serialVersionUID = 1L;
10 
11     public static void main(String[] args) {
12         Wzlz wzlzTest = new Wzlz();
13         wzlzTest.print();
14     }
15 
16 
17     public static void test(int[][] cells, Wzlz.Qiu[][] qius, int x, int z, int qiu) {
18         /*设置格子阻挡信息*/
19         cells[z][x] = 1;
20         /*设置球的id*/
21         qius[z][x].setQiuId(qiu);
22     }
23 }
View Code

棋盘初始化完成;

如何消除棋子;

如何只是横向或者纵向,我们想很多人都知道。

我先看一段简单代码

 1     public static void xiaochu(int[][] cells, Wzlz.Qiu[][] qius) {
 2         Set<Wzlz.Qiu> qiuSet = new HashSet<>();
 3         /*消除横线算法*/
 4         for (int z = 0; z < qius.length; z++) {
 5             int qiuid = 0;
 6             List<Wzlz.Qiu> qiuList = new ArrayList<>();
 7             for (int x = 0; x < qius[z].length; x++) {
 8                 final Wzlz.Qiu qiu = qius[z][x];
 9                 if (qiu.getQiuId() == 0 || (qiuid != 0 && qiu.getQiuId() != 6/*不是万能球*/ && qiu.getQiuId() != qiuid)) {
10                     if (qiuList.size() >= 5) {
11                         qiuSet.addAll(qiuList);
12                     }
13                     qiuid = 0;
14                     qiuList.clear();
15                 }
16 
17                 if (qiu.getQiuId() != 0) {
18                     if (qiu.getQiuId() != 6) {
19                         /*记录除万能球在内的;连续球的数量*/
20                         qiuid = qiu.getQiuId();
21                     }
22                     qiuList.add(qiu);
23                 }
24             }
25             if (qiuList.size() >= 5) {
26                 qiuSet.addAll(qiuList);
27             }
28         }
29         for (Wzlz.Qiu qiu : qiuSet) {
30             qiu.setQiuId(0);
31             /*清理阻挡状态*/
32             cells[qiu.getZ()][qiu.getX()] = 0;
33         }
34     }

我们先来看一段消除横线连珠的代码

编写一下测试代码,这段代码折叠一下

 1     public static void main(String[] args) {
 2         Wzlz wzlzTest = new Wzlz();
 3         test(wzlzTest.blockCells, wzlzTest.qiuCells, 0, 0, 3);
 4         test(wzlzTest.blockCells, wzlzTest.qiuCells, 1, 0, 6);
 5         test(wzlzTest.blockCells, wzlzTest.qiuCells, 2, 0, 6);
 6         test(wzlzTest.blockCells, wzlzTest.qiuCells, 3, 0, 3);
 7         test(wzlzTest.blockCells, wzlzTest.qiuCells, 4, 0, 3);
 8         test(wzlzTest.blockCells, wzlzTest.qiuCells, 5, 0, 4);
 9         test(wzlzTest.blockCells, wzlzTest.qiuCells, 6, 0, 4);
10         wzlzTest.print();
11         xiaochu(wzlzTest.blockCells, wzlzTest.qiuCells);
12         wzlzTest.print();
13     }
View Code

查看一下结果

消除成功;

看到这里,可能还没有发现一个问题

我们修改一下测试代码,我刚才测试代码的第一个球的颜色改为1,把第6个球的颜色改3,也就是2-6是相同的5个颜色

再来看执行效果

可以看出来,棋子并没有被消除;

原因是这段代码是单链循环,

单身我们理想的效果是不是应该是这样?第一个,开始往后找,如果不对,从第二个开始往后找;

所以我们修改递归循环代码

 1 public static void xiaochu(int[][] cells, Wzlz.Qiu[][] qius) {
 2         Set<Wzlz.Qiu> qiuSet = new HashSet<>();
 3         /*消除横线算法*/
 4         for (int z = 0; z < qius.length; z++) {
 5             for (int x = 0; x < qius[z].length; x++) {
 6                 int qiuid = 0;
 7                 List<Wzlz.Qiu> qiuList = new ArrayList<>();
 8                 for (int x1 = x; x1 < qius[z].length; x1++) {
 9                     final Wzlz.Qiu qiu = qius[z][x1];
10                     if (qiu.getQiuId() == 0 || (qiuid != 0 && qiu.getQiuId() != 6/*不是万能球*/ && qiu.getQiuId() != qiuid)) {
11                         if (qiuList.size() >= 5) {
12                             qiuSet.addAll(qiuList);
13                         }
14                         qiuid = 0;
15                         qiuList.clear();
16                     }
17 
18                     if (qiu.getQiuId() != 0) {
19                         if (qiu.getQiuId() != 6) {
20                             /*记录除万能球在内的;连续球的数量*/
21                             qiuid = qiu.getQiuId();
22                         }
23                         qiuList.add(qiu);
24                     }
25                 }
26 
27                 if (qiuList.size() >= 5) {
28                     qiuSet.addAll(qiuList);
29                 }
30             }
31         }
32         for (Wzlz.Qiu qiu : qiuSet) {
33             qiu.setQiuId(0);
34             /*清理阻挡状态*/
35             cells[qiu.getZ()][qiu.getX()] = 0;
36         }
37     }

注意for里面的x和for里面的x1;这两个循环

来看看效果

第2-6个球成功消除;

横线消除,竖线消除其实就是一个道理,只是换一下循环方向就能实现;

暂时就不再赘述;

那么问题和难点在哪里?

其实因为消除规则是《米》字型的,也就是斜线消除;

其实根据刚才写法,找到消除规则和算法并不难;

只需要把x和z坐标都加一取下一个格子就能判断,就不在赘述;

 1 import com.ty.tools.dlog.DLogger;
 2 
 3 import java.io.Serializable;
 4 
 5 /**
 6  * @author: Troy.Chen(失足程序员 , 15388152619)
 7  * @create: 2020-11-18 10:37
 8  **/
 9 public class WzlzTest implements Serializable {
10 
11     private static final long serialVersionUID = 1L;
12     private static final DLogger log = DLogger.getLogger();
13 
14     public static void main(String[] args) {
15         int mx = 7;
16         int x = 0;
17         int z = 0;
18         /* todo         正方形的左上方的三角形 ↙↙↙↙            */
19         while (true) {
20             int z1 = z;
21             int x1 = x;
22             while (true) {
23                 System.out.print("[" + x1 + "," + z1 + "]");
24                 x1--;
25                 z1++;
26                 if (x1 < 0 || z1 > mx) {
27                     break;
28                 }
29             }
30             System.out.println();
31             if (x < 7) {
32                 x++;
33             } else if (z <= mx) {
34                 z++;
35             }
36 
37             if (x >= mx && z > mx) {
38                 break;
39             }
40         }
41         System.out.println("=================================================================");
42         x = 7;
43         z = 0;
44         /*    todo        从左边一直往右边斜 ↘↘↘↘            */
45         while (true) {
46             int z1 = z;
47             int x1 = x;
48             while (true) {
49                 System.out.print("[" + x1 + "," + z1 + "]");
50                 x1++;
51                 z1++;
52                 if (x1 > mx || z1 > mx) {
53                     break;
54                 }
55             }
56             System.out.println();
57             if (x > 0) {
58                 x--;
59             } else if (z <= mx) {
60                 z++;
61             }
62             if (z > mx && x <= 0) {
63                 break;
64             }
65         }
66         System.exit(0);
67     }
68 
69 }
View Code

这是寻找格子的基本算法,愿意的可以打开看看;

如果说这不是重点那么什么才是重点?

其实上面的代码不知道你们发现了没有;其实是再一次移动棋子后去调用执行查找的,每一次都要重新组装棋子。

其实我们是不是可以一次性把棋子组装完成?

  1 import java.io.Serializable;
  2 import java.util.ArrayList;
  3 import java.util.Iterator;
  4 import java.util.LinkedList;
  5 import java.util.List;
  6 
  7 /**
  8  * @author: Troy.Chen(失足程序员 , 15388152619)
  9  * @create: 2020-11-23 22:37
 10  **/
 11 public class Wzlz implements Serializable {
 12 
 13     private static final long serialVersionUID = 1L;
 14 
 15     /*用于A* 算法的移动寻路导航,*/
 16     protected int[][] blockCells;
 17     /*棋盘上每个格子状态*/
 18     protected Qiu[][] qiuCells;
 19     /*纵横交错的排列*/
 20     protected List<List<Wzlz.Qiu>> qiuLines = new LinkedList<>();
 21 
 22 
 23     public Wzlz() {
 24         blockCells = new int[8][8];
 25         qiuCells = new Qiu[8][8];
 26         for (int z = 0; z < blockCells.length; z++) {
 27             for (int x = 0; x < blockCells[z].length; x++) {
 28                 blockCells[z][x] = 0;
 29                 qiuCells[z][x] = new Qiu(0, x, z);
 30             }
 31         }
 32         resetHangline();
 33     }
 34 
 35     /**
 36      * 四个方向的组装
 37      */
 38     public void resetHangline() {
 39         if (qiuCells == null || qiuCells.length < 1) {
 40             return;
 41         }
 42         qiuLines = new ArrayList<>();
 43         /* todo    组装 横着的行数据 → */
 44         for (int z = 0; z < qiuCells.length; z++) {
 45             List<Wzlz.Qiu> line = new LinkedList<>();
 46             for (int x = 0; x < qiuCells[z].length; x++) {
 47                 line.add(qiuCells[z][x]);
 48             }
 49             qiuLines.add(line);
 50         }
 51 
 52         /* todo    组装 竖着的行数据 → */
 53         for (int x = 0; x < qiuCells[0].length; x++) {
 54             List<Wzlz.Qiu> line = new LinkedList<>();
 55             for (int z = 0; z < qiuCells.length; z++) {
 56                 line.add(qiuCells[z][x]);
 57             }
 58             qiuLines.add(line);
 59         }
 60 
 61         int mx = qiuCells.length - 1;
 62         int x = 0;
 63         int z = 0;
 64         /* todo    组装  正方形的左上方的三角形 ↙↙↙↙            */
 65         while (true) {
 66             int z1 = z;
 67             int x1 = x;
 68             List<Wzlz.Qiu> line = new LinkedList<>();
 69             while (true) {
 70                 line.add(qiuCells[z1][x1]);
 71 //                System.out.print("[" + x1 + "," + z1 + "]");
 72                 x1--;
 73                 z1++;
 74                 if (x1 < 0 || z1 > mx) {
 75                     break;
 76                 }
 77             }
 78             qiuLines.add(line);
 79 //            System.out.println();
 80             if (x < 7) {
 81                 x++;
 82             } else if (z <= mx) {
 83                 z++;
 84             }
 85             if (x >= mx && z > mx) {
 86                 break;
 87             }
 88         }
 89 
 90         x = qiuCells.length - 1;
 91         z = 0;
 92         /*    todo        从左边一直往右边斜 ↘↘↘↘            */
 93         while (true) {
 94             int z1 = z;
 95             int x1 = x;
 96             List<Wzlz.Qiu> line = new LinkedList<>();
 97             while (true) {
 98 //                System.out.print("[" + x1 + "," + z1 + "]");
 99                 line.add(qiuCells[z1][x1]);
100                 x1++;
101                 z1++;
102                 if (x1 > mx || z1 > mx) {
103                     break;
104                 }
105             }
106             qiuLines.add(line);
107 //            System.out.println();
108             if (x > 0) {
109                 x--;
110             } else if (z <= mx) {
111                 z++;
112             }
113             if (z > mx && x <= 0) {
114                 break;
115             }
116         }
117         for (Iterator<List<Wzlz.Qiu>> integerIterator = qiuLines.iterator(); integerIterator.hasNext(); ) {
118             List<Wzlz.Qiu> next = integerIterator.next();
119             if (next.size() < 5) {
120                 integerIterator.remove();
121             }
122         }
123     }
124 
125     public class Qiu {
126         /*1-5是五个颜色的球,6是彩色万能球*/
127         private int qiuId;
128         private int x;
129         private int z;
130         private int zhadan;
131 
132         public Qiu() {
133         }
134 
135         public Qiu(int qiuId, int x, int z) {
136             this.qiuId = qiuId;
137             this.x = x;
138             this.z = z;
139         }
140 
141         public int getQiuId() {
142             return qiuId;
143         }
144 
145         public void setQiuId(int qiuId) {
146             this.qiuId = qiuId;
147         }
148 
149         public int getX() {
150             return x;
151         }
152 
153         public void setX(int x) {
154             this.x = x;
155         }
156 
157         public int getZ() {
158             return z;
159         }
160 
161         public void setZ(int z) {
162             this.z = z;
163         }
164 
165         public int getZhadan() {
166             return zhadan;
167         }
168 
169         public void setZhadan(int zhadan) {
170             this.zhadan = zhadan;
171         }
172     }
173 
174     public void print() {
175         StringBuilder stringBuilder = new StringBuilder();
176         stringBuilder.append("==============================================================");
177         stringBuilder.append("
");
178         for (int z = 0; z < qiuCells.length; z++) {
179             for (int x = 0; x < qiuCells[z].length; x++) {
180                 stringBuilder.append(qiuCells[z][x].getQiuId() + "(" + qiuCells[z][x].getZhadan() + ")" + ", ");
181             }
182             stringBuilder.append("
");
183         }
184         stringBuilder.append("==============================================================");
185         System.out.println(stringBuilder.toString());
186     }
187 }

于是有了以上代码,第一次初始化就把横线,纵向,斜线的连线全部组装完成

 1 import java.io.Serializable;
 2 import java.util.ArrayList;
 3 import java.util.HashSet;
 4 import java.util.List;
 5 import java.util.Set;
 6 
 7 /**
 8  * @author: Troy.Chen(失足程序员 , 15388152619)
 9  * @create: 2020-11-23 22:59
10  **/
11 public class WzlzMain implements Serializable {
12 
13     private static final long serialVersionUID = 1L;
14 
15     public static void main(String[] args) {
16         Wzlz wzlzTest = new Wzlz();
17         test(wzlzTest.blockCells, wzlzTest.qiuCells, 0, 0, 1);
18         test(wzlzTest.blockCells, wzlzTest.qiuCells, 1, 1, 6);
19         test(wzlzTest.blockCells, wzlzTest.qiuCells, 2, 2, 6);
20         test(wzlzTest.blockCells, wzlzTest.qiuCells, 3, 3, 3);
21         test(wzlzTest.blockCells, wzlzTest.qiuCells, 4, 4, 3);
22         test(wzlzTest.blockCells, wzlzTest.qiuCells, 5, 5, 3);
23         test(wzlzTest.blockCells, wzlzTest.qiuCells, 6, 6, 4);
24         wzlzTest.print();
25         xiaochu(wzlzTest.blockCells, wzlzTest.qiuLines);
26         wzlzTest.print();
27     }
28 
29 
30     public static void test(int[][] cells, Wzlz.Qiu[][] qius, int x, int z, int qiu) {
31         /*设置格子阻挡信息*/
32         cells[z][x] = 1;
33         /*设置球的id*/
34         qius[z][x].setQiuId(qiu);
35     }
36 
37     public static void xiaochu(int[][] cells, List<List<Wzlz.Qiu>> qiuLines) {
38         Set<Wzlz.Qiu> xiaochu = new HashSet<>();
39         for (List<Wzlz.Qiu> line : qiuLines) {
40             for (int i = 0; i < line.size(); i++) {
41                 int qid = 0;
42                 List<Wzlz.Qiu> list = new ArrayList<>();
43                 for (int k = i; k < line.size(); k++) {
44                     Wzlz.Qiu qiu = line.get(k);
45                     if (qiu.getQiuId() == 0 || (qid != 0 && qid != qiu.getQiuId() && qiu.getQiuId() != 6)) {
46                         if (list.size() >= 5) {
47                             /*todo 前面都是连续相同的*/
48                             xiaochu.addAll(list);
49                         }
50                         /*到这里就表示没有相同的棋子需要清理*/
51                         qid = 0;
52                         list.clear();
53                     }
54                     if (qiu.getQiuId() > 0) {
55                         if (qiu.getQiuId() != 6) {
56                             qid = qiu.getQiuId();
57                         }
58                         list.add(qiu);
59                     }
60                 }
61                 if (list.size() >= 5) {
62                     /*先查找最后消除*/
63                     xiaochu.addAll(list);
64                 }
65             }
66         }
67         for (Wzlz.Qiu qiu : xiaochu) {
68             qiu.setQiuId(0);
69             /*球阻挡清空*/
70             cells[qiu.getZ()][qiu.getX()] = 0;
71         }
72     }
73 
74 }

调整消除代码,这样每次获取连线代码都变得简单清晰

总结:

其实网上算法很多;但是基本都是一次性的,也就是说他们是正中的五子棋,因为只要有五个连珠的棋子就结束了需要重新来;

但是我们这个变种的。有5个相同的只会消除,然后继续玩;

所以算法稍稍不同,但是基本也是大同小异;

原文地址:https://www.cnblogs.com/shizuchengxuyuan/p/14027912.html