From 109440bd1d2e955769886d7cb03edea0ab024fc2 Mon Sep 17 00:00:00 2001 From: Ian Danahy Date: Mon, 5 Apr 2021 06:05:32 -0400 Subject: [PATCH 1/6] Added functionality for moving black pieces so that players can play against the computer --- src/main/java/game/Main.java | 111 ++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 42 deletions(-) diff --git a/src/main/java/game/Main.java b/src/main/java/game/Main.java index 7b2b755..2aba9e0 100644 --- a/src/main/java/game/Main.java +++ b/src/main/java/game/Main.java @@ -1,42 +1,69 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package game; - -import java.awt.EventQueue; -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.JFrame; - -/** - * - * @author gersc - */ -public class Main extends JFrame { - - public Main() { - try { - this.add( new Board()); - } catch (IOException ex) { - Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); - } - this.pack(); - this.setResizable(false); - this.setTitle( "CHESS" ); - this.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); - this.setLocationRelativeTo( null ); - } - - public static void main(String[] args) { - - EventQueue.invokeLater(() -> { - Main main = new Main(); - main.setVisible( true ); - }); - - } - -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package game; + +import java.awt.BorderLayout; +import java.awt.EventQueue; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +/** + * + * @author gersc + */ +public class Main extends JFrame { + + public Main() { + + /// \ref T7_1 Popup will ask users to choose the number of players + boolean onePlayer = isOnePlayerGame(); + + try { + this.add( new Board(onePlayer)); + } catch (IOException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + + this.pack(); + this.setResizable(false); + this.setTitle( "CHESS" ); + this.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); + this.setLocationRelativeTo( null ); + + } + + /// \ref T7_2 Popup for users to choose number of players + //will return true for One player, false for Two player + public boolean isOnePlayerGame() { + String[] options = {"1 Player", "2 Players"}; + int playerChoice = JOptionPane.showOptionDialog(null, "Please choose number of Players", + "How Many Players?", + JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE, null, options, options[0]); + if (playerChoice == 0) { + return true; + } + else { + return false; + } + } + + + public static void main(String[] args) { + + EventQueue.invokeLater(() -> { + Main main = new Main(); + main.setVisible( true ); + }); + + } + +} From 5e3afe80b09678b89a5426c3714c8541648efd45 Mon Sep 17 00:00:00 2001 From: Ian Danahy Date: Thu, 15 Apr 2021 19:30:44 -0400 Subject: [PATCH 2/6] Added functionality to play against a computer player. This allows the game to be played without a second person. --- src/main/java/game/Opponent.java | 206 +++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 src/main/java/game/Opponent.java diff --git a/src/main/java/game/Opponent.java b/src/main/java/game/Opponent.java new file mode 100644 index 0000000..a6155c8 --- /dev/null +++ b/src/main/java/game/Opponent.java @@ -0,0 +1,206 @@ +package game; + +import java.util.ArrayList; + +/// \imp \ref T1_1 \ref T1_2 \ref T1_3 +/// Class that allows the game to be played single player. +/// Holds the methods for the computer choosing a piece to move and moving that piece. +/// These functions allow us to simulate a computer player so that the game can +/// be played without a second person. +public class Opponent { + /// \ref T1_1 \ref T1_2 + ///The computer player must have a list of which pieces it can move so that it can + ///choose a piece to move. This cuts down on time checking possible moves on pieces that + ///cannot move at all. + private ArrayList
moveablePieces = new ArrayList(); + /// \ref T1_1 \ref T1_2 + ///The computer player must know where the player's pieces are in order to choose a proper move + private ArrayList
playerPieces; + /// \ref T1_1 \ref T1_2 + ///The computer player needs to know the current board state in order to choose the + ///correct move to make. + private Field[][] board; + + public Opponent(Field[][] arrayBoard) { + this.board = arrayBoard; + } + + /// \imp \ref T1_1 \ref T1_2 \ref T1_3 + ///The computer player must be able to choose a piece to move, choose where to move it, + ///and then move that piece + public void takeTurn(ArrayList
computerPieces, ArrayList
playerPieces) { + this.playerPieces = playerPieces; + choosePieceToMove(computerPieces); + } + + /// \imp \ref T1_3 + /// The computer player must be able to move their pieces to a new position + private void move(Figure piece, int newXCoord, int newYCoord) { + Field oldField = piece.getField(); + System.out.println("Computer moving piece at " + oldField.getXCord() + ", " + oldField.getYCord()); + System.out.println("Moving to " + newXCoord + ", " + newYCoord); + Field newField = board[newXCoord][newYCoord]; + if(newField.getFigure() != null) { + playerPieces.remove(newField.getFigure()); + } + oldField.getFigure().removeTexture(); + newField.setFigure(piece); + oldField.removeFigure(); + } + + ///\imp \ref T1_1 \ref T1_2 + ///Determine which piece should be moved by the computer. + ///The computer player will use the following rules to determine which piece to move next: + ///1. It will try to get out of check, if necessary + ///2. It will try to take an opponent's piece, if possible. + ///3. It will try to protect it's own pieces, if possible. + ///4. It will move randomly if it cannot do any of the above. + private void choosePieceToMove(ArrayList
pieces) { + moveablePieces.clear(); + for(Figure piece : pieces) { + if(canMove(piece)) { + moveablePieces.add(piece); + } + } + + if(isInCheck(board)) { + escapeCheck(); + return; + } + + for(Figure piece : moveablePieces) { + if(canTakeOpponentPiece(piece)) { + return; + } + } + + for(Figure piece : moveablePieces) { + if(canEscapeFromBeingTaken(piece)) { + return; + } + } + + randomPiece(); + return; + } + + ///\ref T1_1 The computer player has to be able to determine if the piece is + ///able to move before it can decide which piece to move + private boolean canMove(Figure piece) { + for (int xCoord = 0; xCoord < board.length; xCoord++) { + for(int yCoord = 0; yCoord < board[xCoord].length; yCoord++) { + Field localField = board[xCoord][yCoord]; + if(piece.isMovePossible(localField)) + return true; + } + } + return false; + } + + ///\ref T1_1 \ref T1_2 + ///In order to make the correct move, the computer player + ///must be able to determine whether or not it is currently in check + private boolean isInCheck(Field[][] board) { + for(Figure piece : playerPieces) { + for (int xCoord = 0; xCoord < board.length; xCoord++) { + for(int yCoord = 0; yCoord < board[xCoord].length; yCoord++) { + Field localField = board[xCoord][yCoord]; + if(piece.isMovePossible(localField) && localField.getFigure() instanceof King) { + System.out.println("Computer In check!"); + return true; + } + } + } + } + return false; + } + + ///\ref T1_1 \ref T1_2 + ///In order to choose the correct piece and position to a move, + ///the computer player must first attempt to escape from being in check + private void escapeCheck() { + for(Figure piece : moveablePieces) { + for (int xCoord = 0; xCoord < board.length; xCoord++) { + for(int yCoord = 0; yCoord < board[xCoord].length; yCoord++) { + Field localField = board[xCoord][yCoord]; + if(piece.isMovePossible(localField)) { + Figure temp = localField.getFigure(); + Field oldField = piece.getField(); + if(temp != null) { + playerPieces.remove(temp); + } + oldField.getFigure().removeTexture(); + localField.setFigure(piece); + oldField.removeFigure(); + if(isInCheck(board)) { + if(temp == null) { + localField.getFigure().removeTexture(); + oldField.setFigure(piece); + localField.removeFigure(); + } + else { + localField.setFigure(temp); + oldField.setFigure(piece); + playerPieces.add(temp); + } + } + else { + return; + } + + } + } + } + } + } + + ///\ref T1_1 + ///The computer player has to determine if a piece is able to take one of the + ///player's pieces in order to choose which piece to move + private boolean canTakeOpponentPiece(Figure piece) { + for (int xCoord = 0; xCoord < board.length; xCoord++) { + for(int yCoord = 0; yCoord < board[xCoord].length; yCoord++) { + Field localField = board[xCoord][yCoord]; + if(piece.isMovePossible(localField) && localField.getFigure() != null){ + move(piece, xCoord, yCoord); + return true; + } + } + } + return false; + } + + ///\ref T1_1 The computer player has to determine if a piece is able to escape + ///being taken by the player in order to choose which piece to move + private boolean canEscapeFromBeingTaken(Figure piece) { + for(Figure playerPiece : playerPieces) { + if(playerPiece.isMovePossible(piece.getField())) { + for (int xCoord = 0; xCoord < board.length; xCoord++) { + for(int yCoord = 0; yCoord < board[xCoord].length; yCoord++) { + Field field = board[xCoord][yCoord]; + if(piece.isMovePossible(field)) { + move(piece, xCoord, yCoord); + return true; + } + } } + } + } + return false; + } + + ///\ref T1_1 + ///If none of the other conditions are met, the computer player still has to + ///choose a piece, so it will choose a random piece to move + private void randomPiece() { + Figure piece = moveablePieces.get((int)(Math.random() * moveablePieces.size())); + for (int xCoord = 0; xCoord < board.length; xCoord++) { + for(int yCoord = 0; yCoord < board[xCoord].length; yCoord++) { + Field field = board[xCoord][yCoord]; + if(piece.isMovePossible(field)) { + move(piece, xCoord, yCoord); + return; + } + } + } + } +} From 4105da490c222643e34639241cf3fe76b07c7722 Mon Sep 17 00:00:00 2001 From: Ian Danahy Date: Thu, 15 Apr 2021 19:30:57 -0400 Subject: [PATCH 3/6] Added functionality to play against a computer player. This allows the game to be played without a second person. --- src/main/java/game/Board.java | 750 +++++++++++++++++----------------- 1 file changed, 386 insertions(+), 364 deletions(-) diff --git a/src/main/java/game/Board.java b/src/main/java/game/Board.java index 513a720..2025e3a 100644 --- a/src/main/java/game/Board.java +++ b/src/main/java/game/Board.java @@ -1,364 +1,386 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package game; - -import java.awt.Color; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import javax.swing.*; - -/** - * - * @author gersc - */ -public class Board extends JPanel { - - private Field[][] arrayBoard; - - private ArrayList
destroyedFiguresList; - private ArrayList
whiteFiguresList; - private ArrayList
blackFiguresList; - Field field = null; - Field oldField = null; - int saveYCoord; - int saveXCoord; - boolean isWhitesTurn = true; - InformationBoard infoBoard; - Field collisionField; - - private boolean isSelected = false; - - public Board() throws IOException { - - this.initBoard(); - } - - private void initBoard() { - - this.setSize(800, 800); - - BoardListener boardlistener = new BoardListener(); - arrayBoard = new Field[8][8]; - destroyedFiguresList = new ArrayList<>(); - blackFiguresList = new ArrayList<>(); - whiteFiguresList = new ArrayList<>(); - - this.setLayout(new java.awt.GridLayout(8, 8)); - boolean black = true; - - for (int yCord = 0; yCord < arrayBoard.length; yCord++) { - for (int xCord = 0; xCord < arrayBoard.length; xCord++) { - - Field field = new Field(this, black, xCord, yCord); - - field.addActionListener(boardlistener); - field.setBorder(null); - arrayBoard[xCord][yCord] = field; - - field.setStandartColor(); - - if (yCord == 1) { - Pawn pawn = new Pawn(xCord, yCord, true, field); - field.setFigure(pawn); - } else if (yCord == 0) { - switch (xCord) { - case 0: - case 7: - Rook rook = new Rook(xCord, yCord, true, field); - field.setFigure(rook); - break; - case 1: - case 6: - Knight knight = new Knight(xCord, yCord, true, field); - field.setFigure(knight); - break; - case 2: - case 5: - Bishop bishop = new Bishop(xCord, yCord, true, field); - field.setFigure(bishop); - //Laeufer - break; - case 3: - Queen queen = new Queen(xCord, yCord, true, field); - field.setFigure(queen); - //Queen - break; - default: - King king = new King(xCord, yCord, true, field); - field.setFigure(king); - // King - break; - } - } else if (yCord == 6) { - Pawn pawn = new Pawn(xCord, yCord, false, field); - field.setFigure(pawn); - } else if (yCord == 7) { - switch (xCord) { - case 0: - case 7: - Rook rook = new Rook(xCord, yCord, false, field); - field.setFigure(rook); - break; - case 1: - case 6: - Knight knight = new Knight(xCord, yCord, false, field); - field.setFigure(knight); - break; - case 2: - case 5: - Bishop bishop = new Bishop(xCord, yCord, false, field); - field.setFigure(bishop); - //Laeufer - break; - case 3: - Queen queen = new Queen(xCord, yCord, false, field); - field.setFigure(queen); - //Queen - break; - default: - King king = new King(xCord, yCord, false, field); - field.setFigure(king); - // King - break; - } - } - - this.add(field); - - if (field.getFigure() != null) { - if (field.getFigure().getIsBlack()) { - blackFiguresList.add(field.getFigure()); - } else { - whiteFiguresList.add(field.getFigure()); - } - } - - black = !black; - } - black = !black; - } - - this.printActivePlayer(); - - } - - private class BoardListener implements java.awt.event.ActionListener { - - /* - * Executed when a field is pressed - */ - public void actionPerformed(java.awt.event.ActionEvent event) { - - for (int yCoord = 0; yCoord < arrayBoard.length; yCoord++) { - for (int xCoord = 0; xCoord < arrayBoard.length; xCoord++) { - if (event.getSource() == arrayBoard[xCoord][yCoord]) { - field = arrayBoard[xCoord][yCoord]; - saveXCoord = xCoord; - saveYCoord = yCoord; - System.out.println("X: " + xCoord + ", Y: " + yCoord); - break; - } - } - } - - printActivePlayer(); - - /* - * Executed when a pushed friendly unit is on it or the field is empty and no unit is selected - */ - if (field.getFigure() != null && isWhitesTurn != field.getFigure().getIsBlack()) { - this.setCheckedFalse(); - this.removeMarker(); - oldField = field; - isSelected = true; - - if (field.getFigure() instanceof King) { - if (field.getFigure().getIsBlack()) { - this.setCheckedFieldsKing(whiteFiguresList, false); - } else { - this.setCheckedFieldsKing(blackFiguresList, true); - } - } - - /* - * Checks all fields and marks them with the right color - */ - for (int yCoord = 0; yCoord < arrayBoard.length; yCoord++) { - for (int xCoord = 0; xCoord < arrayBoard.length; xCoord++) { - Field localField = arrayBoard[xCoord][yCoord]; - if (field.getFigure().isMovePossible(localField)) { - if (localField.getFigure() == null) { - localField.possibleHighlightOn(); - } else if (localField.getFigure().getIsBlack() != field.getFigure().getIsBlack()) { - if (localField.getFigure() instanceof King) { - localField.checkHighlightOn(); - } else { - localField.collisionHighlightOn(); - } - } - } - } - } - oldField.selectionHighlightOn(); - } /* - * Executed when a unit is selected and the pushed field is valid - */ else if (isSelected && oldField.getFigure().isMoveValid(field)) { - this.removeMarker(); - if (field.getFigure() != null) { - destroyedFiguresList.add(field.getFigure()); - } - oldField.getFigure().removeTexture(); - if (oldField.getFigure() instanceof Pawn) { - Pawn localPawn = (Pawn) oldField.getFigure(); - localPawn.setWasMoved(true); - } - - field.setFigure(oldField.getFigure()); - oldField.removeFigure(); - isSelected = false; - - System.out.println(Arrays.toString(destroyedFiguresList.toArray())); - - this.setCheckedFields(whiteFiguresList, false); - this.setCheckedFields(blackFiguresList, true); - if (isWhitesTurn) { - if (!this.checkCheckmated(true)) { - System.out.println("Player White won!"); - System.exit(0); - } - } else { - if (!this.checkCheckmated(false)) { - System.out.println("Player Black won!"); - System.exit(0); - } - } - isWhitesTurn = !isWhitesTurn; - } - } - - /* - * Helpermethod, which removes all markers - */ - private void removeMarker() { - for (int yCoord = 0; yCoord < arrayBoard.length; yCoord++) { - for (int xCoord = 0; xCoord < arrayBoard.length; xCoord++) { - Field localField = arrayBoard[xCoord][yCoord]; - - localField.setStandartColor(); - - } - } - } - - public void setCheckedFieldsKing(ArrayList teamList, boolean black) { - ArrayList
localteamList = teamList; - - for (Figure figure : localteamList) { - for (int yCoord = 0; yCoord < arrayBoard.length; yCoord++) { - for (int xCoord = 0; xCoord < arrayBoard.length; xCoord++) { - Field field = arrayBoard[xCoord][yCoord]; - if (figure.isMovePossible(field)) { - field.checkHighlightOn(); - if (black) { - field.setCheckedByBlack(true); - } else { - field.setCheckedByWhite(true); - } - } - } - } - } - } - - public void setCheckedFields(ArrayList teamList, boolean black) { - ArrayList
localteamList = teamList; - - for (Figure figure : localteamList) { - for (int yCoord = 0; yCoord < arrayBoard.length; yCoord++) { - for (int xCoord = 0; xCoord < arrayBoard.length; xCoord++) { - Field field = arrayBoard[xCoord][yCoord]; - if (figure.isMovePossible(field)) { - if (black) { - field.setCheckedByBlack(true); - } else { - field.setCheckedByWhite(true); - } - } - } - } - } - } - - private void setCheckedFalse() { - for (int y = 0; y < arrayBoard.length; y++) { - for (int x = 0; x < arrayBoard.length; x++) { - Field field = arrayBoard[x][y]; - field.setCheckedByBlack(false); - field.setCheckedByWhite(false); - } - } - } - - private boolean checkCheckmated(boolean blackKing) { - King king = null; - if (blackKing) { - for (Figure figure : blackFiguresList) { - if (figure instanceof King) { - king = (King) figure; - } - } - for (int y = 0; y < arrayBoard.length; y++) { - for (int x = 0; x < arrayBoard.length; x++) { - Field field = arrayBoard[x][y]; - if (king.isMovePossible(field)) { - System.out.println("black can move"); - return true; - } - } - } - - if (king.getField().isCheckedByWhite()) { - return false; - } - } else { - for (Figure figure : whiteFiguresList) { - if (figure instanceof King) { - king = (King) figure; - } - } - for (int y = 0; y < arrayBoard.length; y++) { - for (int x = 0; x < arrayBoard.length; x++) { - Field field = arrayBoard[x][y]; - if (king.isMovePossible(field)) { - System.out.println("white can move"); - return true; - } - } - } - - if (king.getField().isCheckedByBlack()) { - return false; - } - } - - return true; - } - } - - public Field[][] getArrayChessBoard() { - return arrayBoard; - } - - private void printActivePlayer() { - if (isWhitesTurn) { - System.out.println("It's White's turn!"); - } else { - System.out.println("It's Black's turn!"); - } - } - -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package game; + +import java.awt.Color; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import javax.swing.*; + +/** + * + * @author gersc + */ +public class Board extends JPanel { + + private Field[][] arrayBoard; + + private ArrayList
destroyedFiguresList; + private ArrayList
whiteFiguresList; + private ArrayList
blackFiguresList; + Field field = null; + Field oldField = null; + int saveYCoord; + int saveXCoord; + boolean isWhitesTurn = true; + boolean onePlayer; + InformationBoard infoBoard; + Field collisionField; + Opponent opponent = null; + + private boolean isSelected = false; + + public Board(boolean onePlayer) throws IOException { + + this.onePlayer = onePlayer; + this.initBoard(); + } + + private void initBoard() { + + this.setSize(800, 800); + + BoardListener boardlistener = new BoardListener(); + arrayBoard = new Field[8][8]; + destroyedFiguresList = new ArrayList<>(); + blackFiguresList = new ArrayList<>(); + whiteFiguresList = new ArrayList<>(); + + if(onePlayer) { + opponent = new Opponent(arrayBoard); + } + + this.setLayout(new java.awt.GridLayout(8, 8)); + boolean black = true; + + for (int yCord = 0; yCord < arrayBoard.length; yCord++) { + for (int xCord = 0; xCord < arrayBoard.length; xCord++) { + + Field field = new Field(this, black, xCord, yCord); + + field.addActionListener(boardlistener); + field.setBorder(null); + arrayBoard[xCord][yCord] = field; + + field.setStandartColor(); + + if (yCord == 1) { + Pawn pawn = new Pawn(xCord, yCord, true, field); + field.setFigure(pawn); + } else if (yCord == 0) { + switch (xCord) { + case 0: + case 7: + Rook rook = new Rook(xCord, yCord, true, field); + field.setFigure(rook); + break; + case 1: + case 6: + Knight knight = new Knight(xCord, yCord, true, field); + field.setFigure(knight); + break; + case 2: + case 5: + Bishop bishop = new Bishop(xCord, yCord, true, field); + field.setFigure(bishop); + //Laeufer + break; + case 3: + Queen queen = new Queen(xCord, yCord, true, field); + field.setFigure(queen); + //Queen + break; + default: + King king = new King(xCord, yCord, true, field); + field.setFigure(king); + // King + break; + } + } else if (yCord == 6) { + Pawn pawn = new Pawn(xCord, yCord, false, field); + field.setFigure(pawn); + } else if (yCord == 7) { + switch (xCord) { + case 0: + case 7: + Rook rook = new Rook(xCord, yCord, false, field); + field.setFigure(rook); + break; + case 1: + case 6: + Knight knight = new Knight(xCord, yCord, false, field); + field.setFigure(knight); + break; + case 2: + case 5: + Bishop bishop = new Bishop(xCord, yCord, false, field); + field.setFigure(bishop); + //Laeufer + break; + case 3: + Queen queen = new Queen(xCord, yCord, false, field); + field.setFigure(queen); + //Queen + break; + default: + King king = new King(xCord, yCord, false, field); + field.setFigure(king); + // King + break; + } + } + + this.add(field); + + if (field.getFigure() != null) { + if (field.getFigure().getIsBlack()) { + blackFiguresList.add(field.getFigure()); + } else { + whiteFiguresList.add(field.getFigure()); + } + } + + black = !black; + } + black = !black; + } + + this.printActivePlayer(); + + } + + private class BoardListener implements java.awt.event.ActionListener { + + /* + * Executed when a field is pressed + */ + public void actionPerformed(java.awt.event.ActionEvent event) { + + for (int yCoord = 0; yCoord < arrayBoard.length; yCoord++) { + for (int xCoord = 0; xCoord < arrayBoard.length; xCoord++) { + if (event.getSource() == arrayBoard[xCoord][yCoord]) { + field = arrayBoard[xCoord][yCoord]; + saveXCoord = xCoord; + saveYCoord = yCoord; + System.out.println("X: " + xCoord + ", Y: " + yCoord); + break; + } + } + } + + printActivePlayer(); + + /* + * Executed when a pushed friendly unit is on it or the field is empty and no unit is selected + */ + if (field.getFigure() != null && isWhitesTurn != field.getFigure().getIsBlack()) { + this.setCheckedFalse(); + this.removeMarker(); + oldField = field; + isSelected = true; + + if (field.getFigure() instanceof King) { + if (field.getFigure().getIsBlack()) { + this.setCheckedFieldsKing(whiteFiguresList, false); + } else { + this.setCheckedFieldsKing(blackFiguresList, true); + } + } + + /* + * Checks all fields and marks them with the right color + */ + for (int yCoord = 0; yCoord < arrayBoard.length; yCoord++) { + for (int xCoord = 0; xCoord < arrayBoard.length; xCoord++) { + Field localField = arrayBoard[xCoord][yCoord]; + if (field.getFigure().isMovePossible(localField)) { + if (localField.getFigure() == null) { + localField.possibleHighlightOn(); + } else if (localField.getFigure().getIsBlack() != field.getFigure().getIsBlack()) { + if (localField.getFigure() instanceof King) { + localField.checkHighlightOn(); + } else { + localField.collisionHighlightOn(); + } + } + } + } + } + oldField.selectionHighlightOn(); + } /* + * Executed when a unit is selected and the pushed field is valid + */ else if (isSelected && oldField.getFigure().isMoveValid(field)) { + this.removeMarker(); + if (field.getFigure() != null) { + destroyedFiguresList.add(field.getFigure()); + if(field.getFigure().isBlack) { + blackFiguresList.remove(field.getFigure()); + } + else { + whiteFiguresList.remove(field.getFigure()); + } + } + oldField.getFigure().removeTexture(); + if (oldField.getFigure() instanceof Pawn) { + Pawn localPawn = (Pawn) oldField.getFigure(); + localPawn.setWasMoved(true); + } + + field.setFigure(oldField.getFigure()); + oldField.removeFigure(); + isSelected = false; + + System.out.println(Arrays.toString(destroyedFiguresList.toArray())); + + this.setCheckedFields(whiteFiguresList, false); + this.setCheckedFields(blackFiguresList, true); + if (isWhitesTurn) { + if (!this.checkCheckmated(true)) { + System.out.println("Player White won!"); + System.exit(0); + } + } else { + if (!this.checkCheckmated(false)) { + System.out.println("Player Black won!"); + System.exit(0); + } + } + + //if playing against computer, have them takeTurn + if(onePlayer) { + opponent.takeTurn(blackFiguresList, whiteFiguresList); + } + //otherwise, switch which player's turn it is + else { + isWhitesTurn = !isWhitesTurn; + } + + } + } + + /* + * Helpermethod, which removes all markers + */ + private void removeMarker() { + for (int yCoord = 0; yCoord < arrayBoard.length; yCoord++) { + for (int xCoord = 0; xCoord < arrayBoard.length; xCoord++) { + Field localField = arrayBoard[xCoord][yCoord]; + + localField.setStandartColor(); + + } + } + } + + public void setCheckedFieldsKing(ArrayList teamList, boolean black) { + ArrayList
localteamList = teamList; + + for (Figure figure : localteamList) { + for (int yCoord = 0; yCoord < arrayBoard.length; yCoord++) { + for (int xCoord = 0; xCoord < arrayBoard.length; xCoord++) { + Field field = arrayBoard[xCoord][yCoord]; + if (figure.isMovePossible(field)) { + field.checkHighlightOn(); + if (black) { + field.setCheckedByBlack(true); + } else { + field.setCheckedByWhite(true); + } + } + } + } + } + } + + public void setCheckedFields(ArrayList teamList, boolean black) { + ArrayList
localteamList = teamList; + + for (Figure figure : localteamList) { + for (int yCoord = 0; yCoord < arrayBoard.length; yCoord++) { + for (int xCoord = 0; xCoord < arrayBoard.length; xCoord++) { + Field field = arrayBoard[xCoord][yCoord]; + if (figure.isMovePossible(field)) { + if (black) { + field.setCheckedByBlack(true); + } else { + field.setCheckedByWhite(true); + } + } + } + } + } + } + + private void setCheckedFalse() { + for (int y = 0; y < arrayBoard.length; y++) { + for (int x = 0; x < arrayBoard.length; x++) { + Field field = arrayBoard[x][y]; + field.setCheckedByBlack(false); + field.setCheckedByWhite(false); + } + } + } + + private boolean checkCheckmated(boolean blackKing) { + King king = null; + if (blackKing) { + for (Figure figure : blackFiguresList) { + if (figure instanceof King) { + king = (King) figure; + } + } + for (int y = 0; y < arrayBoard.length; y++) { + for (int x = 0; x < arrayBoard.length; x++) { + Field field = arrayBoard[x][y]; + if (king.isMovePossible(field)) { + System.out.println("black can move"); + return true; + } + } + } + + if (king.getField().isCheckedByWhite()) { + return false; + } + } else { + for (Figure figure : whiteFiguresList) { + if (figure instanceof King) { + king = (King) figure; + } + } + for (int y = 0; y < arrayBoard.length; y++) { + for (int x = 0; x < arrayBoard.length; x++) { + Field field = arrayBoard[x][y]; + if (king.isMovePossible(field)) { + System.out.println("white can move"); + return true; + } + } + } + + if (king.getField().isCheckedByBlack()) { + return false; + } + } + + return true; + } + } + + public Field[][] getArrayChessBoard() { + return arrayBoard; + } + + private void printActivePlayer() { + if (isWhitesTurn) { + System.out.println("It's White's turn!"); + } else { + System.out.println("It's Black's turn!"); + } + } + +} From bd48c87762d3c91a2a1311eb9ba3c990a7e8d514 Mon Sep 17 00:00:00 2001 From: Ian Danahy Date: Tue, 27 Apr 2021 22:56:27 -0400 Subject: [PATCH 4/6] Added Unit tests for Opponent Class --- src/test/java/game/OpponentTest.java | 352 +++++++++++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 src/test/java/game/OpponentTest.java diff --git a/src/test/java/game/OpponentTest.java b/src/test/java/game/OpponentTest.java new file mode 100644 index 0000000..1b91ad8 --- /dev/null +++ b/src/test/java/game/OpponentTest.java @@ -0,0 +1,352 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package game; + +import java.util.ArrayList; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author Ian + */ +public class OpponentTest { + + private static Field[][] boardPositions; + private static Opponent opponent; + private static Board board; + private static ArrayList
whitePieces; + private static ArrayList
blackPieces; + + public OpponentTest() { + try { + setUpClass(); + } catch(Exception e) { + + } + } + + @org.junit.jupiter.api.BeforeAll + public static void setUpClass() throws Exception { + //create empty boardPositions + boardPositions = new Field[8][8]; + opponent = new Opponent(boardPositions); + board = new Board(false); + whitePieces = new ArrayList
(); + blackPieces = new ArrayList
(); + opponent.setPlayerPieces(whitePieces); + } + + @org.junit.jupiter.api.AfterAll + public static void tearDownClass() throws Exception { + } + + @org.junit.jupiter.api.BeforeEach + public void setUp() throws Exception { + boolean black = true; + for(int xCoord = 0; xCoord < 8; xCoord++) { + for(int yCoord = 0; yCoord < 8; yCoord++) { + boardPositions[xCoord][yCoord] = new Field(board, black, xCoord, yCoord); + black = !black; + } + } + } + + + @org.junit.jupiter.api.AfterEach + public void tearDown() throws Exception { + //empty boardPositions + for(int xCoord = 0; xCoord < 8; xCoord++) { + for(int yCoord = 0; yCoord < 8; yCoord++) { + boardPositions[xCoord][yCoord].removeFigure(); + } + } + //empty pieces lists + whitePieces.clear(); + blackPieces.clear(); + } + + /// \ref T1_1 \ref T1_2 \ref T1_3 + @org.junit.jupiter.api.Test + public void testTakeTurn() { + try { + setUp(); + + //opponent will move one piece on its turn + //with only one piece, it moves that piece + Figure queen = new Queen (5, 0, true, boardPositions[5][0]); + boardPositions[5][0].setFigure(queen); + blackPieces.add(queen); + Field queenStart = queen.getField(); + opponent.takeTurn(blackPieces, whitePieces); + Field queenEnd = queen.getField(); + assertTrue(queenStart != queenEnd); + + //with more than that, it moves exactly one piece + opponent.move(queen, 5, 0); + Figure rook = new Rook(0, 0, true, boardPositions[0][0]); + boardPositions[0][0].setFigure(rook); + blackPieces.add(rook); + queenStart = queen.getField(); + Field rookStart = rook.getField(); + + opponent.takeTurn(blackPieces, whitePieces); + queenEnd = queen.getField(); + Field rookEnd = rook.getField(); + assertTrue(queenStart != queenEnd || rookStart != rookEnd); + + tearDown(); + } catch(Exception e) { + fail(e); + } + } + + /// \ref T1_3 + public void testMove() { + try { + setUp(); + + Figure piece = new Queen(0, 4, true, boardPositions[0][4]); + boardPositions[0][4].setFigure(piece); + int startY = piece.getField().getYCord(); + //before move tests + assertTrue(boardPositions[0][4].getFigure() != null); + assertTrue(boardPositions[0][5].getFigure() == null); + opponent.move(piece, 0, 5); + int endY = piece.getField().getYCord(); + //after move tests + assertTrue(startY != endY); + assertTrue(boardPositions[0][4].getFigure() == null); + assertTrue(boardPositions[0][5].getFigure() != null); + + tearDown(); + } catch(Exception e) { + fail(e); + } + } + + /// \ref T1_1 \ref T1_2 + public void testChoosePieceToMove() { + try { + setUp(); + + Figure king = new King(0, 3, true, boardPositions[0][3]); + boardPositions[0][3].setFigure(king); + Figure pawn = new Pawn(3, 5, true, boardPositions[3][5]); + boardPositions[3][5].setFigure(pawn); + blackPieces.add(pawn); + blackPieces.add(king); + + Figure queen = new Queen(0, 6, false, boardPositions[0][6]); + boardPositions[0][6].setFigure(queen); + whitePieces.add(queen); + + //opponent will get itself out of check + //king moves out of danger from queen + assertTrue(opponent.isInCheck(boardPositions)); + opponent.determineMoveablePieces(blackPieces); + opponent.choosePieceToMove(); + assertFalse(opponent.isInCheck(boardPositions)); + + //no longer in check, opponent will take player piece if possible + //bishop takes queen + opponent.move(king, 1, 2); + assertTrue(boardPositions[0][6].getFigure() == queen); + Figure bishop = new Bishop(1, 5, true, boardPositions[1][5]); + boardPositions[1][5].setFigure(bishop); + blackPieces.add(bishop); + opponent.determineMoveablePieces(blackPieces); + opponent.choosePieceToMove(); + assertTrue(boardPositions[0][6].getFigure() == bishop); + + //opponent will attempt to move pieces that are in danger if it cannot take a piece + //pawn moves out of danger from knight + Figure knight = new Knight(2, 7, false, boardPositions[2][7]); + boardPositions[2][7].setFigure(knight); + whitePieces.add(knight); + opponent.determineMoveablePieces(blackPieces); + opponent.choosePieceToMove(); + assertTrue(boardPositions[1][5].getFigure() == null); + + tearDown(); + } catch(Exception e) { + fail(e); + } + } + + /// \ref T1_1 + public void testCanMove() { + try { + setUp(); + + //queen on empty board should be able to move + Figure queen = new Queen(1, 1, false, boardPositions[1][1]); + boardPositions[1][1].setFigure(queen); + assertTrue(opponent.canMove(queen)); + + //bishop in corner blocked by queen should not be able to move + Figure bishop = new Bishop(0, 0, false, boardPositions[0][0]); + boardPositions[0][0].setFigure(bishop); + assertFalse(opponent.canMove(bishop)); + + //once queen moves out of the way, bishop can move + opponent.move(queen, 1, 2); + assertTrue(opponent.canMove(bishop)); + + tearDown(); + } catch(Exception e) { + fail(e); + } + } + + /// \ref T1_1 \ref T1_2 + public void testIsInCheck() { + try { + setUp(); + + //king on empty board is not in check + Figure king = new King(2, 2, true, boardPositions[2][2]); + boardPositions[2][2].setFigure(king); + assertFalse(opponent.isInCheck(boardPositions)); + + //queen in front of king puts it in check + Figure queen = new Queen(2, 4, false, boardPositions[2][4]); + boardPositions[2][4].setFigure(queen); + whitePieces.add(queen); + assertTrue(opponent.isInCheck(boardPositions)); + + //king moves to the side, is no longer in check + opponent.move(king, 3, 2); + assertFalse(opponent.isInCheck(boardPositions)); + + tearDown(); + } catch(Exception e) { + fail(e); + } + } + + /// \ref T1_1 \ref T1_2 + public void testEscapeCheck() { + try { + setUp(); + + //king in check by queen + Figure king = new King(2, 2, true, boardPositions[2][2]); + boardPositions[2][2].setFigure(king); + Figure queen = new Queen(2, 4, false, boardPositions[2][4]); + boardPositions[2][4].setFigure(queen); + blackPieces.add(king); + whitePieces.add(queen); + opponent.determineMoveablePieces(blackPieces); + int startX = king.getField().getXCord(); + int startY = king.getField().getYCord(); + assertTrue(opponent.isInCheck(boardPositions)); + + opponent.escapeCheck(); + + int endX = king.getField().getXCord(); + int endY = king.getField().getYCord(); + //king's position changes after escapeCheck, and king is no longer in check + assertTrue(endX != startX || endY != startY); + assertFalse(opponent.isInCheck(boardPositions)); + + tearDown(); + } catch(Exception e) { + fail(e); + } + } + + /// \ref T1_1 + public void testCanTakePlayerPiece() { + try { + setUp(); + + //queen on empty board can't take a piece + Figure queen = new Queen(2, 2, true, boardPositions[2][2]); + boardPositions[2][2].setFigure(queen); + assertFalse(opponent.canTakePlayerPiece(queen)); + + //queen can take pawn in front of it + Figure pawn = new Pawn(2, 5, false, boardPositions[2][5]); + boardPositions[2][5].setFigure(pawn); + + //queen can take pawn + assertTrue(opponent.canTakePlayerPiece(queen)); + //after taking pawn, queen's new position is pawn's original position + assertTrue(boardPositions[2][5].getFigure() == queen); + assertTrue(queen.getField().getXCord() == 2); + assertTrue(queen.getField().getYCord() == 5); + tearDown(); + } catch(Exception e) { + fail(e); + } + } + + /// \ref T1_1 + public void testCanEscapeFromBeingTaken() { + try { + setUp(); + + + Figure bishop = new Bishop(0, 0, true, boardPositions[0][0]); + boardPositions[0][0].setFigure(bishop); + Figure pawn = new Pawn(1, 1, true, boardPositions[1][1]); + boardPositions[1][1].setFigure(pawn); + blackPieces.add(bishop); + blackPieces.add(pawn); + + //nothing threatening bishop, should return false + assertFalse(opponent.canEscapeFromBeingTaken(bishop)); + + //bishop can't move to escape danger + Figure rook = new Rook(0, 1, false, boardPositions[0][1]); + boardPositions[0][1].setFigure(rook); + whitePieces.add(rook); + assertFalse(opponent.canEscapeFromBeingTaken(bishop)); + + //bishop can move, should return true and move bishop + opponent.move(pawn, 1, 2); + assertTrue(opponent.canEscapeFromBeingTaken(bishop)); + assertTrue(boardPositions[0][0].getFigure() == null); + + tearDown(); + } catch(Exception e) { + fail(e); + } + } + + ///\ref T1_1 + public void testRandomPiece() { + try { + setUp(); + + Figure rook = new Rook(0, 1, true, boardPositions[0][1]); + boardPositions[0][1].setFigure(rook); + Figure pawn = new Pawn(2, 2, true, boardPositions[2][2]); + boardPositions[2][2].setFigure(pawn); + blackPieces.add(rook); + blackPieces.add(pawn); + opponent.determineMoveablePieces(blackPieces); + Field rookStart = rook.getField(); + Field pawnStart = pawn.getField(); + + opponent.randomPiece(); + + Field rookEnd = rook.getField(); + Field pawnEnd = pawn.getField(); + //exactly one of the pieces is moved + assertTrue((rookStart != rookEnd && pawnStart == pawnEnd) || (pawnStart != pawnEnd && rookStart == rookEnd)); + + tearDown(); + } catch(Exception e) { + fail(e); + } + } +} From a039f73e19cbb10631ec1d275a53347eb0422508 Mon Sep 17 00:00:00 2001 From: Ian Danahy Date: Tue, 27 Apr 2021 22:57:16 -0400 Subject: [PATCH 5/6] Added function to find moveable pieces and made functions public so they could be tested --- src/main/java/game/Opponent.java | 42 +++++++++++++++++++------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/main/java/game/Opponent.java b/src/main/java/game/Opponent.java index a6155c8..cd8a77e 100644 --- a/src/main/java/game/Opponent.java +++ b/src/main/java/game/Opponent.java @@ -30,12 +30,13 @@ public Opponent(Field[][] arrayBoard) { ///and then move that piece public void takeTurn(ArrayList
computerPieces, ArrayList
playerPieces) { this.playerPieces = playerPieces; - choosePieceToMove(computerPieces); + determineMoveablePieces(computerPieces); + choosePieceToMove(); } /// \imp \ref T1_3 /// The computer player must be able to move their pieces to a new position - private void move(Figure piece, int newXCoord, int newYCoord) { + public void move(Figure piece, int newXCoord, int newYCoord) { Field oldField = piece.getField(); System.out.println("Computer moving piece at " + oldField.getXCord() + ", " + oldField.getYCord()); System.out.println("Moving to " + newXCoord + ", " + newYCoord); @@ -55,13 +56,7 @@ private void move(Figure piece, int newXCoord, int newYCoord) { ///2. It will try to take an opponent's piece, if possible. ///3. It will try to protect it's own pieces, if possible. ///4. It will move randomly if it cannot do any of the above. - private void choosePieceToMove(ArrayList
pieces) { - moveablePieces.clear(); - for(Figure piece : pieces) { - if(canMove(piece)) { - moveablePieces.add(piece); - } - } + public void choosePieceToMove() { if(isInCheck(board)) { escapeCheck(); @@ -69,7 +64,7 @@ private void choosePieceToMove(ArrayList
pieces) { } for(Figure piece : moveablePieces) { - if(canTakeOpponentPiece(piece)) { + if(canTakePlayerPiece(piece)) { return; } } @@ -84,9 +79,18 @@ private void choosePieceToMove(ArrayList
pieces) { return; } + public void determineMoveablePieces(ArrayList
pieces) { + moveablePieces.clear(); + for(Figure piece : pieces) { + if(canMove(piece)) { + moveablePieces.add(piece); + } + } + } + ///\ref T1_1 The computer player has to be able to determine if the piece is ///able to move before it can decide which piece to move - private boolean canMove(Figure piece) { + public boolean canMove(Figure piece) { for (int xCoord = 0; xCoord < board.length; xCoord++) { for(int yCoord = 0; yCoord < board[xCoord].length; yCoord++) { Field localField = board[xCoord][yCoord]; @@ -100,7 +104,7 @@ private boolean canMove(Figure piece) { ///\ref T1_1 \ref T1_2 ///In order to make the correct move, the computer player ///must be able to determine whether or not it is currently in check - private boolean isInCheck(Field[][] board) { + public boolean isInCheck(Field[][] board) { for(Figure piece : playerPieces) { for (int xCoord = 0; xCoord < board.length; xCoord++) { for(int yCoord = 0; yCoord < board[xCoord].length; yCoord++) { @@ -118,7 +122,7 @@ private boolean isInCheck(Field[][] board) { ///\ref T1_1 \ref T1_2 ///In order to choose the correct piece and position to a move, ///the computer player must first attempt to escape from being in check - private void escapeCheck() { + public void escapeCheck() { for(Figure piece : moveablePieces) { for (int xCoord = 0; xCoord < board.length; xCoord++) { for(int yCoord = 0; yCoord < board[xCoord].length; yCoord++) { @@ -157,7 +161,7 @@ private void escapeCheck() { ///\ref T1_1 ///The computer player has to determine if a piece is able to take one of the ///player's pieces in order to choose which piece to move - private boolean canTakeOpponentPiece(Figure piece) { + public boolean canTakePlayerPiece(Figure piece) { for (int xCoord = 0; xCoord < board.length; xCoord++) { for(int yCoord = 0; yCoord < board[xCoord].length; yCoord++) { Field localField = board[xCoord][yCoord]; @@ -172,7 +176,7 @@ private boolean canTakeOpponentPiece(Figure piece) { ///\ref T1_1 The computer player has to determine if a piece is able to escape ///being taken by the player in order to choose which piece to move - private boolean canEscapeFromBeingTaken(Figure piece) { + public boolean canEscapeFromBeingTaken(Figure piece) { for(Figure playerPiece : playerPieces) { if(playerPiece.isMovePossible(piece.getField())) { for (int xCoord = 0; xCoord < board.length; xCoord++) { @@ -182,7 +186,8 @@ private boolean canEscapeFromBeingTaken(Figure piece) { move(piece, xCoord, yCoord); return true; } - } } + } + } } } return false; @@ -191,7 +196,7 @@ private boolean canEscapeFromBeingTaken(Figure piece) { ///\ref T1_1 ///If none of the other conditions are met, the computer player still has to ///choose a piece, so it will choose a random piece to move - private void randomPiece() { + public void randomPiece() { Figure piece = moveablePieces.get((int)(Math.random() * moveablePieces.size())); for (int xCoord = 0; xCoord < board.length; xCoord++) { for(int yCoord = 0; yCoord < board[xCoord].length; yCoord++) { @@ -203,4 +208,7 @@ private void randomPiece() { } } } + public void setPlayerPieces(ArrayList
playerPieces) { + this.playerPieces = playerPieces; + } } From 4074c60e80eb72ec215d59c5bc120dd27cb558dd Mon Sep 17 00:00:00 2001 From: Ian Danahy Date: Wed, 28 Apr 2021 22:52:17 -0400 Subject: [PATCH 6/6] Updated documentation --- src/main/java/game/Opponent.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/game/Opponent.java b/src/main/java/game/Opponent.java index cd8a77e..de8b539 100644 --- a/src/main/java/game/Opponent.java +++ b/src/main/java/game/Opponent.java @@ -79,6 +79,8 @@ public void choosePieceToMove() { return; } + ///\ref T1_1 The computer player must know all pieces that are able to be + ///moved in order to correctly choose which piece it will move public void determineMoveablePieces(ArrayList
pieces) { moveablePieces.clear(); for(Figure piece : pieces) {