Skip to content

Commit e0c3911

Browse files
authored
Merge pull request #3 from vikasvk1/feature-chess-game-lld
Add chess LLD implementation and docs
2 parents d779531 + a3dee56 commit e0c3911

20 files changed

Lines changed: 924 additions & 7 deletions

.github/workflows/sonarcloud.yml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,17 @@ jobs:
2222
run: |
2323
set -e
2424
mkdir -p .sonar_classes
25-
find . -name "*.java" \
26-
-not -path "./out/*" \
27-
-not -path "./.idea/*" \
28-
-not -path "./.git/*" \
29-
-not -path "./skills/*" > .sonar_java_files.txt
25+
mapfile -d '' java_files < <(
26+
find . -name "*.java" \
27+
-not -path "./out/*" \
28+
-not -path "./.idea/*" \
29+
-not -path "./.git/*" \
30+
-not -path "./skills/*" \
31+
-print0
32+
)
3033
31-
if [ -s .sonar_java_files.txt ]; then
32-
javac -d .sonar_classes @.sonar_java_files.txt
34+
if [ "${#java_files[@]}" -gt 0 ]; then
35+
javac -d .sonar_classes "${java_files[@]}"
3336
else
3437
echo "No Java files found to compile."
3538
fi
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
public class Bishop extends Piece {
2+
public Bishop(Color color) {
3+
super(color, PieceType.BISHOP);
4+
}
5+
6+
@Override
7+
public boolean isValidMove(ChessBoard board, Position from, Position to) {
8+
int dr = Math.abs(to.getRow() - from.getRow());
9+
int dc = Math.abs(to.getCol() - from.getCol());
10+
return dr == dc && board.isPathClear(from, to);
11+
}
12+
13+
@Override
14+
public char getSymbol() {
15+
return getColor() == Color.WHITE ? 'B' : 'b';
16+
}
17+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
public class ChessBoard {
2+
private static final int SIZE = 8;
3+
private final Piece[][] grid;
4+
5+
public ChessBoard() {
6+
this.grid = new Piece[SIZE][SIZE];
7+
initializeStandardSetup();
8+
}
9+
10+
public void initializeStandardSetup() {
11+
for (int row = 0; row < SIZE; row++) {
12+
for (int col = 0; col < SIZE; col++) {
13+
grid[row][col] = null;
14+
}
15+
}
16+
17+
setupBackRank(Color.BLACK, 0);
18+
setupPawns(Color.BLACK, 1);
19+
setupPawns(Color.WHITE, 6);
20+
setupBackRank(Color.WHITE, 7);
21+
}
22+
23+
private void setupBackRank(Color color, int row) {
24+
grid[row][0] = new Rook(color);
25+
grid[row][1] = new Knight(color);
26+
grid[row][2] = new Bishop(color);
27+
grid[row][3] = new Queen(color);
28+
grid[row][4] = new King(color);
29+
grid[row][5] = new Bishop(color);
30+
grid[row][6] = new Knight(color);
31+
grid[row][7] = new Rook(color);
32+
}
33+
34+
private void setupPawns(Color color, int row) {
35+
for (int col = 0; col < SIZE; col++) {
36+
grid[row][col] = new Pawn(color);
37+
}
38+
}
39+
40+
public Piece getPiece(Position position) {
41+
validatePosition(position);
42+
return grid[position.getRow()][position.getCol()];
43+
}
44+
45+
public void setPiece(Position position, Piece piece) {
46+
validatePosition(position);
47+
grid[position.getRow()][position.getCol()] = piece;
48+
}
49+
50+
public Piece movePiece(Position from, Position to) {
51+
validatePosition(from);
52+
validatePosition(to);
53+
Piece moving = getPiece(from);
54+
Piece captured = getPiece(to);
55+
setPiece(to, moving);
56+
setPiece(from, null);
57+
return captured;
58+
}
59+
60+
public boolean isPathClear(Position from, Position to) {
61+
int rowStep = Integer.compare(to.getRow(), from.getRow());
62+
int colStep = Integer.compare(to.getCol(), from.getCol());
63+
64+
int currentRow = from.getRow() + rowStep;
65+
int currentCol = from.getCol() + colStep;
66+
67+
while (currentRow != to.getRow() || currentCol != to.getCol()) {
68+
if (grid[currentRow][currentCol] != null) {
69+
return false;
70+
}
71+
currentRow += rowStep;
72+
currentCol += colStep;
73+
}
74+
return true;
75+
}
76+
77+
public Position findKing(Color color) {
78+
for (int row = 0; row < SIZE; row++) {
79+
for (int col = 0; col < SIZE; col++) {
80+
Piece piece = grid[row][col];
81+
if (piece instanceof King && piece.getColor() == color) {
82+
return new Position(row, col);
83+
}
84+
}
85+
}
86+
return null;
87+
}
88+
89+
public int getSize() {
90+
return SIZE;
91+
}
92+
93+
public boolean isInside(Position position) {
94+
return position.getRow() >= 0 && position.getRow() < SIZE
95+
&& position.getCol() >= 0 && position.getCol() < SIZE;
96+
}
97+
98+
private void validatePosition(Position position) {
99+
if (!isInside(position)) {
100+
throw new ChessInvalidMoveException("Invalid board position: " + position);
101+
}
102+
}
103+
104+
public void printBoard() {
105+
System.out.println();
106+
for (int row = 0; row < SIZE; row++) {
107+
System.out.print((8 - row) + " ");
108+
for (int col = 0; col < SIZE; col++) {
109+
Piece piece = grid[row][col];
110+
char symbol = piece == null ? '.' : piece.getSymbol();
111+
System.out.print(symbol + " ");
112+
}
113+
System.out.println();
114+
}
115+
System.out.println(" a b c d e f g h");
116+
System.out.println();
117+
}
118+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import java.util.ArrayList;
2+
import java.util.Collections;
3+
import java.util.List;
4+
5+
public class ChessGame {
6+
private final ChessBoard board;
7+
private final ChessPlayer whitePlayer;
8+
private final ChessPlayer blackPlayer;
9+
private final List<Move> moveHistory;
10+
11+
private Color currentTurn;
12+
private ChessGameStatus status;
13+
private ChessPlayer winner;
14+
15+
public ChessGame(String whitePlayerName, String blackPlayerName) {
16+
this.board = new ChessBoard();
17+
this.whitePlayer = new ChessPlayer(whitePlayerName, Color.WHITE);
18+
this.blackPlayer = new ChessPlayer(blackPlayerName, Color.BLACK);
19+
this.moveHistory = new ArrayList<>();
20+
this.currentTurn = Color.WHITE;
21+
this.status = ChessGameStatus.IN_PROGRESS;
22+
}
23+
24+
public void makeMove(String fromSquare, String toSquare) {
25+
Position from = Position.fromAlgebraic(fromSquare);
26+
Position to = Position.fromAlgebraic(toSquare);
27+
makeMove(from, to);
28+
}
29+
30+
public void makeMove(Position from, Position to) {
31+
if (status != ChessGameStatus.IN_PROGRESS) {
32+
throw new ChessInvalidMoveException("Game is already finished.");
33+
}
34+
if (from.equals(to)) {
35+
throw new ChessInvalidMoveException("Source and destination cannot be same.");
36+
}
37+
38+
Piece piece = board.getPiece(from);
39+
if (piece == null) {
40+
throw new ChessInvalidMoveException("No piece at source square " + from + ".");
41+
}
42+
if (piece.getColor() != currentTurn) {
43+
throw new ChessInvalidMoveException("It is " + currentTurn + " turn.");
44+
}
45+
46+
Piece destinationPiece = board.getPiece(to);
47+
if (destinationPiece != null && destinationPiece.getColor() == currentTurn) {
48+
throw new ChessInvalidMoveException("Cannot capture own piece at " + to + ".");
49+
}
50+
51+
if (!piece.isValidMove(board, from, to)) {
52+
throw new ChessInvalidMoveException("Illegal move for " + piece.getType() + ": " + from + " to " + to + ".");
53+
}
54+
55+
Piece capturedPiece = board.movePiece(from, to);
56+
moveHistory.add(new Move(from, to, piece, capturedPiece));
57+
58+
if (capturedPiece instanceof King) {
59+
status = currentTurn == Color.WHITE ? ChessGameStatus.WHITE_WIN : ChessGameStatus.BLACK_WIN;
60+
winner = currentTurn == Color.WHITE ? whitePlayer : blackPlayer;
61+
return;
62+
}
63+
64+
currentTurn = currentTurn.opposite();
65+
}
66+
67+
public ChessBoard getBoard() {
68+
return board;
69+
}
70+
71+
public ChessPlayer getCurrentPlayer() {
72+
return currentTurn == Color.WHITE ? whitePlayer : blackPlayer;
73+
}
74+
75+
public Color getCurrentTurn() {
76+
return currentTurn;
77+
}
78+
79+
public ChessGameStatus getStatus() {
80+
return status;
81+
}
82+
83+
public ChessPlayer getWinner() {
84+
return winner;
85+
}
86+
87+
public List<Move> getMoveHistory() {
88+
return Collections.unmodifiableList(moveHistory);
89+
}
90+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public enum ChessGameStatus {
2+
IN_PROGRESS,
3+
WHITE_WIN,
4+
BLACK_WIN
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public class ChessInvalidMoveException extends RuntimeException {
2+
public ChessInvalidMoveException(String message) {
3+
super(message);
4+
}
5+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import java.util.Scanner;
2+
3+
public class ChessMain {
4+
public static void main(String[] args) {
5+
Scanner scanner = new Scanner(System.in);
6+
7+
System.out.print("White player name: ");
8+
String white = readNonEmpty(scanner);
9+
System.out.print("Black player name: ");
10+
String black = readNonEmpty(scanner);
11+
12+
ChessGame game = new ChessGame(white, black);
13+
14+
System.out.println("\nChess game started.");
15+
System.out.println("Enter moves as: e2 e4");
16+
System.out.println("Type 'exit' to stop.");
17+
18+
while (game.getStatus() == ChessGameStatus.IN_PROGRESS) {
19+
game.getBoard().printBoard();
20+
ChessPlayer current = game.getCurrentPlayer();
21+
System.out.print(current + " move: ");
22+
String line = scanner.nextLine().trim();
23+
24+
if (line.equalsIgnoreCase("exit")) {
25+
System.out.println("Game stopped.");
26+
return;
27+
}
28+
29+
String[] parts = line.split("\\s+");
30+
if (parts.length != 2) {
31+
System.out.println("Invalid input. Use format: e2 e4");
32+
continue;
33+
}
34+
35+
try {
36+
game.makeMove(parts[0], parts[1]);
37+
} catch (IllegalArgumentException | ChessInvalidMoveException e) {
38+
System.out.println(e.getMessage());
39+
}
40+
}
41+
42+
game.getBoard().printBoard();
43+
System.out.println("Winner: " + game.getWinner());
44+
}
45+
46+
private static String readNonEmpty(Scanner scanner) {
47+
while (true) {
48+
String value = scanner.nextLine().trim();
49+
if (!value.isEmpty()) {
50+
return value;
51+
}
52+
System.out.print("Input cannot be empty, try again: ");
53+
}
54+
}
55+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
public class ChessPlayer {
2+
private final String name;
3+
private final Color color;
4+
5+
public ChessPlayer(String name, Color color) {
6+
if (name == null || name.trim().isEmpty()) {
7+
throw new IllegalArgumentException("Player name cannot be empty.");
8+
}
9+
this.name = name.trim();
10+
this.color = color;
11+
}
12+
13+
public String getName() {
14+
return name;
15+
}
16+
17+
public Color getColor() {
18+
return color;
19+
}
20+
21+
@Override
22+
public String toString() {
23+
return name + " (" + color + ")";
24+
}
25+
}

0 commit comments

Comments
 (0)