Compare commits
13 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
6f850aa11b | |
|
|
c9efa6ecda | |
|
|
833630abcd | |
|
|
2cf0075c0c | |
|
|
65c7486a32 | |
|
|
cf870fec57 | |
|
|
cc18a20588 | |
|
|
49e88ac03e | |
|
|
cf98d45d6a | |
|
|
32f97aa624 | |
|
|
fa8f04805f | |
|
|
59233efcca | |
|
|
aebfb7e38b |
|
|
@ -0,0 +1,259 @@
|
||||||
|
1. Methode toPGN ist vorhanden in Klasse Game.java!!! Mit MoveGenerator werden schon alle legalen züge angezeigt!!!
|
||||||
|
|
||||||
|
2. Klassen von GPT zusammengefasst:
|
||||||
|
https://chatgpt.com/share/684326dc-4ea0-8012-8c10-8b34993140b7
|
||||||
|
|
||||||
|
Event:
|
||||||
|
|
||||||
|
Die Klasse Event beschreibt ein Schachturnier oder -ereignis mit Name, Ort, Datum, Zeitkontrollen, Rundenstruktur und referenzierten PGN-Daten.
|
||||||
|
|
||||||
|
|
||||||
|
EventType:
|
||||||
|
|
||||||
|
EventType beschreibt den strukturellen Typ eines Schachturniers (z. B. KO-System, Rundenturnier oder Analyseveranstaltung).
|
||||||
|
|
||||||
|
|
||||||
|
Game:
|
||||||
|
|
||||||
|
Die Klasse Game speichert und verwaltet alle Informationen einer Schachpartie – wie Züge, Spieler, Kommentare und Metadaten – und erlaubt deren Analyse, Bearbeitung und Ausgabe im PGN-Format.
|
||||||
|
|
||||||
|
|
||||||
|
GameContext:
|
||||||
|
|
||||||
|
Die Klasse GameContext stellt alle benötigten Informationen und Methoden bereit, um Rochaden und Schachvarianten (z. B. Chess960) regelkonform zu verwalten und korrekt zu validieren.
|
||||||
|
|
||||||
|
|
||||||
|
GameFactory:
|
||||||
|
|
||||||
|
GameFactory stellt statische Hilfsmethoden bereit, um neue Schachobjekte (Spiel, Spieler, Runde, Event) schnell und einheitlich zu erzeugen.
|
||||||
|
|
||||||
|
|
||||||
|
GameMode:
|
||||||
|
|
||||||
|
GameMode legt fest, ob eine Partie zwischen Menschen, Maschinen oder gemischt (z. B. Engine vs Mensch) gespielt wird.
|
||||||
|
|
||||||
|
|
||||||
|
GameResult:
|
||||||
|
|
||||||
|
GameResult beschreibt, wie eine Schachpartie geendet hat (Sieg, Remis oder noch laufend) und verknüpft dies mit der entsprechenden PGN-Notation.
|
||||||
|
|
||||||
|
|
||||||
|
MoveGeneratorException
|
||||||
|
|
||||||
|
MoveGeneratorException signalisiert Fehler beim Generieren von Schachzügen und erlaubt dabei flexible Fehlerbeschreibungen.
|
||||||
|
|
||||||
|
|
||||||
|
MoveList
|
||||||
|
|
||||||
|
MoveList verwaltet eine Folge von Schachzügen und erlaubt deren Umwandlung, Validierung und Darstellung in verschiedenen Notationen basierend auf einer Ausgangsstellung.
|
||||||
|
|
||||||
|
|
||||||
|
GameLoader:
|
||||||
|
|
||||||
|
Die Klasse GameLoader lädt eine vollständige Schachpartie inklusive aller Metadaten und Züge aus einem PGN-Dateiiterator und wandelt sie in ein Game-Objekt um.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GenericPlayer:
|
||||||
|
|
||||||
|
Die Klasse GenericPlayer implementiert das Player-Interface und speichert die wichtigsten Eigenschaften eines Schachspielers wie Name, Elo, Typ (Mensch/Maschine) und Beschreibung.
|
||||||
|
|
||||||
|
|
||||||
|
Mode:
|
||||||
|
|
||||||
|
Mode beschreibt den Austragungsort einer Partie: entweder als Präsenzspiel am Brett (OTB) oder über einen Online-Server (ICS).
|
||||||
|
|
||||||
|
|
||||||
|
MovePerTime:
|
||||||
|
|
||||||
|
MovePerTime beschreibt eine Zeitkontrolle, bei der eine bestimmte Anzahl an Zügen in einer definierten Zeit (in Millisekunden) gespielt werden muss, z. B. 40/5400 (40 Züge in 90 Minuten).
|
||||||
|
|
||||||
|
|
||||||
|
Player:
|
||||||
|
|
||||||
|
Player ist ein Interface, das die grundlegenden Eigenschaften und Methoden eines Schachspielers festlegt, darunter ID, Name, Elo, Typ und eine ausführliche Beschreibung.
|
||||||
|
|
||||||
|
|
||||||
|
PlayerType:
|
||||||
|
|
||||||
|
PlayerType unterscheidet, ob ein Spieler ein Mensch (HUMAN) oder eine Engine (ENGINE) ist.
|
||||||
|
|
||||||
|
|
||||||
|
Round:
|
||||||
|
|
||||||
|
Round speichert eine bestimmte Runde eines Schachturniers und enthält eine Liste aller Partien (Game), die in dieser Runde gespielt werden.
|
||||||
|
|
||||||
|
|
||||||
|
Termination:
|
||||||
|
|
||||||
|
Termination gibt an, warum eine Partie beendet wurde, z. B. regulär, durch Zeitüberschreitung, Regelverstoß oder Abbruch.
|
||||||
|
|
||||||
|
|
||||||
|
TimeControl:
|
||||||
|
|
||||||
|
TimeControl speichert verschiedene Zeitregelungen für eine Partie – etwa klassische Zeitkontrollen, Bonuszeiten (Inkrement), feste Zugvorgaben, Knoten-/Tiefenlimits (für Engines) und gibt sie als PGN-kompatible Zeichenkette zurück.
|
||||||
|
|
||||||
|
|
||||||
|
TimeControlType:
|
||||||
|
|
||||||
|
TimeControlType gibt an, in welchem Modus eine Zeitkontrolle funktioniert, z. B. klassisches Zeitlimit mit Inkrement, Zeit pro Zug, feste Tiefe oder Knotenzahl (für Engines).
|
||||||
|
|
||||||
|
|
||||||
|
VariationType:
|
||||||
|
|
||||||
|
VariationType gibt an, welche Schachvariante gespielt wird – z. B. Standard-Schach, Chess960 oder Varianten mit speziellen Rochaderegeln oder Figurenmechaniken.
|
||||||
|
|
||||||
|
|
||||||
|
Move:
|
||||||
|
|
||||||
|
Move repräsentiert einen einzelnen Schachzug mit Start- und Zielfeld, optionaler Bauernumwandlung sowie SAN-Notation, und kann als Ereignis (BoardEvent) weiterverarbeitet werden.
|
||||||
|
|
||||||
|
|
||||||
|
MoveConversionException:
|
||||||
|
|
||||||
|
MoveConversionException signalisiert, dass ein Zug nicht korrekt aus einem Text (z. B. "e2e99" oder "z9z8Q") in ein gültiges Move-Objekt umgewandelt werden konnte.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MoveException:
|
||||||
|
|
||||||
|
MoveException signalisiert, dass ein Zug nicht auf dem aktuellen Spielstand ausgeführt werden kann – typischerweise, weil er regelwidrig, unmöglich oder logisch inkonsistent ist.
|
||||||
|
|
||||||
|
|
||||||
|
MoveGenerator:
|
||||||
|
|
||||||
|
MoveGenerator stellt statische Hilfsmethoden bereit, um aus einem gegebenen Schachbrettzustand alle möglichen Züge (pseudo-legal oder legal) zu erzeugen, einschließlich Spezialzüge wie Rochade oder Bauernumwandlungen.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PgnException
|
||||||
|
|
||||||
|
Die Klasse PgnException signalisiert Laufzeitfehler beim Parsen oder Einlesen von PGN-Schachpartien.
|
||||||
|
|
||||||
|
|
||||||
|
PgnHolder
|
||||||
|
|
||||||
|
Die Klasse PgnHolder verwaltet das Einlesen, Speichern und Abrufen von Schachpartien aus PGN-Dateien und organisiert dabei Spieler, Events und Spiele zentral in einer leicht zugänglichen Struktur.
|
||||||
|
|
||||||
|
|
||||||
|
PgnIterator
|
||||||
|
|
||||||
|
Die Klasse PgnIterator ermöglicht das speicherschonende Durchiterieren von Schachpartien in einer PGN-Datei, indem sie zeilenweise liest und jede Partie einzeln verarbeitet.
|
||||||
|
|
||||||
|
|
||||||
|
PgnLoadListener
|
||||||
|
|
||||||
|
Die Schnittstelle PgnLoadListener erlaubt es, auf Fortschritte beim Laden von PGN-Partien zu reagieren, indem sie bei jedem Ladefortschritt benachrichtigt wird.
|
||||||
|
|
||||||
|
|
||||||
|
PgnProperty
|
||||||
|
|
||||||
|
|
||||||
|
Die Klasse PgnProperty modelliert eine einzelne PGN-Eigenschaft (Tag) und stellt Hilfsmethoden bereit, um sie aus einer Textzeile zu erkennen und zu extrahieren.
|
||||||
|
|
||||||
|
|
||||||
|
UnicodePrinter
|
||||||
|
|
||||||
|
|
||||||
|
Die Klasse UnicodePrinter druckt ein Schachbrett-Objekt (Board) als ASCII-Art mit Unicode-Schachsymbolen zeilenweise in die Konsole oder in einen beliebigen Ausgabestrom.
|
||||||
|
|
||||||
|
|
||||||
|
LargeFile
|
||||||
|
|
||||||
|
|
||||||
|
Die Klasse LargeFile erlaubt das effiziente und speicherschonende zeilenweise Lesen großer Textdateien oder Eingabeströme durch Bereitstellung eines einfachen Java-Iterators.
|
||||||
|
|
||||||
|
|
||||||
|
StringUtil
|
||||||
|
|
||||||
|
|
||||||
|
Die Klasse StringUtil stellt nützliche Methoden zur Verfügung, um Zeichenketten effizient zu analysieren, zu verändern und zu übersetzen – insbesondere bei der Verarbeitung von Schach-PGN-Daten.
|
||||||
|
|
||||||
|
|
||||||
|
XorShiftRandom
|
||||||
|
|
||||||
|
Die Klasse XorShiftRandom implementiert einen leistungsfähigen, einfachen Pseudozufallszahlengenerator auf Basis des Xorshift-Verfahrens, der deterministische long-Werte durch Bitoperationen erzeugt.
|
||||||
|
|
||||||
|
|
||||||
|
Bitboard
|
||||||
|
|
||||||
|
Die Klasse Bitboard stellt für jedes Schachfeld und diverse Feldergruppen (Reihen, Linien, Diagonalen) Bitmasken bereit, um Schachpositionen effizient mit Bitoperationen zu verarbeiten.
|
||||||
|
|
||||||
|
|
||||||
|
Board
|
||||||
|
|
||||||
|
Die Klasse Board modelliert ein vollständiges Schachbrett inklusive Spielregeln, Figurenpositionen, Zugverlauf und ermöglicht die Validierung, Durchführung und Rücknahme von Schachzügen.
|
||||||
|
|
||||||
|
|
||||||
|
BoardEvent
|
||||||
|
|
||||||
|
Das Interface BoardEvent definiert die Struktur für Ereignisse, die beim Ändern des Schachbretts ausgelöst und an Listener weitergegeben werden können.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BoardEventListener
|
||||||
|
|
||||||
|
Das Interface BoardEventListener erlaubt es, auf Ereignisse wie Züge oder Statusänderungen des Schachbretts zu reagieren, indem es über die Methode onEvent() benachrichtigt wird.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BoardEventType
|
||||||
|
|
||||||
|
Das Enum BoardEventType definiert die Arten von Ereignissen, die auf einem Schachbrett ausgelöst und über Event-Listener verarbeitet werden können – etwa beim Ziehen, Zurücknehmen oder Laden.
|
||||||
|
|
||||||
|
|
||||||
|
CastleRight
|
||||||
|
|
||||||
|
Das Enum CastleRight beschreibt, ob eine Seite im Schach kurz, lang, beides oder gar nicht rochieren darf.
|
||||||
|
|
||||||
|
|
||||||
|
Constants
|
||||||
|
|
||||||
|
Die Klasse Constants bündelt feste, zentrale Informationen und Züge wie die Start-FEN, Rochadepfade und Figur-Notation, um typische Schachsituationen schnell und konsistent abrufen zu können.
|
||||||
|
|
||||||
|
|
||||||
|
DiagonalA1H8
|
||||||
|
|
||||||
|
Die Enum DiagonalA1H8 listet alle rechtsschiefen (↘️) Diagonalen des Schachbretts als konstante Werte mit eindeutiger Namensgebung der Begrenzungsfelder auf.
|
||||||
|
|
||||||
|
|
||||||
|
DiagonalH1A8
|
||||||
|
|
||||||
|
Die Enum DiagonalH1A8 listet alle linksschiefen (↙️) Diagonalen des Schachbretts auf, wobei jede Diagonale durch ihre Randfelder eindeutig benannt ist.
|
||||||
|
|
||||||
|
|
||||||
|
File
|
||||||
|
|
||||||
|
Das Enum File beschreibt die Spalten (A–H) des Schachbretts samt zugehöriger Notation und ermöglicht deren einfache Nutzung in Code und Notationen.
|
||||||
|
|
||||||
|
|
||||||
|
MoveBackup
|
||||||
|
|
||||||
|
Die Klasse MoveBackup speichert alle relevanten Zustandsinformationen eines Schachbretts vor einem Zug, um diesen später vollständig rückgängig machen zu können.
|
||||||
|
|
||||||
|
|
||||||
|
Piece
|
||||||
|
|
||||||
|
Die Klasse Piece repräsentiert jede konkrete Schachfigur mit Farbe und Typ und bietet Methoden zur Erstellung und Notation dieser Figuren.
|
||||||
|
|
||||||
|
|
||||||
|
PieceType
|
||||||
|
|
||||||
|
PieceType beschreibt die Typen von Schachfiguren (z. B. Turm, König) und verknüpft sie mit ihrer algebraischen Notation für einfache Identifikation und Verarbeitung.
|
||||||
|
|
||||||
|
|
||||||
|
Rank
|
||||||
|
|
||||||
|
Rank beschreibt die horizontalen Reihen des Schachbretts und stellt deren numerische Notation zur Verfügung, um Positionen eindeutig identifizieren zu können.
|
||||||
|
|
||||||
|
|
||||||
|
Side
|
||||||
|
|
||||||
|
Side repräsentiert eine der beiden Spielerparteien im Schach – Weiß oder Schwarz – und ermöglicht den einfachen Wechsel der Seite mit der Methode flip().
|
||||||
|
|
||||||
|
|
||||||
|
Square
|
||||||
|
|
||||||
|
Square ist ein mächtiges enum, das jedes Schachfeld eindeutig repräsentiert und dabei zahlreiche Hilfsmethoden zur Brettlogik und Bitboard-Darstellung bereitstellt. Es ist eine der Grundpfeiler des gesamten Schachsystems.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
Quellen
|
||||||
|
|
||||||
|
Thomas Müller | 3021788
|
||||||
|
Timer https://chatgpt.com/c/6857ff1e-7ff4-8006-aba3-60d3a2dd59b4
|
||||||
|
|
||||||
|
Valentin Weller | 3019075
|
||||||
|
|
||||||
|
Junit: https://chatgpt.com/share/6859a713-4b98-8012-8cb2-a9f3c7fb37c8
|
||||||
|
QuickSave: https://chatgpt.com/share/6859a73f-e750-8012-a168-f9fa7c5487bd
|
||||||
|
PGNs: https://chatgpt.com/share/6859a8f1-d3c4-8012-98f4-6ae4b057be73
|
||||||
|
https://chatgpt.com/share/6859a95a-cca8-8012-bbbe-4e4b4517d5d9
|
||||||
|
|
||||||
|
Eröffnungserkennung: https://github.com/hell-sh/CompactChessOpenings/blob/master/src/sh/hell/compactchess/game/Opening.java
|
||||||
|
|
||||||
|
Quellen
|
||||||
|
|
||||||
|
Justin Muravjev 3014931
|
||||||
|
|
||||||
|
ChatGPT:
|
||||||
|
https://chatgpt.com/share/685a60b4-dad0-8012-86a8-ca9a7e6eb76b
|
||||||
|
|
||||||
|
|
@ -10,13 +10,12 @@
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<name>schach</name>
|
<name>schach</name>
|
||||||
<description>A simple schach.</description>
|
<description>A simple schach project</description>
|
||||||
<url>http://www.example.com</url>
|
<url>http://www.example.com</url>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.release>17</maven.compiler.release>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
|
|
@ -27,29 +26,31 @@
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- Schachlib (bhlangonijr) -->
|
<!-- Schachlib -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.bhlangonijr</groupId>
|
<groupId>com.github.bhlangonijr</groupId>
|
||||||
<artifactId>chesslib</artifactId>
|
<artifactId>chesslib</artifactId>
|
||||||
<version>1.3.4</version>
|
<version>1.3.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter</artifactId>
|
|
||||||
<version>5.10.2</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<!-- Mockito damit man Controller und Gui besser testen kann-->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>junit-jupiter</artifactId>
|
||||||
<version>5.11.0</version>
|
<version>5.10.2</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
<!-- Mockito -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<version>5.11.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
||||||
<pluginManagement>
|
<pluginManagement>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|
@ -89,14 +90,60 @@
|
||||||
<version>3.1.2</version>
|
<version>3.1.2</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</pluginManagement>
|
</pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<!-- Java Compiler Plugin -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.13.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>17</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<!-- PMD Plugin -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-pmd-plugin</artifactId>
|
||||||
|
<version>3.21.0</version>
|
||||||
|
<configuration>
|
||||||
|
<!-- Set to 17 until PMD supports 21 -->
|
||||||
|
<targetJdk>17</targetJdk>
|
||||||
|
<failOnViolation>false</failOnViolation>
|
||||||
|
<printFailingErrors>true</printFailingErrors>
|
||||||
|
<linkXRef>false</linkXRef>
|
||||||
|
<rulesets>
|
||||||
|
<ruleset>rulesets/java/quickstart.xml</ruleset>
|
||||||
|
<ruleset>rulesets/java/basic.xml</ruleset>
|
||||||
|
<ruleset>rulesets/java/braces.xml</ruleset>
|
||||||
|
<ruleset>rulesets/java/unusedcode.xml</ruleset>
|
||||||
|
<ruleset>rulesets/java/imports.xml</ruleset>
|
||||||
|
</rulesets>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<!-- Surefire Plugin for tests -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>3.3.0</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<reporting>
|
<reporting>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||||
|
<version>3.6.1</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</reporting>
|
</reporting>
|
||||||
</project>
|
</project>
|
||||||
|
|
@ -7,6 +7,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
|
||||||
import com.github.bhlangonijr.chesslib.game.Game;
|
import com.github.bhlangonijr.chesslib.game.Game;
|
||||||
|
|
||||||
|
|
@ -24,8 +25,10 @@ public class GameController {
|
||||||
GameEndCallback callback;
|
GameEndCallback callback;
|
||||||
|
|
||||||
private boolean gameOver = false;
|
private boolean gameOver = false;
|
||||||
private int selectedRow = -1, selectedCol = -1;
|
private int selectedRow = -1;
|
||||||
|
private int selectedCol = -1;
|
||||||
private List<int[]> highlightedFields = new ArrayList<>();
|
private List<int[]> highlightedFields = new ArrayList<>();
|
||||||
|
private boolean gameWasResignedOrDrawn = false;
|
||||||
private GameMode gameMode;
|
private GameMode gameMode;
|
||||||
|
|
||||||
public GameController(GameGui gui, ChessEngine engine, GameEndCallback callback, GameMode gameMode) {
|
public GameController(GameGui gui, ChessEngine engine, GameEndCallback callback, GameMode gameMode) {
|
||||||
|
|
@ -33,8 +36,9 @@ public class GameController {
|
||||||
this.gameMode = gameMode;
|
this.gameMode = gameMode;
|
||||||
if (gameMode != null) {
|
if (gameMode != null) {
|
||||||
engine.initTimers(gameMode.minutes, gameMode.incrementSeconds);
|
engine.initTimers(gameMode.minutes, gameMode.incrementSeconds);
|
||||||
time();
|
setupAndStartTimers();
|
||||||
}
|
}
|
||||||
|
addWindowCloseListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Für Creative/PGN-Mode (ohne Zeit)
|
// Für Creative/PGN-Mode (ohne Zeit)
|
||||||
|
|
@ -43,17 +47,36 @@ public class GameController {
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.gameMode = null;
|
this.gameMode = null;
|
||||||
|
addWindowCloseListener();
|
||||||
// KEINE Timer initialisieren
|
// KEINE Timer initialisieren
|
||||||
initListeners();
|
initListeners();
|
||||||
updateGuiBoard();
|
updateGuiBoard();
|
||||||
}
|
}
|
||||||
private void time() {
|
|
||||||
engine.getWhiteTimer().setOnTick(secs -> gui.updateWhiteTimerLabel(secs));
|
private void setupAndStartTimers() {
|
||||||
engine.getBlackTimer().setOnTick(secs -> gui.updateBlackTimerLabel(secs));
|
if (engine.getWhiteTimer() != null) {
|
||||||
engine.getWhiteTimer().setOnTimeout(() -> onTimeout("WHITE"));
|
engine.getWhiteTimer().setOnTick(secs -> gui.updateWhiteTimerLabel(secs));
|
||||||
engine.getBlackTimer().setOnTimeout(() -> onTimeout("BLACK"));
|
engine.getWhiteTimer().setOnTimeout(() -> onTimeout("WHITE"));
|
||||||
engine.getWhiteTimer().start();
|
engine.getWhiteTimer().stop(); // <-- WICHTIG!
|
||||||
|
}
|
||||||
|
if (engine.getBlackTimer() != null) {
|
||||||
|
engine.getBlackTimer().setOnTick(secs -> gui.updateBlackTimerLabel(secs));
|
||||||
|
engine.getBlackTimer().setOnTimeout(() -> onTimeout("BLACK"));
|
||||||
|
engine.getBlackTimer().stop(); // <-- WICHTIG!
|
||||||
|
}
|
||||||
|
// Timer-Labels initial setzen
|
||||||
|
if (engine.getWhiteTimer() != null) gui.updateWhiteTimerLabel(engine.getWhiteTimer().getSecondsLeft());
|
||||||
|
if (engine.getBlackTimer() != null) gui.updateBlackTimerLabel(engine.getBlackTimer().getSecondsLeft());
|
||||||
|
|
||||||
|
// Aktuellen Spieler-Timer starten:
|
||||||
|
if (engine.getCurrentPlayer().equals("WHITE")) {
|
||||||
|
engine.getWhiteTimer().start();
|
||||||
|
} else {
|
||||||
|
engine.getBlackTimer().start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private int flipRow(int row) {
|
private int flipRow(int row) {
|
||||||
return gui.isFlipped() ? 7 - row : row;
|
return gui.isFlipped() ? 7 - row : row;
|
||||||
}
|
}
|
||||||
|
|
@ -61,6 +84,20 @@ public class GameController {
|
||||||
return gui.isFlipped() ? 7 - col : col;
|
return gui.isFlipped() ? 7 - col : col;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addWindowCloseListener() {
|
||||||
|
if (gui.getFrame() != null) {
|
||||||
|
gui.getFrame().addWindowListener(new java.awt.event.WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(java.awt.event.WindowEvent e) {
|
||||||
|
if (!gameOver) {
|
||||||
|
engine.quicksave();
|
||||||
|
MainController.engineRAM = engine;
|
||||||
|
}
|
||||||
|
new MainController();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
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++) {
|
||||||
|
|
@ -138,14 +175,15 @@ public class GameController {
|
||||||
// --- AUFGEBEN-BUTTON ---
|
// --- AUFGEBEN-BUTTON ---
|
||||||
gui.getResignButton().addActionListener(e -> {
|
gui.getResignButton().addActionListener(e -> {
|
||||||
if (gameOver) return;
|
if (gameOver) return;
|
||||||
int answer = javax.swing.JOptionPane.showConfirmDialog(
|
int answer = JOptionPane.showConfirmDialog(
|
||||||
null,
|
null,
|
||||||
"Willst du wirklich aufgeben?",
|
"Willst du wirklich aufgeben?",
|
||||||
"Aufgeben",
|
"Aufgeben",
|
||||||
javax.swing.JOptionPane.YES_NO_OPTION
|
JOptionPane.YES_NO_OPTION
|
||||||
);
|
);
|
||||||
if (answer == javax.swing.JOptionPane.YES_OPTION) {
|
if (answer == JOptionPane.YES_OPTION) {
|
||||||
gameOver = true;
|
gameOver = true;
|
||||||
|
gameWasResignedOrDrawn = true; // <<<<<<
|
||||||
String winner = engine.getCurrentPlayer().equals("WHITE") ? "SCHWARZ" : "WEIß";
|
String winner = engine.getCurrentPlayer().equals("WHITE") ? "SCHWARZ" : "WEIß";
|
||||||
gui.displayMessage(winner + " gewinnt durch Aufgabe!");
|
gui.displayMessage(winner + " gewinnt durch Aufgabe!");
|
||||||
if (engine.getWhiteTimer() != null) engine.getWhiteTimer().stop();
|
if (engine.getWhiteTimer() != null) engine.getWhiteTimer().stop();
|
||||||
|
|
@ -156,20 +194,22 @@ public class GameController {
|
||||||
|
|
||||||
gui.getDrawButton().addActionListener(e -> {
|
gui.getDrawButton().addActionListener(e -> {
|
||||||
if (gameOver) return;
|
if (gameOver) return;
|
||||||
int answer = javax.swing.JOptionPane.showConfirmDialog(
|
int answer = JOptionPane.showConfirmDialog(
|
||||||
null,
|
null,
|
||||||
"Remis anbieten? (Das Spiel endet sofort unentschieden)",
|
"Remis anbieten? (Das Spiel endet sofort unentschieden)",
|
||||||
"Remis",
|
"Remis",
|
||||||
javax.swing.JOptionPane.YES_NO_OPTION
|
JOptionPane.YES_NO_OPTION
|
||||||
);
|
);
|
||||||
if (answer == javax.swing.JOptionPane.YES_OPTION) {
|
if (answer == JOptionPane.YES_OPTION) {
|
||||||
gameOver = true;
|
gameOver = true;
|
||||||
|
gameWasResignedOrDrawn = true; // <<<<<<
|
||||||
gui.displayMessage("Remis! (durch Einigung)");
|
gui.displayMessage("Remis! (durch Einigung)");
|
||||||
if (engine.getWhiteTimer() != null) engine.getWhiteTimer().stop();
|
if (engine.getWhiteTimer() != null) engine.getWhiteTimer().stop();
|
||||||
if (engine.getBlackTimer() != null) engine.getBlackTimer().stop();
|
if (engine.getBlackTimer() != null) engine.getBlackTimer().stop();
|
||||||
askForRestart();
|
askForRestart();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
gui.getUndoButton().addActionListener(e -> {
|
gui.getUndoButton().addActionListener(e -> {
|
||||||
// Wer ist am Zug? (Das ist der, der gefragt wird)
|
// Wer ist am Zug? (Das ist der, der gefragt wird)
|
||||||
|
|
@ -346,7 +386,7 @@ public class GameController {
|
||||||
return "" + file + rank;
|
return "" + file + rank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Timeout-Methode
|
// Timeout-Methode
|
||||||
private void onTimeout(String color) {
|
private void onTimeout(String color) {
|
||||||
if (gameOver) return; // Doppelt hält besser
|
if (gameOver) return; // Doppelt hält besser
|
||||||
|
|
@ -359,19 +399,31 @@ public class GameController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void askForRestart() {
|
private void askForRestart() {
|
||||||
int answer = javax.swing.JOptionPane.showConfirmDialog(
|
int answer = JOptionPane.showConfirmDialog(
|
||||||
null,
|
null,
|
||||||
"Neue Partie starten?",
|
"Neue Partie starten?",
|
||||||
"Spiel beendet",
|
"Spiel beendet",
|
||||||
javax.swing.JOptionPane.YES_NO_OPTION
|
JOptionPane.YES_NO_OPTION
|
||||||
);
|
);
|
||||||
javax.swing.SwingUtilities.getWindowAncestor(gui.getField(0, 0)).dispose();
|
javax.swing.SwingUtilities.getWindowAncestor(gui.getField(0, 0)).dispose();
|
||||||
if (answer == javax.swing.JOptionPane.YES_OPTION) {
|
if (answer == JOptionPane.YES_OPTION) {
|
||||||
|
engine.clearQuicksave();
|
||||||
|
MainController.engineRAM = null;
|
||||||
callback.onNewGameRequested();
|
callback.onNewGameRequested();
|
||||||
} else {
|
} else {
|
||||||
|
// HIER: QuickSave **NUR** falls das Spiel NICHT durch Aufgabe/Remis/Patt beendet wurde!
|
||||||
|
if (!gameWasResignedOrDrawn) {
|
||||||
|
engine.quicksave();
|
||||||
|
MainController.engineRAM = engine;
|
||||||
|
} else {
|
||||||
|
engine.clearQuicksave();
|
||||||
|
MainController.engineRAM = null;
|
||||||
|
}
|
||||||
callback.onReturnToMenu();
|
callback.onReturnToMenu();
|
||||||
}
|
}
|
||||||
|
gameWasResignedOrDrawn = false; // Reset für nächstes Spiel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void resetFieldBackground(int row, int col) {
|
private void resetFieldBackground(int row, int col) {
|
||||||
Color LIGHT = new Color(0xe0e1dd);
|
Color LIGHT = new Color(0xe0e1dd);
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import de.hs_mannheim.informatik.chess.model.GameMode;
|
||||||
|
|
||||||
public class MainController {
|
public class MainController {
|
||||||
private MainGui mainGui;
|
private MainGui mainGui;
|
||||||
|
static ChessEngine engineRAM = null;
|
||||||
|
|
||||||
public MainController() {
|
public MainController() {
|
||||||
mainGui = new MainGui();
|
mainGui = new MainGui();
|
||||||
|
|
@ -30,20 +31,54 @@ public class MainController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startNormalMode() {
|
private void startNormalMode() {
|
||||||
|
// Prüfe, ob es im RAM ein Quicksave gibt:
|
||||||
GameMode mode = GameModeSelector.selectGameMode();
|
if (engineRAM != null && engineRAM.quickload()) {
|
||||||
|
int choice = JOptionPane.showConfirmDialog(
|
||||||
|
null,
|
||||||
|
"Letzte Partie fortsetzen?",
|
||||||
|
"Quicksave gefunden",
|
||||||
|
JOptionPane.YES_NO_OPTION
|
||||||
|
);
|
||||||
|
if (choice == JOptionPane.YES_OPTION) {
|
||||||
|
GameGui gameGui = new GameGui();
|
||||||
|
GameEndCallback callback = new GameEndCallback() {
|
||||||
|
public void onNewGameRequested() { startNormalMode(); }
|
||||||
|
public void onReturnToMenu() { new MainController(); }
|
||||||
|
};
|
||||||
|
new GameController(gameGui, engineRAM, callback); // KEIN initTimers, KEIN neuer Engine!
|
||||||
|
// --- Timerlabels aktualisieren
|
||||||
|
gameGui.updateWhiteTimerLabel(engineRAM.getWhiteTimer().getSecondsLeft());
|
||||||
|
gameGui.updateBlackTimerLabel(engineRAM.getBlackTimer().getSecondsLeft());
|
||||||
|
// --- Timer des aktuellen Spielers starten
|
||||||
|
if (engineRAM.getCurrentPlayer().equals("WHITE")) {
|
||||||
|
engineRAM.getWhiteTimer().start();
|
||||||
|
} else {
|
||||||
|
engineRAM.getBlackTimer().start();
|
||||||
|
}
|
||||||
|
mainGui.close();
|
||||||
|
return; // Fertig!
|
||||||
|
} else {
|
||||||
|
engineRAM.clearQuicksave();
|
||||||
|
engineRAM = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neues Spiel normal starten:
|
||||||
|
GameMode mode = GameModeSelector.selectGameMode();
|
||||||
|
if (mode == null) return;
|
||||||
mainGui.close();
|
mainGui.close();
|
||||||
GameGui gameGui = new GameGui();
|
|
||||||
ChessEngine engine = new ChessEngine(mode);
|
ChessEngine engine = new ChessEngine(mode);
|
||||||
|
engineRAM = engine; // Für spätere Quicksaves merken!
|
||||||
|
GameGui gameGui = new GameGui();
|
||||||
GameEndCallback callback = new GameEndCallback() {
|
GameEndCallback callback = new GameEndCallback() {
|
||||||
public void onNewGameRequested() {
|
public void onNewGameRequested() {
|
||||||
startNormalMode();
|
startNormalMode();
|
||||||
}
|
}
|
||||||
public void onReturnToMenu() {
|
public void onReturnToMenu() {
|
||||||
new MainController();
|
new MainController();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
new GameController(gameGui, engine, callback,mode);
|
new GameController(gameGui, engine, callback, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startCreativeMode() {
|
private void startCreativeMode() {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package de.hs_mannheim.informatik.chess.model;
|
package de.hs_mannheim.informatik.chess.model;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.ConsoleHandler;
|
import java.util.logging.ConsoleHandler;
|
||||||
|
|
@ -18,422 +20,505 @@ import com.github.bhlangonijr.chesslib.move.Move;
|
||||||
import com.github.bhlangonijr.chesslib.pgn.PgnHolder;
|
import com.github.bhlangonijr.chesslib.pgn.PgnHolder;
|
||||||
import com.github.bhlangonijr.chesslib.game.*;
|
import com.github.bhlangonijr.chesslib.game.*;
|
||||||
import com.github.bhlangonijr.chesslib.move.MoveList;
|
import com.github.bhlangonijr.chesslib.move.MoveList;
|
||||||
import java.time.LocalDate;
|
|
||||||
import com.github.bhlangonijr.chesslib.Side;
|
import com.github.bhlangonijr.chesslib.Side;
|
||||||
|
|
||||||
|
|
||||||
public class ChessEngine {
|
public class ChessEngine {
|
||||||
private Board board;
|
private Board board;
|
||||||
private List<Move> moves = new ArrayList<>();
|
private List<Move> moves = new ArrayList<>();
|
||||||
private String initialFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
private String initialFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||||
private static final Logger logger = Logger.getLogger(ChessEngine.class.getName());
|
private static final Logger logger = Logger.getLogger(ChessEngine.class.getName());
|
||||||
|
private int quicksaveWhiteTimeLeft = -1;
|
||||||
|
private int quicksaveBlackTimeLeft = -1;
|
||||||
private int currentMoveIndex = 0;
|
private int currentMoveIndex = 0;
|
||||||
private Timer whiteTimer;
|
private Timer whiteTimer;
|
||||||
private Timer blackTimer;
|
private Timer blackTimer;
|
||||||
private final GameMode mode;
|
private final GameMode mode;
|
||||||
|
private String quicksaveFen = null;
|
||||||
|
private List<Move> quicksaveMoves = null;
|
||||||
|
private int quicksaveMoveIndex = 0;
|
||||||
private Opening detectedOpening = null;
|
private Opening detectedOpening = null;
|
||||||
|
|
||||||
public ChessEngine() {
|
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();
|
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);
|
|
||||||
|
|
||||||
// Replay? Dann abschneiden
|
public ChessEngine(GameMode mode) {
|
||||||
if (currentMoveIndex < moves.size()) {
|
this.mode = mode;
|
||||||
logger.info("Replay-Modus: Züge nach " + currentMoveIndex + " werden entfernt.");
|
whiteTimer = new Timer(mode.minutes, mode.seconds);
|
||||||
moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
|
blackTimer = new Timer(mode.minutes, mode.seconds);
|
||||||
}
|
logging();
|
||||||
moves.add(libMove);
|
board = new Board();
|
||||||
currentMoveIndex++;
|
}
|
||||||
logger.info("Zug erfolgreich durchgeführt: " + libMove);
|
|
||||||
|
|
||||||
// Opening-Erkennung nach jedem erfolgreichen Zug
|
public boolean move(MoveDTO move) {
|
||||||
String playedMovesUci = movesToUciString(moves);
|
String from = "" + (char) ('A' + move.getFromCol()) + (8 - move.getFromRow());
|
||||||
detectedOpening = Opening.detect(playedMovesUci);
|
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);
|
||||||
|
|
||||||
if (detectedOpening != null) {
|
if (currentMoveIndex < moves.size()) {
|
||||||
logger.info("Aktuelles Opening erkannt: " + detectedOpening.getEco() + " - " + detectedOpening.getName());
|
if (logger.isLoggable(Level.INFO)) {
|
||||||
// Optional: Speichere das Opening in ein Feld, falls benötigt
|
logger.info("Replay-Modus: Züge nach " + currentMoveIndex + " werden entfernt.");
|
||||||
}
|
}
|
||||||
return true;
|
moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
|
||||||
}
|
}
|
||||||
logger.warning("Ungültiger Zug: " + libMove);
|
moves.add(libMove);
|
||||||
return false;
|
currentMoveIndex++;
|
||||||
}
|
if (logger.isLoggable(Level.INFO)) {
|
||||||
|
logger.info("Zug erfolgreich durchgeführt: " + libMove);
|
||||||
|
}
|
||||||
|
|
||||||
public String getOpeningName() {
|
String playedMovesUci = movesToUciString(moves);
|
||||||
if (detectedOpening != null) {
|
detectedOpening = Opening.detect(playedMovesUci);
|
||||||
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 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());
|
|
||||||
|
|
||||||
// Die Farbe bestimmen!
|
if (detectedOpening != null && logger.isLoggable(Level.INFO)) {
|
||||||
boolean isWhite = (8 - move.getFromRow()) < (8 - move.getToRow());
|
logger.info("Aktuelles Opening erkannt: " + detectedOpening.getEco() + " - " + detectedOpening.getName());
|
||||||
Piece promotion;
|
}
|
||||||
switch (promotionPiece) {
|
return true;
|
||||||
case "ROOK": promotion = isWhite ? Piece.WHITE_ROOK : Piece.BLACK_ROOK; break;
|
}
|
||||||
case "KNIGHT": promotion = isWhite ? Piece.WHITE_KNIGHT : Piece.BLACK_KNIGHT; break;
|
if (logger.isLoggable(Level.WARNING)) {
|
||||||
case "BISHOP": promotion = isWhite ? Piece.WHITE_BISHOP : Piece.BLACK_BISHOP; break;
|
logger.warning("Ungültiger Zug: " + libMove);
|
||||||
default: promotion = isWhite ? Piece.WHITE_QUEEN : Piece.BLACK_QUEEN;
|
}
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Move libMove = new Move(Square.valueOf(from), Square.valueOf(to), promotion);
|
public String getOpeningName() {
|
||||||
|
if (detectedOpening != null) {
|
||||||
|
return detectedOpening.getEco() + " - " + detectedOpening.getName();
|
||||||
|
} else {
|
||||||
|
return "unbekannt";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (board.legalMoves().contains(libMove)) {
|
private String movesToUciString(List<Move> moves) {
|
||||||
board.doMove(libMove);
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (Move m : moves) {
|
||||||
|
sb.append(m.toString()).append(" ");
|
||||||
|
}
|
||||||
|
return sb.toString().trim();
|
||||||
|
}
|
||||||
|
|
||||||
if (currentMoveIndex < moves.size()) {
|
public List<MoveDTO> getLegalDestinations(String from) {
|
||||||
moves = new ArrayList<>(moves.subList(0, currentMoveIndex));
|
if (logger.isLoggable(Level.INFO)) {
|
||||||
}
|
logger.info("Hole legale Züge von: " + from);
|
||||||
moves.add(libMove);
|
}
|
||||||
currentMoveIndex++;
|
List<MoveDTO> destinations = new ArrayList<>();
|
||||||
logger.info("Promotionszug durchgeführt: " + libMove);
|
try {
|
||||||
return true;
|
Square fromSq = Square.valueOf(from.toUpperCase(java.util.Locale.ROOT));
|
||||||
}
|
for (Move move : board.legalMoves()) {
|
||||||
logger.warning("Ungültiger Promotionszug: " + libMove);
|
if (move.getFrom().equals(fromSq)) {
|
||||||
return false;
|
int fromRow = 8 - fromSq.getRank().ordinal() - 1;
|
||||||
}
|
int fromCol = fromSq.getFile().ordinal();
|
||||||
|
int toRow = 8 - move.getTo().getRank().ordinal() - 1;
|
||||||
public BoardDTO getBoardAsDTO() {
|
int toCol = move.getTo().getFile().ordinal();
|
||||||
logger.info("Erstelle DTO-Abbild des Boards");
|
destinations.add(new MoveDTO(fromRow, fromCol, toRow, toCol));
|
||||||
PieceDTO[][] dtoBoard = new PieceDTO[8][8];
|
}
|
||||||
for (int rank = 8; rank >= 1; rank--) {
|
}
|
||||||
for (int file = 0; file < 8; file++) {
|
if (logger.isLoggable(Level.INFO)) {
|
||||||
Square square = Square.valueOf("" + (char)('A' + file) + rank);
|
logger.info("Es wurden " + destinations.size() + " Ziele gefunden.");
|
||||||
Piece piece = board.getPiece(square);
|
}
|
||||||
dtoBoard[8-rank][file] = convertPieceToDTO(piece);
|
} catch (Exception e) {
|
||||||
}
|
if (logger.isLoggable(Level.SEVERE)) {
|
||||||
}
|
logger.severe("Fehler beim Holen der legalen Ziele: " + e.getMessage());
|
||||||
return new BoardDTO(dtoBoard);
|
}
|
||||||
}
|
}
|
||||||
|
return destinations;
|
||||||
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 List<String> getMoveListStringsGrouped() {
|
||||||
public boolean isMated() {
|
if (logger.isLoggable(Level.INFO)) {
|
||||||
boolean mated = board.isMated();
|
logger.info("Gruppiere Züge für Anzeige.");
|
||||||
logger.info("isMated() = " + mated);
|
}
|
||||||
return mated;
|
List<String> result = new ArrayList<>();
|
||||||
}
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < moves.size(); i++) {
|
||||||
public boolean isStalemate() {
|
if (i % 2 == 0) {
|
||||||
boolean stale = board.isStaleMate();
|
sb.append((i / 2 + 1)).append(". ");
|
||||||
logger.info("isStalemate() = " + stale);
|
}
|
||||||
return stale;
|
sb.append(moves.get(i).toString()).append(" ");
|
||||||
}
|
if (i % 2 == 1 || i == moves.size() - 1) {
|
||||||
|
result.add(sb.toString().trim());
|
||||||
public boolean isDraw() {
|
sb = new StringBuilder();
|
||||||
boolean draw = board.isDraw();
|
}
|
||||||
logger.info("isDraw() = " + draw);
|
}
|
||||||
return draw;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|
||||||
|
|
||||||
PgnHolder pgnHolder = new PgnHolder(path);
|
public void quicksave() {
|
||||||
try {
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.loadPgn();
|
pgnHolder.loadPgn();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
List<Game> games = pgnHolder.getGames();
|
return pgnHolder.getGames();
|
||||||
return games;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initTimers(int min, int sec) {
|
|
||||||
whiteTimer = new Timer(min, sec);
|
|
||||||
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());
|
|
||||||
|
|
||||||
// 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");
|
|
||||||
|
|
||||||
// Züge als SAN holen
|
|
||||||
StringBuilder moves = new StringBuilder();
|
|
||||||
String[] sanArray = game.getHalfMoves().toSanArray();
|
|
||||||
|
|
||||||
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!
|
|
||||||
|
|
||||||
String file = header + moves.toString();
|
|
||||||
|
|
||||||
// Datei schreiben
|
|
||||||
try {
|
|
||||||
Files.writeString(Path.of(path, dateiname), file, StandardCharsets.UTF_8);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hilfsfunktion für Null-Sicherheit
|
|
||||||
private String safe(String s) {
|
|
||||||
return s == null ? "?" : s;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
// Runde anlegen
|
|
||||||
Round round = new Round(event);
|
|
||||||
round.setNumber(1);
|
|
||||||
|
|
||||||
// Spiel initialisieren
|
|
||||||
Game game = new Game("1", round); // "1" ist die Game-ID
|
|
||||||
|
|
||||||
// Spieler setzen (deine MyPlayer-Klasse)
|
|
||||||
game.setWhitePlayer(new MyPlayer("White"));
|
|
||||||
game.setBlackPlayer(new MyPlayer("Black"));
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Züge übernehmen
|
|
||||||
MoveList moveList = new MoveList();
|
|
||||||
for (Move move : moves) {
|
|
||||||
moveList.add(move);
|
|
||||||
}
|
|
||||||
game.setHalfMoves(moveList);
|
|
||||||
|
|
||||||
// Position auf aktuellen Zug setzen (letzter gespielter Halbzug)
|
|
||||||
if (currentMoveIndex > 0 && currentMoveIndex <= moveList.size()) {
|
|
||||||
game.setPosition(currentMoveIndex - 1);
|
|
||||||
} else {
|
|
||||||
game.setPosition(moveList.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FEN setzen: JETZT das aktuelle Board-FEN verwenden!
|
|
||||||
game.setBoard(new Board());
|
|
||||||
game.getBoard().loadFromFen(board.getFen());
|
|
||||||
|
|
||||||
return game;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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());
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
StringBuilder movesSb = new StringBuilder();
|
||||||
|
String[] sanArray = game.getHalfMoves().toSanArray();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
String file = header + movesSb.toString();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.writeString(Path.of(path, dateiname), file, StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String safe(String s) {
|
||||||
|
return s == null ? "?" : s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Game getCurrentGame() {
|
||||||
|
return getCurrentGame(this.board, this.moves, this.currentMoveIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
Round round = new Round(event);
|
||||||
|
round.setNumber(1);
|
||||||
|
|
||||||
|
Game game = new Game("1", round);
|
||||||
|
|
||||||
|
game.setWhitePlayer(new MyPlayer("White"));
|
||||||
|
game.setBlackPlayer(new MyPlayer("Black"));
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
MoveList moveList = new MoveList();
|
||||||
|
for (Move move : moves) {
|
||||||
|
moveList.add(move);
|
||||||
|
}
|
||||||
|
game.setHalfMoves(moveList);
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
return game;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void undoLastMove() {
|
||||||
|
if (currentMoveIndex > 0 && !moves.isEmpty()) {
|
||||||
|
board.undoMove();
|
||||||
|
moves.remove(currentMoveIndex - 1);
|
||||||
|
currentMoveIndex--;
|
||||||
|
|
||||||
|
String playedMovesUci = movesToUciString(moves.subList(0, currentMoveIndex));
|
||||||
|
detectedOpening = Opening.detect(playedMovesUci);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadMoves(List<Move> moveList) {
|
||||||
|
board = new Board();
|
||||||
|
moves.clear();
|
||||||
|
currentMoveIndex = 0;
|
||||||
|
|
||||||
|
for (Move move : moveList) {
|
||||||
|
board.doMove(move);
|
||||||
|
moves.add(move);
|
||||||
|
currentMoveIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Timer getWhiteTimer() {
|
||||||
|
return whiteTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Timer getBlackTimer() {
|
||||||
|
return blackTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameMode getGameMode() {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,9 @@ public class Timer {
|
||||||
return secondsLeft;
|
return secondsLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSecondsLeft(int secondsLeft) {
|
||||||
|
this.secondsLeft = secondsLeft;
|
||||||
|
}
|
||||||
public void addSeconds(int seconds) {
|
public void addSeconds(int seconds) {
|
||||||
this.secondsLeft += seconds;
|
this.secondsLeft += seconds;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import de.hs_mannheim.informatik.chess.model.BoardDTO;
|
||||||
import de.hs_mannheim.informatik.chess.model.PieceDTO;
|
import de.hs_mannheim.informatik.chess.model.PieceDTO;
|
||||||
|
|
||||||
public class GameGui {
|
public class GameGui {
|
||||||
|
JFrame frame;
|
||||||
|
|
||||||
private JLabel[][] fields = new JLabel[8][8];
|
private JLabel[][] fields = new JLabel[8][8];
|
||||||
private JButton flipBoardButton;
|
private JButton flipBoardButton;
|
||||||
|
|
@ -43,7 +44,6 @@ public class GameGui {
|
||||||
|
|
||||||
private JButton resignButton;
|
private JButton resignButton;
|
||||||
private JButton drawButton;
|
private JButton drawButton;
|
||||||
private JButton quickSaveButton;
|
|
||||||
private JButton undoButton;
|
private JButton undoButton;
|
||||||
|
|
||||||
Color LIGHT = new Color(0xe0e1dd);
|
Color LIGHT = new Color(0xe0e1dd);
|
||||||
|
|
@ -59,13 +59,14 @@ public class GameGui {
|
||||||
|
|
||||||
|
|
||||||
public JFrame mainFrame() {
|
public JFrame mainFrame() {
|
||||||
JFrame frame = new JFrame();
|
frame = new JFrame();
|
||||||
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||||
frame.setUndecorated(false);
|
frame.setUndecorated(false);
|
||||||
frame.setLocationRelativeTo(null);
|
frame.setLocationRelativeTo(null);
|
||||||
frame.add(mainPanel());
|
frame.add(mainPanel());
|
||||||
|
|
||||||
|
|
||||||
frame.setDefaultCloseOperation(2);
|
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
@ -378,4 +379,8 @@ public class GameGui {
|
||||||
JOptionPane.showMessageDialog(null, msg);
|
JOptionPane.showMessageDialog(null, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JFrame getFrame() {
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<groupId>de.hs-mannheim.informatik.schach</groupId>
|
|
||||||
<artifactId>schach</artifactId>
|
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
|
||||||
|
|
||||||
<name>schach</name>
|
|
||||||
<description>A simple schach.</description>
|
|
||||||
<url>http://www.example.com</url>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<repositories>
|
|
||||||
<repository>
|
|
||||||
<id>jitpack.io</id>
|
|
||||||
<url>https://jitpack.io</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<!-- Schachlib (bhlangonijr) -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.bhlangonijr</groupId>
|
|
||||||
<artifactId>chesslib</artifactId>
|
|
||||||
<version>1.3.4</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter</artifactId>
|
|
||||||
<version>5.10.2</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<!-- Mockito damit man Controller und Gui besser testen kann-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-core</artifactId>
|
|
||||||
<version>5.11.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</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>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<reporting>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</reporting>
|
|
||||||
</project>
|
|
||||||
Loading…
Reference in New Issue