Chess案例学习,Class Diagram + 基础代码 + JUnit5
学习笔记+作业笔记。
Class Diagram
画好的 UML 图如下:
如果 CSDN 里 class diagram 显示不出来的话:
根据 UML 图,总共有以下几个类:
- ChessBoard
- ChessPiece,抽象类
- Rook
- Knight
- Bishop
- Queen
- King
- Pawn
- IllegalMoveException
- IllegalPositionException
Java 代码基础结构
而通过 UML 图可以抽出类的框架:
-
ChessBoard
// 省略 imports public class ChessBoard { private ChessPiece[][] board; public ChessBoard() {} public void initialize() {} public ChessPiece getPiece(String position) throws IllegalPositionException { return null; } public boolean placePiece(ChessPiece piece, String position) { return false; } public void move(String fromPosition, String toPosition) throws IllegalMoveException {} public String toString() { return ""; } public static void main(String[] args) { } }
-
ChessPiece
// 省略 imports public abstract class ChessPiece { public enum Color { White, Black } protected ChessBoard board; protected int row; protected int column; protected Color color; public ChessPiece(ChessBoard board, Color color) {} public Color getColor() { return this.color; } public String getPosition() { return null; } public void setPosition(String position) throws IllegalPositionException {} abstract public String toString(); abstract public ArrayList<String> legalMoves(); }
-
Rook
如果使用 Intellij,
alt + enter
可以快速引用需要实现的抽象类,alt + ins
可以快速生成构造函数。属于两个很方便的快捷键。
// 省略 imports public class Rook extends ChessPiece{ public Rook(ChessBoard board, Color color) { super(board, color); } @Override public String toString() { return null; } @Override public ArrayList<String> legalMoves() { return null; } }
-
Knight
与 Rook 相似。
-
Bishop
与 Rook 相似。
-
Queen
与 Rook 相似。
-
King
与 Rook 相似。
-
Pawn
与 Rook 相似。
-
-
Exception
这里用的就是默认的 Exception,直接调用构造函数:
package Chess.Exceptions; public class IllegalPositionException extends Exception{ public IllegalPositionException(String message, Throwable cause) { super(message, cause); } }
测试 - JUnit5
JUnit5 的实现还是比较简单的,和 JUnit4 一样,导入 org.junit.jupiter.api.Test
使用 @Test
注解;导入 org.junit.jupiter.api.Assertions.*
是用具体的 assert
函数。
有一个需要注意的事情就是,JUnit5 中的 assertThrows
的函数写法还是比较有意思的:
@Test
void testExpectedException() {
Assertions.assertThrows(ApplicationException.class, () -> {
//Code under test
});
}
使用的是 Lambda 表达式,属于之前没碰过的东西(确实很久没写 Java 了……),其余的部分和 JUnit4 没有什么特别大的差别。
目前关于测试其实实现的还不是很多,主要写了 ChessBoard
的测试。
其中,movePiece
的测试还是需要等 ChessPiece
中的 legalMoves()
实现了之后才能测试。不过其他关于 初始化(initialize),移动棋子(movePiece, setPiece, getPiece 三个相关函数) 的测试目前都已经打好基础,等待具体实现。
目前完整的 ChessBoard
测试如下:
package Chess;
import Chess.ChessPieces.King;
import Chess.ChessPieces.Rook;
import Chess.Exceptions.IllegalMoveException;
import Chess.Exceptions.IllegalPositionException;
import org.junit.jupiter.api.Test;
import Chess.ChessPieces.ChessPiece;
import Chess.ChessPieces.Pawn;
import static org.junit.jupiter.api.Assertions.*;
public class ChessboardTests {
private static final String[][] PIECE_POSITION = new String[][] {
{"a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8"},
{"a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7"},
{"a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6"},
{"a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5"},
{"a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4"},
{"a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3"},
{"a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2"},
{"a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1"}
};
@Test
public void testConstructor() {
ChessBoard board = new ChessBoard();
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
String position = PIECE_POSITION[row][col];
try {
assertNull(board.getPiece(position));
} catch (IllegalPositionException e) {
fail("Illegal Position Exception in testConstructor");
}
}
}
}
@Test
public void testPlacePieceOutOfBounds() {
ChessBoard board = new ChessBoard();
assertFalse(board.placePiece(new Pawn(board, ChessPiece.Color.BLACK), "i8"));
assertFalse(board.placePiece(new Pawn(board, ChessPiece.Color.BLACK), "a9"));
}
@Test
public void testPlacePieceAtIllegalPos() {
ChessBoard board = new ChessBoard();
assertFalse(board.placePiece(new Pawn(board, ChessPiece.Color.BLACK), "A8"));
assertFalse(board.placePiece(new Pawn(board, ChessPiece.Color.BLACK), "!8"));
assertFalse(board.placePiece(new Pawn(board, ChessPiece.Color.BLACK), "d"));
assertFalse(board.placePiece(new Pawn(board, ChessPiece.Color.BLACK), "8"));
assertFalse(board.placePiece(new Pawn(board, ChessPiece.Color.BLACK), ""));
}
@Test
public void testGetPieceOutOfBounds() {
ChessBoard board = new ChessBoard();
assertThrows(IllegalPositionException.class, () -> board.getPiece("i8"));
assertThrows(IllegalPositionException.class, () -> board.getPiece("a9"));
}
@Test
public void testGetPieceAtIllegalPos() {
ChessBoard board = new ChessBoard();
assertThrows(IllegalPositionException.class, () -> board.getPiece("A8"));
assertThrows(IllegalPositionException.class, () -> board.getPiece("!8"));
assertThrows(IllegalPositionException.class, () -> board.getPiece("d"));
assertThrows(IllegalPositionException.class, () -> board.getPiece("8"));
assertThrows(IllegalPositionException.class, () -> board.getPiece(""));
}
@Test
public void testPlacePiecesAtValidPos() {
ChessBoard board = new ChessBoard();
ChessPiece blackPawn = new Pawn(board, ChessPiece.Color.BLACK);
ChessPiece blackKing = new King(board, ChessPiece.Color.BLACK);
ChessPiece blackRook = new Rook(board, ChessPiece.Color.BLACK);
ChessPiece whitePawn = new Pawn(board, ChessPiece.Color.WHITE);
ChessPiece whiteKing = new King(board, ChessPiece.Color.WHITE);
ChessPiece whiteRook = new Rook(board, ChessPiece.Color.WHITE);
board.placePiece(blackPawn, "a8");
board.placePiece(blackKing, "d8");
board.placePiece(blackRook, "h8");
board.placePiece(whitePawn, "a1");
board.placePiece(whiteKing, "d1");
board.placePiece(whiteRook, "h1");
try {
String blackPawnPos = board.getPiece("a8").toString();
String blackKingPos = board.getPiece("d8").toString();
String blackRookPos = board.getPiece("h8").toString();
String whitePawnPos = board.getPiece("a1").toString();
String whiteKingPos = board.getPiece("d1").toString();
String whiteRookPos = board.getPiece("h1").toString();
assertEquals(blackPawnPos, blackPawn.toString());
assertEquals(blackKingPos, blackKing.toString());
assertEquals(blackRookPos, blackRook.toString());
assertEquals(whitePawnPos, whitePawn.toString());
assertEquals(whiteKingPos, whiteKing.toString());
assertEquals(whiteRookPos, whiteRook.toString());
} catch (IllegalPositionException e) {
fail("Illegal Position Exception in testPlacePiecesAtValidPos");
}
}
@Test
public void testInitialization() {
String[][] initializedPieces = new String[][] {
{"\u265C", "\u265E", "\u265D", "\u265B", "\u265A", "\u265D", "\u265E", "\u265C"},
{"\u265F", "\u265F", "\u265F", "\u265F", "\u265F", "\u265F", "\u265F", "\u265F"},
{null, null, null, null, null, null, null, null},
{null, null, null, null, null, null, null, null},
{null, null, null, null, null, null, null, null},
{null, null, null, null, null, null, null, null},
{"\u2659", "\u2659", "\u2659", "\u2659", "\u2659", "\u2659", "\u2659", "\u2659"},
{"\u2656", "\u2658", "\u2657", "\u2655", "\u2654", "\u2657", "\u2658", "\u2656"}
};
ChessBoard board = new ChessBoard();
board.initialize();
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
String position = PIECE_POSITION[row][col];
String actual = initializedPieces[row][col];
try {
ChessPiece piece = board.getPiece(position);
if (actual == null) {
assertNull(piece);
} else {
assertEquals(piece.toString(), actual);
}
} catch(IllegalPositionException e) {
fail("Illegal Position Exception in testInitialization");
}
}
}
}
@Test
public void testMoveOutOfBoundPosition() {
ChessBoard board = new ChessBoard();
board.initialize();
assertThrows(IllegalMoveException.class, () -> board.move("e8", "e9"));
}
@Test
public void testMoveInvalidPosition() {
ChessBoard board = new ChessBoard();
board.initialize();
assertThrows(IllegalMoveException.class, () -> board.move("e8", "!9"));
}
@Test
public void testMoveBlockingPiece() {
ChessBoard board = new ChessBoard();
board.initialize();
assertThrows(IllegalMoveException.class, () -> board.move("e8", "e7"));
}
// TODO - Check the rule on how Pawn moves
@Test
public void testMovePawnValidSpace() {
ChessBoard board = new ChessBoard();
board.initialize();
// TODO - Check black pawn's move
// TODO - Check white pawn's move
}
// TODO - Check the rule on how Pawn moves
@Test
public void testMovePawnInvalidSpace() {
// TODO - Check black pawn's move
// TODO - Check white pawn's move
}
// TODO - Check the rule on how Pawn moves
@Test
public void testMoveBishiopValidSpace() {
ChessBoard board = new ChessBoard();
board.initialize();
// TODO - Check black pawn's move
// TODO - Check white pawn's move
}
// TODO - Check the rule on how Pawn moves
@Test
public void testMoveBishiopInvalidSpace() {
// TODO - Check black pawn's move
// TODO - Check white pawn's move
}
// TODO - Check the rule on how Pawn moves
@Test
public void testMoveKingValidSpace() {
ChessBoard board = new ChessBoard();
board.initialize();
// TODO - Check black pawn's move
// TODO - Check white pawn's move
}
// TODO - Check the rule on how Pawn moves
@Test
public void testMoveKingInvalidSpace() {
// TODO - Check black pawn's move
// TODO - Check white pawn's move
}
// TODO - Check the rule on how Pawn moves
@Test
public void testMoveKnightValidSpace() {
ChessBoard board = new ChessBoard();
board.initialize();
// TODO - Check black pawn's move
// TODO - Check white pawn's move
}
// TODO - Check the rule on how Pawn moves
@Test
public void testMoveKnightInvalidSpace() {
// TODO - Check black pawn's move
// TODO - Check white pawn's move
}
// TODO - Check the rule on how Pawn moves
@Test
public void testMoveQueenValidSpace() {
ChessBoard board = new ChessBoard();
board.initialize();
// TODO - Check black pawn's move
// TODO - Check white pawn's move
}
// TODO - Check the rule on how Pawn moves
@Test
public void testMoveQueenInvalidSpace() {
// TODO - Check black pawn's move
// TODO - Check white pawn's move
}
// TODO - Check the rule on how Pawn moves
@Test
public void testMoveRookValidSpace() {
ChessBoard board = new ChessBoard();
board.initialize();
// TODO - Check black pawn's move
// TODO - Check white pawn's move
}
// TODO - Check the rule on how Pawn moves
@Test
public void testMoveRookInvalidSpace() {
// TODO - Check black pawn's move
// TODO - Check white pawn's move
}
}