小游戏五子连珠消除解决方案
序言
五子连珠,顾名思义就是当有五个相同的球在一条直线上,横,竖,斜,总共四个方向呈《米》型的消除规则,达到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("\n"); 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("\n"); 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 }
棋盘初始化完成;
如何消除棋子;
如何只是横向或者纵向,我们想很多人都知道。
我先看一段简单代码
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 }
查看一下结果
消除成功;
看到这里,可能还没有发现一个问题
我们修改一下测试代码,我刚才测试代码的第一个球的颜色改为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 }
这是寻找格子的基本算法,愿意的可以打开看看;
如果说这不是重点那么什么才是重点?
其实上面的代码不知道你们发现了没有;其实是再一次移动棋子后去调用执行查找的,每一次都要重新组装棋子。
其实我们是不是可以一次性把棋子组装完成?
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("\n"); 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("\n"); 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个相同的只会消除,然后继续玩;
所以算法稍稍不同,但是基本也是大同小异;
跪求保留标示符 /** * @author: Troy.Chen(失足程序员, 15388152619) * @version: 2021-07-20 10:55 **/ C#版本代码 vs2010及以上工具可以 java 开发工具是netbeans 和 idea 版本,只有项目导入如果出现异常,请根据自己的工具调整 提供免费仓储。 最新的代码地址:↓↓↓ https://gitee.com/wuxindao 觉得我还可以,打赏一下吧,你的肯定是我努力的最大动力