~ubuntu-branches/ubuntu/raring/3dchess/raring

« back to all changes in this revision

Viewing changes to .pc/01_fix_includes.patch/src/ai.c

  • Committer: Bazaar Package Importer
  • Author(s): Paul Wise
  • Date: 2011-02-18 18:54:30 UTC
  • Revision ID: james.westby@ubuntu.com-20110218185430-lfypfxvr72l2g2v0
Tags: 0.8.1-17
* Team upload.
* Update package description to be more accurate (LP: #602662)
* Use new quilt format instead of dpatch and merge inc patches
* Bump Standards-Version, no changes needed
* Switch to debhelper 7 minimal rules file
* Fix path to GPLv2 in the copyright file
* Include a doc-base file pointing at the rules
* Don't link with libraries that are not used (Xmu Xext)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ai.c
 
3
 *
 
4
 * An implementation of computer intelligence (you wot?) for 3Dc.
 
5
 */
 
6
/*
 
7
 
 
8
    3Dc, a game of 3-Dimensional Chess
 
9
    Copyright (C) 1995,1996  Paul Hicks
 
10
 
 
11
    This program is free software; you can redistribute it and/or modify
 
12
    it under the terms of the GNU General Public License as published by
 
13
    the Free Software Foundation; either version 2 of the License, or
 
14
    (at your option) any later version.
 
15
 
 
16
    This program is distributed in the hope that it will be useful,
 
17
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
    GNU General Public License for more details.
 
20
 
 
21
    You should have received a copy of the GNU General Public License
 
22
    along with this program; if not, write to the Free Software
 
23
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
24
 
 
25
    E-Mail: paulh@euristix.ie
 
26
*/
 
27
#ifdef DEBUG
 
28
#include <stdio.h>
 
29
#endif /* DEBUG */
 
30
 
 
31
#include <stdlib.h>
 
32
#include <limits.h>
 
33
#include <sys/time.h>
 
34
 
 
35
#include "machine.h"
 
36
#include "3Dc.h"
 
37
 
 
38
#ifndef MAX
 
39
#define MAX(a,b) ((a) < (b) ? (b) : (a))
 
40
#define MIN(a,b) ((a) > (b) ? (b) : (a))
 
41
#endif /* MAX */
 
42
 
 
43
#define BEST_STACKS 5
 
44
Local struct stackList
 
45
{
 
46
  stack *stacks[BEST_STACKS];
 
47
  int   ratings[BEST_STACKS];
 
48
} bestMoves = {
 
49
{ NULL, NULL, NULL, NULL, NULL },
 
50
{ INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN }
 
51
};
 
52
 
 
53
Local int values[ TITLES ] = 
 
54
{
 
55
  26, 42, 22, 10, 25, /* Royalty */
 
56
  45, 21, 12, 24, 15, /* Nobility */
 
57
  6 /* Pawn */
 
58
};
 
59
 
 
60
 
 
61
Local void
 
62
PushMove(Move *move, int value)
 
63
{
 
64
  int i;
 
65
 
 
66
  if ( value == INT_MIN )
 
67
    return;
 
68
 
 
69
  for ( i = 0; (bestMoves.stacks [i] != NULL) &&
 
70
               (bestMoves.ratings[i] > value) &&
 
71
               (i < BEST_STACKS);
 
72
       ++i )
 
73
    nop();
 
74
 
 
75
  if ( i == BEST_STACKS )
 
76
    {
 
77
      free( move );
 
78
      return;
 
79
    }
 
80
 
 
81
  if ( bestMoves.ratings[i] == value )
 
82
    {
 
83
      StackPush( bestMoves.stacks[i], move );
 
84
      free( move );
 
85
    }
 
86
  else
 
87
    {
 
88
      int j;
 
89
 
 
90
      j = BEST_STACKS-1;
 
91
 
 
92
      /* Get rid of the lowest level (if it falls off the end) */
 
93
      if (bestMoves.stacks[j] != NULL)
 
94
        StackDelete( bestMoves.stacks[j] );
 
95
 
 
96
      /* Move all the lower levels down */
 
97
      for (; j > i; --j)
 
98
        {
 
99
          bestMoves.stacks [j] = bestMoves.stacks [j-1];
 
100
          bestMoves.ratings[j] = bestMoves.ratings[j-1];
 
101
        }
 
102
 
 
103
      /* Create the new stack */
 
104
      bestMoves.stacks[i] = StackNew();
 
105
      StackPush( bestMoves.stacks[i], move );
 
106
      bestMoves.ratings[i] = value;
 
107
    }
 
108
 
 
109
  return;
 
110
}
 
111
 
 
112
/* This function circumvents the problem of negative ratings
 
113
 * by adding to all ratings enough to make the smallest rating == 0 */
 
114
Local void
 
115
FixMoves( void )
 
116
{
 
117
  int i, add;
 
118
 
 
119
  for ( i = (BEST_STACKS -1); (bestMoves.stacks[i] == NULL) && (i >= 0); --i )
 
120
    nop();
 
121
 
 
122
  if ((i < 0) || (bestMoves.ratings[i] >= 0))
 
123
    return;
 
124
 
 
125
  add = -(bestMoves.ratings[i]);
 
126
 
 
127
  for (; i >= 0; --i)
 
128
    bestMoves.ratings[i] += add;
 
129
     
 
130
}
 
131
 
 
132
Local Move *
 
133
PopMove( void )
 
134
{
 
135
  Move *ret;
 
136
  int stacks, randStack, randMove, randBase, randNum;
 
137
 
 
138
  if ( bestMoves.stacks[0] == NULL )
 
139
    return NULL;
 
140
 
 
141
  /*
 
142
   * This algorithm works by generating a number randBase on which to base a
 
143
   * call to random(): think of it as a die with randBase sides.  randBase
 
144
   * it dependant on the rating of the moves at the current level and
 
145
   * on the level itself.  It may be that the number of moves at the current
 
146
   * level will also be a factor in later version.  (A "level" is all moves
 
147
   * with equal rating.  Only the top BEST_STACKS levels are remembered).
 
148
   * Then the generated random number is reverse engineered into a level.
 
149
   * Finally a purely random choice of move within that level is made.
 
150
   */
 
151
  if ( bestMoves.ratings[0] == INT_MAX )
 
152
    {
 
153
      /* If this move wins the game then do it unconditionally */
 
154
      randMove = 0;
 
155
      randStack = 0;
 
156
    }
 
157
  else
 
158
    {
 
159
      for ( stacks = 0, randBase = 0;
 
160
           ( bestMoves.stacks[stacks] != NULL ) &&
 
161
           ( stacks < BEST_STACKS ) ;
 
162
           ++stacks )
 
163
        randBase += ((BEST_STACKS-stacks) * bestMoves.ratings[stacks]);
 
164
 
 
165
      randNum = random()%randBase;
 
166
 
 
167
      for ( randStack = stacks-1;
 
168
           (randStack > 0) && (randNum > 0); --randStack )
 
169
        {
 
170
          randNum -= (( BEST_STACKS - randStack ) *
 
171
                      bestMoves.ratings[randStack] );
 
172
        }
 
173
 
 
174
      randMove = random()%bestMoves.stacks[randStack]->nSize;
 
175
      D( printf( "Choosing move %i from a stack of size %i\n",
 
176
                randMove+1, bestMoves.stacks[randStack]->nSize ) );
 
177
    }
 
178
 
 
179
  ret = StackPeek( bestMoves.stacks[randStack], randMove );
 
180
  CHECK((ret->xyzBefore.zLevel != 3) && (ret->xyzAfter.zLevel != 3));
 
181
 
 
182
  /* This defeats the opaqueness of stack.c but it's easy */
 
183
  /* It just clears the one move we've just made from the move stack */
 
184
 
 
185
  /* If the chosen move was the top of the stack.. */
 
186
  if (randMove == 0)
 
187
    {
 
188
      /* Don't free the move: it's "ret" and still in use! */
 
189
      StackPop( bestMoves.stacks[randStack] );
 
190
 
 
191
      /* If there is only the one move then we remove the stack */
 
192
      if ( bestMoves.stacks[randStack]->nSize == 0 )
 
193
        {
 
194
          StackDelete( bestMoves.stacks[randStack] );
 
195
 
 
196
          while ( ((randStack+1) < BEST_STACKS) &&
 
197
                  (bestMoves.stacks[randStack+1] != NULL) )
 
198
            {
 
199
              bestMoves.stacks [randStack] = bestMoves.stacks [randStack+1];
 
200
              bestMoves.ratings[randStack] = bestMoves.ratings[randStack+1];
 
201
              ++randStack;
 
202
            }
 
203
 
 
204
          bestMoves.stacks[randStack] = NULL;
 
205
          bestMoves.ratings[randStack] = INT_MIN;
 
206
        }
 
207
    }
 
208
  /* We used a second or later move */
 
209
  else
 
210
    {
 
211
      int i;
 
212
      struct stack_el *el, *temp;
 
213
 
 
214
      el = bestMoves.stacks[randStack]->top;
 
215
 
 
216
      for (i = 1; (i < randMove) && (el->below != NULL); ++i)
 
217
        {
 
218
          el = el->below;
 
219
        }
 
220
 
 
221
      if (!CHECK((el->below != NULL) && (el->below->mvt == ret)))
 
222
        {
 
223
          /* Hopefully this can never happen */
 
224
        }
 
225
      else
 
226
        {
 
227
          temp = el->below;
 
228
          el->below = temp->below;
 
229
          bestMoves.stacks[randStack]->nSize--;
 
230
          free( temp );
 
231
        }
 
232
    }
 
233
  
 
234
  return ret;
 
235
}
 
236
 
 
237
Local int
 
238
RateMove( Move *move, Colour bwSide )
 
239
{
 
240
  int rating = 0;
 
241
  Colour bwEnemy;
 
242
  Coord xyzPos;
 
243
  Piece *moving, *storing;
 
244
  bwEnemy = ( bwSide == WHITE ) ? BLACK : WHITE;
 
245
 
 
246
  /* Rate taking king */
 
247
  if (move->pVictim == Muster[ bwEnemy ][ MusterIdx( king, 0 )])
 
248
    return INT_MAX;
 
249
 
 
250
  /* Fake the move for simple lookahead */
 
251
  moving  = Board[ move->xyzBefore.zLevel ]
 
252
                 [ move->xyzBefore.yRank ]
 
253
                 [ move->xyzBefore.xFile ];
 
254
  storing = Board[ move->xyzAfter.zLevel ]
 
255
                 [ move->xyzAfter.yRank ]
 
256
                 [ move->xyzAfter.xFile ];
 
257
 
 
258
  if (!CHECK( moving != NULL ))
 
259
    return INT_MIN;
 
260
 
 
261
  /* Rate saving king */
 
262
  /* It might be more efficient to put the IsKingChecked() call
 
263
   * inside the move faked below but that would mean nasty code
 
264
   * duplication re: finding king coords and so on.  This code
 
265
   * is easier to maintain. */
 
266
  if ( FakeMoveAndIsKingChecked( Muster[ bwSide ][ MusterIdx( king, 0 )],
 
267
                                 move->xyzAfter.xFile,
 
268
                                 move->xyzAfter.yRank,
 
269
                                 move->xyzAfter.zLevel ))
 
270
    return INT_MIN;
 
271
 
 
272
  /* Fake the move */
 
273
  Board[ move->xyzBefore.zLevel ]
 
274
       [ move->xyzBefore.yRank ]
 
275
       [ move->xyzBefore.xFile ] = NULL;
 
276
  Board[ move->xyzAfter.zLevel ]
 
277
       [ move->xyzAfter.yRank ]
 
278
       [ move->xyzAfter.xFile ] = moving;
 
279
  if ( storing != NULL )
 
280
    storing->bVisible = FALSE;
 
281
 
 
282
  /* Rate check */
 
283
  xyzPos = (Muster[ bwEnemy ][ MusterIdx( king, 0 )])->xyzPos;
 
284
  if ( SquareThreatened( bwSide,
 
285
            xyzPos.xFile, xyzPos.yRank, xyzPos.zLevel) != NULL )
 
286
    rating += values[ king ];
 
287
 
 
288
  /* Rate danger: if there's a chance of being captured in the new pos. */
 
289
  xyzPos = move->xyzAfter;
 
290
  if ( SquareThreatened( bwEnemy,
 
291
            xyzPos.xFile, xyzPos.yRank, xyzPos.zLevel) != NULL )
 
292
    rating -= (values[ moving->nName ] /2);
 
293
 
 
294
  /* Undo the fake */
 
295
  Board[ move->xyzBefore.zLevel ]
 
296
       [ move->xyzBefore.yRank ]
 
297
       [ move->xyzBefore.xFile ] = moving;
 
298
  Board[ move->xyzAfter.zLevel ]
 
299
       [ move->xyzAfter.yRank ]
 
300
       [ move->xyzAfter.xFile ] = storing;
 
301
  if ( storing != NULL )
 
302
    storing->bVisible = TRUE;
 
303
 
 
304
  /* Rate capture */
 
305
  if (( move->pVictim != NULL ) &&
 
306
      ( move->pVictim->bwSide == bwEnemy ))
 
307
    {
 
308
      int i;
 
309
 
 
310
      rating += values[ move->pVictim->nName ];
 
311
 
 
312
      /* Rate evasion: if there's a chance of any friendly piece
 
313
       * being captured in the old pos but not in the new (this isn't
 
314
       * an authorative check and needs to be enhanced). */
 
315
      for ( i = 0; i < PIECES; ++i )
 
316
        {
 
317
          if ( Muster[ bwSide ][ i ]->bVisible &&
 
318
               SquareThreatened( bwEnemy,
 
319
                                 Muster[ bwSide ][ i ]->xyzPos.xFile,
 
320
                                 Muster[ bwSide ][ i ]->xyzPos.yRank,
 
321
                                 Muster[ bwSide ][ i ]->xyzPos.zLevel ) ==
 
322
              move->pVictim )
 
323
            rating += (values[ Muster[ bwSide ][ i ]->nName ] /2);
 
324
        }
 
325
    }
 
326
 
 
327
  /* Rate special moves */
 
328
  /* En passant and castling not yet possible for computer */
 
329
  if (( move->pVictim != NULL ) &&
 
330
      ( move->pVictim->bwSide == bwSide))
 
331
    rating += 10; /* Castling */
 
332
  if (( move->xyzAfter.yRank == (bwSide == WHITE ? RANKS-1 : 0) ) &&
 
333
      ( moving->nName == pawn ))
 
334
    rating += values[queen]; /* Promotion */
 
335
  /* Note the horrible magic numbers below */
 
336
  if ( (ABS( move->xyzAfter.yRank - move->xyzBefore.yRank ) == 2) &&
 
337
      ( moving->nName == pawn ))
 
338
    rating += 1; /* Two-forward by pawn: the computer doesn't
 
339
                  * usually like opening its attack routes otherwise */
 
340
 
 
341
  /* Rate position; distance forward (should be proximity to
 
342
   * enemy king except for pawns */
 
343
  if ( bwSide == WHITE )
 
344
    rating += move->xyzAfter.yRank - move->xyzBefore.yRank;
 
345
  else
 
346
    rating += 7 - move->xyzAfter.yRank + move->xyzBefore.yRank;
 
347
 
 
348
  return rating;
 
349
}
 
350
 
 
351
Global Boolean
 
352
GenMove(const Colour bwSide, Move **ret)
 
353
{
 
354
  Local int pieceIdx = 0;
 
355
  stack *moves;
 
356
  Move *thisMove;
 
357
 
 
358
  /* First clear out any old moves */
 
359
  if (pieceIdx == 0)
 
360
    {
 
361
      int i;
 
362
      
 
363
      for ( i = 0; (bestMoves.stacks[i] != NULL) && (i < BEST_STACKS); ++i)
 
364
        {
 
365
          StackDelete(bestMoves.stacks[i]);
 
366
          bestMoves.stacks[i] = NULL;
 
367
          bestMoves.ratings[i] = INT_MIN;
 
368
        }
 
369
    }
 
370
 
 
371
  if ( Muster[bwSide][pieceIdx]->bVisible )
 
372
    {
 
373
      moves = FindAllMoves( Muster[bwSide][pieceIdx] );
 
374
      if (moves != NULL)
 
375
        {
 
376
#         ifdef NOTDEF
 
377
          StackDump( moves );
 
378
#         endif /* DEBUG */
 
379
 
 
380
          while ( (thisMove = StackPop( moves )) != NULL )
 
381
            {
 
382
              PushMove( thisMove, RateMove( thisMove, bwSide ) );
 
383
            }
 
384
 
 
385
          StackDelete( moves );
 
386
        }
 
387
    }
 
388
 
 
389
  if (++pieceIdx == PIECES)
 
390
    {
 
391
      FixMoves();
 
392
      *ret = PopMove();
 
393
      pieceIdx = 0;
 
394
      return TRUE;
 
395
    }
 
396
 
 
397
  *ret = NULL;
 
398
  return FALSE;
 
399
}
 
400
 
 
401
/* This tries again for a move in case the last one failed for some reason */
 
402
Global Boolean
 
403
GenAltMove(const Colour bwSide, Move **ret)
 
404
{
 
405
  *ret = PopMove();
 
406
  return TRUE;
 
407
}
 
408
 
 
409
/* Creates a stack of legal moves that this piece can take in this go */
 
410
stack *
 
411
FindAllMoves(Piece *piece)
 
412
{
 
413
  stack *moves;
 
414
  Move move;
 
415
  Colour bwEnemy;
 
416
  int x, y, z;
 
417
 
 
418
#define CURX (piece->xyzPos.xFile)
 
419
#define CURY (piece->xyzPos.yRank)
 
420
#define CURZ (piece->xyzPos.zLevel)
 
421
 
 
422
  moves = StackNew();
 
423
  if (moves == NULL)
 
424
    return NULL;
 
425
 
 
426
  bwEnemy = ((piece->bwSide == WHITE) ? BLACK : WHITE);
 
427
  move.xyzBefore = piece->xyzPos;
 
428
 
 
429
  if (piece->nName == knight)
 
430
    {
 
431
      for (y = MAX(0, CURY -2); y < MIN(RANKS, CURY +3); y++)
 
432
        {
 
433
          if (y == CURY)
 
434
            continue;
 
435
          for (x = MAX(0, CURX -2); x < MIN(FILES, CURX +3); x++)
 
436
            {
 
437
              if (x == CURX)
 
438
                continue;
 
439
 
 
440
              if (ABS(CURX-x) == ABS(CURY-y))
 
441
                continue;
 
442
 
 
443
              if ((Board[CURZ][y][x] == NULL) ||
 
444
                  (Board[CURZ][y][x]->bwSide == bwEnemy))
 
445
                {
 
446
                  move.xyzAfter.xFile = x;
 
447
                  move.xyzAfter.yRank = y;
 
448
                  move.xyzAfter.zLevel = CURZ;
 
449
                  move.pVictim = Board[CURZ][y][x];
 
450
                  move.nHadMoved = piece->bHasMoved;
 
451
 
 
452
                  if (!FakeMoveAndIsKingChecked( piece, x, y, CURZ ))
 
453
                    StackPush(moves, &move);
 
454
                } /* End valid move */
 
455
            } /* End x loop */
 
456
        } /* End y loop */
 
457
    } /* End knight */
 
458
  else if (piece->nName == cannon)
 
459
    {
 
460
      for (z = 0; z < LEVELS; z++)
 
461
        {
 
462
          if (z == CURZ)
 
463
            continue;
 
464
 
 
465
          for (y = MAX( 0, CURY -3 ); y < MIN( RANKS, CURY +4 ); y++)
 
466
            {
 
467
              if (y == CURY)
 
468
                continue;
 
469
 
 
470
              for (x = MAX( 0, CURX -3 ); x < MIN( FILES, CURX +4 ); x++)
 
471
                {
 
472
                  if (x == CURX)
 
473
                    continue;
 
474
 
 
475
                  if ((ABS(CURX-x) == ABS(CURY-y)) ||
 
476
                      (ABS(CURX-x) == ABS(CURZ-z)) ||
 
477
                      (ABS(CURY-y) == ABS(CURZ-z)))
 
478
                    continue;
 
479
 
 
480
                  if ((Board[z][y][x] == NULL) ||
 
481
                      (Board[z][y][x]->bwSide == bwEnemy))
 
482
                    {
 
483
                      move.xyzAfter.xFile = x;
 
484
                      move.xyzAfter.yRank = y;
 
485
                      move.xyzAfter.zLevel = z;
 
486
                      move.pVictim = Board[z][y][x];
 
487
                      move.nHadMoved = piece->bHasMoved;
 
488
 
 
489
                      if (!FakeMoveAndIsKingChecked( piece, x, y, z ))
 
490
                        StackPush(moves, &move);
 
491
                    } /* End valid move */
 
492
                } /* End x loop */
 
493
            } /* End y loop */
 
494
        } /* End z loop */
 
495
    } /* End cannon */
 
496
  else if (piece->nName == pawn) /* Don't bother searching for en passant */
 
497
    {
 
498
      y = ((piece->bwSide == WHITE) ? 1 : -1);
 
499
 
 
500
      for (x = MAX(0, CURX-1); x < MIN(FILES, CURX+2); ++x)
 
501
        {
 
502
          /* Due to the complexity of the conditional this time,
 
503
           * I've opted for aborting when illegal instead of
 
504
           * proceeding when legal. */
 
505
          if ((x == CURX) && (Board[CURZ][CURY+y][CURX] != NULL))
 
506
            continue;
 
507
 
 
508
          if ( (x != CURX) &&
 
509
              ((Board[CURZ][CURY + y][x] == NULL) ||
 
510
               ((Board[CURZ][CURY + y][x])->bwSide != bwEnemy)) )
 
511
            continue;
 
512
 
 
513
          move.xyzAfter.xFile = x;
 
514
          move.xyzAfter.yRank = CURY + y;
 
515
          move.xyzAfter.zLevel = CURZ;
 
516
          move.pVictim = Board[CURZ][CURY + y][x];
 
517
          move.nHadMoved = piece->bHasMoved;
 
518
 
 
519
          if (!FakeMoveAndIsKingChecked(piece, x, CURY+y, CURZ))
 
520
            StackPush(moves, &move);
 
521
 
 
522
          /* This next conditional is for the two-forward move:
 
523
           * it only happens when the previous attempt was the one-forward
 
524
           * move and makes assumptions based on that fact. */
 
525
          if ( (x==CURX) && (piece->bHasMoved == FALSE) &&
 
526
              (Board[CURZ][CURY + y+y][CURX] == NULL) )
 
527
            {
 
528
              move.xyzAfter.yRank += y;
 
529
              if (!FakeMoveAndIsKingChecked(piece, CURX, CURY+y+y, CURZ))
 
530
                StackPush(moves, &move);
 
531
            }
 
532
        } /* End x loop */
 
533
    } /* End pawn */
 
534
  else
 
535
    {
 
536
      int d, dist;
 
537
      Piece *pEncountered;
 
538
 
 
539
      /*
 
540
       * The king and prince can only move one square;
 
541
       * all others can move MAX(FILES,RANKS)-1.
 
542
       * For a regular board, this is 7.  (Not 8: If you moved 8
 
543
       * in any direction you would be off the edge of the board)
 
544
       */
 
545
      if ((piece->nName == king) ||
 
546
          (piece->nName == prince))
 
547
        dist = 1;
 
548
      else
 
549
        dist = MAX(FILES, RANKS) -1;
 
550
 
 
551
      for (z = -1; z <= 1; ++z)
 
552
      {
 
553
       /*
 
554
        * Cater for pieces that can't change level.
 
555
        */
 
556
       if (((piece->nName == prince) ||
 
557
            (piece->nName == princess) ||
 
558
            (piece->nName == abbey) ||
 
559
            (piece->nName == galley)) &&
 
560
           (z != 0))
 
561
         continue;
 
562
 
 
563
       for (y = -1; y <= 1; ++y)
 
564
       {
 
565
         for (x = -1; x <= 1; ++x)
 
566
         {
 
567
           if ((x==0) && (y==0) && (z==0))
 
568
             continue;
 
569
 
 
570
           /*
 
571
            * Cater for the pieces that can only move
 
572
            * horizontally/vertically.
 
573
            */
 
574
           if (((piece->nName == rook) ||
 
575
                (piece->nName == galley)) &&
 
576
               !HORZ(x, y))
 
577
             continue;
 
578
           /*
 
579
            * Cater for the pieces that can only move
 
580
            * diagonally.
 
581
            */
 
582
           else if (((piece->nName == bishop) ||
 
583
                     (piece->nName == abbey)) &&
 
584
                    !DIAG(x, y))
 
585
             continue;
 
586
 
 
587
           for (d = 1; d <= dist; ++d)
 
588
           {
 
589
             pEncountered = TraverseDir(piece, x, y, z, d);
 
590
             if (IsMoveLegal(piece, pEncountered))
 
591
               {
 
592
                 move.xyzAfter = pEncountered->xyzPos;
 
593
                 move.pVictim = pEncountered;
 
594
                 move.nHadMoved = piece->bHasMoved;
 
595
 
 
596
                 /* Check for putting own king in check */
 
597
                 if (!FakeMoveAndIsKingChecked(piece,
 
598
                                               pEncountered->xyzPos.xFile,
 
599
                                               pEncountered->xyzPos.yRank,
 
600
                                               pEncountered->xyzPos.zLevel))
 
601
                   StackPush(moves, &move);
 
602
               }
 
603
 
 
604
             if (pEncountered != SQUARE_EMPTY)
 
605
               break; /* No point on continuing in this direction if
 
606
                       * we've hit a piece or the edge of the board.. */
 
607
           } /* End d loop */
 
608
         } /* End x loop */
 
609
       } /* End y loop */
 
610
     } /* End z loop */
 
611
    }
 
612
 
 
613
  return moves;
 
614
 
 
615
#undef CURX
 
616
#undef CURY
 
617
#undef CURZ
 
618
}
 
619