Compare commits
No commits in common. "cf870fec576ad784817f3b345dd3795e283d52f8" and "cc18a20588d469b0bf76e4eae7c874cdadf37436" have entirely different histories.
cf870fec57
...
cc18a20588
|
@ -33,12 +33,13 @@
|
|||
<version>1.3.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JUnit 5 -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.10.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.10.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Mockito -->
|
||||
<dependency>
|
||||
|
@ -47,50 +48,9 @@
|
|||
<version>5.11.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.4.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.4.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<!-- Java Compiler Plugin -->
|
||||
<plugin>
|
||||
|
@ -146,4 +106,4 @@
|
|||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package de.hs_mannheim.informatik.chess.model;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.ConsoleHandler;
|
||||
|
@ -20,8 +21,10 @@ import com.github.bhlangonijr.chesslib.move.Move;
|
|||
import com.github.bhlangonijr.chesslib.pgn.PgnHolder;
|
||||
import com.github.bhlangonijr.chesslib.game.*;
|
||||
import com.github.bhlangonijr.chesslib.move.MoveList;
|
||||
import java.time.LocalDate;
|
||||
import com.github.bhlangonijr.chesslib.Side;
|
||||
|
||||
|
||||
public class ChessEngine {
|
||||
private Board board;
|
||||
private List<Move> moves = new ArrayList<>();
|
||||
|
@ -29,496 +32,457 @@ public class ChessEngine {
|
|||
private static final Logger logger = Logger.getLogger(ChessEngine.class.getName());
|
||||
private int quicksaveWhiteTimeLeft = -1;
|
||||
private int quicksaveBlackTimeLeft = -1;
|
||||
|
||||
|
||||
private int currentMoveIndex = 0;
|
||||
private Timer whiteTimer;
|
||||
private Timer blackTimer;
|
||||
private final GameMode mode;
|
||||
|
||||
private String quicksaveFen = null;
|
||||
private List<Move> quicksaveMoves = null;
|
||||
private int quicksaveMoveIndex = 0;
|
||||
|
||||
private Opening detectedOpening = null;
|
||||
|
||||
|
||||
public ChessEngine() {
|
||||
this.mode = null;
|
||||
this.mode = null;
|
||||
logging();
|
||||
board = new Board();
|
||||
}
|
||||
|
||||
public ChessEngine(GameMode mode) {
|
||||
this.mode = mode;
|
||||
whiteTimer = new Timer(mode.minutes, mode.seconds);
|
||||
blackTimer = new Timer(mode.minutes, mode.seconds);
|
||||
logging();
|
||||
board = new Board();
|
||||
}
|
||||
board = new Board();
|
||||
}
|
||||
public boolean move(MoveDTO move) {
|
||||
String from = "" + (char)('A' + move.getFromCol()) + (8 - move.getFromRow());
|
||||
String to = "" + (char)('A' + move.getToCol()) + (8 - move.getToRow());
|
||||
Move libMove = new Move(Square.valueOf(from), Square.valueOf(to));
|
||||
if (board.legalMoves().contains(libMove)) {
|
||||
board.doMove(libMove);
|
||||
|
||||
public ChessEngine(GameMode mode) {
|
||||
this.mode = mode;
|
||||
whiteTimer = new Timer(mode.minutes, mode.seconds);
|
||||
blackTimer = new Timer(mode.minutes, mode.seconds);
|
||||
logging();
|
||||
board = new Board();
|
||||
}
|
||||
// Replay? Dann abschneiden
|
||||
if (currentMoveIndex < moves.size()) {
|
||||
logger.info("Replay-Modus: Züge nach " + currentMoveIndex + " werden entfernt.");
|
||||
moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
|
||||
}
|
||||
moves.add(libMove);
|
||||
currentMoveIndex++;
|
||||
logger.info("Zug erfolgreich durchgeführt: " + libMove);
|
||||
|
||||
public boolean move(MoveDTO move) {
|
||||
String from = "" + (char) ('A' + move.getFromCol()) + (8 - move.getFromRow());
|
||||
String to = "" + (char) ('A' + move.getToCol()) + (8 - move.getToRow());
|
||||
Move libMove = new Move(Square.valueOf(from), Square.valueOf(to));
|
||||
if (board.legalMoves().contains(libMove)) {
|
||||
board.doMove(libMove);
|
||||
// Opening-Erkennung nach jedem erfolgreichen Zug
|
||||
String playedMovesUci = movesToUciString(moves);
|
||||
detectedOpening = Opening.detect(playedMovesUci);
|
||||
|
||||
if (currentMoveIndex < moves.size()) {
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("Replay-Modus: Züge nach " + currentMoveIndex + " werden entfernt.");
|
||||
}
|
||||
moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
|
||||
}
|
||||
moves.add(libMove);
|
||||
currentMoveIndex++;
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("Zug erfolgreich durchgeführt: " + libMove);
|
||||
}
|
||||
if (detectedOpening != null) {
|
||||
logger.info("Aktuelles Opening erkannt: " + detectedOpening.getEco() + " - " + detectedOpening.getName());
|
||||
// Optional: Speichere das Opening in ein Feld, falls benötigt
|
||||
}
|
||||
return true;
|
||||
}
|
||||
logger.warning("Ungültiger Zug: " + libMove);
|
||||
return false;
|
||||
}
|
||||
|
||||
String playedMovesUci = movesToUciString(moves);
|
||||
detectedOpening = Opening.detect(playedMovesUci);
|
||||
public String getOpeningName() {
|
||||
if (detectedOpening != null) {
|
||||
return detectedOpening.getEco() + " - " + detectedOpening.getName();
|
||||
} else {
|
||||
return "unbekannt";
|
||||
}
|
||||
}
|
||||
|
||||
private String movesToUciString(List<Move> moves) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Move m : moves) {
|
||||
sb.append(m.toString()).append(" ");
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
public List<MoveDTO> getLegalDestinations(String from) {
|
||||
logger.info("Hole legale Züge von: " + from);
|
||||
List<MoveDTO> destinations = new ArrayList<>();
|
||||
try {
|
||||
Square fromSq = Square.valueOf(from.toUpperCase());
|
||||
for (Move move : board.legalMoves()) {
|
||||
if (move.getFrom().equals(fromSq)) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
logger.info("Es wurden " + destinations.size() + " Ziele gefunden.");
|
||||
} catch (Exception e) {
|
||||
logger.severe("Fehler beim Holen der legalen Ziele: " + e.getMessage());
|
||||
}
|
||||
return destinations;
|
||||
}
|
||||
|
||||
public List<String> getMoveListStringsGrouped() {
|
||||
logger.info("Gruppiere Züge für Anzeige.");
|
||||
List<String> result = new ArrayList<>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < moves.size(); i++) {
|
||||
if (i % 2 == 0) sb.append((i/2 + 1) + ". ");
|
||||
sb.append(moves.get(i).toString()).append(" ");
|
||||
if (i % 2 == 1 || i == moves.size() - 1) {
|
||||
result.add(sb.toString().trim());
|
||||
sb = new StringBuilder();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void quicksave() {
|
||||
this.quicksaveFen = board.getFen();
|
||||
this.quicksaveMoves = new ArrayList<>(moves);
|
||||
this.quicksaveMoveIndex = currentMoveIndex;
|
||||
if (whiteTimer != null) quicksaveWhiteTimeLeft = whiteTimer.getSecondsLeft();
|
||||
if (blackTimer != null) quicksaveBlackTimeLeft = blackTimer.getSecondsLeft();
|
||||
}
|
||||
public boolean quickload() {
|
||||
if (quicksaveFen == null) return false;
|
||||
board = new Board();
|
||||
board.loadFromFen(quicksaveFen);
|
||||
moves = new ArrayList<>(quicksaveMoves);
|
||||
currentMoveIndex = quicksaveMoveIndex;
|
||||
if (whiteTimer != null && quicksaveWhiteTimeLeft != -1) whiteTimer.setSecondsLeft(quicksaveWhiteTimeLeft);
|
||||
if (blackTimer != null && quicksaveBlackTimeLeft != -1) blackTimer.setSecondsLeft(quicksaveBlackTimeLeft);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void clearQuicksave() {
|
||||
quicksaveFen = null;
|
||||
quicksaveMoves = null;
|
||||
quicksaveMoveIndex = 0;
|
||||
}
|
||||
|
||||
if (detectedOpening != null && logger.isLoggable(Level.INFO)) {
|
||||
logger.info("Aktuelles Opening erkannt: " + detectedOpening.getEco() + " - " + detectedOpening.getName());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (logger.isLoggable(Level.WARNING)) {
|
||||
logger.warning("Ungültiger Zug: " + libMove);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public PieceDTO getPieceAt(String square) {
|
||||
logger.info("Hole Figur an Feld: " + square);
|
||||
Piece piece = board.getPiece(Square.valueOf(square.toUpperCase()));
|
||||
return convertPieceToDTO(piece);
|
||||
}
|
||||
|
||||
public boolean moveWithPromotion(MoveDTO move, String promotionPiece) {
|
||||
String from = "" + (char)('A' + move.getFromCol()) + (8 - move.getFromRow());
|
||||
String to = "" + (char)('A' + move.getToCol()) + (8 - move.getToRow());
|
||||
|
||||
public String getOpeningName() {
|
||||
if (detectedOpening != null) {
|
||||
return detectedOpening.getEco() + " - " + detectedOpening.getName();
|
||||
} else {
|
||||
return "unbekannt";
|
||||
}
|
||||
}
|
||||
// Die Farbe bestimmen!
|
||||
boolean isWhite = (8 - move.getFromRow()) < (8 - move.getToRow());
|
||||
Piece promotion;
|
||||
switch (promotionPiece) {
|
||||
case "ROOK": promotion = isWhite ? Piece.WHITE_ROOK : Piece.BLACK_ROOK; break;
|
||||
case "KNIGHT": promotion = isWhite ? Piece.WHITE_KNIGHT : Piece.BLACK_KNIGHT; break;
|
||||
case "BISHOP": promotion = isWhite ? Piece.WHITE_BISHOP : Piece.BLACK_BISHOP; break;
|
||||
default: promotion = isWhite ? Piece.WHITE_QUEEN : Piece.BLACK_QUEEN;
|
||||
}
|
||||
|
||||
private String movesToUciString(List<Move> moves) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Move m : moves) {
|
||||
sb.append(m.toString()).append(" ");
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
Move libMove = new Move(Square.valueOf(from), Square.valueOf(to), promotion);
|
||||
|
||||
public List<MoveDTO> getLegalDestinations(String from) {
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("Hole legale Züge von: " + from);
|
||||
}
|
||||
List<MoveDTO> destinations = new ArrayList<>();
|
||||
try {
|
||||
Square fromSq = Square.valueOf(from.toUpperCase(java.util.Locale.ROOT));
|
||||
for (Move move : board.legalMoves()) {
|
||||
if (move.getFrom().equals(fromSq)) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("Es wurden " + destinations.size() + " Ziele gefunden.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (logger.isLoggable(Level.SEVERE)) {
|
||||
logger.severe("Fehler beim Holen der legalen Ziele: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return destinations;
|
||||
}
|
||||
if (board.legalMoves().contains(libMove)) {
|
||||
board.doMove(libMove);
|
||||
|
||||
public List<String> getMoveListStringsGrouped() {
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("Gruppiere Züge für Anzeige.");
|
||||
}
|
||||
List<String> result = new ArrayList<>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < moves.size(); i++) {
|
||||
if (i % 2 == 0) {
|
||||
sb.append((i / 2 + 1)).append(". ");
|
||||
}
|
||||
sb.append(moves.get(i).toString()).append(" ");
|
||||
if (i % 2 == 1 || i == moves.size() - 1) {
|
||||
result.add(sb.toString().trim());
|
||||
sb = new StringBuilder();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (currentMoveIndex < moves.size()) {
|
||||
moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
|
||||
}
|
||||
moves.add(libMove);
|
||||
currentMoveIndex++;
|
||||
logger.info("Promotionszug durchgeführt: " + libMove);
|
||||
return true;
|
||||
}
|
||||
logger.warning("Ungültiger Promotionszug: " + libMove);
|
||||
return false;
|
||||
}
|
||||
|
||||
public BoardDTO getBoardAsDTO() {
|
||||
logger.info("Erstelle DTO-Abbild des Boards");
|
||||
PieceDTO[][] dtoBoard = new PieceDTO[8][8];
|
||||
for (int rank = 8; rank >= 1; rank--) {
|
||||
for (int file = 0; file < 8; file++) {
|
||||
Square square = Square.valueOf("" + (char)('A' + file) + rank);
|
||||
Piece piece = board.getPiece(square);
|
||||
dtoBoard[8-rank][file] = convertPieceToDTO(piece);
|
||||
}
|
||||
}
|
||||
return new BoardDTO(dtoBoard);
|
||||
}
|
||||
|
||||
private String pieceToUnicode(Piece piece) {
|
||||
switch (piece) {
|
||||
case WHITE_KING: return "♔";
|
||||
case WHITE_QUEEN: return "♕";
|
||||
case WHITE_ROOK: return "♖";
|
||||
case WHITE_BISHOP: return "♗";
|
||||
case WHITE_KNIGHT: return "♘";
|
||||
case WHITE_PAWN: return "♙";
|
||||
case BLACK_KING: return "♚";
|
||||
case BLACK_QUEEN: return "♛";
|
||||
case BLACK_ROOK: return "♜";
|
||||
case BLACK_BISHOP: return "♝";
|
||||
case BLACK_KNIGHT: return "♞";
|
||||
case BLACK_PAWN: return "♟";
|
||||
default: return " ";
|
||||
}
|
||||
}
|
||||
|
||||
public void setPositionToMoveIndex(int idx) {
|
||||
logger.info("Setze Board auf Zug-Index: " + idx);
|
||||
board = new Board();
|
||||
board.loadFromFen(initialFen); // Statt new Board() -> initialFen!
|
||||
for (int i = 0; i < idx; i++) {
|
||||
board.doMove(moves.get(i));
|
||||
}
|
||||
currentMoveIndex = idx;
|
||||
|
||||
String playedMovesUci = movesToUciString(moves.subList(0, idx));
|
||||
detectedOpening = Opening.detect(playedMovesUci);
|
||||
}
|
||||
public int getCurrentMoveIndex() {
|
||||
logger.info("Hole aktuellen Zug-Index: " + currentMoveIndex);
|
||||
return currentMoveIndex;
|
||||
}
|
||||
|
||||
public int getMoveListSize() {
|
||||
logger.info("Hole Anzahl gespielter Züge: " + moves.size());
|
||||
return moves.size();
|
||||
}
|
||||
|
||||
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 void setPositionFromFEN(String fen) {
|
||||
board.loadFromFen(fen);
|
||||
initialFen = fen;
|
||||
}
|
||||
|
||||
public void quicksave() {
|
||||
this.quicksaveFen = board.getFen();
|
||||
this.quicksaveMoves = new ArrayList<>(moves);
|
||||
this.quicksaveMoveIndex = currentMoveIndex;
|
||||
if (whiteTimer != null) {
|
||||
quicksaveWhiteTimeLeft = whiteTimer.getSecondsLeft();
|
||||
}
|
||||
if (blackTimer != null) {
|
||||
quicksaveBlackTimeLeft = blackTimer.getSecondsLeft();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMated() {
|
||||
boolean mated = board.isMated();
|
||||
logger.info("isMated() = " + mated);
|
||||
return mated;
|
||||
}
|
||||
|
||||
public boolean isStalemate() {
|
||||
boolean stale = board.isStaleMate();
|
||||
logger.info("isStalemate() = " + stale);
|
||||
return stale;
|
||||
}
|
||||
|
||||
public boolean isDraw() {
|
||||
boolean draw = board.isDraw();
|
||||
logger.info("isDraw() = " + draw);
|
||||
return draw;
|
||||
}
|
||||
|
||||
public String getCurrentPlayer() {
|
||||
String player = board.getSideToMove().toString();
|
||||
logger.info("Am Zug: " + player);
|
||||
return player;
|
||||
}
|
||||
|
||||
public void logging() {
|
||||
|
||||
// Eigener Handler nur für diese Klasse
|
||||
ConsoleHandler handler = new ConsoleHandler();
|
||||
handler.setLevel(Level.ALL);
|
||||
handler.setFormatter(new SimpleFormatter() {
|
||||
@Override
|
||||
public synchronized String format(LogRecord lr) {
|
||||
return String.format("[%s] %s%n%n", lr.getLevel().getLocalizedName(), lr.getMessage());
|
||||
}
|
||||
});
|
||||
logger.setUseParentHandlers(false);
|
||||
logger.addHandler(handler);
|
||||
|
||||
logger.info("ChessEngine wurde initialisiert.");
|
||||
}
|
||||
|
||||
public List<Game> loadGamesFromPgn(String path) throws IOException {
|
||||
|
||||
public boolean quickload() {
|
||||
if (quicksaveFen == null) {
|
||||
return false;
|
||||
}
|
||||
board = new Board();
|
||||
board.loadFromFen(quicksaveFen);
|
||||
moves = new ArrayList<>(quicksaveMoves);
|
||||
currentMoveIndex = quicksaveMoveIndex;
|
||||
if (whiteTimer != null && quicksaveWhiteTimeLeft != -1) {
|
||||
whiteTimer.setSecondsLeft(quicksaveWhiteTimeLeft);
|
||||
}
|
||||
if (blackTimer != null && quicksaveBlackTimeLeft != -1) {
|
||||
blackTimer.setSecondsLeft(quicksaveBlackTimeLeft);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void clearQuicksave() {
|
||||
quicksaveFen = null;
|
||||
quicksaveMoves = null;
|
||||
quicksaveMoveIndex = 0;
|
||||
}
|
||||
|
||||
public PieceDTO getPieceAt(String square) {
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("Hole Figur an Feld: " + square);
|
||||
}
|
||||
Piece piece = board.getPiece(Square.valueOf(square.toUpperCase(java.util.Locale.ROOT)));
|
||||
return convertPieceToDTO(piece);
|
||||
}
|
||||
|
||||
public boolean moveWithPromotion(MoveDTO move, String promotionPiece) {
|
||||
String from = "" + (char) ('A' + move.getFromCol()) + (8 - move.getFromRow());
|
||||
String to = "" + (char) ('A' + move.getToCol()) + (8 - move.getToRow());
|
||||
|
||||
boolean isWhite = (8 - move.getFromRow()) < (8 - move.getToRow());
|
||||
Piece promotion;
|
||||
switch (promotionPiece) {
|
||||
case "ROOK":
|
||||
promotion = isWhite ? Piece.WHITE_ROOK : Piece.BLACK_ROOK;
|
||||
break;
|
||||
case "KNIGHT":
|
||||
promotion = isWhite ? Piece.WHITE_KNIGHT : Piece.BLACK_KNIGHT;
|
||||
break;
|
||||
case "BISHOP":
|
||||
promotion = isWhite ? Piece.WHITE_BISHOP : Piece.BLACK_BISHOP;
|
||||
break;
|
||||
default:
|
||||
promotion = isWhite ? Piece.WHITE_QUEEN : Piece.BLACK_QUEEN;
|
||||
break;
|
||||
}
|
||||
|
||||
Move libMove = new Move(Square.valueOf(from), Square.valueOf(to), promotion);
|
||||
|
||||
if (board.legalMoves().contains(libMove)) {
|
||||
board.doMove(libMove);
|
||||
|
||||
if (currentMoveIndex < moves.size()) {
|
||||
moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
|
||||
}
|
||||
moves.add(libMove);
|
||||
currentMoveIndex++;
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("Promotionszug durchgeführt: " + libMove);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (logger.isLoggable(Level.WARNING)) {
|
||||
logger.warning("Ungültiger Promotionszug: " + libMove);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public BoardDTO getBoardAsDTO() {
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("Erstelle DTO-Abbild des Boards");
|
||||
}
|
||||
PieceDTO[][] dtoBoard = new PieceDTO[8][8];
|
||||
for (int rank = 8; rank >= 1; rank--) {
|
||||
for (int file = 0; file < 8; file++) {
|
||||
Square square = Square.valueOf("" + (char) ('A' + file) + rank);
|
||||
Piece piece = board.getPiece(square);
|
||||
dtoBoard[8 - rank][file] = convertPieceToDTO(piece);
|
||||
}
|
||||
}
|
||||
return new BoardDTO(dtoBoard);
|
||||
}
|
||||
|
||||
private String pieceToUnicode(Piece piece) {
|
||||
switch (piece) {
|
||||
case WHITE_KING:
|
||||
return "♔";
|
||||
case WHITE_QUEEN:
|
||||
return "♕";
|
||||
case WHITE_ROOK:
|
||||
return "♖";
|
||||
case WHITE_BISHOP:
|
||||
return "♗";
|
||||
case WHITE_KNIGHT:
|
||||
return "♘";
|
||||
case WHITE_PAWN:
|
||||
return "♙";
|
||||
case BLACK_KING:
|
||||
return "♚";
|
||||
case BLACK_QUEEN:
|
||||
return "♛";
|
||||
case BLACK_ROOK:
|
||||
return "♜";
|
||||
case BLACK_BISHOP:
|
||||
return "♝";
|
||||
case BLACK_KNIGHT:
|
||||
return "♞";
|
||||
case BLACK_PAWN:
|
||||
return "♟";
|
||||
default:
|
||||
return " ";
|
||||
}
|
||||
}
|
||||
|
||||
public void setPositionToMoveIndex(int idx) {
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("Setze Board auf Zug-Index: " + idx);
|
||||
}
|
||||
board = new Board();
|
||||
board.loadFromFen(initialFen);
|
||||
for (int i = 0; i < idx; i++) {
|
||||
board.doMove(moves.get(i));
|
||||
}
|
||||
currentMoveIndex = idx;
|
||||
|
||||
String playedMovesUci = movesToUciString(moves.subList(0, idx));
|
||||
detectedOpening = Opening.detect(playedMovesUci);
|
||||
}
|
||||
|
||||
public int getCurrentMoveIndex() {
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("Hole aktuellen Zug-Index: " + currentMoveIndex);
|
||||
}
|
||||
return currentMoveIndex;
|
||||
}
|
||||
|
||||
public int getMoveListSize() {
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("Hole Anzahl gespielter Züge: " + moves.size());
|
||||
}
|
||||
return moves.size();
|
||||
}
|
||||
|
||||
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);
|
||||
String symbol = pieceToUnicode(piece);
|
||||
return new PieceDTO(type, color, symbol);
|
||||
}
|
||||
|
||||
public void setPositionFromFEN(String fen) {
|
||||
board.loadFromFen(fen);
|
||||
initialFen = fen;
|
||||
}
|
||||
|
||||
public boolean isMated() {
|
||||
boolean mated = board.isMated();
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("isMated() = " + mated);
|
||||
}
|
||||
return mated;
|
||||
}
|
||||
|
||||
public boolean isStalemate() {
|
||||
boolean stale = board.isStaleMate();
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("isStalemate() = " + stale);
|
||||
}
|
||||
return stale;
|
||||
}
|
||||
|
||||
public boolean isDraw() {
|
||||
boolean draw = board.isDraw();
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("isDraw() = " + draw);
|
||||
}
|
||||
return draw;
|
||||
}
|
||||
|
||||
public String getCurrentPlayer() {
|
||||
String player = board.getSideToMove().toString();
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("Am Zug: " + player);
|
||||
}
|
||||
return player;
|
||||
}
|
||||
|
||||
public void logging() {
|
||||
ConsoleHandler handler = new ConsoleHandler();
|
||||
handler.setLevel(Level.ALL);
|
||||
handler.setFormatter(new SimpleFormatter() {
|
||||
@Override
|
||||
public synchronized String format(LogRecord lr) {
|
||||
return String.format("[%s] %s%n%n", lr.getLevel().getLocalizedName(), lr.getMessage());
|
||||
}
|
||||
});
|
||||
logger.setUseParentHandlers(false);
|
||||
logger.addHandler(handler);
|
||||
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
logger.info("ChessEngine wurde initialisiert.");
|
||||
}
|
||||
}
|
||||
|
||||
public List<Game> loadGamesFromPgn(String path) throws IOException {
|
||||
PgnHolder pgnHolder = new PgnHolder(path);
|
||||
try {
|
||||
PgnHolder pgnHolder = new PgnHolder(path);
|
||||
try {
|
||||
pgnHolder.loadPgn();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return pgnHolder.getGames();
|
||||
}
|
||||
}
|
||||
List<Game> games = pgnHolder.getGames();
|
||||
return games;
|
||||
}
|
||||
|
||||
public void initTimers(int min, int sec) {
|
||||
if (whiteTimer == null) {
|
||||
whiteTimer = new Timer(min, sec);
|
||||
} else if (quicksaveWhiteTimeLeft != -1) {
|
||||
whiteTimer = new Timer(min, sec);
|
||||
whiteTimer.setSecondsLeft(quicksaveWhiteTimeLeft);
|
||||
} else {
|
||||
whiteTimer = new Timer(min, sec);
|
||||
}
|
||||
|
||||
public void initTimers(int min, int sec) {
|
||||
if (whiteTimer == null) {
|
||||
whiteTimer = new Timer(min, sec);
|
||||
} else if (quicksaveWhiteTimeLeft != -1) {
|
||||
whiteTimer = new Timer(min, sec);
|
||||
whiteTimer.setSecondsLeft(quicksaveWhiteTimeLeft);
|
||||
} else {
|
||||
whiteTimer = new Timer(min, sec);
|
||||
}
|
||||
if (blackTimer == null) {
|
||||
blackTimer = new Timer(min, sec);
|
||||
} else if (quicksaveBlackTimeLeft != -1) {
|
||||
blackTimer = new Timer(min, sec);
|
||||
blackTimer.setSecondsLeft(quicksaveBlackTimeLeft);
|
||||
} else {
|
||||
blackTimer = new Timer(min, sec);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveAsPgn(Game game, String path, String dateiname) {
|
||||
// Sicher alle Strings holen (nie null)
|
||||
String event = safe(game.getRound().getEvent().getName());
|
||||
String site = safe(game.getRound().getEvent().getSite());
|
||||
String round = "" + game.getRound().getNumber();
|
||||
// Datum für PGN-Format (YYYY.MM.DD)
|
||||
String date = safe(game.getRound().getEvent().getStartDate()).replace("-", ".");
|
||||
String wName = safe(game.getWhitePlayer().getName());
|
||||
String bName = safe(game.getBlackPlayer().getName());
|
||||
String result = safe(game.getResult().getDescription());
|
||||
|
||||
if (blackTimer == null) {
|
||||
blackTimer = new Timer(min, sec);
|
||||
} else if (quicksaveBlackTimeLeft != -1) {
|
||||
blackTimer = new Timer(min, sec);
|
||||
blackTimer.setSecondsLeft(quicksaveBlackTimeLeft);
|
||||
} else {
|
||||
blackTimer = new Timer(min, sec);
|
||||
}
|
||||
}
|
||||
// PGN-Header zusammenbauen
|
||||
StringBuilder header = new StringBuilder();
|
||||
header.append("[Event \"" + event + "\"]\n");
|
||||
header.append("[Site \"" + site + "\"]\n");
|
||||
header.append("[Date \"" + date + "\"]\n");
|
||||
header.append("[Round \"" + round + "\"]\n");
|
||||
header.append("[White \"" + wName + "\"]\n");
|
||||
header.append("[Black \"" + bName + "\"]\n");
|
||||
header.append("[Result \"" + result + "\"]\n\n");
|
||||
|
||||
public void saveAsPgn(Game game, String path, String dateiname) {
|
||||
String event = safe(game.getRound().getEvent().getName());
|
||||
String site = safe(game.getRound().getEvent().getSite());
|
||||
String round = "" + game.getRound().getNumber();
|
||||
String date = safe(game.getRound().getEvent().getStartDate()).replace("-", ".");
|
||||
String wName = safe(game.getWhitePlayer().getName());
|
||||
String bName = safe(game.getBlackPlayer().getName());
|
||||
String result = safe(game.getResult().getDescription());
|
||||
// Züge als SAN holen
|
||||
StringBuilder moves = new StringBuilder();
|
||||
String[] sanArray = game.getHalfMoves().toSanArray();
|
||||
|
||||
StringBuilder header = new StringBuilder();
|
||||
header.append("[Event \"" + event + "\"]\n");
|
||||
header.append("[Site \"" + site + "\"]\n");
|
||||
header.append("[Date \"" + date + "\"]\n");
|
||||
header.append("[Round \"" + round + "\"]\n");
|
||||
header.append("[White \"" + wName + "\"]\n");
|
||||
header.append("[Black \"" + bName + "\"]\n");
|
||||
header.append("[Result \"" + result + "\"]\n\n");
|
||||
for (int i = 0; i < sanArray.length; i++) {
|
||||
if (i % 2 == 0) {
|
||||
moves.append((i / 2 + 1)).append(". ");
|
||||
}
|
||||
moves.append(sanArray[i]).append(" ");
|
||||
// Optional: Zeilenumbruch für Lesbarkeit
|
||||
// if (i > 0 && i % 8 == 0) moves.append("\n");
|
||||
}
|
||||
moves.append(result); // Ergebnis am Ende!
|
||||
|
||||
StringBuilder movesSb = new StringBuilder();
|
||||
String[] sanArray = game.getHalfMoves().toSanArray();
|
||||
String file = header + moves.toString();
|
||||
|
||||
for (int i = 0; i < sanArray.length; i++) {
|
||||
if (i % 2 == 0) {
|
||||
movesSb.append((i / 2 + 1)).append(". ");
|
||||
}
|
||||
movesSb.append(sanArray[i]).append(" ");
|
||||
}
|
||||
movesSb.append(result);
|
||||
// Datei schreiben
|
||||
try {
|
||||
Files.writeString(Path.of(path, dateiname), file, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
String file = header + movesSb.toString();
|
||||
// Hilfsfunktion für Null-Sicherheit
|
||||
private String safe(String s) {
|
||||
return s == null ? "?" : s;
|
||||
}
|
||||
|
||||
try {
|
||||
Files.writeString(Path.of(path, dateiname), file, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public Game getCurrentGame() {
|
||||
return getCurrentGame(this.board, this.moves, this.currentMoveIndex);
|
||||
}
|
||||
|
||||
public Game getCurrentGame(Board board, java.util.List<Move> moves, int currentMoveIndex) {
|
||||
// Event und Turnierdaten setzen
|
||||
Event event = new Event();
|
||||
event.setName("Generated Game");
|
||||
event.setSite("Local");
|
||||
event.setStartDate(LocalDate.now().toString()); // Format: yyyy-MM-dd
|
||||
|
||||
private String safe(String s) {
|
||||
return s == null ? "?" : s;
|
||||
}
|
||||
// Runde anlegen
|
||||
Round round = new Round(event);
|
||||
round.setNumber(1);
|
||||
|
||||
public Game getCurrentGame() {
|
||||
return getCurrentGame(this.board, this.moves, this.currentMoveIndex);
|
||||
}
|
||||
// Spiel initialisieren
|
||||
Game game = new Game("1", round); // "1" ist die Game-ID
|
||||
|
||||
public Game getCurrentGame(Board board, List<Move> moves, int currentMoveIndex) {
|
||||
Event event = new Event();
|
||||
event.setName("Generated Game");
|
||||
event.setSite("Local");
|
||||
event.setStartDate(LocalDate.now().toString());
|
||||
// Spieler setzen (deine MyPlayer-Klasse)
|
||||
game.setWhitePlayer(new MyPlayer("White"));
|
||||
game.setBlackPlayer(new MyPlayer("Black"));
|
||||
|
||||
Round round = new Round(event);
|
||||
round.setNumber(1);
|
||||
// Ergebnis setzen
|
||||
if (board.isMated()) {
|
||||
game.setResult(board.getSideToMove() == Side.WHITE ? GameResult.BLACK_WON : GameResult.WHITE_WON);
|
||||
} else if (board.isStaleMate() || board.isDraw()) {
|
||||
game.setResult(GameResult.DRAW);
|
||||
} else {
|
||||
game.setResult(GameResult.ONGOING);
|
||||
}
|
||||
|
||||
Game game = new Game("1", round);
|
||||
// Züge übernehmen
|
||||
MoveList moveList = new MoveList();
|
||||
for (Move move : moves) {
|
||||
moveList.add(move);
|
||||
}
|
||||
game.setHalfMoves(moveList);
|
||||
|
||||
game.setWhitePlayer(new MyPlayer("White"));
|
||||
game.setBlackPlayer(new MyPlayer("Black"));
|
||||
// Position auf aktuellen Zug setzen (letzter gespielter Halbzug)
|
||||
if (currentMoveIndex > 0 && currentMoveIndex <= moveList.size()) {
|
||||
game.setPosition(currentMoveIndex - 1);
|
||||
} else {
|
||||
game.setPosition(moveList.size() - 1);
|
||||
}
|
||||
|
||||
if (board.isMated()) {
|
||||
game.setResult(board.getSideToMove() == Side.WHITE ? GameResult.BLACK_WON : GameResult.WHITE_WON);
|
||||
} else if (board.isStaleMate() || board.isDraw()) {
|
||||
game.setResult(GameResult.DRAW);
|
||||
} else {
|
||||
game.setResult(GameResult.ONGOING);
|
||||
}
|
||||
// FEN setzen: JETZT das aktuelle Board-FEN verwenden!
|
||||
game.setBoard(new Board());
|
||||
game.getBoard().loadFromFen(board.getFen());
|
||||
|
||||
MoveList moveList = new MoveList();
|
||||
for (Move move : moves) {
|
||||
moveList.add(move);
|
||||
}
|
||||
game.setHalfMoves(moveList);
|
||||
return game;
|
||||
}
|
||||
|
||||
if (currentMoveIndex > 0 && currentMoveIndex <= moveList.size()) {
|
||||
game.setPosition(currentMoveIndex - 1);
|
||||
} else {
|
||||
game.setPosition(moveList.size() - 1);
|
||||
}
|
||||
|
||||
game.setBoard(new Board());
|
||||
game.getBoard().loadFromFen(board.getFen());
|
||||
public void undoLastMove() {
|
||||
if (currentMoveIndex > 0 && moves.size() > 0) {
|
||||
board.undoMove(); // 1. Brett zurücksetzen
|
||||
moves.remove(currentMoveIndex - 1); // 2. Zug aus Move-Liste löschen
|
||||
currentMoveIndex--; // 3. Index anpassen
|
||||
|
||||
return game;
|
||||
}
|
||||
// 4. Erkennung Opening neu machen!
|
||||
String playedMovesUci = movesToUciString(moves.subList(0, currentMoveIndex));
|
||||
detectedOpening = Opening.detect(playedMovesUci);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void loadMoves(List<Move> moveList) {
|
||||
board = new Board(); // Neues leeres Brett
|
||||
moves.clear();
|
||||
currentMoveIndex = 0;
|
||||
|
||||
public void undoLastMove() {
|
||||
if (currentMoveIndex > 0 && !moves.isEmpty()) {
|
||||
board.undoMove();
|
||||
moves.remove(currentMoveIndex - 1);
|
||||
currentMoveIndex--;
|
||||
for (Move move : moveList) {
|
||||
board.doMove(move);
|
||||
moves.add(move);
|
||||
currentMoveIndex++;
|
||||
}
|
||||
|
||||
String playedMovesUci = movesToUciString(moves.subList(0, currentMoveIndex));
|
||||
detectedOpening = Opening.detect(playedMovesUci);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Timer getWhiteTimer() { return whiteTimer; }
|
||||
|
||||
public void loadMoves(List<Move> moveList) {
|
||||
board = new Board();
|
||||
moves.clear();
|
||||
currentMoveIndex = 0;
|
||||
public Timer getBlackTimer() { return blackTimer; }
|
||||
|
||||
for (Move move : moveList) {
|
||||
board.doMove(move);
|
||||
moves.add(move);
|
||||
currentMoveIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
public Timer getWhiteTimer() {
|
||||
return whiteTimer;
|
||||
}
|
||||
|
||||
public Timer getBlackTimer() {
|
||||
return blackTimer;
|
||||
}
|
||||
|
||||
public GameMode getGameMode() {
|
||||
// TODO Auto-generated method stub
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue