Compare commits

...

23 Commits

Author SHA1 Message Date
Justin 08fc96187b Adjust MainGui frame size to match GameGui 2025-06-19 20:51:37 +02:00
Justin 1613ab575f Refactor MainGui to use callback for game start 2025-06-19 20:46:53 +02:00
Justin e9e8c7e650 Testing MainGui in Main 2025-06-19 20:40:55 +02:00
Justin d3111b436c New class MainGui 2025-06-19 20:34:06 +02:00
Justin ddac012fd9 Changed name of Gui to GameGui 2025-06-19 20:30:32 +02:00
Justin 40b50ac12f Removed unused package in Controller 2025-06-19 20:25:44 +02:00
Justin 3b3cc2dd0b Fix wrong highlight positions by correcting board index calculation 2025-06-19 20:24:38 +02:00
Justin 441d4a3343 Changed updateBoard method in Gui to use DTOs 2025-06-19 20:20:03 +02:00
Justin 3ee0a5ece8 Removed unused packages 2025-06-19 20:19:36 +02:00
Justin ed573d3338 Switch Controller to use DTOs for board updates 2025-06-19 20:15:28 +02:00
Justin 9adb0db66b New getLegalDestinations method in ChessEngine 2025-06-19 20:01:05 +02:00
Justin 13cb12717a New getPieceAt method in ChessEngine 2025-06-19 20:00:23 +02:00
Justin 6afb3584e5 New move method in ChessEngine 2025-06-19 19:57:45 +02:00
Justin a4e7517571 New getBoardAsDTO() method in ChessEngine 2025-06-19 19:55:48 +02:00
Justin 86eb04d391 New convertPieceToDTO method in ChessEngine 2025-06-19 19:54:21 +02:00
Justin f07c534205 Add getter to MoveDTO 2025-06-19 18:33:05 +02:00
Justin 329886aa5a Add constructor to MoveDTO 2025-06-19 17:44:24 +02:00
Justin f468f6f285 Add getter to PieceDTO 2025-06-19 17:41:15 +02:00
Justin 326d4ce98c Add constructor to PieceDTO 2025-06-19 17:38:22 +02:00
Justin dc766f961f Add constructor and getter/setter to BoardDTO 2025-06-19 17:33:36 +02:00
Justin 96589f4b6e Changed package name 'gui' to 'view' 2025-06-19 17:17:34 +02:00
Justin 84ea584bb0 Created DTO classes 2025-06-19 17:16:21 +02:00
Justin 3e47cd2163 Newer java version in pom.xml 2025-06-19 02:14:41 +02:00
9 changed files with 280 additions and 107 deletions

View File

@ -15,8 +15,8 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source> <maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target> <maven.compiler.target>21</maven.compiler.target>
</properties> </properties>
<repositories> <repositories>

View File

@ -8,23 +8,25 @@ import java.util.List;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import de.hs_mannheim.informatik.chess.gui.Gui;
import de.hs_mannheim.informatik.chess.model.ChessEngine; import de.hs_mannheim.informatik.chess.model.ChessEngine;
import de.hs_mannheim.informatik.chess.model.MoveDTO;
import de.hs_mannheim.informatik.chess.model.BoardDTO;
import de.hs_mannheim.informatik.chess.view.GameGui;
public class Controller { public class Controller {
Gui gui; GameGui gui;
ChessEngine engine; ChessEngine engine;
private int selectedRow = -1, selectedCol = -1; private int selectedRow = -1, selectedCol = -1;
private List<int[]> highlightedFields = new ArrayList<>(); private List<int[]> highlightedFields = new ArrayList<>();
public Controller(Gui gui, ChessEngine engine) { public Controller(GameGui gui, ChessEngine engine) {
this.gui = gui; this.gui = gui;
this.engine = engine; this.engine = engine;
initListeners(); initListeners();
updateGuiBoard(); updateGuiBoard();
} }
private void initListeners() { private void initListeners() {
for (int row = 0; row < 8; row++) { for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) { for (int col = 0; col < 8; col++) {
final int r = row, c = col; final int r = row, c = col;
@ -36,76 +38,71 @@ public class Controller {
} }
} }
} }
private void handleClick(int row, int col) { private void handleClick(int row, int col) {
if (selectedRow == -1 && selectedCol == -1) { if (selectedRow == -1 && selectedCol == -1) {
// Erstes Feld gewählt // Erstes Feld gewählt
selectedRow = row; selectedRow = row;
selectedCol = col; selectedCol = col;
gui.getField(row, col).setBorder(BorderFactory.createLineBorder(Color.RED, 2)); gui.getField(row, col).setBorder(BorderFactory.createLineBorder(Color.RED, 2));
//Mögliche Ziele highlighten // Mögliche Ziele highlighten (DTOs!)
String from = coordToChessNotation(row, col); String fromSquare = coordToChessNotation(row, col); // z.B. "E2"
List<String> targets = engine.getLegalDestinations(from); List<MoveDTO> moves = engine.getLegalDestinations(fromSquare);
for (String t : targets) { for (MoveDTO move : moves) {
int[] xy = chessNotationToCoord(t); int toRow = move.getToRow();
gui.getField(xy[0], xy[1]).setBackground(Color.YELLOW); int toCol = move.getToCol();
highlightedFields.add(xy); gui.getField(toRow, toCol).setBackground(Color.YELLOW);
} highlightedFields.add(new int[]{toRow, toCol});
} else { }
// Zweites Feld: Zug probieren } else {
// Highlight entfernen // Zweites Feld: Zug probieren
for (int[] xy : highlightedFields) { // Highlight entfernen
resetFieldBackground(xy[0], xy[1]); for (int[] xy : highlightedFields) {
} resetFieldBackground(xy[0], xy[1]);
highlightedFields.clear(); }
highlightedFields.clear();
gui.getField(selectedRow, selectedCol).setBorder(null); gui.getField(selectedRow, selectedCol).setBorder(null);
handleMove(selectedRow, selectedCol, row, col);
selectedRow = -1;
selectedCol = -1;
}
}
public void handleMove(int fromX, int fromY, int toX, int toY) {
String from = coordToChessNotation(fromX, fromY);
String to = coordToChessNotation(toX, toY);
if (engine.move(from, to)) {
updateGuiBoard();
// Jetzt: Spielstatus prüfen! // **Neues MoveDTO statt String-Kram!**
if (engine.isMated()) { MoveDTO move = new MoveDTO(selectedRow, selectedCol, row, col);
String winner = engine.getCurrentPlayer().equals("WHITE") ? "SCHWARZ" : "WEIß"; handleMove(move);
gui.displayMessage(winner + " hat gewonnen (Schachmatt)!");
// Optional: Hier Spiel beenden/disable oder restart anbieten selectedRow = -1;
} else if (engine.isStalemate() || engine.isDraw()) { selectedCol = -1;
gui.displayMessage("Remis! (Stalemate oder andere Regel)"); }
}
} else {
gui.displayMessage("Ungültiger Zug!");
}
}
public void updateGuiBoard() {
gui.updateBoard(engine.getBoardUnicode());
} }
private String coordToChessNotation(int x, int y) { public void handleMove(MoveDTO move) {
// (0,0) -> "A8", (7,7) -> "H1" if (engine.move(move)) {
char file = (char)('A' + y); // ACHTUNG! col == y == FILE, row == x == RANK updateGuiBoard();
// Jetzt: Spielstatus prüfen!
if (engine.isMated()) {
String winner = engine.getCurrentPlayer().equals("WHITE") ? "SCHWARZ" : "WEIß";
gui.displayMessage(winner + " hat gewonnen (Schachmatt)!");
} else if (engine.isStalemate() || engine.isDraw()) {
gui.displayMessage("Remis! (Stalemate oder andere Regel)");
}
} else {
gui.displayMessage("Ungültiger Zug!");
}
}
public void updateGuiBoard() {
BoardDTO board = engine.getBoardAsDTO();
gui.updateBoard(board); // Passe die GUI an, damit sie ein BoardDTO nimmt!
}
// Hilfsmethode, um von Koordinaten (row/col) auf z.B. "E2" zu kommen
private String coordToChessNotation(int x, int y) {
char file = (char)('A' + y);
int rank = 8 - x; int rank = 8 - x;
return "" + file + rank; return "" + file + rank;
} }
private int[] chessNotationToCoord(String square) {
// "A8" -> (0,0), "H1" -> (7,7)
char file = square.charAt(0);
int rank = square.charAt(1) - '0';
int x = 8 - rank;
int y = file - 'A';
return new int[] {x, y};
}
// ... resetFieldBackground wie gehabt ...
private void resetFieldBackground(int row, int col) { private void resetFieldBackground(int row, int col) {
if ((row + col) % 2 == 0) { if ((row + col) % 2 == 0) {
gui.getField(row, col).setBackground(new Color(0x778da9)); gui.getField(row, col).setBackground(new Color(0x778da9));

View File

@ -1,15 +1,19 @@
package de.hs_mannheim.informatik.chess.main; package de.hs_mannheim.informatik.chess.main;
import de.hs_mannheim.informatik.chess.gui.Gui;
import de.hs_mannheim.informatik.chess.controller.Controller; import de.hs_mannheim.informatik.chess.controller.Controller;
import de.hs_mannheim.informatik.chess.model.ChessEngine; import de.hs_mannheim.informatik.chess.model.ChessEngine;
import de.hs_mannheim.informatik.chess.view.GameGui;
import de.hs_mannheim.informatik.chess.view.MainGui;
public class Main{ public class Main{
public static void main( String[] args ){ public static void main( String[] args ){
Gui gui = new Gui(); new MainGui(() -> {
ChessEngine engine = new ChessEngine(); //Wenn "Normal Modus" gedrückt wird
new Controller(gui, engine); GameGui gui = new GameGui();
ChessEngine engine = new ChessEngine();
new Controller(gui, engine);
});
} }
} }

View File

@ -0,0 +1,18 @@
package de.hs_mannheim.informatik.chess.model;
public class BoardDTO {
private PieceDTO[][] board; // 8x8 Feld
public BoardDTO(PieceDTO[][] board) {
this.board = board;
}
public PieceDTO[][] getBoard() {
return board;
}
public void setBoard(PieceDTO[][] board) {
this.board = board;
}
}

View File

@ -1,5 +1,4 @@
package de.hs_mannheim.informatik.chess.model; package de.hs_mannheim.informatik.chess.model;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -15,42 +14,47 @@ public class ChessEngine {
board = new Board(); board = new Board();
} }
public boolean move(String from, String to) { public boolean move(MoveDTO move) {
Move move = new Move(Square.valueOf(from.toUpperCase()), Square.valueOf(to.toUpperCase())); String from = "" + (char)('A' + move.getFromCol()) + (8 - move.getFromRow());
if (board.legalMoves().contains(move)) { String to = "" + (char)('A' + move.getToCol()) + (8 - move.getToRow());
board.doMove(move); Move libMove = new Move(Square.valueOf(from), Square.valueOf(to));
if (board.legalMoves().contains(libMove)) {
board.doMove(libMove);
return true; return true;
} else {
return false;
} }
return false;
} }
public List<String> getLegalDestinations(String from) { public List<MoveDTO> getLegalDestinations(String from) {
List<String> destinations = new ArrayList<>(); List<MoveDTO> destinations = new ArrayList<>();
Square fromSq = Square.valueOf(from.toUpperCase()); Square fromSq = Square.valueOf(from.toUpperCase());
for (Move move : board.legalMoves()) { for (Move move : board.legalMoves()) {
if (move.getFrom().equals(fromSq)) { if (move.getFrom().equals(fromSq)) {
destinations.add(move.getTo().toString()); // z.B. "E4" int fromRow = 8 - fromSq.getRank().ordinal() - 1;
int fromCol = fromSq.getFile().ordinal();
int toRow = 8 - move.getTo().getRank().ordinal() - 1;
int toCol = move.getTo().getFile().ordinal();;
destinations.add(new MoveDTO(fromRow, fromCol, toRow, toCol));
} }
} }
return destinations; return destinations;
} }
public String getPieceAt(String square) { public PieceDTO getPieceAt(String square) {
Piece piece = board.getPiece(Square.valueOf(square.toUpperCase())); Piece piece = board.getPiece(Square.valueOf(square.toUpperCase()));
return piece.toString(); // z.B. "WHITE_PAWN" return convertPieceToDTO(piece);
} }
public String[][] getBoardUnicode() { public BoardDTO getBoardAsDTO() {
String[][] unicodeBoard = new String[8][8]; PieceDTO[][] dtoBoard = new PieceDTO[8][8];
for (int rank = 8; rank >= 1; rank--) { for (int rank = 8; rank >= 1; rank--) {
for (int file = 0; file < 8; file++) { for (int file = 0; file < 8; file++) {
Square square = Square.valueOf("" + (char)('A' + file) + rank); Square square = Square.valueOf("" + (char)('A' + file) + rank);
Piece piece = board.getPiece(square); Piece piece = board.getPiece(square);
unicodeBoard[8-rank][file] = pieceToUnicode(piece); dtoBoard[8-rank][file] = convertPieceToDTO(piece);
} }
} }
return unicodeBoard; return new BoardDTO(dtoBoard);
} }
private String pieceToUnicode(Piece piece) { private String pieceToUnicode(Piece piece) {
@ -71,6 +75,14 @@ public class ChessEngine {
} }
} }
private PieceDTO convertPieceToDTO(Piece piece) {
if (piece == null || piece.equals(Piece.NONE)) return null;
String color = piece.name().startsWith("WHITE") ? "WHITE" : "BLACK";
String type = piece.name().substring(piece.name().indexOf('_') + 1); // "PAWN", "KING"...
String symbol = pieceToUnicode(piece);
return new PieceDTO(type, color, symbol);
}
public boolean isMated() { public boolean isMated() {
return board.isMated(); return board.isMated();
} }

View File

@ -0,0 +1,29 @@
package de.hs_mannheim.informatik.chess.model;
public class MoveDTO {
private int fromRow, fromCol;
private int toRow, toCol;
public MoveDTO(int fromRow, int fromCol, int toRow, int toCol) {
this.fromRow = fromRow;
this.fromCol = fromCol;
this.toRow = toRow;
this.toCol = toCol;
}
public int getFromRow() {
return fromRow;
}
public int getFromCol() {
return fromCol;
}
public int getToRow() {
return toRow;
}
public int getToCol() {
return toCol;
}
}

View File

@ -0,0 +1,25 @@
package de.hs_mannheim.informatik.chess.model;
public class PieceDTO {
private String type; // z.B. "KING", "PAWN"
private String color; // "WHITE" oder "BLACK"
private String unicodeSymbol;
public PieceDTO(String type, String color, String unicodeSymbol) {
this.type = type;
this.color = color;
this.unicodeSymbol = unicodeSymbol;
}
public String getType() {
return type;
}
public String getColor() {
return color;
}
public String getUnicodeSymbol() {
return unicodeSymbol;
}
}

View File

@ -1,4 +1,4 @@
package de.hs_mannheim.informatik.chess.gui; package de.hs_mannheim.informatik.chess.view;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
@ -14,11 +14,14 @@ import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
public class Gui { import de.hs_mannheim.informatik.chess.model.BoardDTO;
import de.hs_mannheim.informatik.chess.model.PieceDTO;
public class GameGui {
private JLabel[][] fields = new JLabel[8][8]; private JLabel[][] fields = new JLabel[8][8];
public Gui(){ public GameGui(){
mainFrame(); mainFrame();
} }
@ -111,13 +114,20 @@ public class Gui {
return fields[row][col]; return fields[row][col];
} }
public void updateBoard(String[][] unicodeBoard) { public void updateBoard(BoardDTO boardDTO) {
for (int row = 0; row < 8; row++) { PieceDTO[][] board = boardDTO.getBoard();
for (int col = 0; col < 8; col++) { for (int row = 0; row < 8; row++) {
fields[row][col].setText(unicodeBoard[row][col]); for (int col = 0; col < 8; col++) {
} PieceDTO piece = board[row][col];
} if (piece != null) {
} fields[row][col].setText(piece.getUnicodeSymbol());
} else {
fields[row][col].setText("");
}
}
}
}
public void displayMessage(String msg) { public void displayMessage(String msg) {
JOptionPane.showMessageDialog(null, msg); JOptionPane.showMessageDialog(null, msg);

View File

@ -0,0 +1,78 @@
package de.hs_mannheim.informatik.chess.view;
import java.awt.*;
import javax.swing.*;
public class MainGui {
private JFrame frame;
private Runnable onStartGame;
public MainGui(Runnable onStartGame) {
this.onStartGame = onStartGame;
frame = new JFrame("Chess - Hauptmenü");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1600, 1000);
frame.setLocationRelativeTo(null);
//Haupt-Panel mit GridBagLayout
JPanel mainPanel = new JPanel(new GridBagLayout());
mainPanel.setBackground(new Color(0xe0e1dd));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(15, 0, 15, 0);
//Title
JLabel title = new JLabel("Chess", SwingConstants.CENTER);
title.setFont(new Font("Serif", Font.BOLD, 150));
title.setForeground(new Color(0x1b263b));
gbc.gridy = 0;
gbc.ipady = 50;
mainPanel.add(title, gbc);
//Abstand nach unten
gbc.gridy = 1;
gbc.ipady = 15;
mainPanel.add(Box.createRigidArea(new Dimension(0, 20)), gbc);
//Buttons
JButton btnMode1 = new JButton("Normal Mode");
JButton btnMode2 = new JButton("Mode 2 (coming soon)");
JButton btnMode3 = new JButton("Mode 3 (coming soon)");
styleButton(btnMode1);
styleButton(btnMode2);
styleButton(btnMode3);
gbc.gridy = 2; gbc.ipady = 25;
mainPanel.add(btnMode1, gbc);
gbc.gridy = 3;
mainPanel.add(btnMode2, gbc);
gbc.gridy = 4;
mainPanel.add(btnMode3, gbc);
frame.add(mainPanel);
frame.setVisible(true);
//Button ActionListener für "Normal Modus"
btnMode1.addActionListener(e -> {
frame.dispose(); // Hauptmenü schließen
onStartGame.run(); // **Ruft den Callback auf**
});
}
// Helper für Button Styling
private void styleButton(JButton btn) {
btn.setFont(new Font("Serif", Font.BOLD, 30));
btn.setBackground(new Color(0x778da9));
btn.setForeground(Color.WHITE);
btn.setFocusPainted(false);
btn.setBorder(BorderFactory.createEmptyBorder(10, 40, 10, 40));
btn.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
}