/*
* Copyright (C) 2014 Tim Declercq <caveman1917@hotmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package chesstrainer;
import chesstrainer.util.EPiece;
import chesstrainer.util.ESide;
import chesstrainer.util.ESquare;
import java.util.EnumMap;
import java.util.Map;
import java.util.Set;
/**
*
* @author Tim Declercq <caveman1917@hotmail.com>
*/
public class CPosition {
public static final String FEN_START =
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -";
private Map<ESquare, EPiece> position = new EnumMap(ESquare.class);
private ESide sideToMove;
private boolean whiteCastleShort, whiteCastleLong, blackCastleShort, blackCastleLong;
private ESquare enPassantSquare;
public CPosition(String fen) {
this.setFEN(fen);
}
public CPosition() {
this(FEN_START);
}
public void clear() {
position.clear();
sideToMove = ESide.WHITE;
whiteCastleShort = false;
whiteCastleLong = false;
blackCastleShort = false;
blackCastleLong = false;
enPassantSquare = null;
}
public CPosition copy() {
CPosition pos = new CPosition();
pos.clear();
pos.setSideToMove(sideToMove);
pos.setBlackCastleLong(blackCastleLong);
pos.setBlackCastleShort(blackCastleShort);
pos.setWhiteCastleLong(whiteCastleLong);
pos.setWhiteCastleShort(whiteCastleShort);
pos.setEnPassantSquare(enPassantSquare);
for (ESquare s : position.keySet()) {
pos.getPosition().put(s, position.get(s));
}
return pos;
}
public final void setFEN(String fen) {
whiteCastleShort = false;
whiteCastleLong = false;
blackCastleShort = false;
blackCastleLong = false;
enPassantSquare = null;
position.clear();
String[] pieces = fen.split(" ");
// pos
String[] ranks = pieces[0].split("/");
ESquare sq;
EPiece piece;
for (int i = 0; i < 8; i++) {
int rank = 7 - i;
int file = 0;
for (int pos = 0; pos < ranks[i].length(); pos++) {
switch (ranks[i].substring(pos, pos + 1)) {
case "1": file += 1; break;
case "2": file += 2; break;
case "3": file += 3; break;
case "4": file += 4; break;
case "5": file += 5; break;
case "6": file += 6; break;
case "7": file += 7; break;
case "8": file += 8; break;
default:
sq = ESquare.get(rank, file);
piece = EPiece.get(ranks[i].substring(pos, pos + 1));
if (piece != null) {
position.put(sq, piece);
}
file++;
}
}
}
// meta
switch (pieces[1]) {
case "w": sideToMove = ESide.WHITE; break;
case "b": sideToMove = ESide.BLACK; break;
}
if (pieces[2].contains("K")) {
whiteCastleShort = true;
}
if (pieces[2].contains("Q")) {
whiteCastleLong = true;
}
if (pieces[2].contains("k")) {
blackCastleShort = true;
}
if (pieces[2].contains("q")) {
blackCastleLong = true;
}
try {
enPassantSquare = ESquare.valueOf(pieces[3]);
} catch (Exception e) {
enPassantSquare = null;
}
}
public String getFEN() {
String fen = "";
ESquare sq;
EPiece piece;
for (int rank = 7; rank >= 0; rank--) {
int empty = 0;
for (int file = 0; file < 8; file++) {
sq = ESquare.get(rank, file);
if (position.containsKey(sq)) {
if (empty > 0) {
fen += String.valueOf(empty).trim();
empty = 0;
}
piece = position.get(sq);
fen += piece.toString();
} else {
empty++;
}
}
if (empty != 0) {
fen += String.valueOf(empty).trim();
}
if (rank > 0) {
fen += "/";
}
}
fen += " ";
if (sideToMove == ESide.WHITE) {
fen += "w";
} else {
fen += "b";
}
fen += " ";
String s = "-";
if (whiteCastleShort) {
fen += "K";
s = "";
}
if (whiteCastleLong) {
fen += "Q";
s = "";
}
if (blackCastleShort) {
fen += "k";
s = "";
}
if (blackCastleLong) {
fen += "q";
s = "";
}
fen += s;
fen += " ";
if (enPassantSquare == null) {
fen += "-";
} else {
fen += enPassantSquare.name();
}
return fen;
}
public void makeMove(CMove move) {
EPiece piece = position.get(move.getFrom());
position.remove(move.getTo());
position.remove(move.getFrom());
position.put(move.getTo(), piece);
if (move.getPromotion() != null) {
position.remove(move.getTo());
position.put(move.getTo(), move.getPromotion());
}
// castling
if (move.getFrom() == ESquare.e1 && move.getTo() == ESquare.g1
&& piece == EPiece.WK) {
position.remove(ESquare.h1);
position.put(ESquare.f1, EPiece.WR);
}
if (move.getFrom() == ESquare.e1 && move.getTo() == ESquare.c1
&& piece == EPiece.WK) {
position.remove(ESquare.a1);
position.put(ESquare.d1, EPiece.WR);
}
if (move.getFrom() == ESquare.e8 && move.getTo() == ESquare.g8
&& piece == EPiece.BK) {
position.remove(ESquare.h8);
position.put(ESquare.f8, EPiece.BR);
}
if (move.getFrom() == ESquare.e8 && move.getTo() == ESquare.c8
&& piece == EPiece.BK) {
position.remove(ESquare.a8);
position.put(ESquare.d8, EPiece.BR);
}
// en passant
if (move.getTo() == enPassantSquare && piece == EPiece.WP) {
position.remove(enPassantSquare.s());
}
if (move.getTo() == enPassantSquare && piece == EPiece.BP) {
position.remove(enPassantSquare.n());
}
// update metadata
sideToMove = sideToMove.other();
enPassantSquare = null;
if (piece == EPiece.WP && move.getFrom().getRank() == 1
&& move.getTo().getRank() == 3) {
enPassantSquare = move.getTo().s();
}
if (piece == EPiece.BP && move.getFrom().getRank() == 6
&& move.getTo().getRank() == 4) {
enPassantSquare = move.getTo().n();
}
if (move.getFrom() == ESquare.a1) {
whiteCastleLong = false;
}
if (move.getFrom() == ESquare.h1) {
whiteCastleShort = false;
}
if (move.getFrom() == ESquare.e1) {
whiteCastleShort = false;
whiteCastleLong = false;
}
if (move.getFrom() == ESquare.a8) {
blackCastleLong = false;
}
if (move.getFrom() == ESquare.h8) {
blackCastleShort = false;
}
if (move.getFrom() == ESquare.e8) {
blackCastleShort = false;
blackCastleLong = false;
}
}
public Map<ESquare, EPiece> getPosition() {
return position;
}
public EPiece get(ESquare square) {
return position.get(square);
}
public ESide getSideToMove() {
return sideToMove;
}
public void setSideToMove(ESide sideToMove) {
this.sideToMove = sideToMove;
}
public boolean isWhiteCastleShort() {
return whiteCastleShort;
}
public void setWhiteCastleShort(boolean whiteCastleShort) {
this.whiteCastleShort = whiteCastleShort;
}
public boolean isWhiteCastleLong() {
return whiteCastleLong;
}
public void setWhiteCastleLong(boolean whiteCastleLong) {
this.whiteCastleLong = whiteCastleLong;
}
public boolean isBlackCastleShort() {
return blackCastleShort;
}
public void setBlackCastleShort(boolean blackCastleShort) {
this.blackCastleShort = blackCastleShort;
}
public boolean isBlackCastleLong() {
return blackCastleLong;
}
public void setBlackCastleLong(boolean blackCastleLong) {
this.blackCastleLong = blackCastleLong;
}
public ESquare getEnPassantSquare() {
return enPassantSquare;
}
public void setEnPassantSquare(ESquare enPassantSquare) {
this.enPassantSquare = enPassantSquare;
}
public Set<CMove> getMoves() {
return SMoveGenerator.getLegalMoves(this);
}
}