Back to index

gcompris  8.2.2
chess_position.c
Go to the documentation of this file.
00001 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
00002 /* engine.h
00003  *
00004  * Copyright (C) 1999  Robert Wilhelm
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License as
00008  * published by the Free Software Foundation; either version 2 of the
00009  * License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public
00017  * License along with this program; if not, write to the
00018  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019  * Boston, MA 02111-1307, USA.
00020  *
00021  * Authors: Robert Wilhelm
00022  *          JP Rosevear
00023  */
00024 
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include "chess_position.h"
00028 #include "chess_notation.h"
00029 
00030 
00031 struct _PositionPrivate {
00032        Square tomove;               /* Color to move */
00033        gshort wr_a_move;    /* Flag if the white 'a' rook has moved */
00034        gshort wr_h_move;    /* Flag if the white 'h' rook has moved */
00035        Square wk_square;    /* The square the white king is on */
00036        gshort br_a_move;    /* Flag if the black 'a' rook has moved */
00037        gshort br_h_move;       /* Flag if the black 'h' rook has moved */
00038        Square bk_square;    /* The square the black king is on */
00039        gshort ep;            /* En passent */
00040        Piece  captured;     /* Last piece captured */
00041 };
00042 
00043 /* Move generation variables */
00044 static const int jump [] = { 8, 12,19, 21,-8,-12,-19,-21,
00045                           9, 11,-9,-11, 1, 10,-10, -1,
00046                           9, 11, 1, 10,-1,  1, 10, -1,
00047                           -9,-11, 1,-10,-1     };
00048 static Square *nindex, *sindex;
00049 
00050 /* Prototypes */
00051 static void class_init (PositionClass *class);
00052 static void init (Position *pos);
00053 
00054 static void position_set_empty (Position *pos);
00055 
00056 GtkType
00057 position_get_type ()
00058 {
00059        static guint position_type = 0;
00060 
00061        if (!position_type) {
00062               GtkTypeInfo position_info = {
00063                      "Position",
00064                      sizeof (Position),
00065                      sizeof (PositionClass),
00066                      (GtkClassInitFunc) class_init,
00067                      (GtkObjectInitFunc) init,
00068                      (gpointer) NULL,
00069                      (gpointer) NULL,
00070                      (GtkClassInitFunc) NULL
00071               };
00072               position_type = gtk_type_unique (gtk_object_get_type (),
00073                                            &position_info);
00074        }
00075 
00076        return position_type;
00077 }
00078 
00079 static void
00080 finalize (GtkObject *object)
00081 {
00082        Position *pos = (Position *) object;
00083 
00084        g_free (pos->priv);
00085 
00086        pos->priv = NULL;
00087 }
00088 
00089 static void
00090 class_init (PositionClass *class)
00091 {
00092        GtkObjectClass *object_class;
00093 
00094        object_class = (GtkObjectClass*) class;
00095 
00096        object_class->destroy = finalize;
00097 }
00098 
00099 static void
00100 init (Position *pos)
00101 {
00102        pos->priv = g_new0 (PositionPrivate, 1);
00103 
00104        position_set_empty (pos);
00105 }
00106 
00107 GtkObject *
00108 position_new ()
00109 {
00110        return GTK_OBJECT (gtk_type_new (position_get_type ()));
00111 }
00112 
00113 GtkObject *
00114 position_new_initial ()
00115 {
00116        Position *pos;
00117 
00118        pos = POSITION (position_new ());
00119        position_set_initial (pos);
00120 
00121        return GTK_OBJECT (pos);
00122 }
00123 
00124 Position *
00125 position_copy (Position *pos)
00126 {
00127        Position *cpPos;
00128 
00129        cpPos = POSITION (position_new ());
00130 
00131        memcpy (cpPos->priv, pos->priv, sizeof (PositionPrivate));
00132        memcpy (cpPos->square, pos->square, sizeof (gchar) * 120);
00133 
00134        return cpPos;
00135 }
00136 
00137 static void
00138 position_set_empty (Position *pos)
00139 {
00140        unsigned int a;
00141 
00142        for (a = 0 ; a < 120 ; a++)
00143               pos->square [a] = EMPTY;
00144 
00145        for (a = 0; a < 10; a++) {
00146               pos->square [a]          = BORDER;
00147               pos->square [a + 10]     = BORDER;
00148               pos->square [a + 100]    = BORDER;
00149               pos->square [a + 110]    = BORDER;
00150               pos->square [a * 10]     = BORDER;
00151               pos->square [a * 10 + 9] = BORDER;
00152        }
00153 
00154        pos->priv->wk_square = 0;
00155        pos->priv->wr_h_move = 0;
00156        pos->priv->wr_a_move = 0;
00157        pos->priv->bk_square = 0;
00158        pos->priv->br_h_move = 0;
00159        pos->priv->br_a_move = 0;
00160        pos->priv->captured = EMPTY;
00161 
00162        pos->priv->tomove = NONE;
00163 }
00164 
00165 void
00166 position_set_initial (Position *pos)
00167 {
00168        unsigned int a;
00169 
00170        /* The white pieces */
00171        pos->square [A1] = WR;
00172        pos->square [B1] = WN;
00173        pos->square [C1] = WB;
00174        pos->square [D1] = WQ;
00175        pos->square [E1] = WK;
00176        pos->square [F1] = WB;
00177        pos->square [G1] = WN;
00178        pos->square [H1] = WR;
00179 
00180        /* The black pieces */
00181        pos->square [A8] = BR;
00182        pos->square [B8] = BN;
00183        pos->square [C8] = BB;
00184        pos->square [D8] = BQ;
00185        pos->square [E8] = BK;
00186        pos->square [F8] = BB;
00187        pos->square [G8] = BN;
00188        pos->square [H8] = BR;
00189 
00190        /* Pawns on the 2nd and 7th ranks */
00191        for (a = A2; a <= H2 ;a++)
00192               pos->square [a] = WP;
00193        for (a = A7; a <= H7 ;a++)
00194               pos->square [a] = BP;
00195 
00196        /* The rest is blank */
00197        for (a = A3; a <= H3 ;a++)
00198               pos->square [a] = EMPTY;
00199        for (a = A4; a <= H4 ;a++)
00200               pos->square [a] = EMPTY;
00201        for (a = A5; a <= H5 ;a++)
00202               pos->square [a] = EMPTY;
00203        for (a = A6; a <= H6 ;a++)
00204               pos->square [a] = EMPTY;
00205 
00206        /* White to move, white king on E1 and black king on E8 */
00207        pos->priv->wr_a_move = 0;
00208        pos->priv->wr_h_move = 0;
00209        pos->priv->wk_square = E1;
00210        pos->priv->br_a_move = 0;
00211        pos->priv->br_h_move = 0;
00212        pos->priv->bk_square = E8;
00213        pos->priv->captured = EMPTY;
00214        pos->priv->tomove = WHITE;
00215 }
00216 
00217 void
00218 position_set_initial_partyend (Position *pos, int level)
00219 {
00220        register Square square;
00221        register gshort rank;
00222 
00223        for (rank = 1; rank <= 8; rank++) {
00224               for (square = A1 + ((rank - 1) * 10);
00225                    square <= H1 + ((rank - 1) * 10);
00226                    square++) {
00227               pos->square [square] = EMPTY;
00228               }
00229        }
00230 
00231        switch(level) {
00232        case 1:
00233        default:
00234               /* The white pieces */
00235               pos->square [A1] = WK;
00236               pos->square [G1] = WQ;
00237               pos->square [F1] = WQ;
00238 
00239               /* The black pieces */
00240               pos->square [E8] = BK;
00241 
00242               /* The kings */
00243               pos->priv->wk_square = A1;
00244               pos->priv->bk_square = E8;
00245               break;
00246        case 2:
00247               /* The white pieces */
00248               pos->square [E1] = WK;
00249               pos->square [F1] = WR;
00250               pos->square [G1] = WR;
00251 
00252               /* The black pieces */
00253               pos->square [A8] = BK;
00254 
00255               /* The kings */
00256               pos->priv->wk_square = E1;
00257               pos->priv->bk_square = A8;
00258               break;
00259        case 3:
00260               /* The white pieces */
00261               pos->square [E1] = WK;
00262               pos->square [B4] = WR;
00263               pos->square [B5] = WB;
00264 
00265               /* The black pieces */
00266               pos->square [A1] = BK;
00267 
00268               /* The kings */
00269               pos->priv->wk_square = E1;
00270               pos->priv->bk_square = A1;
00271               break;
00272        }
00273 
00274        /* White to move */
00275        pos->priv->wr_a_move = 0;
00276        pos->priv->wr_h_move = 0;
00277        pos->priv->br_a_move = 0;
00278        pos->priv->br_h_move = 0;
00279        pos->priv->captured = EMPTY;
00280        pos->priv->tomove = WHITE;
00281 }
00282 
00283 void
00284 position_set_initial_movelearn (Position *pos, int level)
00285 {
00286        register Square square;
00287        register gshort rank;
00288 
00289        for (rank = 1; rank <= 8; rank++) {
00290               for (square = A1 + ((rank - 1) * 10);
00291                    square <= H1 + ((rank - 1) * 10);
00292                    square++) {
00293               pos->square [square] = EMPTY;
00294               }
00295        }
00296 
00297        switch(level) {
00298        case 1:
00299        default:
00300               /* The white pieces */
00301               pos->square [E1] = WK;
00302               pos->square [B4] = WR;
00303 
00304               /* The black pieces */
00305               pos->square [A1] = BK;
00306               pos->square [E7] = BP;
00307 
00308               /* The kings */
00309               pos->priv->wk_square = E1;
00310               pos->priv->bk_square = A1;
00311               break;
00312        case 2:
00313               /* The white pieces */
00314               pos->square [E1] = WK;
00315               pos->square [G1] = WQ;
00316 
00317               /* The black pieces */
00318               pos->square [A1] = BK;
00319               pos->square [E7] = BP;
00320 
00321               /* The kings */
00322               pos->priv->wk_square = E1;
00323               pos->priv->bk_square = A1;
00324               break;
00325        case 3:
00326               /* The white pieces */
00327               pos->square [E1] = WK;
00328               pos->square [C4] = WB;
00329               pos->square [C5] = WB;
00330 
00331               /* The black pieces */
00332               pos->square [A1] = BK;
00333               pos->square [E7] = BP;
00334 
00335               /* The kings */
00336               pos->priv->wk_square = E1;
00337               pos->priv->bk_square = A1;
00338               break;
00339        case 4:
00340               /* The white pieces */
00341               pos->square [E1] = WK;
00342               pos->square [B4] = WN;
00343               pos->square [B5] = WN;
00344 
00345               /* The black pieces */
00346               pos->square [A1] = BK;
00347               pos->square [E7] = BP;
00348 
00349               /* The kings */
00350               pos->priv->wk_square = E1;
00351               pos->priv->bk_square = A1;
00352               break;
00353        case 5:
00354               /* The white pieces */
00355               pos->square [E1] = WK;
00356               pos->square [D2] = WP;
00357               pos->square [E2] = WP;
00358               pos->square [F2] = WP;
00359               pos->square [G2] = WP;
00360               pos->square [H2] = WP;
00361 
00362               /* The black pieces */
00363               pos->square [A1] = BK;
00364               pos->square [E7] = BP;
00365 
00366               /* The kings */
00367               pos->priv->wk_square = E1;
00368               pos->priv->bk_square = A1;
00369               break;
00370        }
00371 
00372        /* White to move */
00373        pos->priv->wr_a_move = 0;
00374        pos->priv->wr_h_move = 0;
00375        pos->priv->br_a_move = 0;
00376        pos->priv->br_h_move = 0;
00377        pos->priv->captured = EMPTY;
00378        pos->priv->tomove = WHITE;
00379 }
00380 
00381 /* Debug purpose */
00382 void
00383 position_display (Position *pos)
00384 {
00385   register Square square;
00386   register gshort rank;
00387 
00388   for (rank = 8; rank >= 1; rank--) {
00389     for (square = A1 + ((rank - 1) * 10);
00390         square <= H1 + ((rank - 1) * 10);
00391         square++) {
00392 
00393            g_warning("%c ", piece_to_ascii(pos->square [square]));
00394     }
00395     g_warning("\n");
00396   }
00397 }
00398 /*
00399  * Move Functions
00400  *
00401  * A set of functions to make a move in the context of the position
00402  * passed in.
00403  */
00404 static void
00405 position_move_white_castle_short (Position *pos)
00406 {
00407         pos->square [E1] = pos->square [H1] = EMPTY;
00408         pos->square [F1] = WR;
00409         pos->square [G1] = WK;
00410 }
00411 
00412 static void
00413 position_move_white_castle_long (Position *pos)
00414 {
00415         pos->square [E1] = pos->square [A1] = EMPTY;
00416         pos->square [C1] = WK;
00417         pos->square [D1] = WR;
00418 }
00419 
00420 static void
00421 position_move_black_castle_short (Position *pos)
00422 {
00423         pos->square [E8] = pos->square [H8] = EMPTY;
00424         pos->square [F8] = BR;
00425         pos->square [G8] = BK;
00426  }
00427 
00428 static void
00429 position_move_black_castle_long (Position *pos)
00430 {
00431         pos->square [E8] = pos->square [A8] = EMPTY;
00432         pos->square [C8] = BK;
00433         pos->square [D8] = BR;
00434 }
00435 
00436 static void
00437 position_move_white (Position *pos, Square from, Square to)
00438 {
00439        Piece piece;
00440        Square new_to;
00441 
00442        piece = pos->square [from];
00443 
00444        switch (piece) {
00445        case WP :
00446               /* If we are promoting a pawn */
00447               if (to & 128) {
00448                      new_to = (to & 7) + A8;
00449                      piece = ((to & 127) >> 3 ) + WP - 1;
00450 
00451                      pos->priv->captured = pos->square [new_to];
00452                      pos->square [from]  = EMPTY;
00453                      pos->square [new_to] = piece;
00454                      pos->priv->ep = EMPTY;
00455                      return;
00456               }
00457 
00458               /* If we are capturing en passent */
00459               if ((to - from) != 10) {
00460                      if((to - from) != 20) {
00461                             if(pos->square [to] == EMPTY) {
00462                                    pos->square [to - 10] = EMPTY;
00463                                    pos->priv->ep = EMPTY;
00464                                    pos->square [to] = piece;
00465                                    pos->square [from] = EMPTY;
00466                                    pos->priv->captured = EMPTY;
00467                                    return;
00468                             }
00469                      }
00470               }
00471 
00472               pos->priv->captured = pos->square [to];
00473               pos->square [to]   = piece;
00474               pos->square [from] = EMPTY;
00475 
00476               if ((to - from) == 20)
00477                      pos->priv->ep = to;
00478               else
00479                      pos->priv->ep = EMPTY;
00480               return;
00481 
00482        case WK :
00483               pos->priv->ep = EMPTY;
00484               pos->priv->wk_square = to;
00485               pos->priv->wr_a_move += 1;
00486               pos->priv->wr_h_move += 1;
00487 
00488               /*  If we are not castling */
00489               if (from != E1 || abs (to - from) != 2) {
00490                      pos->priv->captured = pos->square [to];
00491                      pos->square [to]   = piece;
00492                      pos->square [from] = EMPTY;
00493                      return;
00494               }
00495 
00496               /*  If we are castling */
00497               switch (to) {
00498               case G1 :
00499                      position_move_white_castle_short (pos);
00500                      break;
00501               case C1 :
00502                      position_move_white_castle_long (pos);
00503                      break;
00504               default :
00505                      abort ();
00506               }
00507               return;
00508 
00509        default :
00510               pos->priv->ep = EMPTY;
00511               pos->priv->captured = pos->square [to];
00512               pos->square [to] = piece;
00513               pos->square [from]  = EMPTY;
00514 
00515               /* Indicate if a rook has moved */
00516               if (piece == WR && from == A1)
00517                      pos->priv->wr_a_move += 1;
00518               if (piece == WR && from == H1)
00519                      pos->priv->wr_h_move += 1;
00520               return;
00521        }
00522 }
00523 
00524 static void
00525 position_move_black (Position *pos, Square from, Square to)
00526 {
00527        gshort piece, new_to;
00528 
00529        piece = pos->square [from];
00530 
00531        switch (piece) {
00532        case BP :
00533               /* If we are promoting a pawn */
00534               if (to & 128) {
00535                      new_to = (to & 7) + A1;
00536                      piece = ((to & 127) >> 3) + BP - 1;
00537 
00538                      pos->priv->captured = pos->square [new_to];
00539                      pos->square [from]  = EMPTY;
00540                      pos->square [new_to] = piece;
00541                      pos->priv->ep = EMPTY;
00542                      return;
00543               }
00544 
00545               /* If we are capturing en passent */
00546               if ((from - to) != 10) {
00547                      if ((from - to) != 20) {
00548                             if (pos->square [to] == EMPTY) {
00549                                    pos->square [to + 10] = EMPTY;
00550                                    pos->priv->ep = EMPTY;
00551                                    pos->square [to] = piece;
00552                                    pos->square [from] = EMPTY;
00553                                    pos->priv->captured = EMPTY;
00554                                    return;
00555                             }
00556                      }
00557               }
00558 
00559               pos->priv->captured = pos->square [to];
00560               pos->square [to] = piece;
00561               pos->square [from] = EMPTY;
00562 
00563               if ((from - to) == 20)
00564                      pos->priv->ep = to;
00565               else
00566                      pos->priv->ep = EMPTY;
00567               return;
00568 
00569        case BK :
00570               pos->priv->ep = EMPTY;
00571               pos->priv->bk_square = to;
00572               pos->priv->br_a_move += 1;
00573               pos->priv->br_h_move += 1;
00574 
00575               /*  If we are not castling */
00576               if (from != E8 || abs (to - from) != 2) {
00577                      pos->priv->captured = pos->square [to];
00578                      pos->square [to] = piece;
00579                      pos->square [from]  = EMPTY;
00580                      return;
00581               }
00582 
00583               /*  If we are castling */
00584               switch (to) {
00585               case G8 :
00586                      position_move_black_castle_short (pos);
00587                      break;
00588               case C8 :
00589                      position_move_black_castle_long (pos);
00590                      break;
00591               default :
00592                      abort();
00593               }
00594               return;
00595 
00596        default :
00597               pos->priv->ep = EMPTY;
00598               pos->priv->captured = pos->square [to];
00599               pos->square [to]   = piece;
00600               pos->square [from] = EMPTY;
00601 
00602               /* Indicate if a rook has moved */
00603               if (piece == BR && from == A8)
00604                      pos->priv->br_a_move += 1;
00605               if (piece == BR && from == H8)
00606                      pos->priv->br_h_move += 1;
00607               return;
00608        }
00609 }
00610 
00611 void
00612 position_move (Position *pos, Square from, Square to)
00613 {
00614        switch (pos->priv->tomove) {
00615               case WHITE:
00616                      position_move_white (pos, from, to);
00617                      pos->priv->tomove = BLACK;
00618                      break;
00619               case BLACK:
00620                      position_move_black (pos, from, to);
00621                      pos->priv->tomove = WHITE;
00622                      break;
00623               default:
00624                      g_assert_not_reached ();
00625        }
00626 }
00627 
00628 static Square
00629 position_move_normalize_promotion (Position *pos, Square to, gshort n1,
00630                                gshort n2, gshort n3, gshort n4)
00631 {
00632        Square help;
00633        Piece fi = EMPTY;
00634        gshort c;
00635 
00636         if  (pos->priv->tomove == WHITE)
00637               help = to - A8;
00638         else
00639               help = to - A1;
00640 
00641         if (help == (n1 & 7)) {
00642               /* Automatic queen promotion prefs_get_promotetoqueen */
00643               c = 0;
00644 
00645               if (pos->priv->tomove == WHITE)
00646                      switch (c) {
00647                      case 0 : fi = WQ; break;
00648                      case 1 : fi = WR; break;
00649                      case 2 : fi = WB; break;
00650                      case 3 : fi = WN; break;
00651                      }
00652               else
00653                      switch (c) {
00654                      case 0 : fi = BQ; break;
00655                      case 1 : fi = BR; break;
00656                      case 2 : fi = BB; break;
00657                      case 3 : fi = BN; break;
00658                      }
00659 
00660               if (pos->priv->tomove == WHITE)
00661                      help = 128 + to - A8 + (fi - WP + 1) * 8;
00662               else
00663                      help = 128 + to - A1 + (fi - BP + 1) * 8;
00664 
00665               if (help == n1)
00666                      return n1;
00667               if (help == n2)
00668                      return n2;
00669               if (help == n3)
00670                      return n3;
00671               if (help == n4)
00672                      return n4;
00673 
00674         }
00675         return FALSE;
00676 }
00677 
00678 Square
00679 position_move_normalize (Position *pos, Square from, Square to)
00680 {
00681        gshort legal_moves, anz_n, anz_s;
00682        Square movelist [AB_ZUGL];
00683        Square *ap, *aq, ret;
00684        gshort i;
00685 
00686        ap =  movelist + AB_ZUG_S;
00687        legal_moves = position_legal_move (pos, &ap, &anz_s, &anz_n);
00688 
00689        for (aq = ap, i = 0; i < legal_moves; i++, aq += 2 ) {
00690               if (from == *aq) {
00691                      if (to == *(aq + 1))
00692                             return to;
00693                      else if (*(aq + 1) & 128) {
00694                                 /* Promotion */
00695                             ret = position_move_normalize_promotion (
00696                                    pos, to, *(aq + 1), *(aq + 3),
00697                                    *(aq + 5), *(aq + 7));
00698                             if (ret)
00699                                    return ret;
00700                             aq += 6; /* skip 3 moves */
00701                      }
00702               }
00703        }
00704 
00705        return FALSE;
00706 }
00707 
00708 /*
00709  * Move Reverse Functions
00710  *
00711  * A set of functions to reverse a previous move in the context of the position
00712  * passed in.
00713  *
00714  */
00715 static void
00716 position_move_reverse_castling_white_short (Position *pos)
00717 {
00718         pos->square [E1] = WK;
00719         pos->square [F1] = pos->square [G1] = EMPTY;
00720         pos->square [H1] = WR;
00721 }
00722 
00723 static void
00724 position_move_reverse_castling_white_long (Position *pos)
00725 {
00726         pos->square [A1] = WR;
00727         pos->square [C1] = pos->square [D1] = EMPTY;
00728         pos->square [E1] = WK;
00729 }
00730 
00731 static void
00732 position_move_reverse_castling_black_short (Position *pos)
00733 {
00734         pos->square [E8] = BK;
00735         pos->square [F8] = pos->square [G8] = EMPTY;
00736         pos->square [H8] = BR;
00737 }
00738 
00739 static void
00740 position_move_reverse_castling_black_long (Position *pos)
00741 {
00742         pos->square [A8] = BR;
00743         pos->square [D8] = pos->square [C8] = EMPTY;
00744         pos->square [E8] = BK;
00745 }
00746 
00747 static void
00748 position_move_reverse_promotion_white (Position *pos, Square from, Square to)
00749 {
00750        pos->square [from] = WP;
00751        pos->square [(to & 7) + A8] = pos->priv->captured;
00752 }
00753 
00754 static void
00755 position_move_reverse_promotion_black (Position *pos, Square from, Square to)
00756 {
00757        pos->square [from] = BP;
00758        pos->square [(to & 7) + A1] = pos->priv->captured;
00759 }
00760 
00761 void
00762 position_move_reverse_white (Position *pos, Square from, Square to)
00763 {
00764        Piece fi;
00765 
00766        pos->priv->tomove = WHITE; /* change tomove */
00767 
00768        if (to & 128) {
00769                 /* Promotion */
00770               position_move_reverse_promotion_white (pos, from, to);
00771               return;
00772        }
00773 
00774         fi = pos->square[to];
00775 
00776         /*    look for castling   */
00777         if (fi == WK) {
00778               pos->priv->wk_square = from;
00779               pos->priv->wr_a_move -= 1;
00780               pos->priv->wr_h_move -= 1;
00781 
00782               if (from != E1)  {  /*    no castling   */
00783                             pos->square[from]  = fi;
00784                             pos->square[to] = pos->priv->captured;
00785                             return;
00786               }
00787               if (abs (from - to) != 2)  {  /*  no castling  */
00788                             pos->square[from]  = fi;
00789                             pos->square[to] = pos->priv->captured;
00790                             return;
00791               }
00792 
00793               if (to == G1) {
00794                      position_move_reverse_castling_white_short (pos);
00795                      return;
00796               } else if (to == C1) {
00797                      position_move_reverse_castling_white_long (pos);
00798                      return;
00799               }
00800               abort();
00801        }
00802 
00803        if (fi == WR && from == A1)
00804               pos->priv->wr_a_move -= 1;
00805        if (fi == WR && from == H1)
00806               pos->priv->wr_h_move -= 1;
00807 
00808         if (fi == WP) {
00809               if ((to - from) != 10) {
00810                      if ((to - from) != 20) {
00811                             if (pos->priv->captured == EMPTY) {
00812                                    pos->square [to - 10] = BP;
00813                                    pos->square [to] = EMPTY;
00814                                    pos->square [from] = WP;
00815                                     return;
00816                             }
00817                      }
00818               }
00819               pos->square [from] = fi;
00820               pos->square [to] = pos->priv->captured;
00821               return;
00822        }
00823         pos->square [from]  = fi;
00824         pos->square [to] = pos->priv->captured;
00825 }
00826 
00827 void
00828 position_move_reverse_black (Position *pos, Square from, Square to)
00829 {
00830        int fi;
00831 
00832        pos->priv->tomove = BLACK;      /* change tomove */
00833 
00834        if (to & 128) {
00835                 /* Promotion */
00836               position_move_reverse_promotion_black (pos, from, to);
00837               return;
00838        }
00839 
00840         fi = pos->square[to];
00841 
00842         /* look for castling */
00843         if (fi == BK) {
00844               pos->priv->bk_square = from;
00845               pos->priv->br_a_move -= 1;
00846               pos->priv->br_h_move -= 1;
00847 
00848               if (from != E8)  {  /*    no castling   */
00849                             pos->square[from]  = fi;
00850                             pos->square[to] = pos->priv->captured;
00851                             return;
00852               }
00853               if (abs (from - to) != 2)  {  /*    no castling  */
00854                             pos->square[from]  = fi;
00855                             pos->square[to] = pos->priv->captured;
00856                             return;
00857               }
00858 
00859               if (to == G8) {
00860                      position_move_reverse_castling_black_short (pos);
00861                      return;
00862               } else if (to == C8) {
00863                      position_move_reverse_castling_black_long (pos);
00864                      return;
00865               }
00866               abort ();
00867        }
00868 
00869        if (fi == BR && from == A8)
00870               pos->priv->br_a_move -= 1;
00871        if (fi == BR && from == H8)
00872               pos->priv->br_h_move -= 1;
00873 
00874         if (fi == BP) {
00875               if ((from - to) != 10) {
00876                      if ((from - to) !=20) {
00877                             if (pos->priv->captured == EMPTY) {
00878                                    pos->square[to+10] = WP;
00879                                    pos->square[to] = EMPTY;
00880                                    pos->square[from] = BP;
00881                                     return;
00882                             }
00883                      }
00884               }
00885               pos->square [from] = fi;
00886               pos->square [to]= pos->priv->captured;
00887               return;
00888        }
00889        pos->square [from]  = fi;
00890         pos->square [to] = pos->priv->captured;
00891 }
00892 
00893 void
00894 position_move_reverse (Position *pos, Square from, Square to)
00895 {
00896        switch (pos->priv->tomove) {
00897               case WHITE:
00898                      position_move_reverse_black (pos, from, to);
00899                      break;
00900               case BLACK:
00901                      position_move_reverse_white (pos, from, to);
00902                      break;
00903               default:
00904                      g_assert_not_reached ();
00905        }
00906 }
00907 
00908 /*
00909  * Move Generation Functions
00910  *
00911  * A set of functions to generate moves in the context of the position
00912  * passed in.
00913  *
00914  */
00915 
00916 static void inline
00917 new_move (Square from, Square to)
00918 {
00919        *nindex = from;
00920        *(nindex + 1) = to;
00921        nindex += 2;
00922 }
00923 
00924 static void
00925 new_capture_move (Square from, Square to)
00926 {
00927        sindex -= 2;
00928        *sindex = from;
00929        *(sindex + 1) = to;
00930 }
00931 
00932 static void
00933 wdouble (Position *pos, Square from, gshort a, gshort b)
00934 {
00935        Square to, jp;
00936        Piece piece;
00937 
00938 
00939        for (; a < b; a++) {
00940               to = from;
00941               jp = jump[a];
00942 
00943               do {
00944                      to += jp;
00945                      piece  = pos->square[to];
00946 
00947                      if (piece == EMPTY)
00948                             new_move (from, to);
00949                      else if (piece == BORDER)
00950                             break;
00951                      else if (BPIECE (piece)) {
00952                             new_capture_move (from, to);
00953                             break;
00954                      } else {
00955                             break;
00956                      }
00957               } while (TRUE);
00958         }
00959 }
00960 
00961 static void
00962 white_promotion (Square from, Square to)
00963 {
00964        register Square new_to;
00965        register gshort i;
00966 
00967        for (i = 2; i < 6; i++) {
00968               new_to = 128 + 8 * i + to - A8;
00969               new_capture_move (from, new_to);
00970        }
00971 }
00972 
00973 static void
00974 wpawn2 (Position *pos, Square from)
00975 {
00976        register Square to;
00977 
00978        to = from + 10;
00979        if (pos->square[to] == EMPTY ) {
00980               new_move (from, to);
00981                to = from + 20;
00982               if (pos->square[to] == EMPTY )
00983                      new_move (from, to);
00984        }
00985 
00986        if (BPIECE (pos->square[from + 9]))
00987               new_capture_move (from, from + 9);
00988        if (BPIECE (pos->square[from +11]))
00989               new_capture_move (from, from + 11);
00990 }
00991 
00992 static void
00993 wpawn3 (Position *pos, Square from)
00994 {
00995        register Square to;
00996 
00997        to = from + 10;
00998        if (pos->square[to] == EMPTY)
00999               new_move (from, to);
01000 
01001        if (BPIECE (pos->square[from + 9]))
01002               new_capture_move (from, from + 9);
01003        if (BPIECE (pos->square[from + 11]))
01004               new_capture_move (from, from + 11);
01005 }
01006 
01007 static void
01008 wpawn5 (Position *pos, Square from)
01009 {
01010        wpawn3 (pos, from);
01011 
01012        if ((from - 1) == pos->priv->ep)
01013               new_capture_move (from, from + 9);
01014        else if ((from + 1) == pos->priv->ep)
01015               new_capture_move (from, from + 11);
01016 }
01017 
01018 static void
01019 wpawn7 (Position *pos, Square from)
01020 {
01021        register Square to;
01022 
01023        to = from + 10;
01024        if (pos->square[to] == EMPTY )
01025               white_promotion (from, to);
01026 
01027        if (BPIECE (pos->square[from + 9]))
01028               white_promotion (from, from + 9);
01029        if (BPIECE (pos->square[from + 11]))
01030               white_promotion (from, from + 11);
01031 }
01032 
01033 static void
01034 wknight (Position *pos, gshort from)
01035 {
01036        register Square to;
01037        register Piece piece;
01038        register gshort a;
01039 
01040        for (a = 0; a < 8; a++) {
01041               to = from + jump[a];
01042               piece = pos->square[to];
01043 
01044               switch (piece) {
01045                      case EMPTY:
01046                             new_move (from, to);
01047                             break;
01048                      case BORDER:
01049                             break;
01050                      default:
01051                             if (BPIECE (piece))
01052                                    new_capture_move (from, to);
01053               }
01054        }
01055 }
01056 
01057 static void
01058 wbishop (Position *pos, Square from)
01059 {
01060        gshort a = 8, b = 12;
01061 
01062        wdouble (pos, from, a, b);
01063 }
01064 
01065 static void
01066 wrook (Position *pos, Square from)
01067 {
01068        gshort a = 12, b = 16;
01069 
01070        wdouble (pos, from, a, b);
01071 }
01072 
01073 static void
01074 wqueen (Position *pos, Square from)
01075 {
01076        gshort a = 8, b = 16;
01077 
01078        wdouble (pos, from, a, b);
01079 }
01080 
01081 static void
01082 wking (Position *pos, Square from)
01083 {
01084        register Piece piece;
01085        register Square to;
01086        register gshort a;
01087 
01088        for (a = 8; a < 16 ; a++) {
01089               to = from + jump[a];
01090               piece = pos->square[to];
01091 
01092               switch (piece) {
01093                      case EMPTY:
01094                             new_move (from, to);
01095                             break;
01096                      case BORDER:
01097                             break;
01098                      default:
01099                             if (BPIECE (piece))
01100                                    new_capture_move (from, to);
01101               }
01102        }
01103 }
01104 
01105 static void
01106 w_ro_k (Position *pos)
01107 {
01108        if (pos->square[F1] == EMPTY
01109            && pos->square[G1] == EMPTY
01110            && pos->square[H1] == WR)
01111               new_move (E1, G1);
01112 }
01113 
01114 static void
01115 w_ro_l (Position *pos)
01116 {
01117        if (pos->square[D1] == EMPTY &&
01118            pos->square[C1] == EMPTY &&
01119            pos->square[B1] == EMPTY &&
01120            pos->square[A1] == WR)
01121               new_move (E1, C1);
01122 }
01123 
01124 static void
01125 wkingro (Position *pos, Square from)
01126 {
01127        register Square to;
01128        register Piece piece;
01129        register gshort a;
01130 
01131        for (a = 8; a < 16 ; a++) {
01132               to = from + jump[a];
01133               piece = pos->square[to];
01134 
01135               switch (piece) {
01136               case EMPTY:
01137                      new_move (from, to);
01138                      break;
01139               case BORDER:
01140                      break;
01141               default:
01142                      if (BPIECE (piece))
01143                             new_capture_move (from, to);
01144               }
01145        }
01146 
01147        if (pos->priv->wk_square != E1)
01148               return;
01149        if (!pos->priv->wr_h_move)
01150               w_ro_k (pos);
01151        if (!pos->priv->wr_a_move)
01152               w_ro_l (pos);
01153 }
01154 
01155 static void
01156 bdouble (Position *pos, Square from, gshort a, gshort b)
01157 {
01158        Square to, jp;
01159        Piece piece;
01160 
01161         for (; a < b; a++) {
01162               to = from;
01163               jp = jump[a];
01164 
01165               do {
01166                      to += jp;
01167                         piece  = pos->square[to];
01168 
01169                      if (piece == EMPTY)
01170                             new_move (from, to);
01171                      else if (piece == BORDER)
01172                             break;
01173                      else if (WPIECE (piece)) {
01174                             new_capture_move (from, to);
01175                             break;
01176                      } else {
01177                             break;
01178                      }
01179                 } while (TRUE);
01180         }
01181 }
01182 
01183 static void
01184 black_promotion (gshort from, gshort to)
01185 {
01186        register Square new_to;
01187        register gshort i;
01188 
01189        for (i = 2; i < 6; i++) {
01190               new_to = 128 + 8 * i + to - A1;
01191               new_capture_move (from, new_to);
01192        }
01193 }
01194 
01195 static void
01196 bpawn7 (Position *pos, Square from)
01197 {
01198        register Square to;
01199 
01200        to = from - 10;
01201        if (pos->square[to] == EMPTY) {
01202               new_move (from, to);
01203               to = from - 20;
01204               if (pos->square[to] == EMPTY)
01205                      new_move (from, to);
01206        }
01207 
01208        if (WPIECE (pos->square[from - 9]))
01209               new_capture_move (from, from - 9);
01210        if (WPIECE (pos->square[from - 11]))
01211               new_capture_move (from, from - 11);
01212 }
01213 
01214 static void
01215 bpawn6 (Position *pos, Square from)
01216 {
01217        register Square to;
01218 
01219        to = from - 10;
01220        if (pos->square[to] == EMPTY)
01221               new_move (from, to);
01222 
01223        if (WPIECE (pos->square[from - 9 ]))
01224               new_capture_move (from, from - 9);
01225        if (WPIECE (pos->square[from - 11]))
01226               new_capture_move (from, from - 11);
01227 }
01228 
01229 static void
01230 bpawn4 (Position *pos, Square from)
01231 {
01232        bpawn6 (pos, from);
01233 
01234        if ((from - 1) == pos->priv->ep)
01235               new_capture_move (from, from - 11);
01236        if ((from + 1) == pos->priv->ep)
01237               new_capture_move (from, from - 9);
01238 }
01239 
01240 static void
01241 bpawn2 (Position *pos, Square from)
01242 {
01243        register Square to;
01244 
01245        to = from - 10;
01246        if (pos->square[to] == EMPTY)
01247               black_promotion (from, to);
01248 
01249        if (WPIECE (pos->square[from - 9]))
01250               black_promotion (from, from - 9);
01251        if (WPIECE (pos->square[from - 11]))
01252               black_promotion (from, from - 11);
01253 }
01254 
01255 static void
01256 bknight (Position *pos, Square from)
01257 {
01258        register Square to;
01259        register Piece piece;
01260        register gshort a;
01261 
01262        for (a = 0 ; a < 8; a++) {
01263               to = from + jump[a];
01264               piece = pos->square[to];
01265 
01266               switch (piece) {
01267                      case EMPTY:
01268                             new_move (from, to);
01269                             break;
01270                      case BORDER:
01271                             break;
01272                      default:
01273                             if (WPIECE (piece))
01274                                    new_capture_move (from, to);
01275               }
01276        }
01277 }
01278 
01279 static void
01280 bbishop (Position *pos, Square from)
01281 {
01282        gshort a = 8, b = 12;
01283 
01284        bdouble (pos, from, a, b);
01285 }
01286 
01287 static void
01288 brook (Position *pos, Square from)
01289 {
01290        gshort a = 12, b = 16;
01291 
01292        bdouble (pos, from, a, b);
01293 }
01294 
01295 static void
01296 bqueen(Position *pos, Square from)
01297 {
01298        gshort a = 8, b = 16;
01299 
01300        bdouble (pos, from, a, b);
01301 }
01302 
01303 static void
01304 bking (Position *pos, Square from)
01305 {
01306        register Piece piece;
01307        register Square to;
01308        register gshort a;
01309 
01310        for (a = 8; a < 16 ; a++) {
01311               to = from + jump[a];
01312               piece = pos->square[to];
01313 
01314               switch (piece) {
01315                      case EMPTY:
01316                             new_move (from, to);
01317                             break;
01318                      case BORDER:
01319                             break;
01320                      default:
01321                             if (WPIECE (piece))
01322                                    new_capture_move (from, to);
01323               }
01324        }
01325 }
01326 
01327 static
01328 void b_ro_k (Position *pos)
01329 {
01330        if (pos->square[F8] == EMPTY &&
01331            pos->square[G8] == EMPTY &&
01332            pos->square[H8] == BR)
01333               new_move (E8, G8);
01334 
01335 }
01336 
01337 static
01338 void b_ro_l (Position *pos)
01339 {
01340        if (pos->square[D8] == EMPTY &&
01341            pos->square[C8] == EMPTY &&
01342            pos->square[B8] == EMPTY &&
01343            pos->square[A8] == BR)
01344               new_move(E8, C8);
01345 }
01346 
01347 static void
01348 bkingro (Position *pos, Square from)
01349 {
01350        register Square to;
01351        register Piece piece;
01352        register gshort a;
01353 
01354        for (a = 8; a < 16 ; a++) {
01355               to = from + jump[a];
01356               piece = pos->square[to];
01357 
01358               switch (piece) {
01359               case EMPTY:
01360                      new_move (from, to);
01361                      break;
01362               case BORDER:
01363                      break;
01364               default:
01365                      if (WPIECE (piece))
01366                             new_capture_move (from, to);
01367               }
01368        }
01369 
01370        if ( pos->priv->bk_square != E8)
01371               return;
01372        if (!pos->priv->br_h_move)
01373               b_ro_k (pos);
01374        if (!pos->priv->br_a_move)
01375               b_ro_l (pos);
01376 }
01377 
01378 static int
01379 position_move_generator_white (Position *pos, Square **index0, gshort *anz_s, gshort *anz_n)
01380 {
01381        register Square square;
01382        register Piece piece;
01383        register gshort rank;
01384 
01385        nindex = sindex = *index0;
01386 
01387        for (rank = 1; rank <= 8; rank++) {
01388               for (square = A1 + ((rank - 1) * 10);
01389                    square <= H1 + ((rank - 1) * 10);
01390                    square++) {
01391                      piece = pos->square[square];
01392 
01393                      if (!WPIECE (piece))
01394                             continue;
01395 
01396                      switch (piece) {
01397                      case WP:
01398                             switch (rank) {
01399                             case 1:
01400                             case 8:
01401                                    g_assert_not_reached ();
01402                                    break;
01403                             case 2:
01404                                    wpawn2 (pos, square);
01405                                    break;
01406                             case 3:
01407                             case 4:
01408                             case 6:
01409                                    wpawn3 (pos, square);
01410                                    break;
01411                             case 5:
01412                                    wpawn5 (pos, square);
01413                                    break;
01414                             case 7:
01415                                    wpawn7 (pos, square);
01416                                    break;
01417                             }
01418                             break;
01419                      case WN:
01420                             wknight (pos, square);
01421                             break;
01422                      case WB:
01423                             wbishop (pos, square);
01424                             break;
01425                      case WR:
01426                             wrook (pos, square);
01427                             break;
01428                      case WQ:
01429                             wqueen (pos, square);
01430                             break;
01431                      case WK:
01432                             if (rank == 1)
01433                                    wkingro (pos, square);
01434                             else
01435                                    wking (pos, square);
01436                             break;
01437                      }
01438               }
01439        }
01440 
01441        *anz_n = (gshort) ((nindex  - *index0) / 2);
01442        *anz_s = (gshort) ((*index0 - sindex) / 2 );
01443        *index0 = sindex;
01444 
01445        return *anz_n + *anz_s;
01446 }
01447 
01448 static int
01449 position_move_generator_black (Position *pos, Square **index0, gshort *anz_s, gshort *anz_n)
01450 {
01451        register Square square;
01452        register Piece piece;
01453        register gshort rank;
01454 
01455        nindex = sindex = *index0;
01456 
01457        for (rank = 1; rank <= 8; rank++) {
01458               for (square = A1 + ((rank - 1) * 10);
01459                    square <= H1 + ((rank - 1) * 10);
01460                    square++ ) {
01461                      piece = pos->square[square];
01462                      if (!BPIECE (piece))
01463                             continue;
01464 
01465                      switch (piece)   {
01466                      case BP:
01467                             switch (rank) {
01468                             case 1:
01469                             case 8:
01470                                    g_assert_not_reached ();
01471                                    break;
01472                             case 2:
01473                                    bpawn2 (pos, square);
01474                                    break;
01475                             case 3:
01476                             case 5:
01477                             case 6:
01478                                    bpawn6 (pos, square);
01479                                    break;
01480                             case 4:
01481                                    bpawn4 (pos, square);
01482                                    break;
01483                             case 7:
01484                                    bpawn7 (pos, square);
01485                                    break;
01486                             }
01487                             break;
01488                      case BN:
01489                             bknight (pos, square);
01490                             break;
01491                      case BB:
01492                             bbishop (pos, square);
01493                             break;
01494                      case BR:
01495                             brook (pos, square);
01496                             break;
01497                      case BQ:
01498                             bqueen (pos, square);
01499                             break;
01500                      case BK:
01501                             if (rank == 8)
01502                                    bkingro (pos, square);
01503                             else
01504                                    bking (pos, square);
01505                             break;
01506                      }
01507               }
01508        }
01509 
01510        *anz_n = (gshort) ((nindex  - *index0) / 2);
01511        *anz_s = (gshort) ((*index0 - sindex) / 2);
01512        *index0 = sindex;
01513 
01514        return *anz_n + *anz_s;
01515 }
01516 
01517 gint
01518 position_move_generator (Position *pos, Square **index0,
01519                       gshort *anz_s, gshort *anz_n)
01520 {
01521 
01522        if (pos->priv->tomove == WHITE )
01523               return position_move_generator_white (pos, index0, anz_s, anz_n);
01524        else if (pos->priv->tomove == BLACK )
01525               return position_move_generator_black (pos, index0, anz_s, anz_n);
01526        else
01527               abort();
01528 }
01529 
01530 /*
01531  * Position Characteristic Functions
01532  *
01533  * A set of functions to give information about the position
01534  * passed in.
01535  *
01536  */
01537 
01538 #define CHECK(king_place,direction,piece1,piece2)\
01539 {  int        i= king_place; \
01540    do { i += direction; } \
01541    while(!pos->square[i]); \
01542    if (pos->square[i] == piece1) return piece1; \
01543    if (pos->square[i] == piece2) return piece2; \
01544 }
01545 
01546 static int long4 (Position *pos, int ort, int r1, int r2, int r3, int r4, int f1, int f2)
01547 {
01548 
01549        CHECK (ort,r1,f1,f2);
01550        CHECK (ort,r2,f1,f2);
01551        CHECK (ort,r3,f1,f2);
01552        CHECK (ort,r4,f1,f2);
01553 
01554        return FALSE;
01555 }
01556 
01557 #define KURZ_TEST(r)   if (pos->square[ort+r] == f1) return f1
01558 
01559 static int
01560 short8 (Position *pos, int ort, int r1, int r2, int r3,
01561        int r4, int r5, int r6, int r7, int r8, int f1)
01562 {
01563        KURZ_TEST (r1);
01564        KURZ_TEST (r2);
01565        KURZ_TEST (r3);
01566        KURZ_TEST (r4);
01567        KURZ_TEST (r5);
01568        KURZ_TEST (r6);
01569        KURZ_TEST (r7);
01570        KURZ_TEST (r8);
01571 
01572        return FALSE;
01573 }
01574 
01575 gboolean
01576 position_white_king_attack (Position *pos)
01577 {
01578        Square k = pos->priv->wk_square;
01579        int ret;
01580 
01581        g_return_val_if_fail (pos != NULL, 0);
01582        g_return_val_if_fail (IS_POSITION (pos), 0);
01583 
01584        ret = long4 (pos, k, 9, 11, -9, -11, BQ, BB);
01585        if (ret)
01586               return ret;
01587 
01588        ret = long4 (pos, k, 1, 10, -10, -1, BQ, BR);
01589        if (ret)
01590               return ret;
01591 
01592        if (short8 (pos, k, 8, 12, 19, 21, -8, -12, -19, -21, BN))
01593               return BN;
01594        if (short8 (pos, k, 9, 11, -9, -11, 1, 10, -10, -1, BK))
01595               return BK;
01596 
01597        if (pos->square[k+OL] == BP)
01598               return BP;
01599        if (pos->square[k+OR] == BP)
01600               return BP;
01601 
01602        return FALSE;
01603 }
01604 
01605 gboolean
01606 position_black_king_attack (Position *pos)
01607 {
01608        Square k = pos->priv->bk_square;
01609        int ret;
01610 
01611        g_return_val_if_fail (pos != NULL, 0);
01612        g_return_val_if_fail (IS_POSITION (pos), 0);
01613 
01614        ret = long4 (pos, k, 9, 11, -9, -11, WQ, WB);
01615        if (ret)
01616               return ret;
01617 
01618        ret = long4 (pos, k, 1, 10, -10, -1, WQ, WR);
01619        if (ret)
01620               return ret;
01621 
01622        if (short8 (pos, k, 8, 12, 19, 21, -8, -12, -19, -21, WN))
01623               return WN;
01624        if (short8 (pos, k, 9, 11, -9, -11, 1, 10, -10, -1, WK))
01625               return WK;
01626 
01627        if (pos->square[k+UL] == WP)
01628               return WP;
01629        if (pos->square[k+UR] == WP)
01630               return WP;
01631 
01632        return FALSE;
01633 }
01634 
01635 gshort
01636 position_legal_move (Position *pos, Square **zl, gshort *as, gshort *an)
01637 {
01638        Position temp;
01639        Square tomove = pos->priv->tomove;
01640        gboolean check = FALSE;
01641        gshort gen_moves, a;
01642        Square *ap, *ap2;
01643        gshort anz_s, anz_n, legal_moves;
01644        Square zugl[AB_ZUGL];
01645 
01646        g_return_val_if_fail (pos != NULL, 0);
01647        g_return_val_if_fail (IS_POSITION (pos), 0);
01648 
01649         ap =  zugl + AB_ZUG_S;
01650         gen_moves = position_move_generator (pos, &ap, &anz_s, &anz_n);
01651         legal_moves = 0;
01652         ap2 = *zl;
01653 
01654         for (a = 0; a < gen_moves; a++) {
01655                 temp = *pos;
01656                 position_move (pos, *ap, *(ap+1));
01657 
01658                 switch (tomove) {
01659                         case WHITE:
01660                             check = position_white_king_attack (pos);
01661                             break;
01662                         case BLACK:
01663                             check = position_black_king_attack (pos);
01664                             break;
01665                         default:
01666                             g_assert_not_reached ();
01667                 }
01668 
01669                 if (!check) {
01670                         *ap2++ = *ap++;
01671                         *ap2++ = *ap++;
01672                         legal_moves++;
01673                 } else {
01674                       ap += 2;
01675               }
01676                 switch (tomove) {
01677                         case WHITE:
01678                                 position_move_reverse_white (pos, *(ap - 2),
01679                                                       *(ap - 1));
01680                                 break;
01681                         case BLACK:
01682                                 position_move_reverse_black (pos, *(ap - 2),
01683                                                       *(ap - 1));
01684                                 break;
01685                 }
01686                 *pos = temp;
01687         }
01688         *as = legal_moves;
01689        *an = 0;
01690 
01691         return legal_moves;
01692 }
01693 
01694 short
01695 position_last_piece_captured (Position *pos)
01696 {
01697        g_return_val_if_fail (pos != NULL, EMPTY);
01698        g_return_val_if_fail (IS_POSITION (pos), EMPTY);
01699 
01700        return pos->priv->captured;
01701 }
01702 
01703 short
01704 position_get_color_to_move (Position *pos)
01705 {
01706        g_return_val_if_fail (pos != NULL, NONE);
01707        g_return_val_if_fail (IS_POSITION (pos), NONE);
01708 
01709        return pos->priv->tomove;
01710 }
01711 
01712 void
01713 position_set_white_king (Position *pos, Square square)
01714 {
01715        g_return_if_fail (pos != NULL);
01716        g_return_if_fail (IS_POSITION (pos));
01717 
01718        pos->priv->wk_square = square;
01719 }
01720 
01721 void
01722 position_set_black_king (Position *pos, Square square)
01723 {
01724        g_return_if_fail (pos != NULL);
01725        g_return_if_fail (IS_POSITION (pos));
01726 
01727        pos->priv->bk_square = square;
01728 }
01729 
01730 void
01731 position_set_color_to_move (Position *pos, short color)
01732 {
01733        g_return_if_fail (pos != NULL);
01734        g_return_if_fail (IS_POSITION (pos));
01735 
01736        pos->priv->tomove = color;
01737 }
01738