PS:这学期期末成绩差不多出完了,接下来会陆续把这学期课程中的代码陆续扔到这里来以便后人****,同时自己也留个纪念。
本学期选了java选修,期末大作业面向GitHub编程写了个中国跳棋。代码中还有写小bug,不过懒得调了...
1.游戏介绍
中国跳棋,简称跳棋,是一种可以让二至六人一起玩的棋,棋盘为六角星形状,棋子一般分为六种颜色,每种颜色有10或15枚棋子(或弹珠),每一位玩家占一个角,执一种颜色的棋子,如果玩的人数较,也能每人执两种颜色的棋子玩。
游戏规则如下:
先将一种颜色的棋子按规则全部放在一个角上,各人循顺时针或逆时针方向轮流走子,每次只能动一枚棋子,全部棋子先到达对角那一边的为赢家。棋子有两种走法:
1)一枚棋子移动到相邻六格其中一格。
2)“搭桥”:自己的棋子(A)同一条直线上还有一枚棋子(B),不限属于哪一方,大家之间没有任何棋子阻隔。如果B的另一方也没有棋子阻隔,A就可以跳到B的相反方向,而且和两枚棋子原来的距离一样。跳跃可以一直进行下去,直到没有前进的路径为止。如果有循环情况,可在任意一处停下。
2.项目介绍
1)本跳棋project支持两人、四人、六人跳棋对战
2)具有计时功能,可显示当前时间,同时也可判断当前玩家是否超时
3)游戏可暂停
4)可保存当前局面,从本地打开已有文件(文件I/O)
3.游戏界面
4.工程布局(太懒了直接把所有class写在了一个文件里)
5.代码
1 import java.awt.Color;
2 import java.awt.Font;
3 import java.awt.Image;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import java.awt.event.KeyEvent;
7 import java.awt.event.MouseAdapter;
8 import java.awt.event.MouseEvent;
9 import java.io.File;
10 import java.io.FileNotFoundException;
11 import java.io.IOException;
12 import java.io.PrintWriter;
13 import java.text.SimpleDateFormat;
14 import java.util.Date;
15 import java.util.Scanner;
16
17 import javax.imageio.ImageIO;
18 import javax.management.MBeanOperationInfo;
19 import javax.swing.ImageIcon;
20 import javax.swing.JFileChooser;
21 import javax.swing.JFrame;
22 import javax.swing.JLabel;
23 import javax.swing.JLayeredPane;
24 import javax.swing.JMenu;
25 import javax.swing.JMenuBar;
26 import javax.swing.JMenuItem;
27 import javax.swing.JOptionPane;
28
29
30
31 public class ChineseChecker {
32
33 public static MyFrame myFrame;
34 public static int numberOfPlayers; //游戏玩家的数量
35 public static boolean numbersDone = false;//游戏玩家数量是否设定完毕
36 public static boolean gameStatus = false;//游戏状态(是否暂停)
37 public static char[] series = new char[6];//六种棋子
38 public static int currentIndex = 0;//当前下标
39 public static String pieceToMove;//将要移动的棋子
40 public static int []piecePos;//记录棋子位置
41 public static boolean isPieceToMoveAcquired = false;//是否已经选中将要移动的棋子
42 public static boolean isTheStartingOfTheGame = false;//游戏是否开始
43 public static boolean isPositionToGoToAcquired = false;//将要去的位置是否设定完毕
44 public static int[] posToGoTo;
45 public static boolean isANewGame = false;
46
47 public static void main(String[] args) {
48 // TODO Auto-generated method stub
49 myFrame = new MyFrame();//实例化窗口
50 myFrame.setSize(710, 870);//设置窗口大小
51 myFrame.setVisible(true);//窗口可见
52 Pieces pieces = new Pieces();//实例化棋子类
53
54 /**等待设定游戏玩家数量**/
55 while(!numbersDone){
56 try {
57 Thread.sleep(500);
58 } catch (InterruptedException e) {
59 // TODO Auto-generated catch block
60 e.printStackTrace();
61 }
62 }
63 numbersDone = false;
64
65 /*
66 * 游戏分为双人对战,四人对战和六人对战
67 */
68 switch (numberOfPlayers) {
69 case 2:
70 series[0] = 'D';series[1] = 'A';
71 break;
72 case 4:
73 series[0] = 'F';series[1] = 'B';series[2] = 'C';series[3] = 'E';
74 break;
75 case 6:
76 series[0] = 'F';series[1] = 'A';series[2] = 'B';series[3] = 'C';series[4] = 'D';series[5] = 'E';
77 break;
78 default:
79 break;
80 }
81 //pieces.init();
82 myFrame.init(series);
83 initPlayers(series);
84
85 pieces.init();
86
87 /**一旦玩家数量设定完成,游戏开始**/
88 isTheStartingOfTheGame = true;
89
90 while (true) {
91 Trace.isSkipped = false;
92
93 Trace.nextStep();
94
95 //展示当前玩家
96 myFrame.showCurrent();
97 myFrame.showCurrentPlayer();
98 MyFrame.timer = new Timer();
99
100
101 while (!isPositionToGoToAcquired) {
102
103 if (MyFrame.timer.listen() <= 0) {//如果玩家超时
104 if (isPieceToMoveAcquired) //如果将要移动的的棋子设定过
105 PieceActionListener.clearPossiblePos();//清除之前的可能移动到的合法位置标记
106 pieceToMove = series[currentIndex] + "0";
107 piecePos = Pieces.getPiecePos("A0 ");
108 posToGoTo = piecePos ;
109 Services.msg("Player " + series[currentIndex] + " time exceeded!");//提示玩家超时
110 break;
111 }
112 if (Trace.isSkipped)//如果已经跳过了,就退出
113 break;
114 try {
115 Thread.sleep(0500);
116 } catch (InterruptedException e) {
117 // TODO Auto-generated catch block
118 e.printStackTrace();
119 }
120 }
121 if (Trace.isSkipped) continue;//如果已经跳过了,就到下一次循环
122 isPositionToGoToAcquired = false;
123 if (isANewGame) {
124 isANewGame = false;
125 continue;
126 }
127 /*记录轨迹 */
128 Pieces.moveAward(pieceToMove, piecePos, posToGoTo);
129 Trace.recordStep(pieceToMove, piecePos, posToGoTo);
130
131 /*判断是否出现胜利者*/
132 for (int order = 0; order < numberOfPlayers; order++) {
133 if (isWinner(series[order])) {
134 Services.msg("Player " + series[order] + " wins!");
135 System.exit(0);
136 }
137 }
138 Trace.step = Trace.step + 1;
139 }
140 }
141
142 public static void setNumber(int number){//设定游戏玩家数量
143 ChineseChecker.numbersDone = true;
144 ChineseChecker.gameStatus = true;
145 ChineseChecker.numberOfPlayers = number;
146 ChineseChecker.myFrame.mNewGame.setEnabled(false);
147 }
148
149 public static void initPlayers(char[] players) {//初始化players
150 for (char player : players) {
151 if (player == 0)
152 return;
153 int[][] initPositions = myFrame.zoneOfPlayer[player - 'A'];
154 for (int index = 0; index < 10; index++) {
155 Pieces.cell[initPositions[index][0]][initPositions[index][1]] = "" + player + index + " ";
156 }
157 }
158 }
159
160 public static boolean isWinner(char player) {//判断player是否已经获胜
161 char opponentPlayer = player < 'D' ? (char) ((int) player + 3) : (char) ((int) player - 3);
162
163 int[][] positionsBelongedToThePlayer = MyFrame.zoneOfPlayer[opponentPlayer - 'A'];
164
165 for (int index = 0; index < 10; index++) {
166 int[] position = positionsBelongedToThePlayer[index];
167 if (Pieces.cell[position[0]][position[1]].charAt(0) != player)
168 return false;
169 }
170 return true;
171 }
172
173 }
174
175 class MyFrame extends JFrame{
176
177 public Image image;
178
179 public ImageIcon imgBoard;
180 public static JLayeredPane panel;
181 public static JLabel lblBoard,lblPlayer,lblTime,lblCurrent;
182 public JMenuBar menuBar;
183 public JMenu mControl = new JMenu("control"),
184 mNewGame = new JMenu("New Game");
185 public JMenuItem mTwoPlayers = new JMenuItem("Two players"),
186 mFourPlayers = new JMenuItem("Four players"),
187 mSixPlayers = new JMenuItem("Six players"),
188 mExit = new JMenuItem("Exit", KeyEvent.VK_X),
189 mPauseGame = new JMenuItem("Pause Game", KeyEvent.VK_P),
190 mOpen = new JMenuItem("Open",KeyEvent.VK_O),
191 mSave = new JMenuItem("Save",KeyEvent.VK_S);
192 public JLabel[][] pieces = new JLabel[6][10];
193 public static final int[][][] zoneOfPlayer = {
194 {{5, 1}, {5, 2}, {6, 2}, {5, 3}, {6, 3}, {7, 3}, {5, 4}, {6, 4}, {7, 4}, {8, 4}},
195 {{1, 5}, {2, 6}, {2, 5}, {3, 7}, {3, 6}, {3, 5}, {4, 8}, {4, 7}, {4, 6}, {4, 5}},
196 {{5, 13}, {6, 13}, {5, 12}, {7, 13}, {6, 12}, {5, 11}, {8, 13}, {7, 12}, {6, 11}, {5, 10}},
197 {{13, 17}, {13, 16}, {12, 16}, {13, 15}, {12, 15}, {11, 15}, {13, 14}, {12, 14}, {11, 14}, {10, 14}},
198 {{17, 13}, {16, 12}, {16, 13}, {15, 11}, {15, 12}, {15, 13}, {14, 10}, {14, 11}, {14, 12}, {14, 13}},
199 {{13, 5}, {12, 5}, {13, 6}, {11, 5}, {12, 6}, {13, 7}, {10, 5}, {11, 6}, {12, 7}, {13, 8}}};
200 public static Timer timer;
201 public MyFrame(){
202
203 imgBoard = new ImageIcon("Board.jpg");
204 lblTime = new JLabel();
205 lblTime.setForeground(Color.BLUE);
206 lblTime.setFont(new Font("黑体", Font.BOLD, 20));
207 lblTime.setBounds(50, 50, 280, 30);
208
209 lblCurrent = new JLabel("当前玩家");
210 lblCurrent.setFont(new Font("当前玩家", 20, 20));
211 lblCurrent.setBounds(40, 80, 200, 30);
212
213 lblBoard = new JLabel(imgBoard);
214 lblBoard.setBounds(0, 20, 685, 800);
215
216 lblPlayer = new JLabel(new ImageIcon());
217 lblPlayer.setBounds(50, 100, 50, 50);
218
219 panel = new JLayeredPane();
220 panel.add(lblBoard,JLayeredPane.DEFAULT_LAYER);
221 panel.add(lblPlayer, JLayeredPane.MODAL_LAYER);
222 panel.add(lblTime, JLayeredPane.MODAL_LAYER);
223
224
225 setLayeredPane(panel);
226
227 mControl.setMnemonic(KeyEvent.VK_C);
228 mControl.add(mOpen);
229 mControl.add(mSave);
230 mControl.add(mNewGame);
231 mControl.add(mPauseGame);
232
233 mNewGame.add(mTwoPlayers);
234 mNewGame.add(mFourPlayers);
235 mNewGame.add(mSixPlayers);
236
237 menuBar = new JMenuBar();
238 menuBar.add(mControl);
239 setJMenuBar(menuBar);
240
241 /**设置两个玩家、四个玩家或六个玩家**/
242 mTwoPlayers.addActionListener(new ActionListener() {
243 @Override
244 public void actionPerformed(ActionEvent e) {
245 // TODO Auto-generated method stub
246 ChineseChecker.setNumber(2);
247 }
248 });
249 mFourPlayers.addActionListener(new ActionListener() {
250 @Override
251 public void actionPerformed(ActionEvent e) {
252 // TODO Auto-generated method stub
253 ChineseChecker.setNumber(4);
254 }
255 });
256 mSixPlayers.addActionListener(new ActionListener() {
257 @Override
258 public void actionPerformed(ActionEvent e) {
259 // TODO Auto-generated method stub
260 ChineseChecker.setNumber(6);
261 }
262 });
263 /**暂停游戏**/
264 mPauseGame.addActionListener(new ActionListener() {
265 @Override
266 public void actionPerformed(ActionEvent e) {
267 // TODO Auto-generated method stub
268 ChineseChecker.gameStatus = false;
269 }
270 });
271
272 mOpen.addActionListener(new ActionListener() {//打开已保存过的游戏
273 @Override
274 public void actionPerformed(ActionEvent arg0) {
275 JFileChooser chooser = new JFileChooser();
276 chooser.showOpenDialog(null);
277
278 try {
279 File file = chooser.getSelectedFile();
280 if (file == null) {
281 throw new Exception("FileNotExisted");
282 }
283 Scanner scanner = new Scanner(file);
284 String[] temp = scanner.nextLine().split(",");
285 int num = Integer.parseInt(temp[0]);
286 char cur = temp[1].charAt(0);
287 int curIndex = Integer.parseInt(temp[2]);
288 int step = Integer.parseInt(temp[3]);
289
290 ChineseChecker.numbersDone = true;
291 if (!(ChineseChecker.numberOfPlayers == num) && !ChineseChecker.isTheStartingOfTheGame)
292 throw new Exception("PlayersNumberUnmatched");
293 ChineseChecker.numberOfPlayers = num;
294 System.out.println(num);
295 ChineseChecker.currentIndex = curIndex;
296 ChineseChecker.series[curIndex] = cur;
297 Trace.step = step;
298 //Diagram.getDiagram().init();
299
300 while (!ChineseChecker.isTheStartingOfTheGame) {
301 }
302 while (scanner.hasNext()) {
303 in(scanner.nextLine());
304 }
305 ChineseChecker.myFrame.mNewGame.setEnabled(false);
306 ChineseChecker.isANewGame = true;
307 ChineseChecker.isPositionToGoToAcquired = true;
308 } catch (FileNotFoundException e) {
309 // e.printStackTrace();
310 } catch (Exception e) {
311 Services.msg("Import failed: " + e.getMessage());
312 }
313 }
314
315 public void in(String line) {
316 String[] temp = line.split(",");
317 String piece = temp[0] + " ";
318 int i = Integer.parseInt(temp[1]), j = Integer.parseInt(temp[2]);
319 int player = piece.charAt(0) - 65;
320 int index = piece.charAt(1) - 48;
321 Pieces.pieces[player][index][0] = i;
322 Pieces.pieces[player][index][1] = j;
323 Pieces.cell[i][j] = piece;
324 int[] pos = {i, j};
325 ChineseChecker.myFrame.move(piece,pos);
326 }
327 });
328
329 mSave.addActionListener(new ActionListener() {//保存当前游戏
330
331 @Override
332 public void actionPerformed(ActionEvent arg0) {
333 JFileChooser chooser = new JFileChooser();
334 chooser.showOpenDialog(null);
335 File file = chooser.getSelectedFile();
336
337 PrintWriter writer;
338 try {
339 writer = new PrintWriter(file);
340 writer.write(new Output().s);
341 writer.close();
342 } catch (FileNotFoundException e) {
343 // e.printStackTrace();
344 } catch (Exception e) {
345 Services.msg("Export failed!");
346 }
347 }
348
349 class Output {
350 String s = "";
351
352 Output() {
353 out();
354 }
355
356 void out() {
357 int num = ChineseChecker.numberOfPlayers;
358 System.out.println(num);
359 int[] position;
360 s += num;
361 char cur = ChineseChecker.series[ChineseChecker.currentIndex];
362 s += "," + cur;
363 int curIndex = ChineseChecker.currentIndex;
364 s += "," + curIndex;
365 int step = Trace.step;
366 s += "," + step;
367 char[][] player = {null, null, {'A', 'D'}, {'A', 'C', 'E'},
368 {'B', 'C', 'E', 'F'}, null,
369 {'A', 'B', 'C', 'D', 'E', 'F'}};
370 for (int i = 0; i < 10; i++) {
371 for (char j : player[num]) {
372 position = Pieces.getPiecePos(j - 65, i);
373 s += "\n" + j + i + "," + position[0] + "," + position[1];
374 }
375 }
376 }
377 }
378 });
379
380 TimerThread timerThread = new TimerThread("Timer");
381 timerThread.start();
382
383 }
384
385 public void showCurrent() {
386 panel.add(lblCurrent, JLayeredPane.MODAL_LAYER);
387 }
388
389 public void move(String pieceToMove, int[] targetPosition) {
390 char playerOnTheMove = pieceToMove.charAt(0);
391 int index = pieceToMove.charAt(1) - '0';
392 int x = Map.map[targetPosition[0]][targetPosition[1]][0];
393 int y = Map.map[targetPosition[0]][targetPosition[1]][1];
394
395 pieces[playerOnTheMove - 'A'][index].setBounds(x, y, 39, 39);
396 }
397
398 public void init(char[] playerSeries) {
399 for (char player : playerSeries) {
400 if (player == 0)
401 return;
402 initPlayer(player);
403 }
404 }
405
406 private void initPlayer(char player) {
407 for (int pieceIndex = 0; pieceIndex < 10; pieceIndex++) {
408 initPiece(player, pieceIndex);
409 }
410 }
411
412 private void initPiece(char player, int pieceIndex) {
413 //Image image =
414 Map myMap = new Map();
415 int playerIndex = player - 'A';
416 int[] pieceSeries = zoneOfPlayer[player - 'A'][pieceIndex];
417 int x = myMap.map[pieceSeries[0]][pieceSeries[1]][0];
418 int y = myMap.map[pieceSeries[0]][pieceSeries[1]][1];
419
420 pieces[playerIndex][pieceIndex] = new JLabel(new ImageIcon("Piece_" + player + ".PNG"));
421 pieces[playerIndex][pieceIndex]
422 .addMouseListener(new PieceActionListener("" + player + pieceIndex));
423
424 pieces[playerIndex][pieceIndex].setBounds(x, y, 39, 39);
425 panel.add(pieces[playerIndex][pieceIndex], JLayeredPane.MODAL_LAYER);
426 }
427
428 public static void showCurrentPlayer() {
429
430 lblPlayer.setIcon(new ImageIcon("Piece_" + ChineseChecker.series[ChineseChecker.currentIndex] + ".PNG"));
431 panel.repaint();
432 }
433
434
435 class TimerThread extends Thread {
436 TimerThread(String name) {
437 super(name);
438 }
439
440 @Override
441 public void run() {
442 while (true) {
443 lblTime.setText(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
444 panel.repaint();
445 try {
446 Thread.sleep(0500);
447 } catch (InterruptedException e) {
448 e.printStackTrace();
449 }
450 }
451 }
452 }
453
454 }
455
456 class Map {//map记录棋盘上每个点在myFrame中的坐标
457 //map[i][j][0]表示点(i,j)在棋盘中的横坐标,map[i][j][1]表示点(i,j)在棋盘中的纵坐标
458 public static int [][][] map = new int[18][18][2];
459 public Map(){//计算各点坐标,并将其存入map中
460 for (int i = 5; i <= 5; i++)
461 setSinglePosition(i, 1, 325 + 51 * (i - 5), 780 + 0 * (i - 5));
462 for (int i = 5; i <= 6; i++)
463 setSinglePosition(i, 2, 325 - 28 + 54 * (i - 5), 780 - 47);
464 for (int i = 5; i <= 7; i++)
465 setSinglePosition(i, 3, 325 - 28 * 2 + 54 * (i - 5), 780 - 47*2);
466 for (int i = 5; i <= 8; i++)
467 setSinglePosition(i, 4, 325 - 28 * 3 + 54 * (i - 5), 780 - 47*3);
468 for (int i = 1; i <= 13; i++)
469 setSinglePosition(i, 5, 0 + 28 * 0 + 54 * (i - 1), 780 - 47*4);
470 for (int i = 2; i <= 13; i++)
471 setSinglePosition(i, 6, 0 + 28 * 1 + 54 * (i - 2), 780 - 47*5);
472 for (int i = 3; i <= 13; i++)
473 setSinglePosition(i, 7, 0 + 28 * 2 + 54 * (i - 3), 780 - 47*6);
474 for (int i = 4; i <= 13; i++)
475 setSinglePosition(i, 8, 0 + 28 * 3 + 54 * (i - 4), 780 - 47*7);
476 for (int i = 5; i <= 13; i++)
477 setSinglePosition(i, 9, 0 + 28 * 4 + 54 * (i - 5), 780 - 47*8);
478 for (int i = 5; i <= 14; i++)
479 setSinglePosition(i, 10, 0 + 28 * 3 + 54 * (i - 5), 780 - 47*9);
480 for (int i = 5; i <= 15; i++)
481 setSinglePosition(i, 11, 0 + 28 * 2 + 54 * (i - 5), 780 - 47*10);
482 for (int i = 5; i <= 16; i++)
483 setSinglePosition(i, 12, 0 + 28 * 1 + 54 * (i - 5), 780 - 47*11);
484 for (int i = 5; i <= 17; i++)
485 setSinglePosition(i, 13, 0 + 28 * 0 + 54 * (i - 5), 780 - 47*12);
486 for (int i = 10; i <= 13; i++)
487 setSinglePosition(i, 14, 325 - 28 * 3 + 54 * (i - 10), 780 - 47*13);
488 for (int i = 11; i <= 13; i++)
489 setSinglePosition(i, 15, 325 - 28 * 2 + 54 * (i - 11),780 - 47*14);
490 for (int i = 12; i <= 13; i++)
491 setSinglePosition(i, 16, 325 - 28 * 1 + 54 * (i - 12), 780 - 47*15);
492 for (int i = 13; i <= 13; i++)
493 setSinglePosition(i, 17, 325 - 28 * 0 + 54 * (i - 13), 780 - 47*16);
494 }
495 public void setSinglePosition(int i,int j,double x,double y){
496 map[i][j][0] = (int)x;
497 map[i][j][1] = (int)y;
498 }
499 }
500
501 class Pieces {//棋子类
502 public static int [][][] pieces = new int [6][10][2];
503 public static String [][] cell = new String[20][20];
504 public final static String EMPTY_MARK = "** ";
505 public final static String OUTSIDE_MARK = " ";
506 public final static String SPACE_MARK = " ";
507
508 public Pieces(){
509
510 for (int i = 1; i <= 17; i++)
511 for (int j = 1; j <= 17; j++)
512 cell[i][j]= OUTSIDE_MARK;//初始化认为所有cell都在棋盘外
513
514 /**将所有在棋盘内的cell标记为EMPTY_MARK**/
515 for (int j = 1; j <= 4; j++)
516 for (int i = 5; i <= j + 4; i++)
517 cell[i][j]= EMPTY_MARK;
518 for (int j = 5; j <= 8; j++)
519 for (int i = j - 4; i <= 13; i++)
520 cell[i][j]= EMPTY_MARK;
521 for (int j = 9; j <= 13; j++)
522 for (int i = 5; i <= j + 4; i++)
523 cell[i][j]= EMPTY_MARK;
524 for (int j = 14; j <= 17; j++)
525 for (int i = j - 4; i <= 13; i++)
526 cell[i][j]= EMPTY_MARK;
527 }
528 public void init(){//初始化
529 for (int i = 1;i <= 17;++i){
530 for (int j = 1;j <= 17;++j){
531 if (cell[i][j].charAt(0) >= 65 && cell[i][j].charAt(0) <= 70){
532 setPosition(cell[i][j],i,j);
533 }
534 }
535 }
536 }
537
538 public void setPosition(String s,int x,int y){
539 int player = s.charAt(0) - 65;
540 int index = s.charAt(1) -48;
541 pieces[player][index][0] = x;
542 pieces[player][index][1] = y;
543 }
544
545 public static void setPiecePos(String piece, int[] value) {
546 int player = piece.charAt(0) - 65;
547 int index = piece.charAt(1) - 48;
548 pieces[player][index] = value;
549 }
550
551 public static int[] getPiecePos(String piece) {
552 int player = piece.charAt(0) - 65;
553 int index = piece.charAt(1) - 48;
554 return new int[]{pieces[player][index][0], pieces[player][index][1]};
555 }
556
557 public static int[] getPiecePos(int player, int index) {
558 return new int[]{pieces[player][index][0], pieces[player][index][1]};
559 }
560
561 public static void moveAward(String piece, int[] prevPos, int[] postPos) {//前进
562 setPiecePos(piece, postPos);
563 cell[prevPos[0]][prevPos[1]] = EMPTY_MARK;
564 cell[postPos[0]][postPos[1]] = piece + SPACE_MARK;
565 }
566
567 public static class Next {
568
569
570 public static int[][] getPossiblePosition(String pieceToMove) {
571 /**
572 * get all possible positions via adjacent hop/distant/consecutive hops.
573 */
574 int[] piecePosition = Pieces.getPiecePos(pieceToMove);
575 int[][] possiblePosition = distantHopping(piecePosition);
576
577
578 cell[piecePosition[0]][piecePosition[1]] = " ";
579 // apply Breadth-First-Search to accomplish consecutive hops
580 for (int k = 0; possiblePosition[k][0] != 0; k++) {
581 int[][] recursion = distantHopping(possiblePosition[k]);
582 possiblePosition = Services.concatTwoArrays(possiblePosition, recursion);
583 }
584 possiblePosition = Services.concatTwoArrays(possiblePosition, adjacentHopping(piecePosition));
585
586 cell[piecePosition[0]][piecePosition[1]] = pieceToMove;
587 return possiblePosition;
588 }
589
590 public static int getPossiblePositionCount(String pieceToMove) {
591 int count = 0;
592 int[][] possiblePosition = getPossiblePosition(pieceToMove);
593
594 for (int k = 0; possiblePosition[k][0] != 0; k++) {
595 count++;
596 }
597 return count;
598 }
599
600 private static int[][] adjacentHopping(int[] piecePosition) {
601
602 int[][] possiblePositions = new int[100][2];
603 int pointer = 0;
604 int[] displacementAdjacent = {-1, 0, 1};
605 // (-1,-1)(-1,0)(0,-1)(0,1)(1,0)(1,1)
606
607 for (int i : displacementAdjacent) {
608 for (int j : displacementAdjacent) {
609 // check whether the adjacent position is empty
610 String current = cell[piecePosition[0] + i][piecePosition[1] + j];
611 if (current == EMPTY_MARK && i != -j) {
612 possiblePositions[pointer][0] = piecePosition[0] + i;
613 possiblePositions[pointer][1] = piecePosition[1] + j;
614 pointer++;
615 }
616 }
617 }
618 return possiblePositions;
619 }
620
621 private static int[][] distantHopping(int[] piecePosition) {
622 int[][] possiblePos = new int[100][2];
623 int[] displacement = {-1, 0, 1};
624 // stores possible direction
625
626 for (int x : displacement) {
627 for (int y : displacement) {
628 possiblePos = Services.concatTwoArrays(possiblePos,
629 distantHoppingForOneDirection(x, y, piecePosition, true));
630 }
631 }
632
633 return possiblePos;
634 }
635
636 public static boolean isPosInsideDiagram(String position) {
637 return !(position == OUTSIDE_MARK || position == null);
638 }
639
640 private static int[][] distantHoppingForOneDirection(int x, int y,
641 int[] piecePos, boolean isDistantHoppingDisabled) {
642 /*
643 * x: indicates up or down moveAward in x direction. y: indicates up or down
644 * moveAward in x direction
645 */
646 int[][] possiblePos = new int[100][2];
647 int[] displacement = (isDistantHoppingDisabled)?new int[]{1}:new int[]{1, 2, 3, 4, 5, 6, 7, 8};
648 // stores possible displacements of coordinates in each direction
649 int pointer = 0;
650 boolean isDeadDirection;
651
652 for (int i : displacement) {
653 // avoid illegal direction
654 if (x * y == -1)
655 continue;
656 // avoid array index out of bound
657 boolean isiInside = (x == 0) || ((x == -1) ? piecePos[0] > 1 + 1 : piecePos[0] < 17 - 1);
658 boolean isjInside = (y == 0) || ((y == -1) ? piecePos[1] > 1 + 1 : piecePos[1] < 17 - 1);
659 boolean isInside = isiInside
660 && isjInside
661 && isPosInsideDiagram(cell[piecePos[0] + i * 2 * x - 1 * x][piecePos[1] + i* 2 * y - 1 * y])
662 && isPosInsideDiagram(cell[piecePos[0] + i * 2 * x][piecePos[1] + i * 2 * y]);
663 if (!isInside)
664 break;
665 boolean isAvailable = (isDeadDirection = !(cell[piecePos[0] + i * x][piecePos[1] + i * y] == EMPTY_MARK)
666 && cell[piecePos[0] + i * 2 * x][ piecePos[1] + i * 2 * y] == EMPTY_MARK);
667
668 label1:
669 if (isAvailable) {
670 // position between object position and hopped piece
671 // ought to be empty
672 for (int ii = i + 1; ii < 2 * i; ii++) {
673 if (cell[piecePos[0] + ii * x][piecePos[1] + ii * y] != EMPTY_MARK) {
674 isDeadDirection = true;
675 break label1;
676 }
677 }
678 possiblePos[pointer][0] = piecePos[0] + i * 2 * x;
679 possiblePos[pointer][1] = piecePos[1] + i * 2 * y;
680 pointer++;
681 }
682
683 if (isDeadDirection)
684 break;
685 }
686 return possiblePos;
687 }
688
689 }
690 }
691
692 class PieceActionListener extends MouseAdapter{//棋子事件侦听
693 private final static ImageIcon imgPossiblePosition = new ImageIcon("Piece_Transparant.PNG");
694 private static boolean isPieceSelected;
695 private static JLabel[] lblPossible = new JLabel[50];
696 private int[][] possiblePos = new int[50][2];
697 private String piece;
698
699 public PieceActionListener(String piece) {
700 this.piece = piece + " ";
701 }
702
703 public static void clearPossiblePos() {//清空可能到达的位置
704 for (int index = 0; lblPossible[index] != null; index++) {
705 ChineseChecker.myFrame.panel.remove(lblPossible[index]);
706 }
707 ChineseChecker.myFrame.repaint();
708 isPieceSelected = false;
709 }
710
711 @Override
712 public void mouseClicked(MouseEvent arg0) {//鼠标点击事件处理
713 if (ChineseChecker.series[ChineseChecker.currentIndex] != piece.charAt(0))
714 return;
715 if (!ChineseChecker.gameStatus)
716 return;
717
718 clearPossiblePos();
719 showPossiblePos();
720 isPieceSelected = true;
721 ChineseChecker.pieceToMove = piece.substring(0, 2);
722 ChineseChecker.piecePos = new int[]{Pieces.pieces[piece.charAt(0) - 65][piece.charAt(1) - 48][0],
723 Pieces.pieces[piece.charAt(0) - 65][piece.charAt(1) - 48][1]};
724 ChineseChecker.isPieceToMoveAcquired = true;
725 }
726
727 @Override
728 public void mouseEntered(MouseEvent arg0) {//鼠标移动事件处理
729 if (!ChineseChecker.gameStatus)
730 return;
731 if (ChineseChecker.series[ChineseChecker.currentIndex] != piece.charAt(0))
732 return;
733 if (isPieceSelected)
734 return;
735 showPossiblePos();
736 }
737
738 @Override
739 public void mouseExited(MouseEvent arg0) {//鼠标挪开事件处理
740 if (isPieceSelected)
741 return;
742 for (int k = 0; lblPossible[k] != null; k++) {
743 ChineseChecker.myFrame.panel.remove(lblPossible[k]);
744 ChineseChecker.myFrame.repaint();
745 }
746 }
747
748 public void showPossiblePos() {//展示可能到达的位置
749 possiblePos = Pieces.Next.getPossiblePosition(piece);
750 for (int k = 0; k < possiblePos.length && possiblePos[k][0] != 0; k++) {
751 lblPossible[k] = new JLabel(imgPossiblePosition);
752 lblPossible[k].addMouseListener(new PossiblePositionListener(piece,
753 possiblePos[k]));
754 ChineseChecker.myFrame.panel.add(lblPossible[k], JLayeredPane.MODAL_LAYER);
755 int[] positionInCanvas = Map.map[possiblePos[k][0]][possiblePos[k][1]];
756 lblPossible[k].setBounds(positionInCanvas[0], positionInCanvas[1], 39, 39);
757 }
758 }
759 }
760
761 class PossiblePositionListener extends MouseAdapter {
762
763 public static String piece;
764 public int[] position = new int[2];
765 public final static String EMPTY_MARK = "** ";
766 public final static String OUTSIDE_MARK = " ";
767 public final static String SPACE_MARK = " ";
768 PossiblePositionListener(String piece, int[] position) {
769 this.piece = piece;
770 this.position = position;
771 }
772
773 @Override
774 public void mouseClicked(MouseEvent arg0) {
775 if (!ChineseChecker.gameStatus)
776 return;
777
778 Pieces.cell[Pieces.getPiecePos(piece)[0]][Pieces.getPiecePos(piece)[1]] = EMPTY_MARK;
779 Pieces.cell[position[0]][position[1]] = piece + SPACE_MARK;
780
781 ChineseChecker.myFrame.move(piece, position);
782 PieceActionListener.clearPossiblePos();
783 ChineseChecker.posToGoTo = position;
784 ChineseChecker.isPositionToGoToAcquired = true;
785 }
786
787 }
788
789 class Services {
790
791 public static void msg(String content) {
792 JOptionPane.showMessageDialog(null, content, "Chinese Checkers",
793 JOptionPane.INFORMATION_MESSAGE);
794 }
795
796 public static String in(String content) {
797 return JOptionPane.showInputDialog(null, content, "Chinese Checkers",
798 JOptionPane.INFORMATION_MESSAGE);
799 }
800
801
802 public static int[][] concatTwoArrays(int[][] targetArray, int[][] temporaryArray) {
803 /** combine two 2D arrays into one. */
804 int pointer = 0;// point to the operating index of a1
805 while (targetArray[pointer][0] != 0) {
806 pointer++;
807 }
808 for (int j = 0; ; j++) {
809 boolean isRepeated = false;
810 if (temporaryArray[j][0] == 0)
811 break;
812 for (int i = 0; i < pointer; i++)
813 if (temporaryArray[j][0] == targetArray[i][0] && temporaryArray[j][1] == targetArray[i][1]) {
814 isRepeated = true;
815 break;
816 }
817 if (!isRepeated)
818 targetArray[pointer++] = temporaryArray[j];
819 }
820 return targetArray;
821 }
822 }
823
824 class Timer {
825
826 private long startingTime;
827 private long interruptedTime;
828 private boolean paused;
829
830 public Timer() {
831 this.startingTime = System.currentTimeMillis();
832 }
833
834 public long listen() {
835 if (paused)
836 return (30000 - interruptedTime + startingTime) / 1000;
837 long cur = System.currentTimeMillis();
838 return (30000 - cur + startingTime) / 1000;
839 }
840
841 public void pause() {
842 this.interruptedTime = System.currentTimeMillis();
843 this.paused = true;
844 }
845 }
846
847 class Trace {
848
849 public static final int MAX_STACK_SIZE = 1000;
850 public static int step = 1;
851 public static boolean isSkipped;
852 public static String[] pieceStack = new String[MAX_STACK_SIZE];
853 public static int[][] prevPosStack = new int[MAX_STACK_SIZE][2];
854 public static int[][] postPosStack = new int[MAX_STACK_SIZE][2];
855
856 public boolean isSkipped() {
857 return isSkipped;
858 }
859
860 public static void recordStep(String piece, int[] prev, int[] post) {
861 pieceStack[step] = piece;
862 prevPosStack[step] = prev;
863 postPosStack[step] = post;
864 }
865
866 public static void nextStep() {
867 ChineseChecker.currentIndex= Trace.step % ChineseChecker.numberOfPlayers;
868 }
869 }