package chess.view.simplerender; import java.awt.Color; import java.awt.GridLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.IOException; import java.util.List; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; import chess.controller.Command; import chess.controller.Command.CommandResult; import chess.controller.CommandExecutor; import chess.controller.OutputSystem; import chess.controller.commands.CastlingCommand; import chess.controller.commands.GetAllowedMovesCommand; import chess.controller.commands.GetPieceAtCommand; import chess.controller.commands.MoveCommand; import chess.controller.commands.PromoteCommand; import chess.controller.commands.PromoteCommand.PromoteType; import chess.controller.commands.UndoCommand; import chess.model.Coordinate; import chess.model.Move; import chess.model.Piece; public class Window extends JFrame implements OutputSystem { private final CommandExecutor commandExecutor; private Coordinate lastClick = null; private final JLabel cells[][]; private final JLabel displayText; private final JButton castlingButton = new JButton("Roque"); private final JButton bigCastlingButton = new JButton("Grand Roque"); private final JButton undoButton = new JButton("Annuler le coup précédent"); public Window(CommandExecutor commandExecutor) { this.cells = new JLabel[8][8]; this.displayText = new JLabel(); this.commandExecutor = commandExecutor; setSize(800, 910); setVisible(true); setLocationRelativeTo(null); setDefaultCloseOperation(DISPOSE_ON_CLOSE); } private CommandResult sendCommand(Command command) { return this.commandExecutor.executeCommand(command); } private Color getCellColor(int x, int y) { return ((x + y) % 2 == 1) ? Color.BLACK : Color.WHITE; } private void buildButtons(JPanel bottom) { castlingButton.addActionListener((event) -> { sendCommand(new CastlingCommand(false)); }); bigCastlingButton.addActionListener((event) -> { sendCommand(new CastlingCommand(true)); }); undoButton.addActionListener((event) -> { sendCommand(new UndoCommand()); }); bottom.add(castlingButton); bottom.add(bigCastlingButton); bottom.add(undoButton); } private void buildBoard() { JPanel content = new JPanel(); JPanel grid = new JPanel(new GridLayout(8, 8)); JPanel bottom = new JPanel(); buildButtons(bottom); content.add(this.displayText); content.add(grid); content.add(bottom); setContentPane(content); for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) { JLabel label = new JLabel(); label.setOpaque(true); label.setBackground(getCellColor(x, y)); this.cells[x][y] = label; final int xx = x; final int yy = y; label.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { onCellClicked(xx, yy); } }); grid.add(label); } } 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() { PieceIcon pieceIcon = new PieceIcon(); for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) { JLabel cell = this.cells[x][y]; try { cell.setIcon(pieceIcon.getIcon(pieceAt(x, y))); } catch (IOException e) { e.printStackTrace(); } } } } private boolean previewMoves(int x, int y) { GetAllowedMovesCommand movesCommand = new GetAllowedMovesCommand(new Coordinate(x, y)); if (sendCommand(movesCommand) == CommandResult.NotAllowed) return false; List allowedMoves = movesCommand.getDestinations(); if (allowedMoves.isEmpty()) return false; for (Coordinate destCoord : allowedMoves) { JLabel cell = this.cells[destCoord.getX()][destCoord.getY()]; cell.setBackground(Color.CYAN); } return true; } private void drawInvalid(Move move) { JLabel from = this.cells[move.getStart().getX()][move.getStart().getY()]; JLabel to = this.cells[move.getFinish().getX()][move.getFinish().getY()]; from.setBackground(Color.RED); to.setBackground(Color.RED); } private void clearMoves() { for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) { JLabel cell = this.cells[x][y]; cell.setBackground(getCellColor(x, y)); } } } private void onCellClicked(int x, int y) { clearMoves(); if (this.lastClick == null) { if (isCellEmpty(x, y)) return; if (!previewMoves(x, y)) return; this.lastClick = new Coordinate(x, y); return; } if (!this.lastClick.equals(new Coordinate(x, y))) { Move move = new Move(lastClick, new Coordinate(x, y)); if (sendCommand(new MoveCommand(move)) == CommandResult.NotAllowed) { drawInvalid(move); } } this.lastClick = null; } @Override public void playerTurn(chess.model.Color color) { this.displayText.setText("C'est au tour de " + color); } @Override public void winnerIs(chess.model.Color color) { SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(this, "Victoire de " + color); this.dispose(); }); } @Override public void kingIsInCheck() { SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(this, "Échec !"); }); } @Override public void kingIsInMat() { SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(this, "Échec et mat !"); }); } @Override public void patSituation() { SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(this, "Pat. Égalité !"); }); } @Override public void hasSurrendered(chess.model.Color color) { SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(this, "Abandon de " + color); }); } @Override public void gameStarted() { buildBoard(); } @Override public void promotePawn(Coordinate pieceCoords) { SwingUtilities.invokeLater(() -> { String result = null; Object[] possibilities = new Object[PromoteType.values().length]; int i = 0; for (PromoteType type : PromoteType.values()) { possibilities[i] = type.name(); i++; } while (result == null || result.isEmpty()) { result = (String) JOptionPane.showInputDialog( this, "Choose the type of piece to upgrade the pawn", "Promote Dialog", JOptionPane.PLAIN_MESSAGE, null, possibilities, possibilities[0]); } PromoteType choosedType = null; for (PromoteType type : PromoteType.values()) { if (type.name().equals(result)) { choosedType = type; break; } } if (choosedType != null) sendCommand(new PromoteCommand(choosedType)); }); } @Override public void updateDisplay() { updateBoard(); } }