小遊戲五子連珠消除解決方案

失足程式設計師發表於2020-11-24

序言

五子連珠,顧名思義就是當有五個相同的球在一條直線上,橫,豎,斜,總共四個方向呈《米》型的消除規則,達到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 }
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("\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個相同的只會消除,然後繼續玩;

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

 

相關文章