diff --git a/OOP_2B1_Project/src/backend/Bishop.java b/OOP_2B1_Project/src/backend/Bishop.java new file mode 100644 index 0000000..1218be0 --- /dev/null +++ b/OOP_2B1_Project/src/backend/Bishop.java @@ -0,0 +1,47 @@ +package backend; + +import java.util.ArrayList; +import java.util.List; + +public class Bishop extends Piece { + public Bishop(boolean isWhite, int x, int y) { + super(isWhite, PieceType.Bishop, x, y); + } + + @Override + public PieceType getType() { + return PieceType.Bishop; + } + + @Override + public List getLegalMoves(Board board, int row, int col) { + List moves = new ArrayList<>(); + int[][] directions = { + {-1, -1}, {-1, 1}, {1, -1}, {1, 1} + }; + + for (int[] dir : directions) { + int r = row + dir[0]; + int c = col + dir[1]; + while (board.isInBounds(r, c)) { + Piece target = board.getPieceAt(r, c); + if (target == null) { + moves.add(new Move(this, row, col, r, c)); + } else { + if (target.isWhite() != this.isWhite) + moves.add(new Move(this, row, col, r, c)); + break; + } + r += dir[0]; + c += dir[1]; + } + } + + return moves; + } + + @Override + public Piece clone() { + return new Bishop(this.isWhite, this.x, this.y); + } +} \ No newline at end of file diff --git a/OOP_2B1_Project/src/backend/Board.java b/OOP_2B1_Project/src/backend/Board.java index 2bf1823..b7341df 100644 --- a/OOP_2B1_Project/src/backend/Board.java +++ b/OOP_2B1_Project/src/backend/Board.java @@ -1,4 +1,8 @@ package backend; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; + import java.util.ArrayList; import java.util.LinkedList; @@ -6,36 +10,39 @@ import java.util.LinkedList; public class Board { - - -private int Width; -private int Height; -private ArrayList pieces; -private int turnNumber = 0; - -private boolean turnIsWhite = true; - -private Integer selectedX = null; - -private Integer selectedY = null; - -private ArrayList highlightedPositions = new ArrayList<>(); - -private LinkedList> boardHistory = new LinkedList<>(); + private int Width; + private int Height; + private ArrayList pieces; + private int turnNumber = 0; + private boolean turnIsWhite = true; + + private Integer selectedX = null; + + private Integer selectedY = null; + + private ArrayList highlightedPositions = new ArrayList<>(); + + private LinkedList> boardHistory = new LinkedList<>(); + + /* ====== AUDIO STATE ====== */ + private Clip moveClip; + private boolean soundEnabled = false; public Board(int colNum, int lineNum) { this.Width=colNum; this.Height=lineNum; this.pieces= new ArrayList <> (); - - - + initMoveSound(); + + + + } public int getWidth() { @@ -47,21 +54,41 @@ private LinkedList> boardHistory = new LinkedList<>(); } public int getTurnNumber() { - + return turnNumber; } public boolean isTurnWhite() { - + return turnIsWhite; } public void setPiece(boolean isWhite, PieceType type, int x, int y) { - - pieces.add(new Piece(isWhite, type, x, y)); - - - + // Create a new instance of the specific piece type + Piece newPiece; + switch (type) { + case Pawn: + newPiece = new Pawn(isWhite, x, y); + break; + case King: + newPiece = new King(isWhite, x, y); + break; + case Queen: + newPiece = new Queen(isWhite, x, y); + break; + case Rook: + newPiece = new Rook(isWhite, x, y); + break; + case Bishop: + newPiece = new Bishop(isWhite, x, y); + break; + case Knight: + newPiece = new Knight(isWhite, x, y); + break; + default: + throw new IllegalArgumentException("Unknown piece type"); + } + pieces.add(newPiece); } public void populateBoard() { @@ -87,158 +114,175 @@ private LinkedList> boardHistory = new LinkedList<>(); for (int i=0;i<8;i++) { setPiece(false,PieceType.Pawn,i,6); } - - + + } - + public void cleanBoard() { - pieces.clear(); - selectedX = null; - selectedY = null; + pieces.clear(); + selectedX = null; + selectedY = null; } - - - + + + public ArrayList getPieces() { - return pieces; + return pieces; } - + public String toString() { StringBuilder sb = new StringBuilder(); - for (int y = 0; y < Height; y++) { - for (int x = 0; x < Width; x++) { - Piece pieceAtPos = null; - for (Piece p : pieces) { - if (p.getX() == x && p.getY() == y) { - pieceAtPos = p; - break; - } - } + for (int y = 0; y < Height; y++) { + for (int x = 0; x < Width; x++) { + Piece pieceAtPos = null; + for (Piece p : pieces) { + if (p.getX() == x && p.getY() == y) { + pieceAtPos = p; + break; + } + } - if (pieceAtPos != null) { - char colorChar = pieceAtPos.isWhite() ? 'W' : 'B'; - String typeChar = pieceAtPos.getType().getSummary(); - sb.append(colorChar).append(typeChar); - } else { - sb.append(", "); - } + if (pieceAtPos != null) { + char colorChar = pieceAtPos.isWhite() ? 'W' : 'B'; + String typeChar = pieceAtPos.getType().getSummary(); + sb.append(colorChar).append(typeChar); + } else { + sb.append(", "); + } - sb.append(" "); - } - sb.append("\n"); - } + sb.append(" "); + } + sb.append("\n"); + } - sb.append("Turn: ").append(turnIsWhite ? "White" : "Black"); - sb.append(" (Turn number: ").append(turnNumber).append(")\n"); + sb.append("Turn: ").append(turnIsWhite ? "White" : "Black"); + sb.append(" (Turn number: ").append(turnNumber).append(")\n"); + + return sb.toString(); - return sb.toString(); - } - + public void userTouch(int x, int y) { - - if (selectedX == null && selectedY == null) { - - Piece pieceAtPos = getPieceAt(x, y); - - if (pieceAtPos != null) { - - selectedX = x; - selectedY = y; - } - } else { - - if (selectedX == x && selectedY == y) { - - selectedX = null; - selectedY = null; - } else { - - Piece pieceToMove = getPieceAt(selectedX, selectedY); - - if (pieceToMove != null) { - - Piece pieceAtDestination = getPieceAt(x, y); - - - if (pieceAtDestination == null || - pieceAtDestination.isWhite() != pieceToMove.isWhite()) { - - saveStateToHistory(); - if (pieceAtDestination != null) { - pieces.remove(pieceAtDestination); - } - - pieces.remove(pieceToMove); - pieces.add(new Piece(pieceToMove.isWhite(), pieceToMove.getType(), x, y)); - - - turnNumber++; - turnIsWhite = !turnIsWhite; - } - - - - selectedX = null; - selectedY = null; - } - } - } - - - } - + if (selectedX == null && selectedY == null) { + Piece pieceAtPos = getPieceAt(x, y); + if (pieceAtPos != null) { + selectedX = x; + selectedY = y; + } + } else { + if (selectedX == x && selectedY == y) { + selectedX = null; + selectedY = null; + } else { + Piece pieceToMove = getPieceAt(selectedX, selectedY); + if (pieceToMove != null) { + Piece pieceAtDestination = getPieceAt(x, y); + if (pieceAtDestination == null || + pieceAtDestination.isWhite() != pieceToMove.isWhite()) { + + saveStateToHistory(); + if (pieceAtDestination != null) { + pieces.remove(pieceAtDestination); + } + + pieces.remove(pieceToMove); + + // Create a new instance of the specific piece type + Piece newPiece = makeNewPiece(pieceToMove.getType(), + pieceToMove.isWhite, x, y); + pieces.add(newPiece); + + playMoveSound(); + + turnNumber++; + turnIsWhite = !turnIsWhite; + } + } + selectedX = null; + selectedY = null; + } + } + + } + + private Piece makeNewPiece(PieceType type, boolean isWhite, int x, int y) { + Piece newPiece; + switch (type) { + case Pawn: + newPiece = new Pawn(isWhite, x, y); + break; + case King: + newPiece = new King(isWhite, x, y); + break; + case Queen: + newPiece = new Queen(isWhite, x, y); + break; + case Rook: + newPiece = new Rook(isWhite, x, y); + break; + case Bishop: + newPiece = new Bishop(isWhite, x, y); + break; + case Knight: + newPiece = new Knight(isWhite, x, y); + break; + default: + throw new IllegalArgumentException("Unknown piece type"); + } + return newPiece; + } + private void saveStateToHistory() { ArrayList clonedList = new ArrayList<>(); for(int i =0; i> boardHistory = new LinkedList<>(); turnIsWhite = false; } } - - + + /* The following methods require more work ! */ public boolean isHighlighted(int x, int y) { @@ -277,50 +321,82 @@ private LinkedList> boardHistory = new LinkedList<>(); } public void undoLastMove() { - - pieces = boardHistory.getLast(); - boardHistory.removeLast(); + + pieces = boardHistory.getLast(); + boardHistory.removeLast(); } public Board(Board board) { //TODO } - + public void playMove(Move move) { //TODO } - -public ArrayList getAllLegalMoves(boolean isWhite) { - ArrayList moves = new ArrayList<>(); - for (int row = 0; row < 8; row++) { - for (int col = 0; col < 8; col++) { - Piece piece = getPieceAt(row, col); - if (piece != null && piece.isWhite() == isWhite) { - //LinkedList pieceMoves = piece.getLegalMoves(this, row, col); // This method must exist in Piece - //moves.addAll(pieceMoves); - } - } - } + public ArrayList getAllLegalMoves(boolean isWhite) { + ArrayList moves = new ArrayList<>(); - return moves; + for (int row = 0; row < 8; row++) { + for (int col = 0; col < 8; col++) { + Piece piece = getPieceAt(row, col); + if (piece != null && piece.isWhite() == isWhite) { + //LinkedList pieceMoves = piece.getLegalMoves(this, row, col); // This method must exist in Piece + //moves.addAll(pieceMoves); + } + } + } + + return moves; } -public ArrayList getAllPieces() { - ArrayList pieces = new ArrayList<>(); + public ArrayList getAllPieces() { + ArrayList pieces = new ArrayList<>(); - for (int row = 0; row < 8; row++) { - for (int col = 0; col < 8; col++) { - Piece p = getPieceAt(row, col); - if (p != null) { - pieces.add(p); - } - } - } - - return pieces; -} + for (int row = 0; row < 8; row++) { + for (int col = 0; col < 8; col++) { + Piece p = getPieceAt(row, col); + if (p != null) { + pieces.add(p); + } + } + } + return pieces; + } + public boolean isInBounds(int row, int col) { + return row >= 0 && row < 8 && col >= 0 && col < 8; + } + private void initMoveSound() { + try { + AudioInputStream ais = AudioSystem.getAudioInputStream( + Board.class.getResource("/sounds/move.wav")); + + if (ais == null) { // resource not found + System.err.println("move.wav not on class-path!"); + return; + } + + moveClip = AudioSystem.getClip(); + moveClip.open(ais); + + soundEnabled = true; // <<< MISSING LINE + System.out.println("Move-sound loaded OK"); + } catch (Exception e) { + e.printStackTrace(); + soundEnabled = false; + } + } + + private void playMoveSound() { + if (!soundEnabled || moveClip == null) return; + + if (moveClip.isRunning()) { + moveClip.stop(); + } + moveClip.setFramePosition(0); + moveClip.start(); + } } diff --git a/OOP_2B1_Project/src/backend/King.java b/OOP_2B1_Project/src/backend/King.java new file mode 100644 index 0000000..3d31626 --- /dev/null +++ b/OOP_2B1_Project/src/backend/King.java @@ -0,0 +1,41 @@ +package backend; + +import java.util.ArrayList; +import java.util.List; + +public class King extends Piece { + public King(boolean isWhite, int x, int y) { + super(isWhite, PieceType.King, x, y); + } + + @Override + public PieceType getType() { + return PieceType.King; + } + + @Override + public List getLegalMoves(Board board, int row, int col) { + List moves = new ArrayList<>(); + int[] d = {-1, 0, 1}; + + for (int dr : d) { + for (int dc : d) { + if (dr == 0 && dc == 0) continue; + int r = row + dr; + int c = col + dc; + if (board.isInBounds(r, c)) { + Piece p = board.getPieceAt(r, c); + if (p == null || p.isWhite() != this.isWhite) + moves.add(new Move(this, row, col, r, c)); + } + } + } + + return moves; + } + + @Override + public Piece clone() { + return new King(this.isWhite, this.x, this.y); + } +} \ No newline at end of file diff --git a/OOP_2B1_Project/src/backend/Knight.java b/OOP_2B1_Project/src/backend/Knight.java new file mode 100644 index 0000000..1a43c34 --- /dev/null +++ b/OOP_2B1_Project/src/backend/Knight.java @@ -0,0 +1,41 @@ +package backend; + +import java.util.ArrayList; +import java.util.List; + +public class Knight extends Piece { + public Knight(boolean isWhite, int x, int y) { + super(isWhite, PieceType.Knight, x, y); + } + + @Override + public PieceType getType() { + return PieceType.Knight; + } + + @Override + public List getLegalMoves(Board board, int row, int col) { + List moves = new ArrayList<>(); + int[][] offsets = { + {-2, -1}, {-2, 1}, {-1, -2}, {-1, 2}, + {1, -2}, {1, 2}, {2, -1}, {2, 1} + }; + + for (int[] offset : offsets) { + int r = row + offset[0]; + int c = col + offset[1]; + if (board.isInBounds(r, c)) { + Piece p = board.getPieceAt(r, c); + if (p == null || p.isWhite() != this.isWhite) + moves.add(new Move(this, row, col, r, c)); + } + } + + return moves; + } + + @Override + public Piece clone() { + return new Knight(this.isWhite, this.x, this.y); + } +} diff --git a/OOP_2B1_Project/src/backend/Move.java b/OOP_2B1_Project/src/backend/Move.java index 38328d3..73c867b 100644 --- a/OOP_2B1_Project/src/backend/Move.java +++ b/OOP_2B1_Project/src/backend/Move.java @@ -1,20 +1,51 @@ package backend; public class Move { - private final Piece piece; - private final int fromX, fromY, toX, toY; + private final Piece movedPiece; + private final int fromRow, fromCol; + private final int toRow, toCol; + private final Piece capturedPiece; // Optional, can be null - public Move(Piece piece, int fromX, int fromY, int toX, int toY) { - this.piece = piece; - this.fromX = fromX; - this.fromY = fromY; - this.toX = toX; - this.toY = toY; + public Move(Piece movedPiece, int fromRow, int fromCol, int toRow, int toCol) { + this(movedPiece, fromRow, fromCol, toRow, toCol, null); } - public Piece getPiece() { return piece; } - public int getFromX() { return fromX; } - public int getFromY() { return fromY; } - public int getToX() { return toX; } - public int getToY() { return toY; } + public Move(Piece movedPiece, int fromRow, int fromCol, int toRow, int toCol, Piece capturedPiece) { + this.movedPiece = movedPiece; + this.fromRow = fromRow; + this.fromCol = fromCol; + this.toRow = toRow; + this.toCol = toCol; + this.capturedPiece = capturedPiece; + } + + public Piece getMovedPiece() { + return movedPiece; + } + + public int getFromRow() { + return fromRow; + } + + public int getFromCol() { + return fromCol; + } + + public int getToRow() { + return toRow; + } + + public int getToCol() { + return toCol; + } + + public Piece getCapturedPiece() { + return capturedPiece; + } + + @Override + public String toString() { + return movedPiece.getType() + " from (" + fromRow + "," + fromCol + ") to (" + toRow + "," + toCol + ")" + + (capturedPiece != null ? " capturing " + capturedPiece.getType() : ""); + } } diff --git a/OOP_2B1_Project/src/backend/Pawn.java b/OOP_2B1_Project/src/backend/Pawn.java new file mode 100644 index 0000000..156291d --- /dev/null +++ b/OOP_2B1_Project/src/backend/Pawn.java @@ -0,0 +1,51 @@ +package backend; + +import java.util.ArrayList; +import java.util.List; + +public class Pawn extends Piece { + public Pawn(boolean isWhite, int x, int y) { + super(isWhite, PieceType.Pawn, x, y); + } + + @Override + public PieceType getType() { + return PieceType.Pawn; + } + + @Override + public List getLegalMoves(Board board, int row, int col) { + List moves = new ArrayList<>(); + int direction = isWhite ? -1 : 1; + int startRow = isWhite ? 6 : 1; + + // Forward 1 square + int forwardRow = row + direction; + if (board.isInBounds(forwardRow, col) && board.getPieceAt(forwardRow, col) == null) { + moves.add(new Move(this, row, col, forwardRow, col)); + + // Forward 2 squares from starting position + int doubleForwardRow = row + 2 * direction; + if (row == startRow && board.getPieceAt(doubleForwardRow, col) == null) { + moves.add(new Move(this, row, col, doubleForwardRow, col)); + } + } + + // Diagonal captures + for (int dc = -1; dc <= 1; dc += 2) { + int c = col + dc; + if (board.isInBounds(forwardRow, c)) { + Piece target = board.getPieceAt(forwardRow, c); + if (target != null && target.isWhite() != this.isWhite) + moves.add(new Move(this, row, col, forwardRow, c)); + } + } + + return moves; + } + + @Override + public Piece clone() { + return new Pawn(this.isWhite, this.x, this.y); + } +} diff --git a/OOP_2B1_Project/src/backend/Piece.java b/OOP_2B1_Project/src/backend/Piece.java index 618c43c..b856535 100644 --- a/OOP_2B1_Project/src/backend/Piece.java +++ b/OOP_2B1_Project/src/backend/Piece.java @@ -1,35 +1,39 @@ package backend; -public class Piece { - - private int x; - private int y; - private PieceType type; - private boolean isWhite; - +import java.util.List; - public int getX() { - return x; - } +public abstract class Piece { + protected int x; + protected int y; + protected PieceType type; + protected boolean isWhite; - public int getY() { - return y; - } - - public PieceType getType() { - return type; - } - - public boolean isWhite() { - return isWhite; - } - - public Piece(boolean isWhite, PieceType type, int x, int y){ - this.x=x; - this.y=y; - this.isWhite=isWhite; - this.type=type; - - } + public Piece(boolean isWhite, PieceType type, int x, int y) { + this.x = x; + this.y = y; + this.type = type; + this.isWhite = isWhite; + } + + public int getX() { return x; } + + public int getY() { return y; } + + public PieceType getType() { return type; } + + public boolean isWhite() { return isWhite; } + + public abstract List getLegalMoves(Board board, int row, int col); + + public abstract Piece clone(); } + + + + + + + + + diff --git a/OOP_2B1_Project/src/backend/Queen.java b/OOP_2B1_Project/src/backend/Queen.java new file mode 100644 index 0000000..8b8692d --- /dev/null +++ b/OOP_2B1_Project/src/backend/Queen.java @@ -0,0 +1,49 @@ +package backend; + +import java.util.ArrayList; +import java.util.List; + +public class Queen extends Piece { + public Queen(boolean isWhite, int x, int y) { + super(isWhite, PieceType.Queen, x, y); + } + + @Override + public PieceType getType() { + return PieceType.Queen; + } + + @Override + public List getLegalMoves(Board board, int row, int col) { + List moves = new ArrayList<>(); + int[][] directions = { + {-1, 0}, {1, 0}, {0, -1}, {0, 1}, // Rook-like + {-1, -1}, {-1, 1}, {1, -1}, {1, 1} // Bishop-like + }; + + for (int[] dir : directions) { + int r = row + dir[0]; + int c = col + dir[1]; + while (board.isInBounds(r, c)) { + Piece target = board.getPieceAt(r, c); + if (target == null) { + moves.add(new Move(this, row, col, r, c)); + } else { + if (target.isWhite() != this.isWhite) { + moves.add(new Move(this, row, col, r, c)); + } + break; + } + r += dir[0]; + c += dir[1]; + } + } + + return moves; + } + + @Override + public Piece clone() { + return new Queen(this.isWhite, this.x, this.y); + } +} diff --git a/OOP_2B1_Project/src/backend/Rook.java b/OOP_2B1_Project/src/backend/Rook.java new file mode 100644 index 0000000..d5202f0 --- /dev/null +++ b/OOP_2B1_Project/src/backend/Rook.java @@ -0,0 +1,44 @@ +package backend; + +import java.util.ArrayList; +import java.util.List; + +public class Rook extends Piece { + public Rook(boolean isWhite, int x, int y) { + super(isWhite, PieceType.Rook, x, y); + } + + @Override + public PieceType getType() { + return PieceType.Rook; + } + + @Override + public List getLegalMoves(Board board, int row, int col) { + List moves = new ArrayList<>(); + int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + + for (int[] dir : directions) { + int r = row + dir[0], c = col + dir[1]; + while (board.isInBounds(r, c)) { + Piece target = board.getPieceAt(r, c); + if (target == null) { + moves.add(new Move(this, row, col, r, c)); + } else { + if (target.isWhite() != this.isWhite) + moves.add(new Move(this, row, col, r, c)); + break; + } + r += dir[0]; + c += dir[1]; + } + } + + return moves; + } + + @Override + public Piece clone() { + return new Rook(this.isWhite, this.x, this.y); + } +} \ No newline at end of file diff --git a/OOP_2B1_Project/src/sounds/move.wav b/OOP_2B1_Project/src/sounds/move.wav new file mode 100644 index 0000000..1e6615e Binary files /dev/null and b/OOP_2B1_Project/src/sounds/move.wav differ