/*
* 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 static chesstrainer.util.EPiece.BB;
import static chesstrainer.util.EPiece.BK;
import static chesstrainer.util.EPiece.BN;
import static chesstrainer.util.EPiece.BP;
import static chesstrainer.util.EPiece.BQ;
import static chesstrainer.util.EPiece.BR;
import static chesstrainer.util.EPiece.WB;
import static chesstrainer.util.EPiece.WK;
import static chesstrainer.util.EPiece.WN;
import static chesstrainer.util.EPiece.WP;
import static chesstrainer.util.EPiece.WQ;
import static chesstrainer.util.EPiece.WR;
import chesstrainer.util.ESide;
import chesstrainer.util.ESquare;
import java.util.HashSet;
import java.util.Set;
/**
*
* @author Tim Declercq <caveman1917@hotmail.com>
*/
public class SMoveGenerator {
private static Set<CMove> getWhitePawnMoves(CPosition position, ESquare square) {
Set<CMove> moves = new HashSet<>();
if (square.n() != null) {
if (position.get(square.n()) == null) {
if (square.getRank() != 6) {
moves.add(new CMove(square, square.n()));
} else {
moves.add(new CMove(square, square.n(), EPiece.WN));
moves.add(new CMove(square, square.n(), EPiece.WB));
moves.add(new CMove(square, square.n(), EPiece.WR));
moves.add(new CMove(square, square.n(), EPiece.WQ));
}
if (square.getRank() == 1 && position.get(square.n().n()) == null) {
moves.add(new CMove(square, square.n().n()));
}
}
}
if (square.nw() != null) {
if (position.get(square.nw()) != null) {
if (position.get(square.nw()).getSide() == ESide.BLACK
|| square.nw() == position.getEnPassantSquare()) {
if (square.getRank() != 6) {
moves.add(new CMove(square, square.nw()));
} else {
moves.add(new CMove(square, square.nw(), EPiece.WN));
moves.add(new CMove(square, square.nw(), EPiece.WB));
moves.add(new CMove(square, square.nw(), EPiece.WR));
moves.add(new CMove(square, square.nw(), EPiece.WQ));
}
}
}
}
if (square.ne() != null) {
if (position.get(square.ne()) != null) {
if (position.get(square.ne()).getSide() == ESide.BLACK
|| square.nw() == position.getEnPassantSquare()) {
if (square.getRank() != 6) {
moves.add(new CMove(square, square.ne()));
} else {
moves.add(new CMove(square, square.ne(), EPiece.WN));
moves.add(new CMove(square, square.ne(), EPiece.WB));
moves.add(new CMove(square, square.ne(), EPiece.WR));
moves.add(new CMove(square, square.ne(), EPiece.WQ));
}
}
}
}
return moves;
}
private static Set<CMove> getBlackPawnMoves(CPosition position, ESquare square) {
Set<CMove> moves = new HashSet<>();
if (square.s() != null) {
if (position.get(square.s()) == null) {
if (square.getRank() != 1) {
moves.add(new CMove(square, square.s()));
} else {
moves.add(new CMove(square, square.s(), EPiece.BN));
moves.add(new CMove(square, square.s(), EPiece.BB));
moves.add(new CMove(square, square.s(), EPiece.BR));
moves.add(new CMove(square, square.s(), EPiece.BQ));
}
if (square.getRank() == 6 && position.get(square.s().s()) == null) {
moves.add(new CMove(square, square.s().s()));
}
}
}
if (square.sw() != null) {
if (position.get(square.sw()) != null) {
if (position.get(square.sw()).getSide() == ESide.WHITE
|| square.nw() == position.getEnPassantSquare()) {
if (square.getRank() != 1) {
moves.add(new CMove(square, square.sw()));
} else {
moves.add(new CMove(square, square.sw(), EPiece.BN));
moves.add(new CMove(square, square.sw(), EPiece.BB));
moves.add(new CMove(square, square.sw(), EPiece.BR));
moves.add(new CMove(square, square.sw(), EPiece.BQ));
}
}
}
}
if (square.se() != null) {
if (position.get(square.se()) != null) {
if (position.get(square.se()).getSide() == ESide.WHITE
|| square.nw() == position.getEnPassantSquare()) {
if (square.getRank() != 1) {
moves.add(new CMove(square, square.se()));
} else {
moves.add(new CMove(square, square.se(), EPiece.BN));
moves.add(new CMove(square, square.se(), EPiece.BB));
moves.add(new CMove(square, square.se(), EPiece.BR));
moves.add(new CMove(square, square.se(), EPiece.BQ));
}
}
}
}
return moves;
}
private static Set<CMove> getKnightMoves(CPosition position, ESquare square) {
Set<CMove> moves = new HashSet<>();
ESide side = position.get(square).getSide();
for (ESquare s : new ESquare[]{square.knight1(), square.knight2(),
square.knight3(), square.knight4(), square.knight5(), square.knight6(),
square.knight7(), square.knight8()}) {
if (s != null) {
if (position.get(s) == null) {
moves.add(new CMove(square, s));
} else if (position.get(s).getSide() != side) {
moves.add(new CMove(square, s));
}
}
}
return moves;
}
private static Set<CMove> getBishopMoves(CPosition position, ESquare square) {
Set<CMove> moves = new HashSet<>();
ESide side = position.get(square).getSide();
ESquare s;
s = square;
while (s.nw() != null) {
s = s.nw();
if (position.get(s) == null) {
moves.add(new CMove(square, s));
} else if (position.get(s).getSide() != side) {
moves.add(new CMove(square, s));
break;
} else {
break;
}
}
s = square;
while (s.ne() != null) {
s = s.ne();
if (position.get(s) == null) {
moves.add(new CMove(square, s));
} else if (position.get(s).getSide() != side) {
moves.add(new CMove(square, s));
break;
} else {
break;
}
}
s = square;
while (s.se() != null) {
s = s.se();
if (position.get(s) == null) {
moves.add(new CMove(square, s));
} else if (position.get(s).getSide() != side) {
moves.add(new CMove(square, s));
break;
} else {
break;
}
}
s = square;
while (s.sw() != null) {
s = s.sw();
if (position.get(s) == null) {
moves.add(new CMove(square, s));
} else if (position.get(s).getSide() != side) {
moves.add(new CMove(square, s));
break;
} else {
break;
}
}
return moves;
}
private static Set<CMove> getRookMoves(CPosition position, ESquare square) {
Set<CMove> moves = new HashSet<>();
ESide side = position.get(square).getSide();
ESquare s;
s = square;
while (s.n() != null) {
s = s.n();
if (position.get(s) == null) {
moves.add(new CMove(square, s));
} else if (position.get(s).getSide() != side) {
moves.add(new CMove(square, s));
break;
} else {
break;
}
}
s = square;
while (s.e() != null) {
s = s.e();
if (position.get(s) == null) {
moves.add(new CMove(square, s));
} else if (position.get(s).getSide() != side) {
moves.add(new CMove(square, s));
break;
} else {
break;
}
}
s = square;
while (s.s() != null) {
s = s.s();
if (position.get(s) == null) {
moves.add(new CMove(square, s));
} else if (position.get(s).getSide() != side) {
moves.add(new CMove(square, s));
break;
} else {
break;
}
}
s = square;
while (s.w() != null) {
s = s.w();
if (position.get(s) == null) {
moves.add(new CMove(square, s));
} else if (position.get(s).getSide() != side) {
moves.add(new CMove(square, s));
break;
} else {
break;
}
}
return moves;
}
private static Set<CMove> getQueenMoves(CPosition position, ESquare square) {
Set<CMove> moves = getBishopMoves(position, square);
moves.addAll(getRookMoves(position, square));
return moves;
}
private static Set<CMove> getKingMoves(CPosition position, ESquare square) {
Set<CMove> moves = new HashSet<>();
ESide side = position.get(square).getSide();
for (ESquare s : new ESquare[]{square.n(), square.ne(), square.e()
, square.se(), square.s(), square.sw(), square.w(), square.nw()}) {
if (s != null) {
if (position.get(s) == null) {
moves.add(new CMove(square, s));
} else if (position.get(s).getSide() != side) {
moves.add(new CMove(square, s));
}
}
}
if (side == ESide.WHITE && square == ESquare.e1) {
if (position.isWhiteCastleShort()) {
if (position.get(ESquare.f1) == null
&& position.get(ESquare.g1) == null) {
if (!isInCheck(position)
&& !isAttackedBy(position, ESquare.f1, ESide.BLACK)) {
moves.add(new CMove(ESquare.e1, ESquare.g1));
}
}
}
if (position.isWhiteCastleLong()) {
if (position.get(ESquare.d1) == null
&& position.get(ESquare.c1) == null
&& position.get(ESquare.b1) == null) {
if (!isInCheck(position)
&& !isAttackedBy(position, ESquare.d1, ESide.BLACK)) {
moves.add(new CMove(ESquare.e1, ESquare.c1));
}
}
}
}
if (side == ESide.BLACK && square == ESquare.e8) {
if (position.isBlackCastleShort()) {
if (position.get(ESquare.f8) == null
&& position.get(ESquare.g8) == null) {
if (!isInCheck(position)
&& !isAttackedBy(position, ESquare.f8, ESide.WHITE)) {
moves.add(new CMove(ESquare.e8, ESquare.g8));
}
}
}
if (position.isBlackCastleLong()) {
if (position.get(ESquare.d8) == null
&& position.get(ESquare.c8) == null
&& position.get(ESquare.b8) == null) {
if (!isInCheck(position)
&& !isAttackedBy(position, ESquare.d8, ESide.WHITE)) {
moves.add(new CMove(ESquare.e8, ESquare.c8));
}
}
}
}
return moves;
}
private static Set<CMove> getMoves(CPosition position, ESquare square) {
Set<CMove> moves = new HashSet<>();
if (square == null) {
return moves;
}
if (position.get(square) == null) {
return moves;
}
switch (position.get(square)) {
case WP: moves.addAll(getWhitePawnMoves(position, square)); break;
case BP: moves.addAll(getBlackPawnMoves(position, square)); break;
case WN:
case BN: moves.addAll(getKnightMoves(position, square)); break;
case WB:
case BB: moves.addAll(getBishopMoves(position, square)); break;
case WR:
case BR: moves.addAll(getRookMoves(position, square)); break;
case WQ:
case BQ: moves.addAll(getQueenMoves(position, square)); break;
case WK:
case BK: moves.addAll(getKingMoves(position, square)); break;
}
return moves;
}
private static Set<CMove> getPseudoLegalMoves(CPosition position, ESide side) {
Set<CMove> moves = new HashSet<>();
for (ESquare square : position.getPosition().keySet()) {
if (position.get(square).getSide() == side) {
moves.addAll(getMoves(position, square));
}
}
return moves;
}
private static Set<CMove> getPseudoLegalMoves(CPosition position) {
return getPseudoLegalMoves(position, position.getSideToMove());
}
private static Set<CMove> retainLegalMoves(CPosition position, Set<CMove> moves) {
CPosition pos;
Set<CMove> legalMoves = new HashSet<>();
ESide side = position.getSideToMove();
for (CMove move : moves) {
if (side != position.getPosition().get(move.getFrom()).getSide()) {
continue;
}
pos = position.copy();
pos.makeMove(move);
if (!isInCheck(pos)) {
legalMoves.add(move);
}
}
return legalMoves;
}
public static Set<CMove> getLegalMoves(CPosition position) {
return retainLegalMoves(position, getPseudoLegalMoves(position));
}
public static Set<CMove> getLegalMoves(CPosition position, ESquare square) {
return retainLegalMoves(position, getMoves(position, square));
}
public static boolean isLegalMove(CPosition position, CMove move) {
Set<CMove> legalMoves = getLegalMoves(position, move.getFrom());
for (CMove legalMove : legalMoves) {
if (move.equals(legalMove)) {
return true;
}
}
return false;
}
public static boolean isAttackedBy(CPosition position, ESquare square, ESide side) {
if (side == ESide.WHITE) {
if (position.get(square.sw()) == EPiece.WP) {
return true;
}
if (position.get(square.se()) == EPiece.WP) {
return true;
}
if (position.get(square.n()) == EPiece.WK) {
return true;
}
if (position.get(square.ne()) == EPiece.WK) {
return true;
}
if (position.get(square.e()) == EPiece.WK) {
return true;
}
if (position.get(square.se()) == EPiece.WK) {
return true;
}
if (position.get(square.s()) == EPiece.WK) {
return true;
}
if (position.get(square.sw()) == EPiece.WK) {
return true;
}
if (position.get(square.w()) == EPiece.WK) {
return true;
}
if (position.get(square.nw()) == EPiece.WK) {
return true;
}
if (position.get(square.knight1()) == EPiece.WN) {
return true;
}
if (position.get(square.knight2()) == EPiece.WN) {
return true;
}
if (position.get(square.knight3()) == EPiece.WN) {
return true;
}
if (position.get(square.knight4()) == EPiece.WN) {
return true;
}
if (position.get(square.knight5()) == EPiece.WN) {
return true;
}
if (position.get(square.knight6()) == EPiece.WN) {
return true;
}
if (position.get(square.knight7()) == EPiece.WN) {
return true;
}
if (position.get(square.knight8()) == EPiece.WN) {
return true;
}
ESquare s = square;
while (s.nw() != null && position.get(s.nw()) == null) {
s = s.nw();
}
if (position.get(s.nw()) == EPiece.WB
|| position.get(s.nw()) == EPiece.WQ) {
return true;
}
s = square;
while (s.ne() != null && position.get(s.ne()) == null) {
s = s.ne();
}
if (position.get(s.ne()) == EPiece.WB
|| position.get(s.ne()) == EPiece.WQ) {
return true;
}
s = square;
while (s.se() != null && position.get(s.se()) == null) {
s = s.se();
}
if (position.get(s.se()) == EPiece.WB
|| position.get(s.se()) == EPiece.WQ) {
return true;
}
s = square;
while (s.sw() != null && position.get(s.sw()) == null) {
s = s.sw();
}
if (position.get(s.sw()) == EPiece.WB
|| position.get(s.sw()) == EPiece.WQ) {
return true;
}
s = square;
while (s.n() != null && position.get(s.n()) == null) {
s = s.n();
}
if (position.get(s.n()) == EPiece.WR
|| position.get(s.n()) == EPiece.WQ) {
return true;
}
s = square;
while (s.e() != null && position.get(s.e()) == null) {
s = s.e();
}
if (position.get(s.e()) == EPiece.WR
|| position.get(s.e()) == EPiece.WQ) {
return true;
}
s = square;
while (s.s() != null && position.get(s.s()) == null) {
s = s.s();
}
if (position.get(s.s()) == EPiece.WR
|| position.get(s.s()) == EPiece.WQ) {
return true;
}
s = square;
while (s.w() != null && position.get(s.w()) == null) {
s = s.w();
}
if (position.get(s.w()) == EPiece.WR
|| position.get(s.w()) == EPiece.WQ) {
return true;
}
} else {
if (position.get(square.nw()) == EPiece.BP) {
return true;
}
if (position.get(square.ne()) == EPiece.BP) {
return true;
}
if (position.get(square.n()) == EPiece.BK) {
return true;
}
if (position.get(square.ne()) == EPiece.BK) {
return true;
}
if (position.get(square.e()) == EPiece.BK) {
return true;
}
if (position.get(square.se()) == EPiece.BK) {
return true;
}
if (position.get(square.s()) == EPiece.BK) {
return true;
}
if (position.get(square.sw()) == EPiece.BK) {
return true;
}
if (position.get(square.w()) == EPiece.BK) {
return true;
}
if (position.get(square.nw()) == EPiece.BK) {
return true;
}
if (position.get(square.knight1()) == EPiece.BN) {
return true;
}
if (position.get(square.knight2()) == EPiece.BN) {
return true;
}
if (position.get(square.knight3()) == EPiece.BN) {
return true;
}
if (position.get(square.knight4()) == EPiece.BN) {
return true;
}
if (position.get(square.knight5()) == EPiece.BN) {
return true;
}
if (position.get(square.knight6()) == EPiece.BN) {
return true;
}
if (position.get(square.knight7()) == EPiece.BN) {
return true;
}
if (position.get(square.knight8()) == EPiece.BN) {
return true;
}
ESquare s = square;
while (s.nw() != null && position.get(s.nw()) == null) {
s = s.nw();
}
if (position.get(s.nw()) == EPiece.BB
|| position.get(s.nw()) == EPiece.BQ) {
return true;
}
s = square;
while (s.ne() != null && position.get(s.ne()) == null) {
s = s.ne();
}
if (position.get(s.ne()) == EPiece.BB
|| position.get(s.ne()) == EPiece.BQ) {
return true;
}
s = square;
while (s.se() != null && position.get(s.se()) == null) {
s = s.se();
}
if (position.get(s.se()) == EPiece.BB
|| position.get(s.se()) == EPiece.BQ) {
return true;
}
s = square;
while (s.sw() != null && position.get(s.sw()) == null) {
s = s.sw();
}
if (position.get(s.sw()) == EPiece.BB
|| position.get(s.sw()) == EPiece.BQ) {
return true;
}
s = square;
while (s.n() != null && position.get(s.n()) == null) {
s = s.n();
}
if (position.get(s.n()) == EPiece.BR
|| position.get(s.n()) == EPiece.BQ) {
return true;
}
s = square;
while (s.e() != null && position.get(s.e()) == null) {
s = s.e();
}
if (position.get(s.e()) == EPiece.BR
|| position.get(s.e()) == EPiece.BQ) {
return true;
}
s = square;
while (s.s() != null && position.get(s.s()) == null) {
s = s.s();
}
if (position.get(s.s()) == EPiece.BR
|| position.get(s.s()) == EPiece.BQ) {
return true;
}
s = square;
while (s.w() != null && position.get(s.w()) == null) {
s = s.w();
}
if (position.get(s.w()) == EPiece.BR
|| position.get(s.w()) == EPiece.BQ) {
return true;
}
}
return false;
}
public static boolean isInCheck(CPosition position) {
ESquare kingSquare = null;
ESide side = position.getSideToMove();
for (ESquare s : position.getPosition().keySet()) {
if (side == ESide.BLACK && position.get(s) == EPiece.WK) {
kingSquare = s;
break;
}
if (side == ESide.WHITE && position.get(s) == EPiece.BK) {
kingSquare = s;
break;
}
}
return isAttackedBy(position, kingSquare, side);
}
}