/*
* 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.Iterator;
import java.util.Set;
/**
*
* @author Tim Declercq <caveman1917@hotmail.com>
*/
public class CMove {
private ESquare from, to;
private EPiece promotion;
public CMove(ESquare from, ESquare to, EPiece promotion) {
this.from = from;
this.to = to;
this.promotion = promotion;
}
public CMove(ESquare from, ESquare to) {
this(from, to, null);
}
public ESquare getFrom() {
return from;
}
public ESquare getTo() {
return to;
}
public EPiece getPromotion() {
return promotion;
}
public static CMove getMove(CPosition position, String san) {
// castling
if (san.equals("O-O")) {
if (position.getSideToMove() == ESide.WHITE) {
return new CMove(ESquare.e1, ESquare.g1);
} else {
return new CMove(ESquare.e8, ESquare.g8);
}
}
if (san.equals("O-O-O")) {
if (position.getSideToMove() == ESide.WHITE) {
return new CMove(ESquare.e1, ESquare.c1);
} else {
return new CMove(ESquare.e8, ESquare.c8);
}
}
ESquare to = null;
Set<CMove> moves = position.getMoves();
CMove move;
EPiece piece;
EPiece promotion = null;
for (ESquare s : ESquare.values()) {
if (san.contains(s.name())) {
to = s;
break;
}
}
// first reduction based on target square
Iterator<CMove> it = moves.iterator();
while (it.hasNext()) {
move = it.next();
if (move.getTo() != to) {
it.remove();
}
}
if (moves.size() == 1) {
return (CMove)moves.toArray()[0];
}
// second reduction based on piece
switch (san.substring(0, 1)) {
case "K": piece = EPiece.WK.toSide(position.getSideToMove()); break;
case "Q": piece = EPiece.WQ.toSide(position.getSideToMove()); break;
case "R": piece = EPiece.WR.toSide(position.getSideToMove()); break;
case "B": piece = EPiece.WB.toSide(position.getSideToMove()); break;
case "N": piece = EPiece.WN.toSide(position.getSideToMove()); break;
default: piece = EPiece.WP.toSide(position.getSideToMove()); break;
}
if (san.toUpperCase().contains("=Q")) {
promotion = EPiece.WQ.toSide(position.getSideToMove());
}
if (san.toUpperCase().contains("=R")) {
promotion = EPiece.WR.toSide(position.getSideToMove());
}
if (san.toUpperCase().contains("=B")) {
promotion = EPiece.WB.toSide(position.getSideToMove());
}
if (san.toUpperCase().contains("=N")) {
promotion = EPiece.WN.toSide(position.getSideToMove());
}
it = moves.iterator();
while (it.hasNext()) {
move = it.next();
if (position.get(move.getFrom()) != piece
|| move.getPromotion() != promotion) {
it.remove();
}
}
if (moves.size() == 1) {
return (CMove)moves.toArray()[0];
}
// third reduction based on multiple piece disambiguation
int rank = -1, file = -1;
int a = 1;
if (piece == EPiece.WP || piece == EPiece.BP) {
a = 0;
}
switch (san.substring(a, a + 1)) {
case "1": rank = 0; break;
case "2": rank = 1; break;
case "3": rank = 2; break;
case "4": rank = 3; break;
case "5": rank = 4; break;
case "6": rank = 5; break;
case "7": rank = 6; break;
case "8": rank = 7; break;
case "a": file = 0; break;
case "b": file = 1; break;
case "c": file = 2; break;
case "d": file = 3; break;
case "e": file = 4; break;
case "f": file = 5; break;
case "g": file = 6; break;
case "h": file = 7; break;
}
it = moves.iterator();
while (it.hasNext()) {
move = it.next();
if (rank >=0 && move.getFrom().getRank() != rank) {
it.remove();
} else if (file >= 0 && move.getFrom().getFile() != file) {
it.remove();
}
}
if (moves.size() == 1) {
return (CMove)moves.toArray()[0];
}
return null;
}
@Override
public String toString() {
if (getPromotion() == null) {
return getFrom().name() + "-" + getTo().name();
} else {
return getFrom().name() + "-" + getTo().name() + "="
+ getPromotion().toString().toLowerCase();
}
}
@Override
public boolean equals(Object other) {
CMove o = (CMove)other;
if (from != o.from) {
return false;
}
if (to != o.to) {
return false;
}
if (promotion != o.promotion) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 0;
if (from != null) {
hash ^= from.hashCode();
}
if (to != null) {
hash ^= to.hashCode();
}
if (promotion != null) {
hash ^= promotion.hashCode();
}
return hash;
}
}