HDU 1691 Chinese Chess

严格按规则实现、使用多态加异常来简化代码逻辑

Player类表示玩家

  存储身份信息和持有棋子信息

Board类表示棋盘

  可以通过坐标得到棋子

Piece类表示棋子

  存储位置信息和持有人信息

  各个棋子的实现提供对棋子走法的支持

Game类控制程序逻辑

具体见代码

  1 package acm.hdu.p1691;
  2
  3 import java.io.FileInputStream;
  4 import java.util.ArrayList;
  5 import java.util.List;
  6 import java.util.Scanner;
  7
  8 @SuppressWarnings("serial")
  9 class ChessException extends Exception
 10 {
 11     public ChessException(String message)
 12     {
 13         super(message);
 14     }
 15 }
 16
 17 enum PlayerColor
 18 {
 19     RED, BLACK
 20 }
 21
 22 class Player
 23 {
 24     private PlayerColor color;
 25     private Board board;
 26     private List<Piece> pieces = new ArrayList<Piece>();
 27
 28     public Player(PlayerColor color)
 29     {
 30         this.color = color;
 31     }
 32
 33     public PlayerColor getColor()
 34     {
 35         return color;
 36     }
 37
 38     public void setBoard(Board board)
 39     {
 40         this.board = board;
 41     }
 42
 43     public void addPiece(Piece piece)
 44     {
 45         this.pieces.add(piece);
 46     }
 47
 48     public void removePiece(Piece piece)
 49     {
 50         this.pieces.remove(piece);
 51     }
 52
 53     public List<Piece> getPieces()
 54     {
 55         return pieces;
 56     }
 57
 58     public Piece getKing()
 59     {
 60         for (Piece piece : pieces)
 61             if (piece instanceof PieceKing)
 62                 return piece;
 63         return null;
 64     }
 65 }
 66
 67 class Board
 68 {
 69     private Piece pieces[][];
 70
 71     public Board()
 72     {
 73         pieces = new Piece[10][9];
 74     }
 75
 76     public void setCell(int row, int column, Piece piece)
 77     {
 78         pieces[row - 1][column - 1] = piece;
 79     }
 80
 81     public Piece getCell(int row, int column)
 82     {
 83         return pieces[row - 1][column - 1];
 84     }
 85
 86     @Override
 87     public String toString()
 88     {
 89         String result = "";
 90
 91         result += String.format("%2s", "");
 92         for (int column = 1; column <= 9; column++)
 93             result += String.format("%12s", column);
 94         result += "\n";
 95
 96         for (int row = 1; row <= 10; row++)
 97         {
 98             result += String.format("%2s", row);
 99             for (int column = 1; column <= 9; column++)
100                 result += (String.format("%12s", getCell(row, column)));
101             result += "\n";
102         }
103         return result;
104     }
105 }
106
107 abstract class Piece
108 {
109     private Player player;
110     private int currentRow;
111     private int currentColumn;
112
113     public Piece(Player player)
114     {
115         this.player = player;
116     }
117
118     public Player getPlayer()
119     {
120         return player;
121     }
122
123     public int getCurrentRow()
124     {
125         return currentRow;
126     }
127
128     public void setCurrentRow(int currentRow)
129     {
130         this.currentRow = currentRow;
131     }
132
133     public int getCurrentColumn()
134     {
135         return currentColumn;
136     }
137
138     public void setCurrentColumn(int currentColumn)
139     {
140         this.currentColumn = currentColumn;
141     }
142
143     @Override
144     public String toString()
145     {
146         String simpleName = getClass().getSimpleName().replaceAll("Piece", "");
147         if (player.getColor() == PlayerColor.RED)
148             return simpleName;
149         else
150             return String.format("[%s]", simpleName);
151     }
152
153     public boolean isCrossRiver(int row, int column)
154     {
155         switch (player.getColor())
156         {
157         case RED:
158             return row <= 5;
159         default:
160             return row >= 6;
161         }
162     }
163
164     public boolean isLeavePalace(int row, int column)
165     {
166         int minRow, maxRow;
167         int minColumn = 4, maxColumn = 6;
168         switch (player.getColor())
169         {
170         case RED:
171             minRow = 8;
172             maxRow = 10;
173             break;
174         default:
175             minRow = 1;
176             maxRow = 3;
177             break;
178         }
179         if (row < minRow || row > maxRow)
180             return true;
181         if (column < minColumn || column > maxColumn)
182             return true;
183         return false;
184     }
185
186     public abstract void checkMove(Board board, int startRow, int startColumn, int endRow, int endColumn)
187             throws ChessException;
188 }
189
190 class PieceKing extends Piece
191 {
192
193     public PieceKing(Player player)
194     {
195         super(player);
196     }
197
198     @Override
199     public void checkMove(Board board, int startRow, int startColumn, int endRow, int endColumn) throws ChessException
200     {
201         //基本走法
202         {
203             if (Math.abs(startRow - endRow) + Math.abs(startColumn - endColumn) != 1)
204                 throw new ChessException("checkMove PieceKing Basic");
205         }
206         //离开老窝
207         {
208             if (isLeavePalace(endRow, endColumn))
209                 throw new ChessException("checkMove PieceKing LeavePalace");
210         }
211     }
212 }
213
214 class PieceMandarins extends Piece
215 {
216
217     public PieceMandarins(Player player)
218     {
219         super(player);
220     }
221
222     @Override
223     public void checkMove(Board board, int startRow, int startColumn, int endRow, int endColumn) throws ChessException
224     {
225         //基本走法
226         {
227             if (Math.abs(startRow - endRow) != Math.abs(startColumn - endColumn))
228                 throw new ChessException("checkMove PieceMandarins Basic");
229             if (Math.abs(startRow - endRow) != 1)
230                 throw new ChessException("checkMove PieceMandarins Basic");
231         }
232         //离开老窝
233         {
234             if (isLeavePalace(endRow, endColumn))
235                 throw new ChessException("checkMove PieceMandarins LeavePalace");
236         }
237     }
238 }
239
240 class PieceElephants extends Piece
241 {
242
243     public PieceElephants(Player player)
244     {
245         super(player);
246     }
247
248     @Override
249     public void checkMove(Board board, int startRow, int startColumn, int endRow, int endColumn) throws ChessException
250     {
251         //基本走法
252         {
253             if (Math.abs(startRow - endRow) != 2 || Math.abs(startColumn - endColumn) != 2)
254                 throw new ChessException("checkMove PieceElephants Basic");
255         }
256         //阻挡
257         {
258             if (board.getCell((startRow + endRow) / 2, (startColumn + endColumn) / 2) != null)
259                 throw new ChessException("checkMove PieceElephants Block");
260         }
261         //过河
262         {
263             if (isCrossRiver(endRow, endColumn))
264                 throw new ChessException("checkMove PieceElephants River");
265         }
266     }
267 }
268
269 class PieceKnights extends Piece
270 {
271
272     public PieceKnights(Player player)
273     {
274         super(player);
275     }
276
277     @Override
278     public void checkMove(Board board, int startRow, int startColumn, int endRow, int endColumn) throws ChessException
279     {
280         //基本走法
281         {
282             boolean flag1 = (Math.abs(startRow - endRow) == 2 && Math.abs(startColumn - endColumn) == 1);
283             boolean flag2 = (Math.abs(startRow - endRow) == 1 && Math.abs(startColumn - endColumn) == 2);
284             if (!flag1 && !flag2)
285                 throw new ChessException("checkMove PieceKnights Basic");
286         }
287         //阻挡
288         {
289             if (startRow + 2 == endRow && board.getCell(startRow + 1, startColumn) != null)
290                 throw new ChessException("checkMove PieceKnights Block");
291             if (startRow - 2 == endRow && board.getCell(startRow - 1, startColumn) != null)
292                 throw new ChessException("checkMove PieceKnights Block");
293             if (startColumn + 2 == endColumn && board.getCell(startRow, startColumn + 1) != null)
294                 throw new ChessException("checkMove PieceKnights Block");
295             if (startColumn - 2 == endColumn && board.getCell(startRow, startColumn - 1) != null)
296                 throw new ChessException("checkMove PieceKnights Block");
297         }
298     }
299 }
300
301 class PieceRooks extends Piece
302 {
303
304     public PieceRooks(Player player)
305     {
306         super(player);
307     }
308
309     @Override
310     public void checkMove(Board board, int startRow, int startColumn, int endRow, int endColumn) throws ChessException
311     {
312         //基本走法
313         {
314             if (startRow != endRow && startColumn != endColumn)
315                 throw new ChessException("checkMove PieceRooks Basic");
316         }
317
318         //阻挡
319         {
320             if (startColumn == endColumn)
321                 for (int row = Math.min(startRow, endRow) + 1; row <= Math.max(startRow, endRow) - 1; row++)
322                     if (board.getCell(row, startColumn) != null)
323                         throw new ChessException("checkMove PieceRooks Block");
324             if (startRow == endRow)
325                 for (int column = Math.min(startColumn, endColumn) + 1; column <= Math.max(startColumn, endColumn) - 1; column++)
326                     if (board.getCell(startRow, column) != null)
327                         throw new ChessException("checkMove PieceRooks Block");
328         }
329
330     }
331 }
332
333 class PieceCannons extends Piece
334 {
335
336     public PieceCannons(Player player)
337     {
338         super(player);
339     }
340
341     @Override
342     public void checkMove(Board board, int startRow, int startColumn, int endRow, int endColumn) throws ChessException
343     {
344         //基本走法
345         {
346             if (startRow != endRow && startColumn != endColumn)
347                 throw new ChessException("checkMove PieceCannons Basic");
348         }
349
350         //阻挡(若目标为空)
351         if (board.getCell(endRow, endColumn) == null)
352         {
353             if (startColumn == endColumn)
354                 for (int row = Math.min(startRow, endRow) + 1; row <= Math.max(startRow, endRow) - 1; row++)
355                     if (board.getCell(row, startColumn) != null)
356                         throw new ChessException("checkMove PieceCannons Block");
357             if (startRow == endRow)
358                 for (int column = Math.min(startColumn, endColumn) + 1; column <= Math.max(startColumn, endColumn) - 1; column++)
359                     if (board.getCell(startRow, column) != null)
360                         throw new ChessException("checkMove PieceCannons Block");
361         }
362         //阻挡(若目标不为空)
363         else
364         {
365             int blockCount = 0;
366             if (startColumn == endColumn)
367                 for (int row = Math.min(startRow, endRow) + 1; row <= Math.max(startRow, endRow) - 1; row++)
368                     if (board.getCell(row, startColumn) != null)
369                         blockCount++;
370             if (startRow == endRow)
371                 for (int column = Math.min(startColumn, endColumn) + 1; column <= Math.max(startColumn, endColumn) - 1; column++)
372                     if (board.getCell(startRow, column) != null)
373                         blockCount++;
374             if (blockCount != 1)
375                 throw new ChessException("checkMove PieceCannons Block " + blockCount);
376         }
377
378     }
379 }
380
381 class PiecePawns extends Piece
382 {
383
384     public PiecePawns(Player player)
385     {
386         super(player);
387     }
388
389     @Override
390     public void checkMove(Board board, int startRow, int startColumn, int endRow, int endColumn) throws ChessException
391     {
392         //基本走法(未过河)
393         if (!isCrossRiver(startRow, startColumn))
394         {
395             //步数
396             if (Math.abs(startRow - endRow) + Math.abs(startColumn - endColumn) != 1)
397                 throw new ChessException("checkMove PiecePawns Basic Not Cross River");
398             //方向
399             if (startColumn != endColumn)
400                 throw new ChessException("checkMove PiecePawns Basic Not Cross River");
401             if (getPlayer().getColor() == PlayerColor.RED && startRow < endRow)
402                 throw new ChessException("checkMove PiecePawns Basic Not Cross River");
403             if (getPlayer().getColor() == PlayerColor.BLACK && startRow > endRow)
404                 throw new ChessException("checkMove PiecePawns Basic Not Cross River");
405         }
406         //基本走法(已过河)
407         else
408         {
409             //步数
410             if (Math.abs(startRow - endRow) + Math.abs(startColumn - endColumn) != 1)
411                 throw new ChessException("checkMove PiecePawns Basic Crossed River");
412             //方向
413             if (getPlayer().getColor() == PlayerColor.RED && startRow < endRow)
414                 throw new ChessException("checkMove PiecePawns Basic Crossed River");
415             if (getPlayer().getColor() == PlayerColor.BLACK && startRow > endRow)
416                 throw new ChessException("checkMove PiecePawns Basic Crossed River");
417         }
418     }
419
420 }
421
422 class PieceFactory
423 {
424     public Piece createPiece(Player playerRed, Player playerBlack, int value)
425     {
426         if (value == 0)
427             return null;
428         Player currentPlayer;
429         if (value <= 7)
430             currentPlayer = playerRed;
431         else
432         {
433             currentPlayer = playerBlack;
434             value -= 7;
435         }
436         switch (value)
437         {
438         case 1:
439             return new PieceKing(currentPlayer);
440         case 2:
441             return new PieceMandarins(currentPlayer);
442         case 3:
443             return new PieceElephants(currentPlayer);
444         case 4:
445             return new PieceKnights(currentPlayer);
446         case 5:
447             return new PieceRooks(currentPlayer);
448         case 6:
449             return new PieceCannons(currentPlayer);
450         case 7:
451             return new PiecePawns(currentPlayer);
452         default:
453             return null;
454         }
455     }
456 }
457
458 class Game
459 {
460     private Board board;
461     private Player[] players;
462     private Player playerRed, playerBlack;
463     private int currentPlayerIndex;
464
465     public Game()
466     {
467         board = new Board();
468         playerRed = new Player(PlayerColor.RED);
469         playerBlack = new Player(PlayerColor.BLACK);
470         players = new Player[] { playerRed, playerBlack };
471         for (int i = 0; i < 2; i++)
472             players[i].setBoard(board);
473     }
474
475     public void init(Scanner cin)
476     {
477         for (int row = 1; row <= 10; row++)
478             for (int column = 1; column <= 9; column++)
479             {
480                 int value = cin.nextInt();
481                 Piece piece = new PieceFactory().createPiece(playerRed, playerBlack, value);
482                 board.setCell(row, column, piece);
483                 if (piece != null)
484                 {
485                     piece.setCurrentRow(row);
486                     piece.setCurrentColumn(column);
487                     piece.getPlayer().addPiece(piece);
488                 }
489             }
490         //        System.out.println("init ok");
491         //        System.out.println(board);
492
493     }
494
495     public int play(Scanner cin)
496     {
497         int n = cin.nextInt();
498         int k = cin.nextInt();
499         int errorStep = -1;
500         currentPlayerIndex = k;
501
502         for (int step = 1; step <= n; step++)
503         {
504             int startRow = cin.nextInt();
505             int startColumn = cin.nextInt();
506             int endRow = cin.nextInt();
507             int endColumn = cin.nextInt();
508             //            System.out.println("Move Step : " + step);
509             //            System.out.println("Command : " + startRow + " " + startColumn + " " + endRow + " " + endColumn);
510             if (errorStep != -1)
511             {
512                 //                System.out.println("Errored!");
513                 continue;
514             }
515             try
516             {
517                 moveOneStep(startRow, startColumn, endRow, endColumn);
518             }
519             catch (ChessException e)
520             {
521                 errorStep = step;
522                 //                System.err.println("Move Step : " + step + " Error!");
523                 //                System.err.println(e);
524             }
525             //            System.out.println(board);
526             currentPlayerIndex = 1 - currentPlayerIndex;
527         }
528
529         return errorStep;
530     }
531
532     private void checkGameOver() throws ChessException
533     {
534         for (Player player : players)
535             if (player.getKing() == null)
536                 throw new ChessException("checkGameOver " + player.getColor());
537     }
538
539     private void checkCoordinates(int startRow, int startColumn, int endRow, int endColumn)
540             throws ChessException
541     {
542         if (startRow < 1 || startRow > 10)
543             throw new ChessException("checkCoordinates startRow");
544         if (startColumn < 1 || startColumn > 9)
545             throw new ChessException("checkCoordinates startColumn");
546         if (endRow < 1 || endRow > 10)
547             throw new ChessException("checkCoordinates endRow");
548         if (endColumn < 1 || endColumn > 9)
549             throw new ChessException("checkCoordinates endColumn");
550     }
551
552     private void checkEmpty(int startRow, int startColumn, int endRow, int endColumn)
553             throws ChessException
554     {
555         if (board.getCell(startRow, startColumn) == null)
556             throw new ChessException("checkEmpty " + board.getCell(startRow, startColumn));
557     }
558
559     private void checkOwner(int startRow, int startColumn, int endRow, int endColumn)
560             throws ChessException
561     {
562         Player currentPlayer = players[currentPlayerIndex];
563         if (board.getCell(startRow, startColumn).getPlayer() != currentPlayer)
564             throw new ChessException("checkOwner " + board.getCell(startRow, startColumn));
565         if (board.getCell(endRow, endColumn) != null && board.getCell(endRow, endColumn).getPlayer() == currentPlayer)
566             throw new ChessException("checkOwner " + board.getCell(startRow, startColumn));
567     }
568
569     private void checkMove(int startRow, int startColumn, int endRow, int endColumn)
570             throws ChessException
571     {
572         board.getCell(startRow, startColumn).checkMove(board, startRow, startColumn, endRow, endColumn);
573     }
574
575     private void checkFaceToFace() throws ChessException
576     {
577         if (playerRed.getKing() == null || playerBlack.getKing() == null)
578             return;
579         if (playerRed.getKing().getCurrentColumn() != playerBlack.getKing().getCurrentColumn())
580             return;
581         boolean exist = false;
582         for (int row = playerBlack.getKing().getCurrentRow() + 1; row <= playerRed.getKing().getCurrentRow() - 1; row++)
583             if (board.getCell(row, playerBlack.getKing().getCurrentColumn()) != null)
584                 exist = true;
585         if (!exist)
586             throw new ChessException("checkFaceToFace ");
587     }
588
589     private boolean isGameOver()
590     {
591         return (playerRed.getKing() == null || playerBlack.getKing() == null);
592     }
593
594     private boolean isCheckmate()
595     {
596         for (Piece piece : players[1 - currentPlayerIndex].getPieces())
597             try
598             {
599                 piece.checkMove(board, piece.getCurrentRow(), piece.getCurrentColumn(),
600                         players[currentPlayerIndex].getKing().getCurrentRow()
601                         , players[currentPlayerIndex].getKing().getCurrentColumn());
602                 return true;
603             }
604             catch (ChessException e)
605             {
606                 // TODO Auto-generated catch block
607                 //                e.printStackTrace();
608             }
609         return false;
610     }
611
612     public void moveOneStep(int startRow, int startColumn, int endRow, int endColumn)
613             throws ChessException
614     {
615         //判断游戏结束
616         checkGameOver();
617         //记录是否处于将军状态
618         boolean isCheckmateBefore = isCheckmate();
619         //判断坐标是否合法
620         checkCoordinates(startRow, startColumn, endRow, endColumn);
621         //判断起始位置是否为空
622         checkEmpty(startRow, startColumn, endRow, endColumn);
623         //判断所有者
624         checkOwner(startRow, startColumn, endRow, endColumn);
625         //判断移动
626         checkMove(startRow, startColumn, endRow, endColumn);
627
628         //移动
629         {
630             Piece pieceStart = board.getCell(startRow, startColumn);
631             Piece pieceEnd = board.getCell(endRow, endColumn);
632             if (pieceEnd != null)
633                 pieceEnd.getPlayer().removePiece(pieceEnd);
634             board.setCell(endRow, endColumn, pieceStart);
635             board.setCell(startRow, startColumn, null);
636             pieceStart.setCurrentRow(endRow);
637             pieceStart.setCurrentColumn(endColumn);
638         }
639
640         //如果游戏结束
641         if (isGameOver())
642             return;
643         //判断是否脱离将军状态
644         boolean isCheckmateAfter = isCheckmate();
645         if (isCheckmateBefore && isCheckmateAfter)
646             throw new ChessException("is checkmate ");
647         //判断老将对面
648         checkFaceToFace();
649
650     }
651 }
652
653 public class Main
654 {
655     public static void main(String args[]) throws Exception
656     {
657         //        System.setIn(new FileInputStream("input2"));
658         Scanner cin = new Scanner(System.in);
659         int caseCount = cin.nextInt();
660         for (int caseIndex = 1; caseIndex <= caseCount; caseIndex++)
661         {
662             Game game = new Game();
663             game.init(cin);
664             int result = game.play(cin);
665             if (result == -1)
666                 System.out.println(String.format("Case %d: Legal move", caseIndex));
667             else
668                 System.out.println(String.format("Case %d: Illegal move on step %d", caseIndex, result));
669
670         }
671     }
672 }
时间: 2024-08-02 21:06:29

HDU 1691 Chinese Chess的相关文章

hdu 3004 The Chess【广独优先搜索】

The Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 466    Accepted Submission(s): 130 Problem Description Mr Li likes playing chess very much. One day he made a simplified version of the

HDU 4405 Aeroplane chess (概率DP求期望)

题意:有一个n个点的飞行棋,问从0点掷骰子(1~6)走到n点需要步数的期望 其中有m个跳跃a,b表示走到a点可以直接跳到b点. dp[ i ]表示从i点走到n点的期望,在正常情况下i点可以到走到i+1,i+2,i+3,i+4,i+5,i+6 点且每个点的概率都为1/6 所以dp[i]=(dp[i+1]+dp[i+2]+dp[i+3]+dp[i+4]+dp[i+5]+dp[i+6])/6  + 1(步数加一). 而对于有跳跃的点直接为dp[a]=dp[b]; #include<stdio.h>

hdu 3345 War Chess (bfs+优先队列)

War Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1732    Accepted Submission(s): 416 Problem Description War chess is hh's favorite game: In this game, there is an N * M battle map, an

hdu 4405 Aeroplane chess

题意: hzz一开始在0位置,然后hzz掷骰子,骰子为i,就往前走i步,当hzz位置大于等于n的时候结束,求掷骰子次数的期望 有m个直达点 (x,y),走到x时可以直接到y 求期望一般从后往前推 当 i不等于任何一个x时 dp[i]=seg(1/6*dp[i+k])+1 否则 dp[i]=dp[y] 1 #include<iostream> 2 #include<string> 3 #include<cstdio> 4 #include<vector> 5

HDU 2842 Chinese Rings (带常数矩阵+矩阵快速幂)

HDU 2842 Chinese Rings (带常数矩阵+矩阵快速幂) ACM 题目地址:HDU 2842 Chinese Rings 题意: 一种中国环,解开第k个环需要先解开前(k-2)个环,并留有第(k-1)环.问解开n环最少需要几步. 分析: 设f(n)表示解开n环. 1. 由于游戏规则,解开n环不能一下子把n-1全解开了,否则第n个就没法拿掉了. 2. 得先拿掉第n个:先完成f(n-2),然后再拿掉第n环. 3. 然后放回前(n-2),其实这也是f(n-2),因为是一个逆的过程. 4

HDU - 2842 Chinese Rings

Description Dumbear likes to play the Chinese Rings (Baguenaudier). It's a game played with nine rings on a bar. The rules of this game are very simple: At first, the nine rings are all on the bar. The first ring can be taken off or taken on with one

[ACM] hdu 4405 Aeroplane chess (概率DP)

Aeroplane chess Problem Description Hzz loves aeroplane chess very much. The chess map contains N+1 grids labeled from 0 to N. Hzz starts at grid 0. For each step he throws a dice(a dice have six faces with equal probability to face up and the number

HDU 1788 Chinese remainder theorem again 中国剩余定理

题意: 给定n,AA 下面n个数m1,m2···mn 则有n条方程 res % m1 = m1-AA res % m2 = m2-AA 问res的最小值 直接上剩余定理,嘿嘿 #include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<math.h> #include<set> #include<queue> #i

HDU 1788 Chinese remainder theorem again

题目链接 题意 : 中文题不详述. 思路 : 由N%Mi=(Mi-a)可得(N+a)%Mi=0;要取最小的N即找Mi的最小公倍数即可. 1 //1788 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <iostream> 6 #define LL long long 7 8 using namespace std ; 9 10 LL gcd(LL x,LL y)