Assignment

Chess Game

Problem Description

In this homework, you will begin creating many useful classes for our end goal of making a chess database!

  • Ply
    • One player’s move in chess. Kind of like half of a move.
  • Move
    • One turn of chess: both White’s Ply and Black’s Ply.
  • ChessGame
    • a sequence of Moves.

Solution Description

Classes:

  • Ply
    • fields:
      • Piece piece
      • Square from
      • Square to
      • Optional<String> comment
    • methods:
      • Getter methods for all fields.
      • Constructor that takes in and assigns all fields.
  • Move
    • fields:
      • Ply whitePly
      • Ply blackPly
    • methods:
      • Getter methods for all fields.
      • Constructor that takes in and assigns both Plies.
  • ChessGame
    • fields:
      • List<Move> moves
    • methods:
      • Move getMove(int n): returns the nth move.
      • List<Move>filter(Predicate<Move> filter): Returns a list filtered by the predicate. Must not change moves field.
      • List<Move>getMovesWithComment(): returns a list of moves with comments (if either or both Ply has a comment). Must not change moves field. Must call filter with a lambda.
      • List<Move>getMovesWithoutComment(): returns a list of moves without comments (if neither Ply has a comment). Must not change moves field. Must call filter with an anonymous inner class.
      • List<Move>getMovesWithPiece(Piece p): returns a list of moves with a piece of this type (if either Ply uses a piece of the same type as p). Note: the pieces don’t have to be the exact same but only must be the same type (both pawns or both queens etc.). Must not change moves field. Must call filter with an instance of an inner class.
      • Constructor that takes in a List of moves.
      • Getter for moves.

Important:getMovesWithComment, getMovesWithoutComment, getMovesWithPiece(Piece p) must use filter with a lambda, an anonymous class, and inner class respectively.

If there are any classes that you are unfamiliar with (e.g. Predicate or Optional), look them up in Javadocs. Make the visibility of all the methods and fields as you see best fits good programming style.

Solution

Bishop.java

package main.java;

public class Bishop extends Piece {

public Bishop(Color c) {

super(c);

}

public String algebraicName() {

return “B”;

}

public String fenName() {

returngetColor() == Color.WHITE ? “B” : “b”;

}

public Square[] movesFrom(Square square) {

Square[] sq = new Square[27];

int counter = 0;

char rank = square.getRank();

char file = square.getFile();

for (int i = 1; i <= 8; i++) {

char[] ranks = new char[]{(char) (rank + i), (char) (rank – i)};

char[] files = new char[]{(char) (file + i), (char) (file – i)};

if (isInBoard(files[0], ranks[0])) {

sq[counter++] = new Square(files[0], ranks[0]);

}

if (isInBoard(files[1], ranks[0])) {

sq[counter++] = new Square(files[1], ranks[0]);

}

if (isInBoard(files[0], ranks[1])) {

sq[counter++] = new Square(files[0], ranks[1]);

}

if (isInBoard(files[1], ranks[1])) {

sq[counter++] = new Square(files[1], ranks[1]);

}

}

Square[] full = new Square[counter];

for (int i = 0; i < counter; i++) {

full[i] = sq[i];

}

return full;

}

}

ChessGame.java

package main.java;

importjava.util.List;

importjava.util.function.Predicate;

importjava.util.stream.Collectors;

/**

* A sequence of Moves.

*/

public class ChessGame {

private List<Move> moves;

publicChessGame(List<Move> moves) {

this.moves = moves;

}

public List<Move>getMoves() {

return moves;

}

public Move getMove(int n) {

returnmoves.get(n);

}

public List<Move> filter(Predicate<Move> filter) {

returnmoves.stream().filter(filter).collect(Collectors.toList());

}

public List<Move>getMovesWithComment() {

returnmoves.stream().filter(move ->move.getWhitePly().getComment().isPresent()

|| move.getBlackPly().getComment().isPresent()).collect(Collectors.toList());

}

public List<Move>getMovesWithoutComment() {

returnmoves.stream().filter(new Predicate<Move>() {

@Override

publicboolean test(Move move) {

return !move.getWhitePly().getComment().isPresent()

&& !move.getBlackPly().getComment().isPresent();

}

}).collect(Collectors.toList());

}

public List<Move>getMovesWithPiece(Piece piece) {

returnmoves.stream().filter(new MovesFilter(piece)).collect(Collectors.toList());

}

classMovesFilter implements Predicate<Move> {

Piece piece;

MovesFilter(Piece piece) {

this.piece = piece;

}

@Override

publicboolean test(Move move) {

returnmove.getWhitePly().getPiece().fenName().equals(piece.fenName())

|| move.getBlackPly().getPiece().fenName().equals(piece.fenName());

}

}

}

ChessGameTest.java

package main.java;

importorg.junit.jupiter.api.Assertions;

importorg.junit.jupiter.api.BeforeAll;

importorg.junit.jupiter.api.Test;

importjava.util.ArrayList;

importjava.util.List;

importjava.util.Optional;

importjava.util.function.Predicate;

importjava.util.stream.Collectors;

classChessGameTest {

private static ChessGamechessGame;

@BeforeAll

static void setUp() {

Move move1 = new Move(new Ply(new King(Color.BLACK), null, null, Optional.of(“Comment”)),

new Ply(new Knight(Color.WHITE), null, null, Optional.empty()));

Move move2 = new Move(new Ply(new King(Color.BLACK), null, null, Optional.empty()),

new Ply(new Knight(Color.WHITE), null, null, Optional.empty()));

Move move3 = new Move(new Ply(new King(Color.BLACK), null, null, Optional.empty()),

new Ply(new Knight(Color.WHITE), null, null, Optional.empty()));

Move move4 = new Move(new Ply(new King(Color.BLACK), null, null, Optional.empty()),

new Ply(new Pawn(Color.WHITE), null, null, Optional.empty()));

Move move5 = new Move(new Ply(new King(Color.BLACK), null, null, Optional.empty()),

new Ply(new Knight(Color.WHITE), null, null, Optional.empty()));

Move move6 = new Move(new Ply(new King(Color.BLACK), null, null, Optional.of(“Comment”)),

new Ply(new Knight(Color.WHITE), null, null, Optional.empty()));

List<Move> moves = new ArrayList<>();

moves.add(move1);

moves.add(move2);

moves.add(move3);

moves.add(move4);

moves.add(move5);

moves.add(move6);

chessGame= new ChessGame(moves);

}

@Test

voidgetMove() {

Assertions.assertEquals(chessGame.getMoves().get(1), chessGame.getMove(1));

}

@Test

void filter() {

Predicate<Move> predicate = new Predicate<Move>() {

@Override

publicboolean test(Move move) {

return move != null;

}

};

Assertions.assertIterableEquals(chessGame.getMoves().stream()

.filter(move -> move != null).collect(Collectors.toList()),

chessGame.filter(predicate));

}

@Test

voidgetMovesWithComment() {

List<Move> expected = new ArrayList<>();

expected.add(chessGame.getMoves().get(0));

expected.add(chessGame.getMoves().get(chessGame.getMoves().size() – 1));

Assertions.assertIterableEquals(expected, chessGame.getMovesWithComment());

}

@Test

voidgetMovesWithoutComment() {

List<Move> expected = new ArrayList<>();

expected.add(chessGame.getMoves().get(1));

expected.add(chessGame.getMoves().get(2));

expected.add(chessGame.getMoves().get(3));

expected.add(chessGame.getMoves().get(4));

Assertions.assertIterableEquals(expected, chessGame.getMovesWithoutComment());

}

@Test

voidgetMovesWithPiece() {

List<Move> expected = new ArrayList<>();

expected.add(chessGame.getMoves().get(3));

Assertions.assertIterableEquals(expected, chessGame.getMovesWithPiece(new Pawn(Color.WHITE)));

}

}

Color.java

package main.java;

publicenum Color {

WHITE, BLACK

}

InvalidSquareException.java

package main.java;

public class InvalidSquareException extends RuntimeException {

publicInvalidSquareException(String square) {

super(square);

}

} 

King.java

package main.java;

public class King extends Piece {

public King(Color c) {

super(c);

}

public String algebraicName() {

return “K”;

}

public String fenName() {

returngetColor() == Color.WHITE ? “K” : “k”;

}

public Square[] movesFrom(Square square) {

Square[] sq = new Square[8];

int counter = 0;

char rank = square.getRank();

char file = square.getFile();

for (int r = -1; r <= 1; r++) {

for (int c = -1; c <= 1; c++) {

if (r == 0 && c == 0) {

continue;

}

if (isInBoard((char) (file + c), (char) (rank + r))) {

sq[counter++] = new Square((char) (file + c), (char) (rank + r));

}

}

}

Square[] full = new Square[counter];

for (int i = 0; i < counter; i++) {

full[i] = sq[i];

}

return full;

}

}

Knight.java

package main.java;

public class Knight extends Piece {

public Knight(Color c) {

super(c);

}

public String algebraicName() {

return “N”;

}

public String fenName() {

returngetColor() == Color.WHITE ? “N” : “n”;

}

public Square[] movesFrom(Square square) {

Square[] sq = new Square[8];

int counter = 0;

char rank = square.getRank();

char file = square.getFile();

char[] ranks = new char[]{(char) (rank – 2), (char) (rank – 1), (char) (rank + 1), (char) (rank + 2)};

char[] files = new char[]{(char) (file – 2), (char) (file – 1), (char) (file + 1), (char) (file + 2)};

if (isInBoard(files[0], ranks[1])) {

sq[counter++] = new Square(files[0], ranks[1]);

}

if (isInBoard(files[0], ranks[2])) {

sq[counter++] = new Square(files[0], ranks[2]);

}

if (isInBoard(files[1], ranks[0])) {

sq[counter++] = new Square(files[1], ranks[0]);

}

if (isInBoard(files[1], ranks[3])) {

sq[counter++] = new Square(files[1], ranks[3]);

}

if (isInBoard(files[2], ranks[0])) {

sq[counter++] = new Square(files[2], ranks[0]);

}

if (isInBoard(files[2], ranks[3])) {

sq[counter++] = new Square(files[2], ranks[3]);

}

if (isInBoard(files[3], ranks[1])) {

sq[counter++] = new Square(files[3], ranks[1]);

}

if (isInBoard(files[3], ranks[2])) {

sq[counter++] = new Square(files[3], ranks[2]);

}

Square[] full = new Square[counter];

for (int i = 0; i < counter; i++) {

full[i] = sq[i];

}

return full;

}

}

Move.java

package main.java;

/**

* One turn of chess: both White’s Ply and Black’s Ply.

*/

public class Move {

private Ply whitePly;

private Ply blackPly;

public Move(Ply whitePly, Ply blackPly) {

this.whitePly = whitePly;

this.blackPly = blackPly;

}

public Ply getWhitePly() {

returnwhitePly;

}

public Ply getBlackPly() {

returnblackPly;

}

}

Pawn.java

package main.java;

public class Pawn extends Piece {

public Pawn(Color c) {

super(c);

}

public String algebraicName() {

return “”;

}

public String fenName() {

returngetColor() == Color.WHITE ? “P” : “p”;

}

public Square[] movesFrom(Square square) {

char rank = square.getRank();

char file = square.getFile();

if (getColor() == Color.WHITE) {

if (rank == ‘8’) {

return new Square[0];

} else if (rank == ‘2’) {

return new Square[]{new Square(file, ‘4’), new Square(file, ‘3’)};

} else {

return new Square[]{new Square(file, (char) (rank + 1))};

}

} else {

if (rank == ‘1’) {

return new Square[0];

} else if (rank == ‘7’) {

return new Square[]{new Square(file, ‘5’), new Square(file, ‘6’)};

} else {

return new Square[]{new Square(file, (char) (rank – 1))};

}

}

}

} 

Piece.java

package main.java;

public abstract class Piece {

private Color color;

public Piece(Color c) {

color = c;

}

public Color getColor() {

return color;

}

publicbooleanisInBoard(char file, char rank) {

return file >= ‘a’ && file <= ‘h’ && rank >= ‘1’ && rank <= ‘8’;

}

public abstract String algebraicName();

public abstract String fenName();

public abstract Square[] movesFrom(Square square);

public String toString() {

returncolor.toString() + ” ” + this.getClass();

}

}

Ply.java

package main.java;

importjava.util.Optional;

/**

* One player’s move in chess. Kind of like half of a move.

*/

public class Ply {

private Piece piece;

private Square from;

private Square to;

private Optional<String> comment;

public Ply(Piece piece, Square from, Square to, Optional<String> comment) {

this.piece = piece;

this.from = from;

this.to = to;

this.comment = comment;

}

public Piece getPiece() {

return piece;

}

public Square getFrom() {

return from;

}

public Square getTo() {

return to;

}

public Optional<String>getComment() {

return comment;

}

} 

Queen.java

package main.java;

public class Queen extends Piece {

public Queen(Color c) {

super(c);

}

public String algebraicName() {

return “Q”;

}

public String fenName() {

returngetColor() == Color.WHITE ? “Q” : “q”;

}

public Square[] movesFrom(Square square) {

Square[] sq = new Square[64];

int counter = 0;

char rank = square.getRank();

char file = square.getFile();

for (int i = 1; i <= 8; i++) {

char[] ranks = new char[]{(char) (rank + i), (char) (rank – i)};

char[] files = new char[]{(char) (file + i), (char) (file – i)};

if (isInBoard(files[0], ranks[0])) {

sq[counter++] = new Square(files[0], ranks[0]);

}

if (isInBoard(files[1], ranks[0])) {

sq[counter++] = new Square(files[1], ranks[0]);

}

if (isInBoard(files[0], ranks[1])) {

sq[counter++] = new Square(files[0], ranks[1]);

}

if (isInBoard(files[1], ranks[1])) {

sq[counter++] = new Square(files[1], ranks[1]);

}

if (isInBoard(files[0], rank)) {

sq[counter++] = new Square(files[0], rank);

}

if (isInBoard(files[1], rank)) {

sq[counter++] = new Square(files[1], rank);

}

if (isInBoard(file, ranks[0])) {

sq[counter++] = new Square(file, ranks[0]);

}

if (isInBoard(file, ranks[1])) {

sq[counter++] = new Square(file, ranks[1]);

}

}

Square[] full = new Square[counter];

for (int i = 0; i < counter; i++) {

full[i] = sq[i];

}

return full;

}

}

Rook.java

package main.java;

public class Rook extends Piece {

public Rook(Color c) {

super(c);

}

public String algebraicName() {

return “R”;

}

public String fenName() {

returngetColor() == Color.WHITE ? “R” : “r”;

}

public Square[] movesFrom(Square square) {

Square[] sq = new Square[27];

int counter = 0;

char rank = square.getRank();

char file = square.getFile();

for (int i = 1; i <= 8; i++) {

char[] ranks = new char[]{(char) (rank + i), (char) (rank – i)};

char[] files = new char[]{(char) (file + i), (char) (file – i)};

if (isInBoard(files[0], rank)) {

sq[counter++] = new Square(files[0], rank);

}

if (isInBoard(files[1], rank)) {

sq[counter++] = new Square(files[1], rank);

}

if (isInBoard(file, ranks[0])) {

sq[counter++] = new Square(file, ranks[0]);

}

if (isInBoard(file, ranks[1])) {

sq[counter++] = new Square(file, ranks[1]);

}

}

Square[] full = new Square[counter];

for (int i = 0; i < counter; i++) {

full[i] = sq[i];

}

return full;

}

}

Square.java

package main.java;

public class Square {

private char rank;

private char file;

private String name;

public Square(char file, char rank) {

this(“” + file + rank);

}

public Square(String name) {

this.name = name;

if (name != null &&name.length() == 2) {

file = name.charAt(0);

rank = name.charAt(1);

if (file >= ‘a’ && file <= ‘h’ && rank >= ‘1’ && rank <= ‘8’) {

this.name = name;

} else {

throw new InvalidSquareException(name);

}

} else {

throw new InvalidSquareException(name);

}

}

public char getFile() {

return file;

}

public char getRank() {

return rank;

}

public String toString() {

return name;

}

publicboolean equals(Object o) {

if (o instanceof Square) {

Square that = (Square) o;

returnthat.rank == rank &&that.file == file;

} else {

return false;

}

}

}