diff --git a/app/src/main/java/chess/ConsoleMain.java b/app/src/main/java/chess/ConsoleMain.java index 484bd41..322cfe9 100644 --- a/app/src/main/java/chess/ConsoleMain.java +++ b/app/src/main/java/chess/ConsoleMain.java @@ -7,7 +7,7 @@ import chess.controller.CommandExecutor; import chess.controller.commands.NewGameCommand; import chess.model.ChessBoard; import chess.model.Game; -import chess.simulator.CastlingTest; +import chess.simulator.PromoteTest; import chess.view.consolerender.Console; public class ConsoleMain { @@ -15,8 +15,15 @@ public class ConsoleMain { Game game = new Game(new ChessBoard()); CommandExecutor commandExecutor = new CommandExecutor(game); + PromoteTest promoteTest = new PromoteTest(commandExecutor); + commandExecutor.addListener(promoteTest); + Console console = new Console(commandExecutor); commandExecutor.addListener(console); + + promoteTest.onComplete.connect(() -> { + console.setCaptureInput(true); + }); commandExecutor.executeCommand(new NewGameCommand()); } diff --git a/app/src/main/java/chess/controller/commands/CastlingCommand.java b/app/src/main/java/chess/controller/commands/CastlingCommand.java index 6bd3a20..36af108 100644 --- a/app/src/main/java/chess/controller/commands/CastlingCommand.java +++ b/app/src/main/java/chess/controller/commands/CastlingCommand.java @@ -21,7 +21,7 @@ public class CastlingCommand extends PlayerCommand { @Override public CommandResult execute(Game game, GameListener outputSystem) { final ChessBoard board = game.getBoard(); - + // we must promote the pending pawn before if (board.pawnShouldBePromoted()) return CommandResult.NotAllowed; @@ -39,7 +39,7 @@ public class CastlingCommand extends PlayerCommand { int kingEndX = bigCastling ? 2 : 6; int colorLine = game.getPlayerTurn() == Color.White ? 7 : 0; - + Coordinate kingCoords = new Coordinate(kingBeginX, colorLine); Coordinate rookCoords = new Coordinate(rookBeginX, colorLine); @@ -52,6 +52,10 @@ public class CastlingCommand extends PlayerCommand { return CommandResult.Moved; } + public boolean isBigCastling() { + return bigCastling; + } + @Override protected CommandResult undoImpl(Game game, GameListener outputSystem) { game.getBoard().undoMove(this.kingMove, null); diff --git a/app/src/main/java/chess/controller/commands/PromoteCommand.java b/app/src/main/java/chess/controller/commands/PromoteCommand.java index ebf9136..c012e8d 100644 --- a/app/src/main/java/chess/controller/commands/PromoteCommand.java +++ b/app/src/main/java/chess/controller/commands/PromoteCommand.java @@ -94,4 +94,8 @@ public class PromoteCommand extends PlayerCommand { return CommandResult.Moved; } + public PromoteType getPromoteType() { + return promoteType; + } + } diff --git a/app/src/main/java/chess/simulator/Simulator.java b/app/src/main/java/chess/simulator/Simulator.java index 2e8f52d..62b887c 100644 --- a/app/src/main/java/chess/simulator/Simulator.java +++ b/app/src/main/java/chess/simulator/Simulator.java @@ -6,11 +6,15 @@ import chess.controller.CommandExecutor; import chess.controller.commands.MoveCommand; import chess.controller.event.GameAdaptator; import chess.model.Move; +import common.Signal0; -public abstract class Simulator extends GameAdaptator{ +public abstract class Simulator extends GameAdaptator { protected final CommandExecutor commandExecutor; + public final Signal0 onComplete = new Signal0(); + private int currentMove = 0; + public Simulator(CommandExecutor commandExecutor) { this.commandExecutor = commandExecutor; } @@ -22,6 +26,14 @@ public abstract class Simulator extends GameAdaptator{ } } + @Override + public void onMove(Move move) { + currentMove++; + if (currentMove == getMoves().size()) { + onComplete.emit(); + } + } + protected abstract List getMoves(); - + } diff --git a/app/src/main/java/chess/view/consolerender/Console.java b/app/src/main/java/chess/view/consolerender/Console.java index f38e76f..48a098c 100644 --- a/app/src/main/java/chess/view/consolerender/Console.java +++ b/app/src/main/java/chess/view/consolerender/Console.java @@ -3,6 +3,7 @@ package chess.view.consolerender; import chess.controller.Command; import chess.controller.CommandExecutor; import chess.controller.commands.*; +import chess.controller.commands.PromoteCommand.PromoteType; import chess.controller.event.GameListener; import chess.model.Color; import chess.model.Coordinate; @@ -12,14 +13,19 @@ import chess.model.Piece; import java.util.List; import java.util.Objects; import java.util.Scanner; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; public class Console implements GameListener { private final Scanner scanner = new Scanner(System.in); private final CommandExecutor commandExecutor; private final ConsolePieceName consolePieceName = new ConsolePieceName(); + private boolean captureInput = false; + private final ExecutorService executor; public Console(CommandExecutor commandExecutor) { this.commandExecutor = commandExecutor; + this.executor = Executors.newSingleThreadExecutor(); } private Piece pieceAt(int x, int y) { @@ -56,22 +62,31 @@ public class Console implements GameListener { @Override public void onPlayerTurn(Color color) { + if (!captureInput) + return; System.out.println(Colors.RED + "Player turn: " + color + Colors.RESET); - boolean endTurn; - do { - System.out.println(""" - Pick your choice: - 1 - Move - 2 - Show potential moves - 3 - Surrender - """); - endTurn = switch (scanner.nextLine()) { - case "1" -> playerPickedMove(color); - case "2" -> playerPickedShowMoves(color); - case "3" -> playerPickedSurrender(color); - default -> false; - }; - } while (!endTurn); + this.executor.submit(() -> { + boolean endTurn; + String line = "0"; + do { + if (!line.isEmpty()) { + System.out.println(""" + Pick your choice: + 1 - Move + 2 - Show potential moves + 3 - Surrender + """); + System.out.flush(); + } + line = scanner.nextLine(); + endTurn = switch (line) { + case "1" -> playerPickedMove(color); + case "2" -> playerPickedShowMoves(color); + case "3" -> playerPickedSurrender(color); + default -> false; + }; + } while (!endTurn); + }); } private boolean playerPickedSurrender(Color color) { @@ -131,7 +146,7 @@ public class Console implements GameListener { @Override public void onKingInCheck() { - System.out.println(Colors.RED + "Check!" + Colors.RESET); + System.out.println(Colors.RED + "Check!" + Colors.RESET); } @Override @@ -159,57 +174,61 @@ public class Console implements GameListener { public void onGameEnd() { System.out.println("Thank you for playing!"); this.commandExecutor.close(); + this.executor.shutdown(); } @Override public void onPromotePawn(Coordinate pieceCoords) { System.out.println("The pawn on the " + pieceCoords + " coordinates needs to be promoted."); System.out.println("Enter 'B' to promote it into a Bishop, 'N' for a Knight, 'Q' for a Queen, 'R' for a Rook."); - boolean valid = false; - PromoteCommand.PromoteType newPiece; - do { - try { - String promotion = scanner.next(); - newPiece = switch (promotion) { - case "B", "b", "Bishop", "bishop" -> PromoteCommand.PromoteType.Bishop; - case "N", "n", "Knight", "knight" -> PromoteCommand.PromoteType.Knight; - case "Q", "q", "Queen", "queen" -> PromoteCommand.PromoteType.Queen; - case "R", "r", "Rook", "rook" -> PromoteCommand.PromoteType.Rook; - default -> throw new Exception(); - }; - valid = true; - sendCommand(new PromoteCommand(newPiece)); - } catch (Exception e) { - System.out.println("Invalid input!"); - } - } while (!valid); - + System.out.flush(); + this.executor.submit(() -> { + PromoteType newPiece; + boolean valid = false; + do { + try { + String promotion = scanner.next(); + newPiece = switch (promotion) { + case "B", "b", "Bishop", "bishop" -> PromoteType.Bishop; + case "N", "n", "Knight", "knight" -> PromoteType.Knight; + case "Q", "q", "Queen", "queen" -> PromoteType.Queen; + case "R", "r", "Rook", "rook" -> PromoteType.Rook; + default -> throw new Exception(); + }; + valid = true; + sendCommand(new PromoteCommand(newPiece)); + } catch (Exception e) { + System.out.println("Invalid input!"); + } + } while (!valid); + }); } @Override public void onBoardUpdate() { + if (!this.captureInput) + return; StringBuilder string = new StringBuilder(); string.append(" a b c d e f g h \n"); for (int i = 0; i < Coordinate.VALUE_MAX; i++) { string.append(8 - i).append(" "); for (int j = 0; j < Coordinate.VALUE_MAX; j++) { Piece p = pieceAt(j, i); - if ((i+j)%2==0) { + if ((i + j) % 2 == 0) { string.append(Colors.LIGHT_GRAY_BACKGROUND); - } - else { + } else { string.append(Colors.DARK_GRAY_BACKGROUND); } if (p == null) { string.append(" " + Colors.RESET); - } - else { + } else { string.append(" ").append(consolePieceName.getString(p)).append(" ").append(Colors.RESET); } } string.append("\n"); } System.out.println(string); + System.out.flush(); } public void displayMoves(Coordinate piece, List moves) { @@ -220,7 +239,7 @@ public class Console implements GameListener { for (int j = 0; j < Coordinate.VALUE_MAX; j++) { Coordinate currentCell = new Coordinate(j, i); Piece p = pieceAt(j, i); - if (moves.contains(currentCell)){ + if (moves.contains(currentCell)) { string.append(Colors.YELLOW_BACKGROUND); } else { if ((i + j) % 2 == 0) { @@ -231,10 +250,10 @@ public class Console implements GameListener { } if (p == null) { string.append(" " + Colors.RESET); - } - else { + } else { if (currentCell.equals(piece)) { - string.append(Colors.RED_BACKGROUND).append(" ").append(consolePieceName.getString(p)).append(" ").append(Colors.RESET); + string.append(Colors.RED_BACKGROUND).append(" ").append(consolePieceName.getString(p)) + .append(" ").append(Colors.RESET); } else { string.append(" ").append(consolePieceName.getString(p)).append(" ").append(Colors.RESET); } @@ -246,7 +265,8 @@ public class Console implements GameListener { } @Override - public void onMove(Move move) {} + public void onMove(Move move) { + } @Override public void onMoveNotAllowed(Move move) { @@ -262,9 +282,9 @@ public class Console implements GameListener { GetAllowedCastlingsCommand cmd = new GetAllowedCastlingsCommand(); sendCommand(cmd); return switch (cmd.getCastlingResult()) { - case GetAllowedCastlingsCommand.CastlingResult.Small -> onSmallCastling(); - case GetAllowedCastlingsCommand.CastlingResult.Big -> onBigCastling(); - case GetAllowedCastlingsCommand.CastlingResult.Both -> onBothCastling(); + case Small -> onSmallCastling(); + case Big -> onBigCastling(); + case Both -> onBothCastling(); default -> { System.out.println("No castling allowed."); yield false; @@ -277,8 +297,7 @@ public class Console implements GameListener { String answer = scanner.nextLine(); if (!(answer.equalsIgnoreCase("y") || answer.equalsIgnoreCase("yes"))) { return false; - } - else { + } else { return (commandExecutor.executeCommand(new CastlingCommand(false)) != Command.CommandResult.Moved); } } @@ -288,8 +307,7 @@ public class Console implements GameListener { String answer = scanner.nextLine(); if (!(answer.equalsIgnoreCase("y") || answer.equalsIgnoreCase("yes"))) { return false; - } - else { + } else { return (commandExecutor.executeCommand(new CastlingCommand(true)) != Command.CommandResult.Moved); } } @@ -299,11 +317,15 @@ public class Console implements GameListener { String answer = scanner.nextLine(); return switch (answer) { case "s", "S", "small", "Small", "castling", "normal", "Normal" -> - (commandExecutor.executeCommand(new CastlingCommand(false)) != Command.CommandResult.Moved); + (commandExecutor.executeCommand(new CastlingCommand(false)) != Command.CommandResult.Moved); case "b", "B", "big", "Big", "big castling", "Big castling" -> - (commandExecutor.executeCommand(new CastlingCommand(true)) != Command.CommandResult.Moved); + (commandExecutor.executeCommand(new CastlingCommand(true)) != Command.CommandResult.Moved); default -> false; }; } + public void setCaptureInput(boolean captureInput) { + this.captureInput = captureInput; + } + }