/* chess_position.c
*
* Copyright (C) 1999 Robert Wilhelm
*
* 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 .
*
* Authors: Robert Wilhelm
* JP Rosevear
*/
#include
#include
#include "chess_position.h"
#include "chess_notation.h"
struct _PositionPrivate {
Square tomove; /* Color to move */
gshort wr_a_move; /* Flag if the white 'a' rook has moved */
gshort wr_h_move; /* Flag if the white 'h' rook has moved */
Square wk_square; /* The square the white king is on */
gshort br_a_move; /* Flag if the black 'a' rook has moved */
gshort br_h_move; /* Flag if the black 'h' rook has moved */
Square bk_square; /* The square the black king is on */
gshort ep; /* En passent */
Piece captured; /* Last piece captured */
};
/* Move generation variables */
static const int jump [] = { 8, 12,19, 21,-8,-12,-19,-21,
9, 11,-9,-11, 1, 10,-10, -1,
9, 11, 1, 10,-1, 1, 10, -1,
-9,-11, 1,-10,-1 };
static Square *nindex, *sindex;
G_DEFINE_TYPE(Position, position, G_TYPE_OBJECT);
/* Prototypes */
static void position_set_empty (Position *pos);
static GObject *
position_constructor (GType gtype,
guint n_properties,
GObjectConstructParam *properties)
{
GObject *obj;
{
/* Always chain up to the parent constructor */
obj = G_OBJECT_CLASS (position_parent_class)->constructor (gtype, n_properties, properties);
}
/* update the object state depending on constructor properties */
return obj;
}
static void
position_class_init (PositionClass *klass)
{
g_type_class_add_private (klass, sizeof (PositionPrivate));
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->constructor = position_constructor;
}
static void
position_init (Position *self)
{
self->priv = POSITION_GET_PRIVATE (self);
position_set_empty (self);
}
GObject *
position_new ()
{
return G_OBJECT (g_object_new (position_get_type (), NULL));
}
GObject *
position_new_initial ()
{
Position *pos;
pos = POSITION (position_new ());
position_set_initial (pos);
return G_OBJECT (pos);
}
Position *
position_copy (Position *pos)
{
Position *cpPos;
cpPos = POSITION (position_new ());
memcpy (cpPos->priv, pos->priv, sizeof (PositionPrivate));
memcpy (cpPos->square, pos->square, sizeof (gchar) * 120);
return cpPos;
}
static void
position_set_empty (Position *pos)
{
unsigned int a;
for (a = 0 ; a < 120 ; a++)
pos->square [a] = EMPTY;
for (a = 0; a < 10; a++) {
pos->square [a] = BORDER;
pos->square [a + 10] = BORDER;
pos->square [a + 100] = BORDER;
pos->square [a + 110] = BORDER;
pos->square [a * 10] = BORDER;
pos->square [a * 10 + 9] = BORDER;
}
pos->priv->wk_square = 0;
pos->priv->wr_h_move = 0;
pos->priv->wr_a_move = 0;
pos->priv->bk_square = 0;
pos->priv->br_h_move = 0;
pos->priv->br_a_move = 0;
pos->priv->captured = EMPTY;
pos->priv->tomove = NONE;
}
void
position_set_initial (Position *pos)
{
unsigned int a;
/* The white pieces */
pos->square [A1] = WR;
pos->square [B1] = WN;
pos->square [C1] = WB;
pos->square [D1] = WQ;
pos->square [E1] = WK;
pos->square [F1] = WB;
pos->square [G1] = WN;
pos->square [H1] = WR;
/* The black pieces */
pos->square [A8] = BR;
pos->square [B8] = BN;
pos->square [C8] = BB;
pos->square [D8] = BQ;
pos->square [E8] = BK;
pos->square [F8] = BB;
pos->square [G8] = BN;
pos->square [H8] = BR;
/* Pawns on the 2nd and 7th ranks */
for (a = A2; a <= H2 ;a++)
pos->square [a] = WP;
for (a = A7; a <= H7 ;a++)
pos->square [a] = BP;
/* The rest is blank */
for (a = A3; a <= H3 ;a++)
pos->square [a] = EMPTY;
for (a = A4; a <= H4 ;a++)
pos->square [a] = EMPTY;
for (a = A5; a <= H5 ;a++)
pos->square [a] = EMPTY;
for (a = A6; a <= H6 ;a++)
pos->square [a] = EMPTY;
/* White to move, white king on E1 and black king on E8 */
pos->priv->wr_a_move = 0;
pos->priv->wr_h_move = 0;
pos->priv->wk_square = E1;
pos->priv->br_a_move = 0;
pos->priv->br_h_move = 0;
pos->priv->bk_square = E8;
pos->priv->captured = EMPTY;
pos->priv->tomove = WHITE;
}
void
position_set_initial_partyend (Position *pos, int level)
{
register Square square;
register gshort rank;
for (rank = 1; rank <= 8; rank++) {
for (square = A1 + ((rank - 1) * 10);
square <= H1 + ((rank - 1) * 10);
square++) {
pos->square [square] = EMPTY;
}
}
switch(level) {
case 1:
default:
/* The white pieces */
pos->square [A1] = WK;
pos->square [G1] = WQ;
pos->square [F1] = WQ;
/* The black pieces */
pos->square [E8] = BK;
/* The kings */
pos->priv->wk_square = A1;
pos->priv->bk_square = E8;
break;
case 2:
/* The white pieces */
pos->square [E1] = WK;
pos->square [F1] = WR;
pos->square [G1] = WR;
/* The black pieces */
pos->square [A8] = BK;
/* The kings */
pos->priv->wk_square = E1;
pos->priv->bk_square = A8;
break;
case 3:
/* The white pieces */
pos->square [E1] = WK;
pos->square [B4] = WR;
pos->square [B5] = WB;
/* The black pieces */
pos->square [A1] = BK;
/* The kings */
pos->priv->wk_square = E1;
pos->priv->bk_square = A1;
break;
}
/* White to move */
pos->priv->wr_a_move = 0;
pos->priv->wr_h_move = 0;
pos->priv->br_a_move = 0;
pos->priv->br_h_move = 0;
pos->priv->captured = EMPTY;
pos->priv->tomove = WHITE;
}
void
position_set_initial_movelearn (Position *pos, int level)
{
register Square square;
register gshort rank;
for (rank = 1; rank <= 8; rank++) {
for (square = A1 + ((rank - 1) * 10);
square <= H1 + ((rank - 1) * 10);
square++) {
pos->square [square] = EMPTY;
}
}
switch(level) {
case 1:
default:
/* The white pieces */
pos->square [E1] = WK;
pos->square [B4] = WR;
/* The black pieces */
pos->square [A1] = BK;
pos->square [E7] = BP;
/* The kings */
pos->priv->wk_square = E1;
pos->priv->bk_square = A1;
break;
case 2:
/* The white pieces */
pos->square [E1] = WK;
pos->square [G1] = WQ;
/* The black pieces */
pos->square [A1] = BK;
pos->square [E7] = BP;
/* The kings */
pos->priv->wk_square = E1;
pos->priv->bk_square = A1;
break;
case 3:
/* The white pieces */
pos->square [E1] = WK;
pos->square [C4] = WB;
pos->square [C5] = WB;
/* The black pieces */
pos->square [A1] = BK;
pos->square [E7] = BP;
/* The kings */
pos->priv->wk_square = E1;
pos->priv->bk_square = A1;
break;
case 4:
/* The white pieces */
pos->square [E1] = WK;
pos->square [B4] = WN;
pos->square [B5] = WN;
/* The black pieces */
pos->square [A1] = BK;
pos->square [E7] = BP;
/* The kings */
pos->priv->wk_square = E1;
pos->priv->bk_square = A1;
break;
case 5:
/* The white pieces */
pos->square [E1] = WK;
pos->square [D2] = WP;
pos->square [E2] = WP;
pos->square [F2] = WP;
pos->square [G2] = WP;
pos->square [H2] = WP;
/* The black pieces */
pos->square [A1] = BK;
pos->square [E7] = BP;
/* The kings */
pos->priv->wk_square = E1;
pos->priv->bk_square = A1;
break;
}
/* White to move */
pos->priv->wr_a_move = 0;
pos->priv->wr_h_move = 0;
pos->priv->br_a_move = 0;
pos->priv->br_h_move = 0;
pos->priv->captured = EMPTY;
pos->priv->tomove = WHITE;
}
/* Debug purpose */
void
position_display (Position *pos)
{
register Square square;
register gshort rank;
for (rank = 8; rank >= 1; rank--) {
for (square = A1 + ((rank - 1) * 10);
square <= H1 + ((rank - 1) * 10);
square++) {
g_warning("%c ", piece_to_ascii(pos->square [square]));
}
g_warning("\n");
}
}
/*
* Move Functions
*
* A set of functions to make a move in the context of the position
* passed in.
*/
static void
position_move_white_castle_short (Position *pos)
{
pos->square [E1] = pos->square [H1] = EMPTY;
pos->square [F1] = WR;
pos->square [G1] = WK;
}
static void
position_move_white_castle_long (Position *pos)
{
pos->square [E1] = pos->square [A1] = EMPTY;
pos->square [C1] = WK;
pos->square [D1] = WR;
}
static void
position_move_black_castle_short (Position *pos)
{
pos->square [E8] = pos->square [H8] = EMPTY;
pos->square [F8] = BR;
pos->square [G8] = BK;
}
static void
position_move_black_castle_long (Position *pos)
{
pos->square [E8] = pos->square [A8] = EMPTY;
pos->square [C8] = BK;
pos->square [D8] = BR;
}
static void
position_move_white (Position *pos, Square from, Square to)
{
Piece piece;
Square new_to;
piece = pos->square [from];
switch (piece) {
case WP :
/* If we are promoting a pawn */
if (to & 128) {
new_to = (to & 7) + A8;
piece = ((to & 127) >> 3 ) + WP - 1;
pos->priv->captured = pos->square [new_to];
pos->square [from] = EMPTY;
pos->square [new_to] = piece;
pos->priv->ep = EMPTY;
return;
}
/* If we are capturing en passent */
if ((to - from) != 10) {
if((to - from) != 20) {
if(pos->square [to] == EMPTY) {
pos->square [to - 10] = EMPTY;
pos->priv->ep = EMPTY;
pos->square [to] = piece;
pos->square [from] = EMPTY;
pos->priv->captured = EMPTY;
return;
}
}
}
pos->priv->captured = pos->square [to];
pos->square [to] = piece;
pos->square [from] = EMPTY;
if ((to - from) == 20)
pos->priv->ep = to;
else
pos->priv->ep = EMPTY;
return;
case WK :
pos->priv->ep = EMPTY;
pos->priv->wk_square = to;
pos->priv->wr_a_move += 1;
pos->priv->wr_h_move += 1;
/* If we are not castling */
if (from != E1 || abs (to - from) != 2) {
pos->priv->captured = pos->square [to];
pos->square [to] = piece;
pos->square [from] = EMPTY;
return;
}
/* If we are castling */
switch (to) {
case G1 :
position_move_white_castle_short (pos);
break;
case C1 :
position_move_white_castle_long (pos);
break;
default :
abort ();
}
return;
default :
pos->priv->ep = EMPTY;
pos->priv->captured = pos->square [to];
pos->square [to] = piece;
pos->square [from] = EMPTY;
/* Indicate if a rook has moved */
if (piece == WR && from == A1)
pos->priv->wr_a_move += 1;
if (piece == WR && from == H1)
pos->priv->wr_h_move += 1;
return;
}
}
static void
position_move_black (Position *pos, Square from, Square to)
{
gshort piece, new_to;
piece = pos->square [from];
switch (piece) {
case BP :
/* If we are promoting a pawn */
if (to & 128) {
new_to = (to & 7) + A1;
piece = ((to & 127) >> 3) + BP - 1;
pos->priv->captured = pos->square [new_to];
pos->square [from] = EMPTY;
pos->square [new_to] = piece;
pos->priv->ep = EMPTY;
return;
}
/* If we are capturing en passent */
if ((from - to) != 10) {
if ((from - to) != 20) {
if (pos->square [to] == EMPTY) {
pos->square [to + 10] = EMPTY;
pos->priv->ep = EMPTY;
pos->square [to] = piece;
pos->square [from] = EMPTY;
pos->priv->captured = EMPTY;
return;
}
}
}
pos->priv->captured = pos->square [to];
pos->square [to] = piece;
pos->square [from] = EMPTY;
if ((from - to) == 20)
pos->priv->ep = to;
else
pos->priv->ep = EMPTY;
return;
case BK :
pos->priv->ep = EMPTY;
pos->priv->bk_square = to;
pos->priv->br_a_move += 1;
pos->priv->br_h_move += 1;
/* If we are not castling */
if (from != E8 || abs (to - from) != 2) {
pos->priv->captured = pos->square [to];
pos->square [to] = piece;
pos->square [from] = EMPTY;
return;
}
/* If we are castling */
switch (to) {
case G8 :
position_move_black_castle_short (pos);
break;
case C8 :
position_move_black_castle_long (pos);
break;
default :
abort();
}
return;
default :
pos->priv->ep = EMPTY;
pos->priv->captured = pos->square [to];
pos->square [to] = piece;
pos->square [from] = EMPTY;
/* Indicate if a rook has moved */
if (piece == BR && from == A8)
pos->priv->br_a_move += 1;
if (piece == BR && from == H8)
pos->priv->br_h_move += 1;
return;
}
}
void
position_move (Position *pos, Square from, Square to)
{
switch (pos->priv->tomove) {
case WHITE:
position_move_white (pos, from, to);
pos->priv->tomove = BLACK;
break;
case BLACK:
position_move_black (pos, from, to);
pos->priv->tomove = WHITE;
break;
default:
g_assert_not_reached ();
}
}
static Square
position_move_normalize_promotion (Position *pos, Square to, gshort n1,
gshort n2, gshort n3, gshort n4)
{
Square help;
Piece fi = EMPTY;
gshort c;
if (pos->priv->tomove == WHITE)
help = to - A8;
else
help = to - A1;
if (help == (n1 & 7)) {
/* Automatic queen promotion prefs_get_promotetoqueen */
c = 0;
if (pos->priv->tomove == WHITE)
switch (c) {
case 0 : fi = WQ; break;
case 1 : fi = WR; break;
case 2 : fi = WB; break;
case 3 : fi = WN; break;
}
else
switch (c) {
case 0 : fi = BQ; break;
case 1 : fi = BR; break;
case 2 : fi = BB; break;
case 3 : fi = BN; break;
}
if (pos->priv->tomove == WHITE)
help = 128 + to - A8 + (fi - WP + 1) * 8;
else
help = 128 + to - A1 + (fi - BP + 1) * 8;
if (help == n1)
return n1;
if (help == n2)
return n2;
if (help == n3)
return n3;
if (help == n4)
return n4;
}
return FALSE;
}
Square
position_move_normalize (Position *pos, Square from, Square to)
{
gshort legal_moves, anz_n, anz_s;
Square movelist [AB_ZUGL];
Square *ap, *aq, ret;
gshort i;
ap = movelist + AB_ZUG_S;
legal_moves = position_legal_move (pos, &ap, &anz_s, &anz_n);
for (aq = ap, i = 0; i < legal_moves; i++, aq += 2 ) {
if (from == *aq) {
if (to == *(aq + 1))
return to;
else if (*(aq + 1) & 128) {
/* Promotion */
ret = position_move_normalize_promotion (
pos, to, *(aq + 1), *(aq + 3),
*(aq + 5), *(aq + 7));
if (ret)
return ret;
aq += 6; /* skip 3 moves */
}
}
}
return FALSE;
}
/*
* Move Reverse Functions
*
* A set of functions to reverse a previous move in the context of the position
* passed in.
*
*/
static void
position_move_reverse_castling_white_short (Position *pos)
{
pos->square [E1] = WK;
pos->square [F1] = pos->square [G1] = EMPTY;
pos->square [H1] = WR;
}
static void
position_move_reverse_castling_white_long (Position *pos)
{
pos->square [A1] = WR;
pos->square [C1] = pos->square [D1] = EMPTY;
pos->square [E1] = WK;
}
static void
position_move_reverse_castling_black_short (Position *pos)
{
pos->square [E8] = BK;
pos->square [F8] = pos->square [G8] = EMPTY;
pos->square [H8] = BR;
}
static void
position_move_reverse_castling_black_long (Position *pos)
{
pos->square [A8] = BR;
pos->square [D8] = pos->square [C8] = EMPTY;
pos->square [E8] = BK;
}
static void
position_move_reverse_promotion_white (Position *pos, Square from, Square to)
{
pos->square [from] = WP;
pos->square [(to & 7) + A8] = pos->priv->captured;
}
static void
position_move_reverse_promotion_black (Position *pos, Square from, Square to)
{
pos->square [from] = BP;
pos->square [(to & 7) + A1] = pos->priv->captured;
}
void
position_move_reverse_white (Position *pos, Square from, Square to)
{
Piece fi;
pos->priv->tomove = WHITE; /* change tomove */
if (to & 128) {
/* Promotion */
position_move_reverse_promotion_white (pos, from, to);
return;
}
fi = pos->square[to];
/* look for castling */
if (fi == WK) {
pos->priv->wk_square = from;
pos->priv->wr_a_move -= 1;
pos->priv->wr_h_move -= 1;
if (from != E1) { /* no castling */
pos->square[from] = fi;
pos->square[to] = pos->priv->captured;
return;
}
if (abs (from - to) != 2) { /* no castling */
pos->square[from] = fi;
pos->square[to] = pos->priv->captured;
return;
}
if (to == G1) {
position_move_reverse_castling_white_short (pos);
return;
} else if (to == C1) {
position_move_reverse_castling_white_long (pos);
return;
}
abort();
}
if (fi == WR && from == A1)
pos->priv->wr_a_move -= 1;
if (fi == WR && from == H1)
pos->priv->wr_h_move -= 1;
if (fi == WP) {
if ((to - from) != 10) {
if ((to - from) != 20) {
if (pos->priv->captured == EMPTY) {
pos->square [to - 10] = BP;
pos->square [to] = EMPTY;
pos->square [from] = WP;
return;
}
}
}
pos->square [from] = fi;
pos->square [to] = pos->priv->captured;
return;
}
pos->square [from] = fi;
pos->square [to] = pos->priv->captured;
}
void
position_move_reverse_black (Position *pos, Square from, Square to)
{
int fi;
pos->priv->tomove = BLACK; /* change tomove */
if (to & 128) {
/* Promotion */
position_move_reverse_promotion_black (pos, from, to);
return;
}
fi = pos->square[to];
/* look for castling */
if (fi == BK) {
pos->priv->bk_square = from;
pos->priv->br_a_move -= 1;
pos->priv->br_h_move -= 1;
if (from != E8) { /* no castling */
pos->square[from] = fi;
pos->square[to] = pos->priv->captured;
return;
}
if (abs (from - to) != 2) { /* no castling */
pos->square[from] = fi;
pos->square[to] = pos->priv->captured;
return;
}
if (to == G8) {
position_move_reverse_castling_black_short (pos);
return;
} else if (to == C8) {
position_move_reverse_castling_black_long (pos);
return;
}
abort ();
}
if (fi == BR && from == A8)
pos->priv->br_a_move -= 1;
if (fi == BR && from == H8)
pos->priv->br_h_move -= 1;
if (fi == BP) {
if ((from - to) != 10) {
if ((from - to) !=20) {
if (pos->priv->captured == EMPTY) {
pos->square[to+10] = WP;
pos->square[to] = EMPTY;
pos->square[from] = BP;
return;
}
}
}
pos->square [from] = fi;
pos->square [to]= pos->priv->captured;
return;
}
pos->square [from] = fi;
pos->square [to] = pos->priv->captured;
}
void
position_move_reverse (Position *pos, Square from, Square to)
{
switch (pos->priv->tomove) {
case WHITE:
position_move_reverse_black (pos, from, to);
break;
case BLACK:
position_move_reverse_white (pos, from, to);
break;
default:
g_assert_not_reached ();
}
}
/*
* Move Generation Functions
*
* A set of functions to generate moves in the context of the position
* passed in.
*
*/
static void inline
new_move (Square from, Square to)
{
*nindex = from;
*(nindex + 1) = to;
nindex += 2;
}
static void
new_capture_move (Square from, Square to)
{
sindex -= 2;
*sindex = from;
*(sindex + 1) = to;
}
static void
wdouble (Position *pos, Square from, gshort a, gshort b)
{
Square to, jp;
Piece piece;
for (; a < b; a++) {
to = from;
jp = jump[a];
do {
to += jp;
piece = pos->square[to];
if (piece == EMPTY)
new_move (from, to);
else if (piece == BORDER)
break;
else if (BPIECE (piece)) {
new_capture_move (from, to);
break;
} else {
break;
}
} while (TRUE);
}
}
static void
white_promotion (Square from, Square to)
{
register Square new_to;
register gshort i;
for (i = 2; i < 6; i++) {
new_to = 128 + 8 * i + to - A8;
new_capture_move (from, new_to);
}
}
static void
wpawn2 (Position *pos, Square from)
{
register Square to;
to = from + 10;
if (pos->square[to] == EMPTY ) {
new_move (from, to);
to = from + 20;
if (pos->square[to] == EMPTY )
new_move (from, to);
}
if (BPIECE (pos->square[from + 9]))
new_capture_move (from, from + 9);
if (BPIECE (pos->square[from +11]))
new_capture_move (from, from + 11);
}
static void
wpawn3 (Position *pos, Square from)
{
register Square to;
to = from + 10;
if (pos->square[to] == EMPTY)
new_move (from, to);
if (BPIECE (pos->square[from + 9]))
new_capture_move (from, from + 9);
if (BPIECE (pos->square[from + 11]))
new_capture_move (from, from + 11);
}
static void
wpawn5 (Position *pos, Square from)
{
wpawn3 (pos, from);
if ((from - 1) == pos->priv->ep)
new_capture_move (from, from + 9);
else if ((from + 1) == pos->priv->ep)
new_capture_move (from, from + 11);
}
static void
wpawn7 (Position *pos, Square from)
{
register Square to;
to = from + 10;
if (pos->square[to] == EMPTY )
white_promotion (from, to);
if (BPIECE (pos->square[from + 9]))
white_promotion (from, from + 9);
if (BPIECE (pos->square[from + 11]))
white_promotion (from, from + 11);
}
static void
wknight (Position *pos, gshort from)
{
register Square to;
register Piece piece;
register gshort a;
for (a = 0; a < 8; a++) {
to = from + jump[a];
piece = pos->square[to];
switch (piece) {
case EMPTY:
new_move (from, to);
break;
case BORDER:
break;
default:
if (BPIECE (piece))
new_capture_move (from, to);
}
}
}
static void
wbishop (Position *pos, Square from)
{
gshort a = 8, b = 12;
wdouble (pos, from, a, b);
}
static void
wrook (Position *pos, Square from)
{
gshort a = 12, b = 16;
wdouble (pos, from, a, b);
}
static void
wqueen (Position *pos, Square from)
{
gshort a = 8, b = 16;
wdouble (pos, from, a, b);
}
static void
wking (Position *pos, Square from)
{
register Piece piece;
register Square to;
register gshort a;
for (a = 8; a < 16 ; a++) {
to = from + jump[a];
piece = pos->square[to];
switch (piece) {
case EMPTY:
new_move (from, to);
break;
case BORDER:
break;
default:
if (BPIECE (piece))
new_capture_move (from, to);
}
}
}
static void
w_ro_k (Position *pos)
{
if (pos->square[F1] == EMPTY
&& pos->square[G1] == EMPTY
&& pos->square[H1] == WR)
new_move (E1, G1);
}
static void
w_ro_l (Position *pos)
{
if (pos->square[D1] == EMPTY &&
pos->square[C1] == EMPTY &&
pos->square[B1] == EMPTY &&
pos->square[A1] == WR)
new_move (E1, C1);
}
static void
wkingro (Position *pos, Square from)
{
register Square to;
register Piece piece;
register gshort a;
for (a = 8; a < 16 ; a++) {
to = from + jump[a];
piece = pos->square[to];
switch (piece) {
case EMPTY:
new_move (from, to);
break;
case BORDER:
break;
default:
if (BPIECE (piece))
new_capture_move (from, to);
}
}
if (pos->priv->wk_square != E1)
return;
if (!pos->priv->wr_h_move)
w_ro_k (pos);
if (!pos->priv->wr_a_move)
w_ro_l (pos);
}
static void
bdouble (Position *pos, Square from, gshort a, gshort b)
{
Square to, jp;
Piece piece;
for (; a < b; a++) {
to = from;
jp = jump[a];
do {
to += jp;
piece = pos->square[to];
if (piece == EMPTY)
new_move (from, to);
else if (piece == BORDER)
break;
else if (WPIECE (piece)) {
new_capture_move (from, to);
break;
} else {
break;
}
} while (TRUE);
}
}
static void
black_promotion (gshort from, gshort to)
{
register Square new_to;
register gshort i;
for (i = 2; i < 6; i++) {
new_to = 128 + 8 * i + to - A1;
new_capture_move (from, new_to);
}
}
static void
bpawn7 (Position *pos, Square from)
{
register Square to;
to = from - 10;
if (pos->square[to] == EMPTY) {
new_move (from, to);
to = from - 20;
if (pos->square[to] == EMPTY)
new_move (from, to);
}
if (WPIECE (pos->square[from - 9]))
new_capture_move (from, from - 9);
if (WPIECE (pos->square[from - 11]))
new_capture_move (from, from - 11);
}
static void
bpawn6 (Position *pos, Square from)
{
register Square to;
to = from - 10;
if (pos->square[to] == EMPTY)
new_move (from, to);
if (WPIECE (pos->square[from - 9 ]))
new_capture_move (from, from - 9);
if (WPIECE (pos->square[from - 11]))
new_capture_move (from, from - 11);
}
static void
bpawn4 (Position *pos, Square from)
{
bpawn6 (pos, from);
if ((from - 1) == pos->priv->ep)
new_capture_move (from, from - 11);
if ((from + 1) == pos->priv->ep)
new_capture_move (from, from - 9);
}
static void
bpawn2 (Position *pos, Square from)
{
register Square to;
to = from - 10;
if (pos->square[to] == EMPTY)
black_promotion (from, to);
if (WPIECE (pos->square[from - 9]))
black_promotion (from, from - 9);
if (WPIECE (pos->square[from - 11]))
black_promotion (from, from - 11);
}
static void
bknight (Position *pos, Square from)
{
register Square to;
register Piece piece;
register gshort a;
for (a = 0 ; a < 8; a++) {
to = from + jump[a];
piece = pos->square[to];
switch (piece) {
case EMPTY:
new_move (from, to);
break;
case BORDER:
break;
default:
if (WPIECE (piece))
new_capture_move (from, to);
}
}
}
static void
bbishop (Position *pos, Square from)
{
gshort a = 8, b = 12;
bdouble (pos, from, a, b);
}
static void
brook (Position *pos, Square from)
{
gshort a = 12, b = 16;
bdouble (pos, from, a, b);
}
static void
bqueen(Position *pos, Square from)
{
gshort a = 8, b = 16;
bdouble (pos, from, a, b);
}
static void
bking (Position *pos, Square from)
{
register Piece piece;
register Square to;
register gshort a;
for (a = 8; a < 16 ; a++) {
to = from + jump[a];
piece = pos->square[to];
switch (piece) {
case EMPTY:
new_move (from, to);
break;
case BORDER:
break;
default:
if (WPIECE (piece))
new_capture_move (from, to);
}
}
}
static
void b_ro_k (Position *pos)
{
if (pos->square[F8] == EMPTY &&
pos->square[G8] == EMPTY &&
pos->square[H8] == BR)
new_move (E8, G8);
}
static
void b_ro_l (Position *pos)
{
if (pos->square[D8] == EMPTY &&
pos->square[C8] == EMPTY &&
pos->square[B8] == EMPTY &&
pos->square[A8] == BR)
new_move(E8, C8);
}
static void
bkingro (Position *pos, Square from)
{
register Square to;
register Piece piece;
register gshort a;
for (a = 8; a < 16 ; a++) {
to = from + jump[a];
piece = pos->square[to];
switch (piece) {
case EMPTY:
new_move (from, to);
break;
case BORDER:
break;
default:
if (WPIECE (piece))
new_capture_move (from, to);
}
}
if ( pos->priv->bk_square != E8)
return;
if (!pos->priv->br_h_move)
b_ro_k (pos);
if (!pos->priv->br_a_move)
b_ro_l (pos);
}
static int
position_move_generator_white (Position *pos, Square **index0, gshort *anz_s, gshort *anz_n)
{
register Square square;
register Piece piece;
register gshort rank;
nindex = sindex = *index0;
for (rank = 1; rank <= 8; rank++) {
for (square = A1 + ((rank - 1) * 10);
square <= H1 + ((rank - 1) * 10);
square++) {
piece = pos->square[square];
if (!WPIECE (piece))
continue;
switch (piece) {
case WP:
switch (rank) {
case 1:
case 8:
g_assert_not_reached ();
break;
case 2:
wpawn2 (pos, square);
break;
case 3:
case 4:
case 6:
wpawn3 (pos, square);
break;
case 5:
wpawn5 (pos, square);
break;
case 7:
wpawn7 (pos, square);
break;
}
break;
case WN:
wknight (pos, square);
break;
case WB:
wbishop (pos, square);
break;
case WR:
wrook (pos, square);
break;
case WQ:
wqueen (pos, square);
break;
case WK:
if (rank == 1)
wkingro (pos, square);
else
wking (pos, square);
break;
}
}
}
*anz_n = (gshort) ((nindex - *index0) / 2);
*anz_s = (gshort) ((*index0 - sindex) / 2 );
*index0 = sindex;
return *anz_n + *anz_s;
}
static int
position_move_generator_black (Position *pos, Square **index0, gshort *anz_s, gshort *anz_n)
{
register Square square;
register Piece piece;
register gshort rank;
nindex = sindex = *index0;
for (rank = 1; rank <= 8; rank++) {
for (square = A1 + ((rank - 1) * 10);
square <= H1 + ((rank - 1) * 10);
square++ ) {
piece = pos->square[square];
if (!BPIECE (piece))
continue;
switch (piece) {
case BP:
switch (rank) {
case 1:
case 8:
g_assert_not_reached ();
break;
case 2:
bpawn2 (pos, square);
break;
case 3:
case 5:
case 6:
bpawn6 (pos, square);
break;
case 4:
bpawn4 (pos, square);
break;
case 7:
bpawn7 (pos, square);
break;
}
break;
case BN:
bknight (pos, square);
break;
case BB:
bbishop (pos, square);
break;
case BR:
brook (pos, square);
break;
case BQ:
bqueen (pos, square);
break;
case BK:
if (rank == 8)
bkingro (pos, square);
else
bking (pos, square);
break;
}
}
}
*anz_n = (gshort) ((nindex - *index0) / 2);
*anz_s = (gshort) ((*index0 - sindex) / 2);
*index0 = sindex;
return *anz_n + *anz_s;
}
gint
position_move_generator (Position *pos, Square **index0,
gshort *anz_s, gshort *anz_n)
{
if (pos->priv->tomove == WHITE )
return position_move_generator_white (pos, index0, anz_s, anz_n);
else if (pos->priv->tomove == BLACK )
return position_move_generator_black (pos, index0, anz_s, anz_n);
else
abort();
}
/*
* Position Characteristic Functions
*
* A set of functions to give information about the position
* passed in.
*
*/
#define CHECK(king_place,direction,piece1,piece2)\
{ int i= king_place; \
do { i += direction; } \
while(!pos->square[i]); \
if (pos->square[i] == piece1) return piece1; \
if (pos->square[i] == piece2) return piece2; \
}
static int long4 (Position *pos, int ort, int r1, int r2, int r3, int r4, int f1, int f2)
{
CHECK (ort,r1,f1,f2);
CHECK (ort,r2,f1,f2);
CHECK (ort,r3,f1,f2);
CHECK (ort,r4,f1,f2);
return FALSE;
}
#define KURZ_TEST(r) if (pos->square[ort+r] == f1) return f1
static int
short8 (Position *pos, int ort, int r1, int r2, int r3,
int r4, int r5, int r6, int r7, int r8, int f1)
{
KURZ_TEST (r1);
KURZ_TEST (r2);
KURZ_TEST (r3);
KURZ_TEST (r4);
KURZ_TEST (r5);
KURZ_TEST (r6);
KURZ_TEST (r7);
KURZ_TEST (r8);
return FALSE;
}
gboolean
position_white_king_attack (Position *pos)
{
Square k = pos->priv->wk_square;
int ret;
g_return_val_if_fail (pos != NULL, 0);
g_return_val_if_fail (IS_POSITION (pos), 0);
ret = long4 (pos, k, 9, 11, -9, -11, BQ, BB);
if (ret)
return ret;
ret = long4 (pos, k, 1, 10, -10, -1, BQ, BR);
if (ret)
return ret;
if (short8 (pos, k, 8, 12, 19, 21, -8, -12, -19, -21, BN))
return BN;
if (short8 (pos, k, 9, 11, -9, -11, 1, 10, -10, -1, BK))
return BK;
if (pos->square[k+OL] == BP)
return BP;
if (pos->square[k+OR] == BP)
return BP;
return FALSE;
}
gboolean
position_black_king_attack (Position *pos)
{
Square k = pos->priv->bk_square;
int ret;
g_return_val_if_fail (pos != NULL, 0);
g_return_val_if_fail (IS_POSITION (pos), 0);
ret = long4 (pos, k, 9, 11, -9, -11, WQ, WB);
if (ret)
return ret;
ret = long4 (pos, k, 1, 10, -10, -1, WQ, WR);
if (ret)
return ret;
if (short8 (pos, k, 8, 12, 19, 21, -8, -12, -19, -21, WN))
return WN;
if (short8 (pos, k, 9, 11, -9, -11, 1, 10, -10, -1, WK))
return WK;
if (pos->square[k+UL] == WP)
return WP;
if (pos->square[k+UR] == WP)
return WP;
return FALSE;
}
gshort
position_legal_move (Position *pos, Square **zl, gshort *as, gshort *an)
{
Position temp;
Square tomove = pos->priv->tomove;
gboolean check = FALSE;
gshort gen_moves, a;
Square *ap, *ap2;
gshort anz_s, anz_n, legal_moves;
Square zugl[AB_ZUGL];
g_return_val_if_fail (pos != NULL, 0);
g_return_val_if_fail (IS_POSITION (pos), 0);
ap = zugl + AB_ZUG_S;
gen_moves = position_move_generator (pos, &ap, &anz_s, &anz_n);
legal_moves = 0;
ap2 = *zl;
for (a = 0; a < gen_moves; a++) {
temp = *pos;
position_move (pos, *ap, *(ap+1));
switch (tomove) {
case WHITE:
check = position_white_king_attack (pos);
break;
case BLACK:
check = position_black_king_attack (pos);
break;
default:
g_assert_not_reached ();
}
if (!check) {
*ap2++ = *ap++;
*ap2++ = *ap++;
legal_moves++;
} else {
ap += 2;
}
switch (tomove) {
case WHITE:
position_move_reverse_white (pos, *(ap - 2),
*(ap - 1));
break;
case BLACK:
position_move_reverse_black (pos, *(ap - 2),
*(ap - 1));
break;
}
*pos = temp;
}
*as = legal_moves;
*an = 0;
return legal_moves;
}
short
position_last_piece_captured (Position *pos)
{
g_return_val_if_fail (pos != NULL, EMPTY);
g_return_val_if_fail (IS_POSITION (pos), EMPTY);
return pos->priv->captured;
}
short
position_get_color_to_move (Position *pos)
{
g_return_val_if_fail (pos != NULL, NONE);
g_return_val_if_fail (IS_POSITION (pos), NONE);
return pos->priv->tomove;
}
void
position_set_white_king (Position *pos, Square square)
{
g_return_if_fail (pos != NULL);
g_return_if_fail (IS_POSITION (pos));
pos->priv->wk_square = square;
}
void
position_set_black_king (Position *pos, Square square)
{
g_return_if_fail (pos != NULL);
g_return_if_fail (IS_POSITION (pos));
pos->priv->bk_square = square;
}
void
position_set_color_to_move (Position *pos, short color)
{
g_return_if_fail (pos != NULL);
g_return_if_fail (IS_POSITION (pos));
pos->priv->tomove = color;
}