package game;
import game.GameSettings.GameType;
import gameTree.NextMove;
import gui.Checkerboard;
import gui.Gui;
import gui.StartWindow;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import util.ChessfigureConstants;
import camera.ImageLoader;
import components.Field;
import components.Figure;
/**
* Startet das Spiel
*
* @author Florian Franke 31.10.2012
*
*/
public class Chess
{
/**
* Objekt des GameCoordinators
*/
private GameCoordinator gameCoordinator = null;
/**
* Liste an Zuegen, falls ein Spiel simuliert werden soll.
*/
private List<Move> simulatedMoves = new ArrayList<Move>();
/**
* Objekt zur Kommunikation mit der Kamera
*/
private ImageLoader im = null;
/**
* Leerer Konstruktor
*/
public Chess()
{
// Kamera benötigt?
if (GameSettings.currentGameType == GameType.PlayerVsComputer ||
GameSettings.currentGameType == GameType.PlayerVsSimulatedComputer) {
this.im = new ImageLoader();
// Winkel setzen
this.im.setAngle(im.calcAngle());
this.im.calcOffset();
}
}
/**
* Konstruktor, mit Zuegen fuer ein simuliertes Spiel
* @param moves Zuege des simulierten Spiels
*/
public Chess(List<Move> moves)
{
this();
this.simulatedMoves = moves;
}
/**
* Konstruktor, mit dem ein Spielfeld vorgegeben wird, von wo aus weitergespielt wird.
* @param arbitraryField HashMap bestehend aus dem Feld und dem Byte-Wert der Figur.
*/
public Chess(HashMap<Integer, Byte> arbitraryField)
{
this();
// Bestückt das Feld nach Benutzereingabe
Field.getInstance().equipArbitraryField(arbitraryField);
}
/**
* Startet das Spiel
*/
public void startGame()
{
// GUI initialisieren, Start-Button wird angezeigt
Gui gui = Gui.getInstance();
// Warten, bis Benutzer das Spiel gestartet hat
while (!gui.isStartPressed()) {
try {
Thread.sleep(333);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
// Schach-Koordinator holen
this.gameCoordinator = GameCoordinator.getInstance(true);
// GUI uebergeben
this.gameCoordinator.setGui(gui);
int moveCounter = 0;
byte currentPlayer = ChessfigureConstants.WHITE;
while (!this.gameCoordinator.isEndOfGame()) {
if (moveCounter %2 == 0)
currentPlayer = ChessfigureConstants.WHITE;
else
currentPlayer = ChessfigureConstants.BLACK;
Move move = null;
if (currentPlayer == ChessfigureConstants.WHITE) {
if (GameSettings.currentGameType == GameType.PlayerVsComputer ||
GameSettings.currentGameType == GameType.PlayerVsSimulatedComputer) {
// Menschlicher Spieler
move = this.getMoveFromCamera(currentPlayer);
if (move == null)
move = convertFieldnumbersToMoves(currentPlayer, Gui.getInstance().getCheckerboard().manualMove());
} else if (GameSettings.currentGameType == GameType.Simulated) {
// Simulierten Zug holen
move = this.getSimulatedMove(moveCounter, currentPlayer);
} else if (GameSettings.currentGameType == GameType.PlayerWithoutCameraVsComputer) {
// Zug soll manuell vom Spieler eingegeben werden
move = additionalInformationForMove(currentPlayer, convertFieldnumbersToMoves(currentPlayer, Gui.getInstance().getCheckerboard().manualMove()));
}
} else if (currentPlayer == ChessfigureConstants.BLACK) {
if (GameSettings.currentGameType == GameType.PlayerVsComputer ||
GameSettings.currentGameType == GameType.PlayerWithoutCameraVsComputer) {
// KI
NextMove moveTo = new NextMove();
move = moveTo.getNext(Field.getInstance(), currentPlayer);
} else if (GameSettings.currentGameType == GameType.Simulated ||
GameSettings.currentGameType == GameType.SimulatedWithRobot) {
// Simulierter Zug holen
move = this.getSimulatedMove(moveCounter, currentPlayer);
}
} else {
System.out.println("Hier läuft was falsch! (Chess.java)");
}
moveCounter++;
// Aktuellen Spieler setzen
move.setPlayerColor(currentPlayer);
// Ende des simulierten Spiels ermitteln
if ((GameSettings.currentGameType == GameType.Simulated ||
GameSettings.currentGameType == GameType.SimulatedWithRobot ||
GameSettings.currentGameType == GameType.PlayerVsSimulatedComputer)
&&
(moveCounter == this.simulatedMoves.size())
) {
move.setCheckMate(true);
} else if (move.isCheckMate()) {
Gui.getInstance().getCheckerboard().setCheckerboardInformation(move);
}
// Züge ausführen
this.execMove(currentPlayer, move);
}
// Aktuelles Datum
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy");
// Ergebnis bestimmen
String res = "";
if (moveCounter % 2 == 0) {
// Schwarz hat gewonnen, da gerade Anzahl an Zügen
res = "0-1";
} else {
res = "1-0";
}
// Exportieren
System.out.println(Exporter.exportMovesToPGN(
"Schachspiel gegen den Legoroboter", // Name des Spiels
"Braunschweig", // Ort
sdf.format(new Date()), // Datum
StartWindow.getInstance().getUsername(), // Spieler weiss
"Computer", // Spieler schwarz
res, // Ergebnis
this.gameCoordinator.getAllMoves()) // Zuege
);
}
/**
* Führt einen Zug aus
* @param player Spieler, der den Zug ausführt
* @param move Der auszuführende Zug
*/
public void execMove(byte player, Move move)
{
try {
Thread.sleep(GameSettings.timeBetweenMoves);
} catch (InterruptedException e) {
}
if (!move.isCheckMate()) {
// Wenn Zug gueltig, ausfuehren
if (this.gameCoordinator.receiveMove(move, GameSettings.checkRules)) {
// Zug ausfuehren
this.gameCoordinator.execMove();
} else {
this.execMove(player, convertFieldnumbersToMoves(player, Checkerboard.getInstance().manualMove()));
}
} else {
this.gameCoordinator.setEndOfGame(true);
}
}
/**
* Ermittelt den vom Spieler durchgeführten Zug.
* @param currentPlayer Der aktuelle Spieler
* @return Der durchgeführte Zug
*/
public Move getMoveFromCamera(byte currentPlayer)
{
Move move = null;
try {
if (this.im == null) {
throw new Exception("Kein Kamera-Objekt gefunden");
}
// erste Vergleichsfoto
Gui.getInstance().showWaitingMessage("Achtung", "Bitte Spielfeld freihalten und bestätigen.");
this.im.takePhoto1();
System.out.println("Foto1 taken");
// Warte auf Bestätigung vom Benutzer
Gui.getInstance().showWaitingMessage("Weiß ist am Zug", "Bitte versetzen Sie eine Schachfigur " +
"und bestätigen Sie Ihren Zug.");
// 2te Vergleichsfoto nehmen
this.im.takePhoto2();
System.out.println("Foto2 taken");
// Veraenderte Positionen holen
List<Integer> listOfChangedPositions = this.im.getChangedPositions();
// Konnte Kamera Züge ermitteln?
System.out.println("Anzahl an veränderten Feldern: "+ listOfChangedPositions.size());
if (listOfChangedPositions.size() == 0) {
// Manuelles Einlesen der Züge durch die GUI
move = convertFieldnumbersToMoves(currentPlayer, Checkerboard.getInstance().manualMove());
} else {
move = convertFieldnumbersToMoves(currentPlayer, listOfChangedPositions);
}
} catch (Exception e) {
System.out.println(e.getStackTrace()[0].getMethodName() + "(" + e.getStackTrace()[0].getClassName() + "): " + e.getMessage());
}
return move;
}
/**
* Holt einen simulierten Zug
* @param moveCounter Nummer des aktuellen Zugs
* @param currentPlayer Spieler
* @return Der simulierte Zug
*/
public Move getSimulatedMove(int moveCounter, byte currentPlayer)
{
Move newMove = this.simulatedMoves.get(moveCounter);
newMove = additionalInformationForMove(currentPlayer, newMove);
return newMove;
}
/**
* Erstellt aus der uebergebenen Spielerfarbe und den eingelesenen Feldnummern die Zuege.
* Die Feldnummern werden entweder ueber die Kamera oder die GUI eingelesen.
* @param colorOfPlayer Farbe des Spielers
* @param fieldnumbers Die zwei oder vier betroffenen Feldnummern
* @return Move-Objekt
*/
public static Move convertFieldnumbersToMoves(byte colorOfPlayer, List<Integer> fieldnumbers)
{
Move move = null;
Field f = Field.getInstance();
if (fieldnumbers.size() == 2) {
// Normaler Zug
int fieldFrom = -1,
fieldTo = -1;
// Welches ist das From- und To-Feld?
if ( f.isFigureOnField(fieldnumbers.get(0)) && // Figur auf fieldnumbers[0] vorhanden
f.getFigureAt(fieldnumbers.get(0)).getColor() == colorOfPlayer // eigene Figur auf fieldnumbers[0]
) {
fieldFrom = fieldnumbers.get(0);
fieldTo = fieldnumbers.get(1);
} else if (f.isFigureOnField(fieldnumbers.get(1)) && // Figur auf fieldnumbers[1] vorhanden
f.getFigureAt(fieldnumbers.get(1)).getColor() == colorOfPlayer // eigene Figur auf fieldnumbers[1]
) {
fieldFrom = fieldnumbers.get(1);
fieldTo = fieldnumbers.get(0);
} else {
System.out.println("Felder konnten nicht zugeordnet werden!");
}
move = new Move(colorOfPlayer, fieldFrom, fieldTo);
// Informationen hinzufügen (geschmissen?)
move = additionalInformationForMove(colorOfPlayer, move);
} else if (fieldnumbers.size() == 4) {
// Rochade-Zug
// Darf der Spieler noch eine Rochade spielen?
if ( (colorOfPlayer == ChessfigureConstants.WHITE && f.isCastlingWhitePossible()) ||
(colorOfPlayer == ChessfigureConstants.BLACK && f.isCastlingBlackPossible())
) {
// Spieler spielt Rochade
if (isKingSideCastling(colorOfPlayer, fieldnumbers)) {
// Kurzen Rochade-Zug erstellen und der Liste hinzufuegen
Move kscMove = new Move(colorOfPlayer, 1, 1); // Unwichtige Werte
kscMove.setKingSideCastling(true);
kscMove.setPlayerColor(colorOfPlayer);
move = kscMove;
} else if (isQueenSideCastling(colorOfPlayer, fieldnumbers)) {
// Langen Rochade-Zug erstellen und der Liste hinzufuegen
Move qscMove = new Move(colorOfPlayer, 1, 1); // Unwichtige Werte
qscMove.setQueenSideCastling(true);
qscMove.setPlayerColor(colorOfPlayer);
move = qscMove;
} else {
System.out.println("Ungueltige Rochade angegeben");
}
} else {
System.out.println("Keine Rochade moeglich!");
}
} else {
System.out.println("Ungueltige Anzahl an uebergebenen Feldnummern");
}
return move;
}
/**
* Erweitert das Move-Objekt um Informationen, wie z.B. ob bei dem Zug geschmissen wird.
* @param colorOfPlayer
* @param move
* @return
*/
public static Move additionalInformationForMove(byte colorOfPlayer, Move move)
{
Field f = Field.getInstance();
// Wird geschmissen?
if (f.isFigureOnField(move.getFieldTo()) // Figur auf To-Feld vorhanden?
) {
if (f.getFigureAt(move.getFieldTo()).getColor() != colorOfPlayer) // Gegner auf To-Feld?
{
// Neuen Zug erstellen und der Liste hinzufügen
move.setCaptured(true);
} else {
// Eigene Figur kann nicht geschmissen werden
System.out.println("Die eigene Figur kann nicht geschmissen werden!");
}
}
// Pawn Promotion?
// Bauer-(Neue Figur)-Umwandlung, wenn:
// - Bauer bewegt wird und
// - Weisser Bauer die gegnerische erste Linie erreicht (57-64) oder
// - Schwarzer Bauer die gegnerische erste Linie erreicht (1-8)
Figure movingFigure = f.getFigureAt(move.getFieldFrom());
if (movingFigure.getFigureType() == ChessfigureConstants.PAWN &&
(
( colorOfPlayer == ChessfigureConstants.WHITE &&
move.getFieldTo() >= 57 &&
move.getFieldTo() <= 64) ||
( colorOfPlayer == ChessfigureConstants.BLACK &&
move.getFieldTo() >= 1 &&
move.getFieldTo() <= 8)
)
) {
System.out.println("HIER: " + movingFigure.getFigureType() + " - " + ChessfigureConstants.PAWN);
move.setPawnPromotion(true);
}
return move;
}
/**
* Prueft die uebergebenen Feldnummern und die Farbe, ob es eine gueltige kurze Rochade ist.
* @param colorOfPlayer Schwarz/Weiss
* @param fieldnumbers Die vier Feldnummern der Rochade
* @return
*/
public static boolean isKingSideCastling(byte colorOfPlayer, List<Integer> fieldnumbers)
{
if (fieldnumbers.size() == 4) {
// Weiss
if (colorOfPlayer == ChessfigureConstants.WHITE) {
// Pruefe ob benoetige Felder uebergeben sind
if (!( fieldnumbers.contains(Field.getFieldNumber("e1")) &&
fieldnumbers.contains(Field.getFieldNumber("g1")) &&
fieldnumbers.contains(Field.getFieldNumber("h1")) &&
fieldnumbers.contains(Field.getFieldNumber("f1"))
)) {
return false;
}
} else
// Schwarz
if (colorOfPlayer == ChessfigureConstants.BLACK) {
// Pruefe ob benoetige Felder uebergeben sind
if (!( fieldnumbers.contains(Field.getFieldNumber("e8")) &&
fieldnumbers.contains(Field.getFieldNumber("g8")) &&
fieldnumbers.contains(Field.getFieldNumber("h8")) &&
fieldnumbers.contains(Field.getFieldNumber("f8"))
)) {
return false;
}
} else {
return false;
}
} else {
System.out.println("Fehlerhafte Anzahl an uebergebenen Feldern");
return false;
}
return true;
}
/**
* Prueft die uebergebenen Feldnummern und die Farbe, ob es eine gueltige lange Rochade ist.
* @param colorOfPlayer Schwarz/Weiss
* @param fieldnumbers Die vier Feldnummern
* @return
*/
public static boolean isQueenSideCastling(byte colorOfPlayer, List<Integer> fieldnumbers)
{
if (fieldnumbers.size() == 4) {
// Weiss
if (colorOfPlayer == ChessfigureConstants.WHITE) {
// Pruefe ob benoetige Felder uebergeben sind
if (!( fieldnumbers.contains(Field.getFieldNumber("e1")) &&
fieldnumbers.contains(Field.getFieldNumber("c1")) &&
fieldnumbers.contains(Field.getFieldNumber("a1")) &&
fieldnumbers.contains(Field.getFieldNumber("d1"))
)) {
return false;
}
} else
// Schwarz
if (colorOfPlayer == ChessfigureConstants.BLACK) {
// Pruefe ob benoetige Felder uebergeben sind
if (!( fieldnumbers.contains(Field.getFieldNumber("e8")) &&
fieldnumbers.contains(Field.getFieldNumber("c8")) &&
fieldnumbers.contains(Field.getFieldNumber("a8")) &&
fieldnumbers.contains(Field.getFieldNumber("d8"))
)) {
return false;
}
} else {
return false;
}
} else {
System.out.println("Fehlerhafte Anzahl an uebergebenen Feldern");
return false;
}
return true;
}
/**
* Sofern das Spiel beendet ist, wird das Ergebnis zurueckgegeben.
* TODO Wie wird ermittelt, wer gewonnen hat?
*
* @return
*/
public String getResult() {
String s = "";
if (this.gameCoordinator.isEndOfGame()) {
s = "1-0";
}
return s;
}
}