juste better

This commit is contained in:
2025-04-02 10:54:14 +02:00
parent 1b9ff5bdd1
commit 97cafb903a
12 changed files with 212 additions and 131 deletions

View File

@@ -3,16 +3,22 @@
*/ */
package chess; package chess;
import chess.io.CommandExecutor;
import chess.io.commands.NewGameCommand;
import chess.model.ChessBoard; import chess.model.ChessBoard;
import chess.model.Game; import chess.model.Game;
import chess.simplerender.Window; import chess.simplerender.Window;
public class App { public class App {
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) { public static void main(String[] args) {
new Window(new Game(new ChessBoard())); CommandExecutor commandExecutor = new CommandExecutor();
Game game = new Game(new ChessBoard());
Window window = new Window(commandExecutor);
commandExecutor.setGame(game);
commandExecutor.setOutputSystem(window);
commandExecutor.executeCommand(new NewGameCommand());
} }
} }

View File

@@ -4,12 +4,12 @@ import chess.model.Game;
public class CommandExecutor { public class CommandExecutor {
private final Game game; private Game game;
private final OutputSystem outputSystem; private OutputSystem outputSystem;
public CommandExecutor(Game game, OutputSystem outputSystem) { public CommandExecutor() {
this.game = game; this.game = null;
this.outputSystem = outputSystem; this.outputSystem = null;
} }
public CommandResult executeCommand(Command command) { public CommandResult executeCommand(Command command) {
@@ -22,16 +22,14 @@ public class CommandExecutor {
private void alternatePlayers() { private void alternatePlayers() {
this.game.switchPlayerTurn(); this.game.switchPlayerTurn();
this.outputSystem.playerTurn(this.game.getPlayerTurn()); this.outputSystem.playerTurn(this.game.getPlayerTurn());
}
public void setOutputSystem(OutputSystem outputSystem) {
this.outputSystem = outputSystem;
} }
public Game getGame() { public void setGame(Game game) {
return game; this.game = game;
} }
public OutputSystem getOutputSystem() {
return outputSystem;
}
} }

View File

@@ -1,8 +1,20 @@
package chess.io; package chess.io;
public abstract class OutputSystem implements OutputSystemInterface { import chess.model.Color;
public OutputSystem() { public interface OutputSystem {
}
void playerTurn(Color color);
void winnerIs(Color color);
void kingIsInCheck();
void kingIsInMat();
void patSituation();
void hasSurrendered(Color color);
void gameStarted();
} }

View File

@@ -1,18 +0,0 @@
package chess.io;
import chess.model.Color;
public interface OutputSystemInterface {
void playerTurn(Color color);
void winnerIs(Color color);
void kingIsInCheck();
void kingIsInMat();
void patSituation();
void hasSurrendered(Color color);
}

View File

@@ -0,0 +1,42 @@
package chess.io.commands;
import java.util.ArrayList;
import java.util.List;
import chess.io.Command;
import chess.io.CommandResult;
import chess.io.OutputSystem;
import chess.model.ChessBoard;
import chess.model.Coordinate;
import chess.model.Game;
import chess.model.Piece;
public class GetAllowedMovesCommand extends Command {
private final Coordinate start;
private List<Coordinate> destinations;
public GetAllowedMovesCommand(Coordinate start) {
this.start = start;
this.destinations = new ArrayList<>();
}
@Override
public CommandResult execute(Game game, OutputSystem outputSystem) {
final ChessBoard board = game.getBoard();
Piece piece = board.pieceAt(start);
if (piece == null)
return CommandResult.NotAllowed;
if (piece.getColor() != game.getPlayerTurn())
return CommandResult.NotAllowed;
this.destinations = board.getAllowedMoves(start);
return CommandResult.NotMoved;
}
public List<Coordinate> getDestinations() {
return destinations;
}
}

View File

@@ -0,0 +1,34 @@
package chess.io.commands;
import chess.io.Command;
import chess.io.CommandResult;
import chess.io.OutputSystem;
import chess.model.Coordinate;
import chess.model.Game;
import chess.model.Piece;
public class GetPieceAtCommand extends Command{
private final Coordinate pieceCoords;
private Piece piece;
public GetPieceAtCommand(Coordinate pieceCoords) {
this.pieceCoords = pieceCoords;
this.piece = null;
}
@Override
public CommandResult execute(Game game, OutputSystem outputSystem) {
if (!pieceCoords.isValid())
return CommandResult.NotAllowed;
this.piece = game.getBoard().pieceAt(pieceCoords);
return CommandResult.NotMoved;
}
public Piece getPiece() {
return piece;
}
}

View File

@@ -49,6 +49,8 @@ public class NewGameCommand extends Command {
game.resetPlayerTurn(); game.resetPlayerTurn();
outputSystem.gameStarted();
return CommandResult.NotMoved; return CommandResult.NotMoved;
} }
} }

View File

@@ -1,5 +1,7 @@
package chess.model; package chess.model;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack; import java.util.Stack;
import chess.model.visitor.KingIdentifier; import chess.model.visitor.KingIdentifier;
@@ -148,44 +150,39 @@ public class ChessBoard {
if (attackPiece.getColor() != player) if (attackPiece.getColor() != player)
continue; continue;
if (getAllowedMoves(attackCoords) != null) if (!getAllowedMoves(attackCoords).isEmpty())
return true; return true;
} }
} }
return false; return false;
} }
public boolean[][] getAllowedMoves(Coordinate pieceCoords) { public List<Coordinate> getAllowedMoves(Coordinate pieceCoords) {
Piece piece = pieceAt(pieceCoords); Piece piece = pieceAt(pieceCoords);
if (piece == null) if (piece == null)
return null; return null;
Color player = piece.getColor(); Color player = piece.getColor();
List<Coordinate> result = new ArrayList<>();
boolean[][] result = new boolean[Coordinate.VALUE_MAX][Coordinate.VALUE_MAX];
for (int i = 0; i < Coordinate.VALUE_MAX; i++) { for (int i = 0; i < Coordinate.VALUE_MAX; i++) {
for (int j = 0; j < Coordinate.VALUE_MAX; j++) { for (int j = 0; j < Coordinate.VALUE_MAX; j++) {
Move move = new Move(pieceCoords, new Coordinate(i, j)); Coordinate destination = new Coordinate(i, j);
Move move = new Move(pieceCoords, destination);
PiecePathChecker piecePathChecker = new PiecePathChecker(this, PiecePathChecker piecePathChecker = new PiecePathChecker(this,
move); move);
if (!piecePathChecker.isValid()) if (!piecePathChecker.isValid())
continue; continue;
applyMove(move); applyMove(move);
result[i][j] = !isKingInCheck(player); if (!isKingInCheck(player))
result.add(destination);
undoLastMove(); undoLastMove();
} }
} }
return result;
// return null is no valid moves are possible
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
if (result[x][y])
return result;
}
}
return null;
} }
} }

View File

@@ -24,16 +24,4 @@ public class Game {
playerTurn = Color.getEnemy(playerTurn); playerTurn = Color.getEnemy(playerTurn);
} }
public boolean[][] getAllowedMoves(Coordinate coordinate) {
Piece piece = this.board.pieceAt(coordinate);
if (piece == null)
return null;
if (piece.getColor() != getPlayerTurn())
return null;
return this.board.getAllowedMoves(coordinate);
}
} }

View File

@@ -1,6 +1,8 @@
package chess.simplerender; package chess.simplerender;
import java.awt.Image; import java.awt.Image;
import java.util.HashMap;
import java.util.Map;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
@@ -18,11 +20,22 @@ import chess.model.pieces.Rook;
public class PieceIcon implements PieceVisitor<String> { public class PieceIcon implements PieceVisitor<String> {
private static final String basePath = "app/src/main/resources/pieces2D/"; private static final String basePath = "app/src/main/resources/pieces2D/";
private static final Map<String, Icon> cache = new HashMap<>();
public Icon getIcon(Piece piece) { public Icon getIcon(Piece piece) {
if (piece == null) if (piece == null)
return null; return null;
return new ImageIcon(new ImageIcon(basePath + colorToString(piece.getColor()) + "-" + visit(piece) + ".png").getImage().getScaledInstance(100,100, Image.SCALE_SMOOTH)); String path = basePath + colorToString(piece.getColor()) + "-" + visit(piece) + ".png";
return getIcon(path);
}
private Icon getIcon(String path) {
Icon image = cache.get(path);
if (image != null)
return image;
image = new ImageIcon(new ImageIcon(path).getImage().getScaledInstance(100,100, Image.SCALE_SMOOTH));
cache.put(path, image);
return image;
} }
private String colorToString(Color color) { private String colorToString(Color color) {

View File

@@ -4,6 +4,7 @@ import java.awt.Color;
import java.awt.GridLayout; import java.awt.GridLayout;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.util.List;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JLabel; import javax.swing.JLabel;
@@ -13,68 +14,26 @@ import chess.io.Command;
import chess.io.CommandExecutor; import chess.io.CommandExecutor;
import chess.io.CommandResult; import chess.io.CommandResult;
import chess.io.OutputSystem; import chess.io.OutputSystem;
import chess.io.commands.GetAllowedMovesCommand;
import chess.io.commands.GetPieceAtCommand;
import chess.io.commands.MoveCommand; import chess.io.commands.MoveCommand;
import chess.io.commands.NewGameCommand;
import chess.model.ChessBoard;
import chess.model.Coordinate; import chess.model.Coordinate;
import chess.model.Game;
import chess.model.Move; import chess.model.Move;
import chess.model.Piece;
public class Window extends JFrame { public class Window extends JFrame implements OutputSystem {
private final JLabel cells[][]; private final JLabel cells[][];
private final CommandExecutor commandExecutor; private final CommandExecutor commandExecutor;
private final ChessBoard board;
private Coordinate lastClick = null; private Coordinate lastClick = null;
public Window(Game game) { public Window(CommandExecutor commandExecutor) {
this.cells = new JLabel[8][8]; this.cells = new JLabel[8][8];
this.commandExecutor = new CommandExecutor(game, initSlots()); this.commandExecutor = commandExecutor;
this.board = this.commandExecutor.getGame().getBoard();
build();
setSize(800, 800); setSize(800, 800);
setVisible(true); setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE); setDefaultCloseOperation(EXIT_ON_CLOSE);
sendCommand(new NewGameCommand());
updateBoard();
}
private OutputSystem initSlots() {
OutputSystem outputSystem = new OutputSystem() {
@Override
public void playerTurn(chess.model.Color color) {
System.out.println("Player turn " + color);
}
@Override
public void winnerIs(chess.model.Color color) {
System.out.println("Winner is " + color);
}
@Override
public void kingIsInCheck() {
System.out.println("Check");
}
@Override
public void kingIsInMat() {
System.out.println("CheckMate");
}
@Override
public void patSituation() {
System.out.println("Pat");
}
@Override
public void hasSurrendered(chess.model.Color color) {
System.out.println("Surrendered");
}
};
return outputSystem;
} }
private CommandResult sendCommand(Command command) { private CommandResult sendCommand(Command command) {
@@ -89,7 +48,7 @@ public class Window extends JFrame {
return ((x + y) % 2 == 1) ? Color.BLACK : Color.WHITE; return ((x + y) % 2 == 1) ? Color.BLACK : Color.WHITE;
} }
private void build() { private void buildBoard() {
JPanel content = new JPanel(new GridLayout(8, 8)); JPanel content = new JPanel(new GridLayout(8, 8));
setContentPane(content); setContentPane(content);
for (int y = 0; y < 8; y++) { for (int y = 0; y < 8; y++) {
@@ -104,9 +63,10 @@ public class Window extends JFrame {
label.addMouseListener(new MouseAdapter() { label.addMouseListener(new MouseAdapter() {
@Override @Override
public void mouseClicked(MouseEvent e) { public void mousePressed(MouseEvent e) {
onCellClicked(xx, yy); onCellClicked(xx, yy);
} }
}); });
content.add(label); content.add(label);
} }
@@ -114,26 +74,38 @@ public class Window extends JFrame {
updateBoard(); updateBoard();
} }
private boolean isCellEmpty(int x, int y) {
return pieceAt(x, y) == null;
}
private Piece pieceAt(int x, int y) {
GetPieceAtCommand command = new GetPieceAtCommand(new Coordinate(x, y));
sendCommand(command);
return command.getPiece();
}
private void updateBoard() { private void updateBoard() {
PieceIcon pieceIcon = new PieceIcon(); PieceIcon pieceIcon = new PieceIcon();
for (int y = 0; y < 8; y++) { for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) { for (int x = 0; x < 8; x++) {
JLabel cell = this.cells[x][y]; JLabel cell = this.cells[x][y];
cell.setIcon(pieceIcon.getIcon(this.board.pieceAt(new Coordinate(x, y)))); cell.setIcon(pieceIcon.getIcon(pieceAt(x, y)));
} }
} }
} }
private boolean previewMoves(int x, int y) { private boolean previewMoves(int x, int y) {
boolean[][] allowedMoves = this.commandExecutor.getGame().getAllowedMoves(new Coordinate(x, y)); GetAllowedMovesCommand movesCommand = new GetAllowedMovesCommand(new Coordinate(x, y));
if (allowedMoves == null) if(sendCommand(movesCommand) == CommandResult.NotAllowed)
return false; return false;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) { List<Coordinate> allowedMoves = movesCommand.getDestinations();
JLabel cell = this.cells[i][j]; if (allowedMoves.isEmpty())
if (allowedMoves[i][j]) return false;
cell.setBackground(Color.CYAN);
} for (Coordinate destCoord : allowedMoves) {
JLabel cell = this.cells[destCoord.getX()][destCoord.getY()];
cell.setBackground(Color.CYAN);
} }
return true; return true;
} }
@@ -157,7 +129,7 @@ public class Window extends JFrame {
private void onCellClicked(int x, int y) { private void onCellClicked(int x, int y) {
clearMoves(); clearMoves();
if (this.lastClick == null) { if (this.lastClick == null) {
if (this.board.isCellEmpty(new Coordinate(x, y))) if (isCellEmpty(x, y))
return; return;
if (!previewMoves(x, y)) if (!previewMoves(x, y))
return; return;
@@ -173,4 +145,39 @@ public class Window extends JFrame {
this.lastClick = null; this.lastClick = null;
} }
@Override
public void playerTurn(chess.model.Color color) {
System.out.println("C'est au tour de " + color);
}
@Override
public void winnerIs(chess.model.Color color) {
System.out.println("Victoire de " + color);
}
@Override
public void kingIsInCheck() {
System.out.println("Échec !");
}
@Override
public void kingIsInMat() {
System.out.println("Échec et mat !");
}
@Override
public void patSituation() {
System.out.println("Pat. Égalité !");
}
@Override
public void hasSurrendered(chess.model.Color color) {
System.out.println("Abandon de " + color);
}
@Override
public void gameStarted() {
buildBoard();
}
} }

View File

@@ -8,7 +8,7 @@ import static org.junit.jupiter.api.Assertions.*;
class AppTest { class AppTest {
@Test void appHasAGreeting() { @Test void appHasAGreeting() {
App classUnderTest = new App(); // App classUnderTest = new App();
assertNotNull(classUnderTest.getGreeting(), "app should have a greeting"); // assertNotNull(classUnderTest.getGreeting(), "app should have a greeting");
} }
} }