Files
3DChess/app/src/main/java/chess/view/simplerender/Window.java
Persson-dev 86ea62614b
All checks were successful
Linux arm64 / Build (push) Successful in 43s
feat: add app chooser
2025-05-26 21:33:02 +02:00

329 lines
7.8 KiB
Java

package chess.view.simplerender;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
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.CommandExecutor;
import chess.controller.CommandSender;
import chess.controller.commands.PromoteCommand.PromoteType;
import chess.controller.event.GameListener;
import chess.model.Coordinate;
import chess.model.Move;
import chess.model.Piece;
import chess.view.GameView;
/**
* Window for the 2D chess game.
*/
public class Window extends GameView {
private final CommandExecutor commandExecutor;
private Coordinate lastClick = null;
private final JFrame frame;
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(final CommandExecutor commandExecutor) {
this.frame = new JFrame();
this.cells = new JLabel[8][8];
this.displayText = new JLabel();
this.commandExecutor = commandExecutor;
this.frame.setSize(800, 910);
this.frame.setVisible(true);
this.frame.setLocationRelativeTo(null);
this.frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
commandExecutor.close();
}
});
}
private Color getCellColor(int x, int y) {
return ((x + y) % 2 == 1) ? Color.DARK_GRAY : Color.LIGHT_GRAY;
}
/**
* Build and set the buttons of the window.
* @param bottom the Jpanel in which to add the buttons
*/
@SuppressWarnings("unused")
private void buildButtons(JPanel bottom) {
castlingButton.addActionListener((event) -> {
sendCastling();
});
bigCastlingButton.addActionListener((event) -> {
sendBigCastling();
});
undoButton.addActionListener((event) -> {
sendUndo();
});
bottom.add(castlingButton);
bottom.add(bigCastlingButton);
bottom.add(undoButton);
}
/**
* Build the playable board in the window.
*/
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);
this.frame.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();
}
/**
* Update the board with the newest pieces' positions.
*/
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(getPieceAt(x, y)));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* Show the possible moves of the piece at the given coordinates
* @param x position of the piece on the x axis
* @param y position of the piece on the y axis
* @return true if the piece has possible moves, false otherwise
*/
private boolean previewMoves(int x, int y) {
List<Coordinate> allowedMoves = getPieceAllowedMoves(new Coordinate(x, y));
if (allowedMoves.isEmpty())
return false;
for (Coordinate destCoord : allowedMoves) {
JLabel cell = this.cells[destCoord.getX()][destCoord.getY()];
Graphics g = cell.getGraphics();
g.setColor(new Color(128, 128, 128, 128));
g.fillOval(25, 25, 50, 50);
}
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));
cell.paint(cell.getGraphics());
}
}
}
/**
* Handle the click on a cell. Cancel previous rendering, move the previously selected piece if needed.
* @param x position of the cell on the x axis
* @param y position of the cell on the y axis
*/
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));
sendMove(move);
}
this.lastClick = null;
}
private void updateButtons() {
this.castlingButton.setEnabled(canDoCastling());
this.bigCastlingButton.setEnabled(canDoBigCastling());
}
@Override
public void onPlayerTurn(chess.model.Color color, boolean undone) {
this.displayText.setText("Current turn: " + color);
updateButtons();
}
@Override
public void onWin(chess.model.Color color) {
JOptionPane.showMessageDialog(this.frame, "Victory of " + color);
}
@Override
public void onKingInCheck() {
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(this.frame, "Check!");
});
}
@Override
public void onKingInMat() {
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(this.frame, "Checkmate!");
});
}
@Override
public void onPatSituation() {
JOptionPane.showMessageDialog(this.frame, "Pat. It's a draw!");
}
@Override
public void onSurrender(chess.model.Color color) {
JOptionPane.showMessageDialog(this.frame, color + " has surrendered.");
}
@Override
public void onGameEnd() {
JOptionPane.showMessageDialog(this.frame, "End of the game");
this.frame.dispose();
this.commandExecutor.close();
}
@Override
public void onGameStart() {
buildBoard();
}
/**
* Open a dialog box when a pawn needs to be promoted
*/
@Override
public void onPromotePawn(Coordinate pieceCoords) {
Piece pawn = getPieceAt(pieceCoords);
chess.model.Color player = pawn.getColor();
if (hasAIAttached(player))
return;
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.frame,
"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)
sendPawnPromotion(choosedType);
});
}
@Override
public void onBoardUpdate() {
updateBoard();
}
@Override
public void onMoveNotAllowed(Move move) {
drawInvalid(move);
}
@Override
public void onDraw() {
JOptionPane.showMessageDialog(this.frame, "Same position was repeated three times. It's a draw!");
}
@Override
public CommandExecutor getCommandExecutor() {
return this.commandExecutor;
}
@Override
public void run() {
}
}