Please report any bugs or errors to Fergus Duniho

You may not move into check.

Use your browser's BACK button to go back to the previous page, then reload if necessary.

For general reference, here is the complete list of moves:

1. P b2-b5 
1... p d7-d5 
2. P h2-h5 
2... p c7-c4 
3. P a2-a4 
3... p f7-f5 
4. P g2-g5 
4... p a7-a5 
5. P e2-e5 
5... x f8-f5 
6. P c2-c3 
6... l g8-e6 
7. P h5-h6 
7... p g7-g6 
8. P b5-c5 
8... p b7-b5 
9. C h1-h5 
9... p e7-f7 
10. P f2-e2 
10... x f5-c5 
11. X f1-h3 
11... x c8-d7 
12. P d2-d5 
12... w d8-f6 
13. P g5-f5 
13... w f6-e5 
14. P f5-f6 
14... l e6-g6 
15. L g1-g7 
15... w e5-g5 
16. X h3-f5 
16... c a8-g2 
17. W e1-f2 
17... c g2-h3 
18. X f5-d5 
18... k e8-d8 // Check.
19. K d1-e1 
19... k d8-e7 // Check.
20. K e1-f1 
20... c h3-g4 
21. K f1-g1 
21... c g4-e6 
22. X d5-a8 
22... l b8-d6 
23. X a8-a6 
23... l d6-d5 
24. X c1-d1 
24... l d5-a8 
25. X a6-a5 
25... i h8-e5 
26. P c3-f3 
26... x d7-d4 
27. L b1-c1 
27... i e5-h2 
28. L c1-a3 
28... p b5-b4 
29. L a3-b2 
29... k e7-f8 
30. L b2-g7 
30... k f8-g7 // Check.
31. I a1-f6 
31... l a8-d8 
32. C h5-g5 
32... x c5-f5 
33. resign

If this is your settings file, you may edit it at https://www.chessvariants.com/play/pbm/play.php?game=Ultima&settings=Galactic&submit=Edit

Here is a code listing:

   0 set movetype MOVE
   1 if == thismove null
   2   say This preset enforces the rules and displays legal moves.
   3 endif
   4 echo Please report any bugs or errors to Fergus Duniho
   5 set kpos findpiece k spaces
   6 set Kpos findpiece K spaces
   7 setconst k Black_King
   8 setconst K White_King
   9 setconst c Black_Coordinator
  10 setconst C White_Coordinator
  11 setconst l Black_Long_Leaper
  12 setconst L White_Long_Leaper
  13 setconst x Black_Chameleon
  14 setconst X White_Chameleon
  15 setconst i Black_Immobilizer
  16 setconst I White_Immobilizer
  17 setconst w Black_Withdrawer
  18 setconst W White_Withdrawer
  19 setconst p Black_Pincer_Pawn
  20 setconst P White_Pincer_Pawn
  21 foreach val (King Coordinator Long_Leaper Chameleon Immobilizer Withdrawer Pincer_Pawn)
  22   alias #val White_{#val}
  23   alias #val Black_{#val}
  24 next
  25 include ultima-fairy
  26 allow deletions 1
  27 sub postauto1
  28   if == void space $dest
  29     set temp $old
  30     add @ $dest
  31     setsystem lastmoved #temp
  32     setsystem lastcaptured #temp
  33   endif
  34   set lgl false
  35   if not isconst alias $moved
  36     die The piece moved is undefined.
  37   elseif islower $moved
  38     die You may not move one of your opponent's pieces.
  39   elseif == $moved $old
  40     set from cond $dest $dest $origin
  41     if near #from c 1 and == $old I or near #from i 1 and != #from #Kpos
  42       set lgl true
  43     else
  44       die "Your piece may not commit suicide unless it is immobilized and not a King."
  45     endif
  46   elseif isupper $old
  47     die You may not capture your own pieces.
  48   endif
  49   if capture
  50     set nopvc 0
  51   else
  52     inc nopvc
  53   endif
  54   set codename const alias $moved
  55   if == true #lgl
  56     echo "Suicide move from {#from}"
  57   elseif sub #codename $origin $dest and issub #codename
  58   elseif fn #codename $origin $dest and isfunc #codename and not issub #codename
  59   else
  60     set name alias #codename
  61     set errmsg list thismove "is illegal. You may not move your" #name "from" $origin "to" join $dest ".
" 62 set desc join #name "-Desc" 63 set errmsg str_replace "_" " " join #errmsg str_replace "%s" #name var #desc 64 die #errmsg 65 endif 66 if sub checked var Kpos 67 die You may not move into check. 68 endif 69 unsetflag $origin $dest 70 set posvar join "w" join fencode boardflags 71 inc #posvar 72 endsub 73 sub postauto2 74 if == void space $dest 75 set temp $old 76 add @ $dest 77 setsystem lastmoved #temp 78 setsystem lastcaptured #temp 79 endif 80 set legal false 81 if not isconst alias $moved 82 die The piece $moved is undefined. 83 elseif isupper $moved 84 die You may not move one of your opponent's pieces. 85 elseif == $moved $old 86 set from cond $dest $dest $origin 87 if near #from C 1 and == $old i or near #from I 1 and != #from #kpos 88 set legal true 89 else 90 die "Your piece may not commit suicide unless it is immobilized." 91 endif 92 elseif islower $old 93 die You may not capture your own pieces. 94 endif 95 if capture 96 set nopvc 0 97 else 98 inc nopvc 99 endif 100 set codename const alias $moved 101 if #legal 102 elseif sub #codename $origin $dest and issub #codename 103 elseif fn #codename $origin $dest and isfunc #codename and not issub #codename 104 else 105 set name alias #codename 106 set errmsg list thismove "is illegal. You may not move your" #name "from" $origin "to" join $dest ".
" 107 set desc join #name "-Desc" 108 set errmsg str_replace "_" " " join #errmsg str_replace "%s" #name var #desc 109 die #errmsg 110 endif 111 if sub checked var kpos 112 die You may not move into check. 113 endif 114 unsetflag $origin $dest 115 set posvar join "b" join fencode boardflags 116 inc #posvar 117 endsub 118 moveindex 0 119 MOVE: P b2-b5 120 postauto1 121 moveindex 1 122 MOVE: p d7-d5 123 postauto2 124 moveindex 2 125 MOVE: P h2-h5 126 postauto1 127 moveindex 3 128 MOVE: p c7-c4 129 postauto2 130 moveindex 4 131 MOVE: P a2-a4 132 postauto1 133 moveindex 5 134 MOVE: p f7-f5 135 postauto2 136 moveindex 6 137 MOVE: P g2-g5 138 postauto1 139 moveindex 7 140 MOVE: p a7-a5 141 postauto2 142 moveindex 8 143 MOVE: P e2-e5 144 postauto1 145 moveindex 9 146 MOVE: x f8-f5 147 postauto2 148 moveindex 10 149 MOVE: P c2-c3 150 postauto1 151 moveindex 11 152 MOVE: l g8-e6 153 postauto2 154 moveindex 12 155 MOVE: P h5-h6 156 postauto1 157 moveindex 13 158 MOVE: p g7-g6 159 postauto2 160 moveindex 14 161 MOVE: P b5-c5 162 postauto1 163 moveindex 15 164 MOVE: p b7-b5 165 postauto2 166 moveindex 16 167 MOVE: C h1-h5 168 postauto1 169 moveindex 17 170 MOVE: p e7-f7 171 postauto2 172 moveindex 18 173 MOVE: P f2-e2 174 postauto1 175 moveindex 19 176 MOVE: x f5-c5 177 postauto2 178 moveindex 20 179 MOVE: X f1-h3 180 postauto1 181 moveindex 21 182 MOVE: x c8-d7 183 postauto2 184 moveindex 22 185 MOVE: P d2-d5 186 postauto1 187 moveindex 23 188 MOVE: w d8-f6 189 postauto2 190 moveindex 24 191 MOVE: P g5-f5 192 postauto1 193 moveindex 25 194 MOVE: w f6-e5 195 postauto2 196 moveindex 26 197 MOVE: P f5-f6 198 postauto1 199 moveindex 27 200 MOVE: l e6-g6 201 postauto2 202 moveindex 28 203 MOVE: L g1-g7 204 postauto1 205 moveindex 29 206 MOVE: w e5-g5 207 postauto2 208 moveindex 30 209 MOVE: X h3-f5 210 postauto1 211 moveindex 31 212 MOVE: c a8-g2 213 postauto2 214 moveindex 32 215 MOVE: W e1-f2 216 postauto1 217 moveindex 33 218 MOVE: c g2-h3 219 postauto2 220 moveindex 34 221 MOVE: X f5-d5 222 postauto1 223 moveindex 35 224 MOVE: k e8-d8 225 postauto2 226 moveindex 36 227 MOVE: K d1-e1 228 postauto1 229 moveindex 37 230 MOVE: k d8-e7 231 postauto2 232 moveindex 38 233 MOVE: K e1-f1 234 postauto1 235 moveindex 39 236 MOVE: c h3-g4 237 postauto2 238 moveindex 40 239 MOVE: K f1-g1 240 postauto1 241 moveindex 41 242 MOVE: c g4-e6 243 postauto2 244 moveindex 42 245 MOVE: X d5-a8 246 postauto1 247 moveindex 43 248 MOVE: l b8-d6 249 postauto2 250 moveindex 44 251 MOVE: X a8-a6 252 postauto1 253 moveindex 45 254 MOVE: l d6-d5 255 postauto2 256 moveindex 46 257 MOVE: X c1-d1 258 postauto1 259 moveindex 47 260 MOVE: l d5-a8 261 postauto2 262 moveindex 48 263 MOVE: X a6-a5 264 postauto1 265 moveindex 49 266 MOVE: i h8-e5 267 postauto2 268 moveindex 50 269 MOVE: P c3-f3 270 postauto1 271 moveindex 51 272 MOVE: x d7-d4 273 postauto2 274 moveindex 52 275 MOVE: L b1-c1 276 postauto1 277 moveindex 53 278 MOVE: i e5-h2 279 postauto2 280 moveindex 54 281 MOVE: L c1-a3 282 postauto1 283 moveindex 55 284 MOVE: p b5-b4 285 postauto2 286 moveindex 56 287 MOVE: L a3-b2 288 postauto1 289 moveindex 57 290 MOVE: k e7-f8 291 postauto2 292 moveindex 58 293 MOVE: L b2-g7 294 postauto1 295 moveindex 59 296 MOVE: k f8-g7 297 postauto2 298 moveindex 60 299 MOVE: I a1-f6 300 postauto1 301 moveindex 61 302 MOVE: l a8-d8 303 postauto2 304 moveindex 62 305 MOVE: C h5-g5 306 postauto1 307 moveindex 63 308 MOVE: x c5-f5 309 postauto2 310 moveindex 64 311 MOVE: resign 312 postauto1 313 set posvar join "w" join fencode boardflags 314 if >= var #posvar 3 315 say Three Times Repetition! Drawn Game! 316 drawn 317 elseif sub stalemated var kpos 318 if sub checked var kpos 319 say Checkmate! White has won! 320 won 321 else 322 say Stalemate! White has won! 323 won 324 endif 325 elseif >= #nopvc 100 326 say Fifty Moves Without Moving a Pawn or Capturing! Game Drawn! 327 drawn 328 elseif sub checked var kpos 329 say Check! 330 endif 331 end 332 333 lib ultima-fairy 334 include fairychess 335 set Chameleon-Desc "The %s may move as a Queen without capturing by displacement, and it may use another piece's own powers against it. It will immobilize the opponent's Immobilizer if they are adjacent, and it can capture other pieces of the opponent through their own powers of capture. With repect to Long Leapers, it cannot capture or jump over any pieces between it and the Long Leaper even though a Long Leaper would be able to. So, it sometimes cannot capture a Long Leaper that it could capture if it were a Long Leaper. With respect to Pincer Pawns, it can capture them only by moving orthogonally, as Pincer Pawns do. With respect to the King, it can check it from only one space away. Since the %s borrows its capturing power from another piece and has no native capturing power of its own, it cannot capture another %s." 336 def Black_Chameleon fn join "Black_Chameleon_" var movetype #0 #1 337 def Black_Chameleon-Range fn Queen-Range #0 338 def Black_Chameleon_MOVE remove #cap =cap merge #cap aggregate lambda (#0 onlyif == C space #0) array var co1 var co0 =co1 join filename var kpos rankname #to =co0 join filename #to rankname var kpos =cap merge #cap aggregate lambda ( #foe and islower space #ally and == P space #foe and onboard #ally =ally where #foe #0 #1 and onboard #foe =foe where #to #0 #1 and match direction #frm #to n w s e ) ((0 1) (0 -1) (1 0) (-1 0)) =cap merge #cap aggregate lambda (#0 and == W space #0) where #frm sign - file #frm file #to sign - rank #frm rank #to =cap aggregate lambda (#0 onlyif == L space #0) #thepath and not strstr #str "PP" =str string aggregate lambda (cond empty #0 E P) #thepath and alltrue lambda (== L space #0 or empty #0) #thepath =thepath path #frm #to and match direction #frm #to n s e w nw ne sw se and or and empty #frm not capture empty #to and not near #frm I 1 =frm =to 339 def Black_Chameleon_CHECK fn Black_King #0 #1 340 def White_Chameleon fn join "White_Chameleon_" var movetype #0 #1 341 def White_Chameleon-Range fn Queen-Range #0 342 def White_Chameleon_MOVE remove #cap =cap merge #cap aggregate lambda (#0 onlyif == c space #0) array var co1 var co0 =co1 join filename var Kpos rankname #to =co0 join filename #to rankname var Kpos =cap merge #cap aggregate lambda ( #foe and isupper space #ally and == p space #foe and onboard #ally =ally where #foe #0 #1 and onboard #foe =foe where #to #0 #1 and match direction #frm #to n w s e ) ((0 1) (0 -1) (1 0) (-1 0)) =cap merge #cap aggregate lambda (#0 and == w space #0) where #frm sign - file #frm file #to sign - rank #frm rank #to =cap aggregate lambda (#0 onlyif == l space #0) #thepath and not strstr #str "PP" =str string aggregate lambda (cond empty #0 E P) #thepath and alltrue lambda (== l space #0 or empty #0) #thepath =thepath path #frm #to and match direction #frm #to n s e w nw ne sw se and or and empty #frm not capture empty #to and not near #frm i 1 =frm =to 343 def White_Chameleon_CHECK fn White_King #0 #1 344 set Coordinator-Desc "The %s can move as a Queen without capturing by displacement, and it captures any enemy piece on any corner of the rectangle it forms with the King upon its move. This allows it to capture two pieces at once. When it shares a rank or file with its King, the corners are fully occupied by the King and Coordinator, leaving no corner with an enemy piece to be captured." 345 def Black_Coordinator fn join "Black_Coordinator_" var movetype #0 #1 346 def White_Coordinator fn join "White_Coordinator_" var movetype #0 #1 347 def White_Coordinator-Range fn Queen-Range #0 348 def Black_Coordinator-Range fn Queen-Range #0 349 def Black_Coordinator_MOVE remove aggregate lambda (#0 onlyif isupper space #0) array var co0 var co1 =co1 join filename var kpos rankname #to =co0 join filename #to rankname var kpos and fn Queen #frm #to and or and empty #frm not capture empty #to =frm =to 350 def Coordinator_CHECK == #0 #1 351 def White_Coordinator_MOVE remove aggregate lambda (#0 onlyif islower space #0) array var co0 var co1 =co1 join filename var Kpos rankname #to =co0 join filename #to rankname var Kpos and fn Queen #frm #to and or and empty #frm not capture empty #to =frm =to 352 def Black_Coordinator_CHECK anytrue lambda (fn Queen #frm #0 and empty #0 and fnmatch var pat #0) rays #to 1 0 =pat cond var cf join var cf "?" join "?" var cr and or var cf var cr =cr cond == file var kpos file #to rankname #to false =cf cond == rank var kpos rank #to filename #to false =frm =to 353 def White_Coordinator_CHECK anytrue lambda (fn Queen #frm #0 and empty #0 and fnmatch var pat #0) rays #to 1 0 =pat cond var cf join var cf "?" join "?" var cr and or var cf var cr =cr cond == file var Kpos file #to rankname #to false =cf cond == rank var Kpos rank #to filename #to false =frm =to 354 set Immobilizer-Desc "The %s can move as a Queen without capturing. It immobilizes any adjacent piece of the opponent, rendering it completely unable to move or capture except to commit suicide, which will remove it from the board. This should normally be in the form of the piece moving to nothing. Since a King's suicide would be tantamount to resignation, this will be handled through the normal process of resignation and not through letting the King move off its space, which makes it easier to determine stalemate. Unlike other pieces, Immobilizers cannot capture other pieces." 355 def Black_Immobilizer fn join "Black_Immobilizer_" var movetype #0 #1 356 def Black_Immobilizer-Range fn Queen-Range #0 357 def Black_Immobilizer_MOVE fn Queen #frm #to and or and empty #frm not capture empty #to and not near #frm X 1 and not near #frm I 1 =frm =to 358 def Black_Immobilizer_CHECK == #0 #1 359 def White_Immobilizer fn join "White_Immobilizer_" var movetype #0 #1 360 def White_Immobilizer-Range fn Queen-Range #0 361 def White_Immobilizer_MOVE fn Queen #frm #to and or and empty #frm not capture empty #to and not near #frm x 1 and not near #frm i 1 =frm =to 362 def White_Immobilizer_CHECK == #0 #1 363 set King-Desc "The King may move one space in any direction but not into check. Unlike other pieces, it captures by displacement. There is no castling in this game, and unlike other pieces, an immobilized King may not commit suicide, though a player with one may choose to resign instead." 364 def Black_King checkleap #frm #to 1 1 or checkleap #frm #to 1 0 and not near #frm I 1 =frm =to 365 def White_King checkleap #frm #to 1 1 or checkleap #frm #to 1 0 and not near #frm i 1 =frm =to 366 sub Black_King frm to 367 if fn Black_King #frm #to 368 set kpos #to 369 return true 370 endif 371 return false 372 endsub 373 sub White_King frm to 374 if fn White_King #frm #to 375 set Kpos #to 376 return true 377 endif 378 return false 379 endsub 380 copyfn King-Range Black_King-Range 381 copyfn King-Range White_King-Range 382 set Long_Leaper-Desc "The %s moves as a Queen without capturing. To capture pieces, it must hop over them along a single diagonal or orthogonal direction. It may not hop over pieces on the same side, and any enemy piece it hops over must have an empty space immediately behind it. Within the bounds of these restrictions, it can capture as many pieces in one move as the size of the board allows. For the 8x8 board used in Ultima, it may capture up to three pieces at once." 383 def Black_Long_Leaper fn join "Black_Long_Leaper_" var movetype #0 #1 384 def Black_Long_Leaper-Range fn Queen-Range #0 385 def White_Long_Leaper fn join "White_Long_Leaper_" var movetype #0 #1 386 def White_Long_Leaper-Range fn Queen-Range #0 387 def Black_Long_Leaper_MOVE remove aggregate lambda (#0 onlyif isupper space #0) #thepath and not strstr #str "PP" =str string aggregate lambda (cond empty #0 E P) #thepath and allfalse lambda (islower space #0) #thepath =thepath path #frm #to and match direction #frm #to n s e w nw ne sw se or fn Queen #frm #to and or and empty #frm not capture empty #to and not near #frm I 1 =frm =to 388 def White_Long_Leaper_MOVE remove aggregate lambda (#0 onlyif islower space #0) #thepath and not strstr #str "PP" =str string aggregate lambda (cond empty #0 E P) #thepath and allfalse lambda (isupper space #0) #thepath =thepath path #frm #to and match direction #frm #to n s e w nw ne sw se or fn Queen #frm #to and or and empty #frm not capture empty #to and not near #frm i 1 =frm =to 389 def Black_Long_Leaper_CHECK not strstr #str "PP" =str string aggregate lambda (cond empty #0 E P) #thepath and allfalse lambda (islower space #0) #thepath =thepath path #frm #nxt and empty #nxt and onboard #nxt =nxt where #to sign - file #to file #frm sign - rank #to rank #frm and match direction #frm #to n s e w nw ne sw se and not near #frm I 1 =frm =to 390 def White_Long_Leaper_CHECK not strstr #str "PP" =str string aggregate lambda (cond empty #0 E P) #thepath and allfalse lambda (isupper space #0) #thepath =thepath path #frm #nxt and empty #nxt and onboard #nxt =nxt where #to sign - file #to file #frm sign - rank #to rank #frm and match direction #frm #to n s e w nw ne sw se and not near #frm i 1 =frm =to 391 set Pincer_Pawn-Desc "The %s moves as a Rook without capturing by displacement. On reaching its destination, it captures any orthogonally adjacent enemy piece that is adjacent to another of the player's pieces along the same rank or file as it is adjacent with the %s." 392 def Black_Pincer_Pawn fn join "Black_Pincer_Pawn_" var movetype #0 #1 393 def Black_Pincer_Pawn-Range fn Rook-Range #0 394 def White_Pincer_Pawn fn join "White_Pincer_Pawn_" var movetype #0 #1 395 def White_Pincer_Pawn-Range fn Rook-Range #0 396 def Black_Pincer_Pawn_MOVE remove aggregate lambda (#foe and islower space #ally and isupper space #foe and onboard #ally =ally where #foe #0 #1 and onboard #foe =foe where #to #0 #1) ((0 1) (0 -1) (1 0) (-1 0)) and fn Rook #frm #to and or and empty #frm not capture empty #to and not near #frm I 1 =frm =to 397 def White_Pincer_Pawn_MOVE remove aggregate lambda (#foe and isupper space #ally and islower space #foe and onboard #ally =ally where #foe #0 #1 and onboard #foe =foe where #to #0 #1) ((0 1) (0 -1) (1 0) (-1 0)) and fn Rook #frm #to and or and empty #frm not capture empty #to and not near #frm i 1 =frm =to 398 def Black_Pincer_Pawn_CHECK anytrue lambda ( checkride #frm #nbr 1 0 and islower space #ally and onboard #ally =ally where #to neg #0 neg #1 and empty #nbr and onboard #nbr =nbr where #to #0 #1) ((0 1) (0 -1) (1 0) (-1 0)) and > distance #from #to 1 and not near #frm I 1 =frm =to 399 def White_Pincer_Pawn_CHECK anytrue lambda ( checkride #frm #nbr 1 0 and isupper space #ally and onboard #ally =ally where #to neg #0 neg #1 and empty #nbr and onboard #nbr =nbr where #to #0 #1) ((0 1) (0 -1) (1 0) (-1 0)) and > distance #from #to 1 and not near #frm i 1 =frm =to 400 set Withdrawer-Desc "The %s moves as a Queen without capturing by displacement. It captures any enemy piece that was adjacent to it before its move that it moves directly away from. So, it captures only one piece at a time." 401 def Black_Withdrawer fn join "Black_Withdrawer_" var movetype #0 #1 402 def White_Withdrawer fn join "White_Withdrawer_" var movetype #0 #1 403 def Black_Withdrawer-Range fn Queen-Range #0 404 def White_Withdrawer-Range fn Queen-Range #0 405 def Black_Withdrawer_MOVE remove #foe or islower space #foe or empty #foe or not onboard #foe =foe where #frm sign - file #frm file #to sign - rank #frm rank #to and fn Queen #frm #to and or and empty #frm not capture empty #to and not near #frm I 1 =frm =to 406 def White_Withdrawer_MOVE remove #foe or isupper space #foe or empty #foe or not onboard #foe =foe where #frm sign - file #frm file #to sign - rank #frm rank #to and fn Queen #frm #to and or and empty #frm not capture empty #to and not near #frm i 1 =frm =to 407 def Black_Withdrawer_CHECK empty where #frm - file #frm file #to - rank #frm rank #to and == distance #frm #to 1 and not near #frm I 1 =frm =to 408 def White_Withdrawer_CHECK empty where #frm - file #frm file #to - rank #frm rank #to and == distance #frm #to 1 and not near #frm i 1 =frm =to 409 setsystem maxmove 1 410 ban commands allmoves 411 allow moves 1 captures 1 suicides 1 412 sub stalemated kingpos 413 store 414 local cspaces friend friends from king piece to movetype np prom 415 set movetype MOVE 416 set king alias space #kingpos 417 if hasupper #king 418 set friends lambda (onlyupper) 419 set free lambda (haslower #0 or not hasupper #0) 420 set myI I 421 set enemyI i 422 set enemyX x 423 else 424 set friends lambda (onlylower) 425 set free lambda (hasupper #0 or not haslower #0) 426 set myI i 427 set enemyI I 428 set enemyX X 429 endif 430 store 431 for (from piece) fn #friends 432 for to fn join const alias #piece "-Range" #from 433 if fn const alias #piece #from #to and fn #free alias space #to and onboard #to 434 move #from #to 435 if not fn checked cond == #from #kingpos #to #kingpos 436 set pn alias #piece 437 setlegal "{#pn} {#from}-{#to}" 438 endif 439 endif 440 restore 441 next 442 next 443 for (from piece) fn #friends 444 if near #from #enemyX 1 and == #piece #myI or near #from #enemyI 1 and != #from #kingpos 445 empty #from 446 if not fn checked #kingpos 447 set pn alias #piece 448 setlegal "{#pn} {#from}-" 449 endif 450 endif 451 restore 452 next 453 setsystem autorules sub describe_rules 454 return cond count system legalmoves false true 455 endsub 456 endlib 457 lib fairychess 458 if flag use-chess-defaults 459 setconst k King 460 setconst K King 461 setconst q Queen 462 setconst Q Queen 463 setconst r Rook 464 setconst R Rook 465 setconst b Bishop 466 setconst B Bishop 467 setconst n Knight 468 setconst N Knight 469 setconst p Black_Pawn 470 setconst P White_Pawn 471 endif 472 if flag use-chess-defaults 473 set wpr 2 474 set bpr 7 475 set fps 2 476 set pzs 1 477 set wcastle c1 g1 478 set bcastle c8 g8 479 set wprom Q R B N 480 set bprom q r b n 481 set promotable p P 482 elseif not isset wpr 483 set message join "Set the wpr variable to the value of White's Pawn Rank. This is the single rank on which all of White's Pawns start. This would be 2 for Chess.
" var message 484 elseif not isset bpr 485 set message join "Set the bpr variable to the value of Black's Pawn Rank. This is the single rank on which all of Black's Pawns start. This would be 7 for Chess.
" var message 486 elseif not isset fps 487 set message join "Set the fps variable to the value of the maximum number of spaces a Pawn may move on its first move. This would be 2 in Chess.
" var message 488 elseif not isset pzs 489 set message join "Set the pzs variable to the value of the Promotion Zone Size. This is the number of ranks on the opposite side of the board on which Pawns may promote. This would be 1 for Chess.
" var message 490 elseif not isset wcastle 491 set message join "Set the wcastle variable to a space-separated list of the coordinates of the spaces the White King may move to when castling. This would be c1 g1 for Chess.
" var message 492 elseif not isset bcastle 493 set message join "Set the bcastle variable to a space-separated list of the coordinates of the spaces the Black King may move to when castling. This would be c8 g8 for Chess.
" var message 494 elseif not isset wprom 495 set message join "Set the wprom variable to the pieces that a White Pawn may promote to on reaching the Promotion Zone. White's pieces will normally be uppercase, and this would be Q R B N for Chess.
" var message 496 elseif not isset bprom 497 set message join "Set the bprom variable to the pieces that a Black Pawn may promote to on reaching the Promotion Zone. Black's pieces will normally be lowercase, and this would be q r b n for Chess.
" var message 498 endif 499 set ep false 500 setsystem maxmove 2 501 ban commands allmoves 502 allow moves 1 captures 1 promotions 2 503 set Aanca-Desc "The %s may move one space orthgonally, and so long as it is unblocked, it may continue its move in an outward diagonal direction." 504 def Aanca fn (checkride #0 #1 1 1 and empty #0) where #0 0 sign - rank #1 rank #0 #1 or fn (checkride #0 #1 1 1 and empty #0) where #0 sign - file #1 file #0 0 #1 or checkleap #0 #1 1 0 505 def Aanca-Range mergeall leaps #0 1 0 rays where #0 0 1 1 1 rays where #0 0 -1 1 1 rays where #0 1 0 1 1 rays where #0 -1 0 1 1 506 set Amazon-Desc "The %s may move in a straight line in any direction, as a Queen does, or it may leap the the opposite end of a 1x2 rectangle, as a Knight does." 507 def Amazon fn Bishop #0 #1 or fn Rook #0 #1 or fn Knight #0 #1 508 def Amazon-Range merge leaps # 1 2 merge rays #0 1 0 rays #0 1 1 509 set Bede-Desc "The %s may move along any diagonal line, as a Bishop does, or it may leap two spaces away in any orthogonal direction, as a Dabababah does." 510 def Bede checkride #0 #1 1 1 or checkleap #0 #1 0 2 511 def Bede-Range merge rays #0 1 1 leaps #0 0 2 512 def White_Berolina_Pawn remove var epc and checkleap #0 #1 1 0 and == #1 var epp or and checkride #0 #1 1 1 == rankname #0 var wpr or checkleap #0 #1 1 1 and empty #1 or and islower space #1 checkleap #0 #1 1 0 and <= distance #0 #1 var fps and > rank #1 rank #0 513 def Black_Berolina_Pawn remove var epc and checkleap #0 #1 1 0 and == #1 var epp or and checkride #0 #1 1 1 == rankname #0 var bpr or checkleap #0 #1 1 1 and empty #1 or and isupper space #1 checkleap #0 #1 1 0 and <= distance #0 #1 var fps and < rank #1 rank #0 514 def White_Berolina_Pawn-Range filter lambda (onboard #1) mergeall where #ori 0 1 values lambda (where #ori neg #1 #1) range 1 var fps values lambda (where #ori #1 #1) range 1 var fps =ori 515 def Black_Berolina_Pawn-Range filter lambda (onboard #1) mergeall where #ori 0 -1 values lambda (where #ori neg #1 neg #1) range 1 var fps values lambda (where #ori #1 neg #1) range 1 var fps =ori 516 set White_Berolina_Pawn-Desc "The %s may move one space diagonally forward without capturing, or it may move one space straight forward to capture. On its first move, it may move two spaces diagonally forward without capturing so long as it isn't blocked. If this move takes it next to an enemy %s that could have captured it if it had just moved one space, that %s may immediately capture it by en passant, moving to the space it passed over. On reaching the last rank, it may promote." 517 set Black_Berolina_Pawn-Desc var White_Berolina_Pawn-Desc 518 sub White_Berolina_Pawn from to 519 verify > rank #to rank #from 520 verify <= distance #to #from #fps 521 if capture 522 verify checkleap #from #to 1 0 523 set epp false 524 set epc false 525 elseif checkleap #from #to 1 0 and == #to #epp 526 capture #epc 527 set epp false 528 set epc false 529 elseif > distance #to #from 1 530 verify == rankname #from #wpr 531 verify checkride #from #to 1 1 532 set epp elem 0 path #from #to 533 set epc #to 534 else 535 verify checkleap #from #to 1 1 536 set epp false 537 set epc false 538 endif 539 if onboard where #to 0 #pzs 540 if != space #to $moved 541 set name alias const alias $moved 542 die "You may not promote a" #name "until it reaches the promotion zone." 543 endif 544 elseif onboard where #to 0 1 545 if == White_Berolina_Pawn const alias space #to and count var wprom 546 if not $answered and == mln $maxmln 547 push wprom space #to 548 askpromote #wprom 549 endif 550 elseif not match space #to var wprom and != White_Pawn const alias space #to 551 set name alias const alias $moved 552 set newname alias const alias space #to 553 set msg list "You may not promote your" #name "to a" join #newname ".
" 554 set msg str_replace "_" " " var msg 555 die #msg 556 endif 557 elseif count var wprom 558 if == White_Berolina_Pawn const alias space #to 559 if == count var wprom 1 560 set newpiece join list var wprom 561 set newmove join #newpiece "-dest" 562 add #newpiece $dest 563 appendmove #newmove 564 else 565 askpromote #wprom 566 endif 567 elseif not match space #to var wprom 568 set name alias const alias $moved 569 set newname alias const alias space #to 570 set msg list "You may not promote your" #name "to a" join #newname ".
" 571 set msg str_replace "_" " " var msg 572 die #msg 573 endif 574 else 575 set name alias const alias $moved 576 set msg list "You may not advance your" #name "to the last rank, because there is nothing you may promote it to." 577 set msg str_replace "_" " " var msg 578 die #msg 579 endif 580 set nopvc 0 581 return true 582 endsub 583 sub Black_Berolina_Pawn from to 584 verify < rank #to rank #from 585 verify <= distance #to #from #fps 586 if capture 587 verify checkleap #from #to 1 0 588 set epp false 589 set epc false 590 elseif checkleap #from #to 1 0 and == #to #epp 591 capture #epc 592 set epp false 593 set epc false 594 elseif > distance #to #from 1 595 verify == rankname #from #bpr 596 verify checkride #from #to 1 1 597 set epp elem 0 path #from #to 598 set epc #to 599 else 600 verify checkleap #from #to 1 1 601 set epp false 602 set epc false 603 endif 604 if onboard where #to 0 neg #pzs 605 if != space #to $moved 606 set name alias const alias $moved 607 die "You may not promote a" #name "until it reaches the promotion zone." 608 endif 609 elseif onboard where #to 0 -1 610 if == Black_Berolina_Pawn const alias space #to and count var bprom 611 if not $answered and == mln $maxmln 612 push bprom space #to 613 askpromote #bprom 614 endif 615 elseif not match space #to var bprom and != Black_Pawn const alias space #to 616 set name alias const alias $moved 617 set newname alias const alias space #to 618 set msg list "You may not promote your" #name "to a" join #newname ".
" 619 set msg str_replace "_" " " var msg 620 die #msg 621 endif 622 elseif count var bprom 623 if == Black_Berolina_Pawn const alias space #to 624 if == count var bprom 1 625 set newpiece join list var bprom 626 set newmove join #newpiece "-dest" 627 add #newpiece $dest 628 appendmove #newmove 629 else 630 askpromote #bprom 631 endif 632 elseif not match space #to var bprom 633 set name alias const alias $moved 634 set newname alias const alias space #to 635 set msg list "You may not promote your" #name "to a" join #newname ".
" 636 set msg str_replace "_" " " var msg 637 die #msg 638 endif 639 else 640 set name alias const alias $moved 641 set msg list "You may not advance your" #name "to the last rank, because there is nothing you may promote it to." 642 set msg str_replace "_" " " var msg 643 die #msg 644 endif 645 set nopvc 0 646 return true 647 endsub 648 def Bishop checkride #0 #1 1 1 649 def Bishop-Range rays #0 1 1 650 set Bishop-Desc "The %s may move diagonally any number of spaces until it reaches an occupied space." 651 def Cannon cond cond empty #0 capture (not empty #1) (checkhop #0 #1 0 1) (checkride #0 #1 0 1) and #1 652 def Cannon-Range rays #0 1 0 653 set Cannon-Desc "The %s moves any number of spaces orthogonally, as a Rook does, but it must hop over an intervening piece to capture." 654 def Camel checkleap #0 #1 1 3 655 def Camel-Range leaps #0 1 3 656 set Camel-Desc "The %s leaps to any space at the opposite corner of a 1x3 rectangle." 657 def Camelrider checkride #0 #1 1 3 658 def Camelrider-Range rays #0 1 3 659 set Camelrider-Desc "The %s may make any number of Camel moves in the same direction until it lands on an occupied space." 660 def Cardinal fn Bishop #0 #1 or fn Knight #0 #1 661 def Cardinal-Range merge leaps #0 1 2 rays #0 1 1 662 set Cardinal-Desc "The %s may move along diagonals as a Bishop or leap as a Knight." 663 def Centaur checkleap #0 #1 1 1 or checkleap #0 #1 1 0 or checkleap #0 #1 1 2 664 def Centaur-Range merge leaps #0 1 2 merge leaps #0 1 0 leaps #0 1 1 665 set Centaur-Desc "The %s may move to any adjacent space as a King or leap like a Knight." 666 def Champion fn Elephant #0 #1 or fn Dabbabah #0 #1 or fn Wazir #0 #1 667 def Champion-Range mergeall leaps #0 2 2 leaps #0 2 0 leaps #0 1 0 668 set Champion-Desc "The %s may leap one or two spaces orthogonally or two spaces diagonally." 669 def White_Charging_Knight cond < rank #0 rank #1 (checkleap #0 #1 1 2) (checkleap #0 #1 1 1 or checkleap #0 #1 1 0) 670 def White_Charging_Knight-Range mergeall leaps #0 1 2 leaps #0 1 1 leaps #0 1 0 671 set White_Charging_Knight-Desc "The %s may leap forward as a Knight or move one space sideways or backwards like a King." 672 def Black_Charging_Knight cond > rank #0 rank #1 (checkleap #0 #1 1 2) (checkleap #0 #1 1 1 or checkleap #0 #1 1 0) 673 def Black_Charging_Knight-Range mergeall leaps #0 1 2 leaps #0 1 1 leaps #0 1 0 674 set Black_Charging_Knight-Desc "The %s may leap forward as a Knight or move one space sideways or backwards like a King." 675 def White_Charging_Rook checkride #0 #1 1 0 and <= rank #0 rank #1 or checkaleap #0 #1 -1 -1 or checkaleap #0 #1 -1 0 or checkaleap #0 #1 -1 1 676 def White_Charging_Rook-Range mergeall ray #0 0 -1 ray #0 1 0 ray #0 0 1 where #0 -1 1 where #0 1 0 where #0 1 1 677 set White_Charging_Rook-Desc "The %s may move forward or sideways along its file or rank like a Rook, or it may move one space backwards in any direction like a King." 678 def Black_Charging_Rook checkride #0 #1 1 0 and >= rank #0 rank #1 or checkaleap #0 #1 -1 1 or checkaleap #0 #1 1 0 or checkaleap #0 #1 1 1 679 def Black_Charging_Rook-Range mergeall ray #0 0 -1 ray #0 -1 0 ray #0 0 1 where #0 -1 1 where #0 1 0 where #0 1 1 680 set Black_Charging_Rook-Desc "The %s may move forward or sideways along its file or rank like a Rook, or it may move one space backwards in any direction like a King." 681 def Chinese_Elephant checkpath #0 #1 1 1 1 1 682 def Chinese_Elephant-Range leaps #0 2 2 683 set Chinese_Elephant-Desc "The %s may move two spaces diagonally so long as the space in between is empty." 684 def White_Chinese_Elephant checkpath #0 #1 1 1 1 1 and < rank #1 + 1 / lastrank 2 685 def White_Chinese_Elephant-Range leaps #0 2 2 686 set White_Chinese_Elephant-Desc "The %s may move two spaces diagonally so long as the space in between is empty, but it is confined to the ranks on its own side of the board." 687 def Black_Chinese_Elephant checkpath #0 #1 1 1 1 1 and >= rank #1 + 1 / lastrank 2 688 def Black_Chinese_Elephant-Range leaps #0 2 2 689 set Black_Chinese_Elephant-Desc "The %s may move two spaces diagonally so long as the space in between is empty, but it is confined to the ranks on its own side of the board." 690 def Chinese_General checkride #0 #1 1 0 and == Chinese_General const alias cond empty #0 capture space #1 or checkleap #0 #1 0 1 and flag #1 691 def Chinese_General checkride #0 #1 1 0 and == Chinese_General const alias cond empty #0 capture space #1 or checkleap #0 #1 0 1 and flag #1 692 def Chinese_General == distance #0 #1 1 or == var movetype CHECK and checkride #0 #1 1 0 and flag #1 693 def Chinese_General-Range leaps #0 1 0 694 set Chinese_General-Desc "The %s may move one space orthogonally within the confines of the Palace, but it may not face the opponent's %s along an open file." 695 def Chinese_Guard checkleap #0 #1 1 1 and flag #1 696 def Chinese_Guard-Range leaps #0 1 1 697 set Chinese_Guard-Desc "The %s may move one space diagonally within the confines of the palace." 698 def White_Chinese_Pawn checkaleap #0 #1 -1 0 or checkaleap #0 #1 1 0 and >= rank #0 + 1 / lastrank 2 or checkaleap #0 #1 0 1 699 def Black_Chinese_Pawn checkaleap #0 #1 -1 0 or checkaleap #0 #1 1 0 and < rank #0 + 1 / lastrank 2 or checkaleap #0 #1 0 -1 700 def White_Chinese_Pawn-Range leaps #0 1 0 701 def Black_Chinese_Pawn-Range leaps #0 1 0 702 set White_Chinese_Pawn-Desc "The %s may move one space forward. Once it has reached the other side of the board, it may also move one space sideways." 703 set Black_Chinese_Pawn-Desc "The %s may move one space forward. Once it has reached the other side of the board, it may also move one space sideways." 704 def White_Colonel checkride #0 #1 1 0 or checkleap #0 #1 1 2 and >= rank #1 rank #0 or checkleap #0 #1 1 1 or checkleap #0 #1 1 0 705 def White_Colonel mergeall rays #0 1 0 leaps #0 1 2 leaps #0 1 1 706 set White_Colonel-Desc "The %s may move forward or sideways as a Rook, forward as a Knight, and one space in any direction as a King." 707 def Black_Colonel checkride #0 #1 1 0 or checkleap #0 #1 1 2 and <= rank #1 rank #0 or checkleap #0 #1 1 1 or checkleap #0 #1 1 0 708 def Black_Colonel mergeall rays #0 1 0 leaps #0 1 2 leaps #0 1 1 709 set Black_Colonel-Desc "The %s may move forward or sideways as a Rook, forward as a Knight, and one space in any direction as a King." 710 def Dabbabah checkleap #0 #1 0 2 711 def Dabbabah-Range leaps #0 0 2 712 set Dabbabah-Desc "The %s may leap two spaces vertically or horizontally." 713 def Dabbabahrider checkride #0 #1 0 2 714 def Dabbabahrider-Range rays #0 0 2 715 set Dabbabahrider-Desc "The %s may make any number of two space orthogonal leaps in the same direction until it reaches an occupied space." 716 def Dragon_Horse checkride #0 #1 1 1 or checkleap #0 #1 1 0 717 def Dragon_Horse-Range merge leaps #0 1 0 rays #0 1 1 718 set Dragon_Horse-Desc "The %s may move along diagonals as a Bishop or move one space orthogonally as a Wazir." 719 def Dragon_King checkride #0 #1 1 0 or checkleap #0 #1 1 1 720 def Dragon_King-Range merge leaps #0 1 1 rays #0 1 0 721 set Dragon_King-Desc "The %s may move along its rank or file as a Rook or one space diagonally as a Ferz." 722 def Elephant checkleap #0 #1 2 2 723 def Elephant-Range leaps #0 2 2 724 set Elephant-Desc "The %s may leap two spaces in any diagonal direction." 725 def Elephantrider checkride #0 #1 2 2 726 def Elephantrider-Range rays #0 2 2 727 set Elephantrider-Desc "The %s may make a series of two-space diagonal leaps in the same direction. Each leap but the last must be to an empty space, though a leap may take it over an intervening piece." 728 def Eques_Rex checkleap #0 #1 1 1 or checkleap #0 #1 1 0 or checkleap #0 #1 1 2 729 def Eques_Rex-Range merge leaps #0 1 2 merge leaps #0 1 0 leaps #0 1 1 730 set Eques_Rex-Desc "The %s may move to any adjacent space as a King or leap like a Knight." 731 def Fad checkleap #0 #1 1 1 or checkleap #0 #1 2 2 or checkleap #0 #1 2 0 732 def Fad-Range mergeall leaps #0 1 1 leaps #0 2 2 leaps #0 2 0 733 set Fad-Desc "The %s may move one space diagonally, or it may leap two spaces diagonally or orthogonally." 734 def Ferz checkleap #0 #1 1 1 735 def Ferz-Range leaps #0 1 1 736 set Ferz-Desc "The %s may move one space diagonally." 737 def Fibnif checkleap #0 #1 1 2 or checkleap #0 #1 1 1 and == 1 abs - file #0 file #1 738 def Fibnif-Range merge leaps #0 1 2 leaps #0 1 1 739 set Fibnif-Desc "The %s may move one space diagonally or leap as a Knight to any space that is one file and two ranks away." 740 def Giraffe checkleap #0 #1 1 4 741 def Giraffe-Range leaps #0 1 4 742 set Giraffe-Desc "The %s may leap to any space that is one file and four ranks or one rank and four files away." 743 def White_Gold_General checkaleap #0 #1 1 1 or checkaleap #0 #1 -1 1 or checkleap #0 #1 0 1 744 def White_Gold_General-Range mergeall leaps #0 1 0 where #0 1 1 where #0 -1 1 745 set White_Gold_General-Desc "The %s may move one space in any orthgonal direction or one space diagonally forward." 746 def Black_Gold_General checkaleap #0 #1 1 -1 or checkaleap #0 #1 -1 -1 or checkleap #0 #1 0 1 747 def Black_Gold_General-Range mergeall leaps #0 1 0 where #0 1 -1 where #0 -1 -1 748 set Black_Gold_General-Desc "The %s may move one space in any orthgonal direction or one space diagonally forward." 749 def Grasshopper checkgrasshop #0 #1 1 1 or checkgrasshop #0 #1 1 0 750 def Grasshopper-Range merge rays #0 1 0 rays #0 1 1 751 set "The %s moves any number of spaces orthogonally or diagonally like a Queen except that it must hop over exactly one piece, and it must end its move immediately after the piece it hopped over." 752 def Griffon fn (checkride #0 #1 1 0 and empty #0) where #0 sign - file #1 file #0 sign - rank #1 rank #0 #1 and != file #1 file #0 and != rank #1 rank #0 or checkleap #0 #1 1 1 753 def Griffon-Range mergeall leaps #0 1 1 rays where #0 1 1 1 0 rays where #0 1 -1 1 0 rays where #0 -1 -1 1 0 rays where #0 -1 1 1 0 754 set Griffon-Desc "The %s may move one space diagonally, and it may continue its move by moving as a Rook in an outward orthogonal direction. It may not pass over other pieces." 755 def King checkleap #0 #1 1 1 or checkleap #0 #1 1 0 756 def King-Range merge leaps #0 1 0 leaps #0 1 1 757 set King-Desc "The %s leaps one space in any direction. It may castle with a Rook on its first move so long as it is not in check, there is nothing in between it and the Rook, it doesn't pass through check while castling, and the Rook hasn't moved. In castling, it moves two spaces toward the Rook, and the Rook moves to the space the %s passed over." 758 sub King from to 759 if not fn King #from #to 760 verify sub castle #from #to and match #to var cond isupper space #to wcastle bcastle 761 endif 762 if isupper space #to 763 set Kpos #to 764 else 765 set kpos #to 766 endif 767 return true 768 endsub 769 def Knight checkleap #0 #1 1 2 770 def Knight-Range leaps #0 1 2 771 set Knight-Desc "The %s may leap to any space that is one rank and two files away or two ranks and one file away." 772 def Korean_Elephant checkpath #0 #1 1 0 1 1 1 1 773 def Korean_Elephant-Range leaps #0 2 3 774 set "The %s may move one space orthogonally, followed by two more spaces in the same outward diagonal direction. It must complete every part of its move, and it may not pass over an occupied space." 775 def White_Lance checkaride #0 #1 0 1 776 def White_Lance-Range ray #0 0 1 777 set "The %s may move forward in its file as a Rook." 778 def Black_Lance checkaride #0 #1 0 -1 779 def Black_Lance-Range ray #0 0 -1 780 set "The %s may move forward in its file as a Rook." 781 def Leo fn Vao #0 #1 or fn Cannon #0 #1 782 def Leo-Range merge rays #0 1 0 rays #0 1 1 783 set Leo-Desc "The %s may move any number of spaces diagonally or orthogonally, as a Queen does, but it must hop over one intervening piece when it captures." 784 def Mao checktwostep #0 #1 0 1 1 1 785 def Mao-Range leaps #0 1 2 786 set Mao-Desc "The %s moves one space orthogonally, followed by one more space in an outward diagonal direction. It must complete both parts of its move, and it may not pass over an occupied space. It can reach the same spaces as a Knight except that it can be blocked on the first step of its two-space move." 787 def Marshall fn Knight #0 #1 or fn Rook #0 #1 788 def Marshall-Range merge rays #0 1 0 leaps #0 1 2 789 set Marshall-Desc "The %s moves orthogonally as a Rook or leaps as a Knight." 790 def Moa checktwostep #0 #1 1 1 0 1 791 def Moa-Range leaps #0 1 2 792 set Moa-Desc "The %s moves one space diagonally, followed by one more space in an outward orthogonal direction. It must complete both parts of its move, and it may not pass over an occupied space. It can reach the same spaces as a Knight except that it can be blocked on the first step of its two-space move." 793 def Murray_Lion checkleap #0 #1 1 0 or checkleap #0 #1 1 1 and cond empty #0 capture (not empty #1) or checkleap #0 #1 2 2 or checkleap #0 #1 0 2 794 def Murray_Lion-Range merge merge leaps #0 2 0 leaps #0 2 2 merge leaps #0 1 0 leaps #0 1 1 795 set Murray_Lion-Desc "The %s may leap two spaces in any diagonal or orthogonal direction, and it may capture (but not otherwise move) one space in any direction." 796 def Nightrider checkride #0 #1 1 2 797 def Nightrider-Range rays #0 1 2 798 set Nightrider-Desc "The %s may leap as a Knight any number of times in the same direction. While each Knight leap may take it over other pieces, each leap but the last must be to an empty space." 799 set White_Pawn-Desc "The %s may move one space straight forward without capturing, or it may move one space diagonally forward to capture. On its first move, it may move two spaces forward without capturing so long as it isn't blocked. If this move takes it over a space an enemy %s could have captured it on if it had moved there, that %s may immediately capture it by en passant by moving to that space. On reaching the last rank, it must promote to any other piece except the King." 800 set Black_Pawn-Desc var White_Pawn-Desc 801 def White_Pawn remove var ep and < rankname #1 var bpr and < rankname var ep rankname #1 and == filename var ep filename #1 and checkleap #0 #1 1 1 and var ep or and checkride #0 #1 0 1 == rankname #0 var wpr or checkleap #0 #1 0 1 and empty #1 and != var movetype CHECK or and not empty #1 checkleap #0 #1 1 1 and any onboard where #1 0 1 == var movetype CHECK count var wprom and <= distance #0 #1 var fps and > rank #1 rank #0 802 def Black_Pawn remove var ep and > rankname #1 var wpr and > rankname var ep rankname #1 and == filename var ep filename #1 and checkleap #0 #1 1 1 and var ep or and checkride #0 #1 0 1 == rankname #0 var bpr or checkleap #0 #1 0 1 and empty #1 and != var movetype CHECK or and not empty #1 checkleap #0 #1 1 1 and any count var bprom onboard where #1 0 -1 == var movetype CHECK and <= distance #0 #1 var fps and < rank #1 rank #0 803 def White_Pawn-Range filter lambda (onboard #1) mergeall where #ori -1 1 where #ori 1 1 values lambda (where #ori 0 #1) range 1 var fps =ori 804 def Black_Pawn-Range filter lambda (onboard #1) mergeall where #ori -1 -1 where #ori 1 -1 values lambda (where #ori 0 neg #1) range 1 var fps =ori 805 def White_Pawn-Promote var wprom 806 def Black_Pawn-Promote var bprom 807 sub White_Pawn from to 808 my newpiece 809 my newmove 810 my prom 811 verify > rank #to rank #from 812 verify <= distance #to #from #fps 813 if capture 814 verify checkleap #from #to 1 1 815 set ep false 816 elseif checkleap #from #to 1 1 and #ep 817 verify == filename var ep filename #to 818 verify < rankname var ep rankname #to 819 verify < rankname #to var bpr 820 capture #ep 821 set ep false 822 elseif > distance #to #from 1 823 verify == rankname #from #wpr 824 verify checkride #from #to 0 1 825 set ep #to 826 else 827 verify checkleap #from #to 0 1 828 set ep false 829 endif 830 set prom fn White_Pawn-Promote #to 831 if onboard where #to 0 #pzs 832 if != space #to $moved 833 set name alias const alias $moved 834 die "You may not promote a" #name "until it reaches the promotion zone." 835 endif 836 elseif onboard where #to 0 1 837 if == White_Pawn const alias space #to and count var prom 838 if not $answered and == mln $maxmln and not strstr thismove chr 59 839 if not match alias space #to var prom 840 push prom space #to 841 endif 842 askpromote #prom 843 endif 844 elseif not match space #to var prom and != White_Pawn const alias space #to 845 set name alias const alias $moved 846 set newname alias const alias space #to 847 set msg list "You may not promote your" #name "to a" join #newname ".
" 848 set msg str_replace "_" " " var msg 849 die #msg 850 endif 851 elseif count var prom 852 if == White_Pawn const alias space #to 853 if == count var prom 1 854 set newpiece alias list var prom 855 set pieceid realname #newpiece 856 set newmove join #newpiece "-dest" 857 add #pieceid $dest 858 appendmove #newmove 859 else 860 askpromote #prom 861 endif 862 elseif not match alias space #to var prom 863 set name alias const alias $moved 864 set newname alias const alias space #to 865 set msg list "You may not promote your" #name "to a" join #newname ".
" 866 set msg str_replace "_" " " var msg 867 die #msg 868 endif 869 else 870 set name alias const alias $moved 871 set msg list "You may not advance your" #name "to the last rank, because there is nothing you may promote it to." 872 set msg str_replace "_" " " var msg 873 die #msg 874 endif 875 set nopvc 0 876 return true 877 endsub 878 sub Black_Pawn from to 879 my newpiece, pieceid 880 my newmove 881 my prom 882 verify < rank #to rank #from 883 verify <= distance #to #from #fps 884 if capture 885 verify checkleap #from #to 1 1 886 set ep false 887 elseif checkleap #from #to 1 1 and #ep 888 verify == filename var ep filename #to 889 verify > rankname var ep rankname #to 890 verify > rankname #to var wpr 891 capture #ep 892 set ep false 893 elseif > distance #to #from 1 894 verify == rankname #from #bpr 895 verify checkride #from #to 0 1 896 set ep #to 897 else 898 verify checkleap #from #to 0 1 899 set ep false 900 endif 901 set prom fn Black_Pawn-Promote #to 902 if onboard where #to 0 neg #pzs 903 if != space #to $moved 904 set name alias const alias $moved 905 die "You may not promote a" #name "until it reaches the promotion zone." 906 endif 907 elseif onboard where #to 0 -1 908 if == Black_Pawn const alias space #to and count var prom 909 if not $answered and == mln $maxmln and not strstr thismove chr 59 910 push prom space #to 911 askpromote #prom 912 endif 913 elseif not match space #to var prom and != Black_Pawn const alias space #to 914 set name alias const alias $moved 915 set newname alias const alias space #to 916 set msg list "You may not promote your" #name "to a" join #newname ".
" 917 set msg str_replace "_" " " var msg 918 die #msg 919 endif 920 elseif count var prom 921 if == Black_Pawn const alias space #to 922 if == count var prom 1 923 set newpiece alias list var prom 924 set newmove join #newpiece "-dest" 925 set pieceid realname var newpiece 926 add #pieceid $dest 927 appendmove #newmove 928 else 929 askpromote #prom 930 endif 931 elseif not match alias space #to var prom 932 set name alias const alias $moved 933 set newname alias const alias space #to 934 set msg list "You may not promote your" #name "to a" join #newname ".
" 935 set msg str_replace "_" " " var msg 936 die #msg 937 endif 938 else 939 set name alias const alias $moved 940 set msg list "You may not advance your" #name "to the last rank, because there is nothing you may promote it to." 941 set msg str_replace "_" " " var msg 942 die #msg 943 endif 944 set nopvc 0 945 return true 946 endsub 947 set White_Quick_Pawn-Desc "The %s may move one or two spaces straight forward without capturing, or it may move one space diagonally forward to capture. If its two-space move takes it over a space an enemy %s could have captured it on if it had moved there, that %s may immediately capture it by en passant by moving to that space. On reaching the last rank, it must promote to any other piece except the King." 948 set Black_Quick_Pawn-Desc var White_Quick_Pawn-Desc 949 def White_Quick_Pawn remove var ep and < rankname #1 rankname var epf and < rankname var ep rankname #1 and == filename var ep filename #1 and checkleap #0 #1 1 1 and var ep or checkride #0 #1 0 1 and empty #1 and != var movetype CHECK or and or not empty #1 == var movetype CHECK checkleap #0 #1 1 1 and any onboard where #1 0 1 == var movetype CHECK count var wprom and <= distance #0 #1 var fps and > rank #1 rank #0 950 def Black_Quick_Pawn remove var ep and > rankname #1 rankname var epf and > rankname var ep rankname #1 and == filename var ep filename #1 and checkleap #0 #1 1 1 and var ep or checkride #0 #1 0 1 and empty #1 and != var movetype CHECK or and or not empty #1 == var movetype CHECK checkleap #0 #1 1 1 and any count var bprom onboard where #1 0 -1 == var movetype CHECK and <= distance #0 #1 var fps and < rank #1 rank #0 951 def White_Quick_Pawn-Range filter lambda (onboard #1) mergeall where #ori -1 1 where #ori 1 1 values lambda (where #ori 0 #1) range 1 var fps =ori 952 def Black_Quick_Pawn-Range filter lambda (onboard #1) mergeall where #ori -1 -1 where #ori 1 -1 values lambda (where #ori 0 neg #1) range 1 var fps =ori 953 def White_Quick_Pawn-Promote var wprom 954 def Black_Quick_Pawn-Promote var bprom 955 sub White_Quick_Pawn from to 956 my newpiece 957 my newmove 958 my prom 959 verify > rank #to rank #from 960 verify <= distance #to #from #fps 961 if capture 962 verify checkleap #from #to 1 1 963 set epf false 964 set ep false 965 elseif checkleap #from #to 1 1 and #ep 966 verify == filename var ep filename #to 967 verify < rankname var ep rankname #to 968 verify < rankname #to rankname var epf 969 capture #ep 970 set epf false 971 set ep false 972 elseif > distance #to #from 1 973 verify checkride #from #to 0 1 974 set epf #from 975 set ep #to 976 else 977 verify checkleap #from #to 0 1 978 set epf false 979 set ep false 980 endif 981 set prom fn White_Quick_Pawn-Promote #to 982 if onboard where #to 0 #pzs 983 if != space #to $moved 984 set name alias const alias $moved 985 die "You may not promote a" #name "from" $moved "to" {space #to} "until it reaches the promotion zone." 986 endif 987 elseif onboard where #to 0 1 988 if == White_Quick_Pawn const alias space #to and count var prom 989 if not $answered and == mln $maxmln and not strstr thismove chr 59 990 if not match alias space #to var prom 991 push prom space #to 992 endif 993 askpromote #prom 994 endif 995 elseif not match space #to var prom and != White_Quick_Pawn const alias space #to 996 set name alias const alias $moved 997 set newname alias const alias space #to 998 set msg list "You may not promote your" #name "to a" join #newname ".
" 999 set msg str_replace "_" " " var msg 1000 die #msg 1001 endif 1002 elseif count var prom 1003 if == White_Quick_Pawn const alias space #to 1004 if == count var prom 1 1005 set newpiece alias list var prom 1006 set pieceid realname #newpiece 1007 set newmove join #newpiece "-dest" 1008 add #pieceid $dest 1009 appendmove #newmove 1010 else 1011 askpromote #prom 1012 endif 1013 elseif not match alias space #to var prom 1014 set name alias const alias $moved 1015 set newname alias const alias space #to 1016 set msg list "You may not promote your" #name "to a" join #newname ".
" 1017 set msg str_replace "_" " " var msg 1018 die #msg 1019 endif 1020 else 1021 set name alias const alias $moved 1022 set msg list "You may not advance your" #name "to the last rank, because there is nothing you may promote it to." 1023 set msg str_replace "_" " " var msg 1024 die #msg 1025 endif 1026 set nopvc 0 1027 return true 1028 endsub 1029 sub Black_Quick_Pawn from to 1030 my newpiece, pieceid 1031 my newmove 1032 my prom 1033 verify < rank #to rank #from 1034 verify <= distance #to #from #fps 1035 if capture 1036 verify checkleap #from #to 1 1 1037 set ep false 1038 set epf false 1039 elseif checkleap #from #to 1 1 and #ep 1040 verify == filename var ep filename #to 1041 verify > rankname var ep rankname #to 1042 verify > rankname #to rankname var epf 1043 capture #ep 1044 set ep false 1045 set epf false 1046 elseif > distance #to #from 1 1047 verify checkride #from #to 0 1 1048 set ep #to 1049 set epf #from 1050 else 1051 verify checkleap #from #to 0 1 1052 set ep false 1053 set epf false 1054 endif 1055 set prom fn Black_Quick_Pawn-Promote #to 1056 if onboard where #to 0 neg #pzs 1057 if != space #to $moved 1058 set name alias const alias $moved 1059 die "You may not promote a" #name "until it reaches the promotion zone." 1060 endif 1061 elseif onboard where #to 0 -1 1062 if == Black_Quick_Pawn const alias space #to and count var prom 1063 if not $answered and == mln $maxmln and not strstr thismove chr 59 1064 push prom space #to 1065 askpromote #prom 1066 endif 1067 elseif not match space #to var prom and != Black_Quick_Pawn const alias space #to 1068 set name alias const alias $moved 1069 set newname alias const alias space #to 1070 set msg list "You may not promote your" #name "to a" join #newname ".
" 1071 set msg str_replace "_" " " var msg 1072 die #msg 1073 endif 1074 elseif count var prom 1075 if == Black_Quick_Pawn const alias space #to 1076 if == count var prom 1 1077 set newpiece alias list var prom 1078 set newmove join #newpiece "-dest" 1079 set pieceid realname var newpiece 1080 add #pieceid $dest 1081 appendmove #newmove 1082 else 1083 askpromote #prom 1084 endif 1085 elseif not match alias space #to var prom 1086 set name alias const alias $moved 1087 set newname alias const alias space #to 1088 set msg list "You may not promote your" #name "to a" join #newname ".
" 1089 set msg str_replace "_" " " var msg 1090 die #msg 1091 endif 1092 else 1093 set name alias const alias $moved 1094 set msg list "You may not advance your" #name "to the last rank, because there is nothing you may promote it to." 1095 set msg str_replace "_" " " var msg 1096 die #msg 1097 endif 1098 set nopvc 0 1099 return true 1100 endsub 1101 def Queen fn Bishop #0 #1 or fn Rook #0 #1 1102 def Queen-Range merge rays #0 1 0 rays #0 1 1 1103 set Queen-Desc "The %s may move as a Rook or a Bishop." 1104 def Rhino windingride #0 #1 1 0 1 1 or windingride #0 #1 0 1 1 1 1105 def Rhino-Range merge eval (windingrays #0 1 0 1 1) windingrays #0 0 1 1 1 1106 set Rhino-Desc "The %s moves along a winding path that alternates between the same one-space orthogonal move and the same one-space diagonal move both in the same general direction." 1107 def Rook checkride #0 #1 1 0 1108 def Rook-Range rays #0 1 0 1109 set Rook-Desc "The %s may move any number of spaces in any vertical or horizontal direction until it reaches an occupied space." 1110 def Short_Rook checkride #0 #1 1 0 and <= distance #0 #1 4 1111 def Short_Rook-Range merge merge leaps #0 1 0 leaps #0 2 0 merge leaps #0 3 0 leaps #0 4 0 1112 set "The %s may move up to four spaces along its rank or file as a Rook." 1113 def White_Shogi_Knight checkaleap #0 #1 1 2 or checkaleap #0 #1 -1 2 1114 def White_Shogi_Knight-Range array where #0 1 2 where #0 -1 2 1115 set White_Shogi_Knight-Desc "The %s may leap to either space that is two ranks ahead and one file to the side." 1116 def Black_Shogi_Knight checkaleap #0 #1 1 -2 or checkaleap #0 #1 -1 -2 1117 def Black_Shogi_Knight-Range array where #0 1 -2 where #0 -1 -2 1118 set Black_Shogi_Knight-Desc "The %s may leap to either space that is two ranks ahead and one file to the side." 1119 def White_Shogi_Pawn checkaleap #0 #1 0 1 1120 def White_Shogi_Pawn-Range array where #0 0 1 1121 set White_Shogi_Pawn-Desc "The %s map move one space forward in the same file." 1122 def Black_Shogi_Pawn checkaleap #0 #1 0 -1 1123 def Black_Shogi_Pawn-Range array where #0 0 -1 1124 set Black_Shogi_Pawn-Desc "The %s map move one space forward in the same file." 1125 def White_Silver_General checkaleap #0 #1 0 1 or checkleap #0 #1 1 1 1126 def White_Silver_General-Range mergeall leaps #0 1 1 where #0 0 1 1127 set White_Silver_General-Desc "The %s may move one space in any diagonal direction or one space vertically foward." 1128 def Black_Silver_General checkaleap #0 #1 0 -1 or checkleap #0 #1 1 1 1129 def Black_Silver_General-Range mergeall leaps #0 1 1 where #0 0 -1 1130 set Black_Silver_General-Desc "The %s may move one space in any diagonal direction or one space vertically foward." 1131 def Squirrel fn Elephant #0 #1 or fn Dabbabah #0 #1 or fn Knight #0 #1 1132 def Squirrel-Range mergeall leaps #0 2 2 leaps #0 2 0 leaps #0 1 2 1133 set Squirrel-Desc "The %s may leap any non-adjacent space that is no more than two spaces away." 1134 def Spider fn Dabbabah #0 #1 or fn Elephant #0 #1 1135 def Spider-Range merge leaps #0 2 2 leaps #0 0 2 1136 set Spider-Desc "The %s may leap to any space that is two spaces away orthogonally or diagonally." 1137 def Spider-rider fn Dabbabahrider #0 #1 or fn Elephantrider #0 #1 1138 def Spider-rider-Range merge rays #0 2 2 rays #0 0 2 1139 set Spider-rider-Desc "The %s may make any number of two-space leaps in a single orthogonal or diagonal direction. While each leap may take it over an occupied space, each leap but the last must be to an empty space." 1140 def Squire checktwostep #0 #1 0 1 1 1 or checktwostep #0 #1 1 1 0 1 1141 def Squire-Range leaps #0 1 2 1142 set Squire-Desc "The %s may move one space orthogonally, followed by one more space in an outward diagonal direction, or it may move one space diagonally, followed by one more space in an outward orthogonal direction. It must complete both parts of its move, and it may not pass over an occupied space. It can reach the same spaces as a Knight except that it can be blocked on the first step of its two-space move." 1143 def Unicorn fn Nightrider #0 #1 or fn Bishop #0 #1 1144 def Unicorn-Range merge rays #0 1 2 rays #0 1 1 1145 set Unicorn-Desc "The %s may make consecutive Knight moves in the same direction, as a Nightrider does, or it may move diagonally as a Bishop." 1146 def Vao cond cond empty #0 capture (not empty #1) (checkhop #0 #1 1 1) (checkride #0 #1 1 1) and #1 1147 def Vao-Range rays #0 1 1 1148 set Vao-Desc "The %s may move diagonally as a Bishop, but it must hop over exactly one intervening piece when it captures." 1149 def Wazir checkleap #0 #1 1 0 1150 def Wazir-Range leaps #0 1 0 1151 set Wazir-Desc "The %s may move one space horizontally or vertically." 1152 def Wizard fn Ferz #0 #1 or fn Camel #0 #1 1153 def Wizard-Range merge leaps #0 1 1 leaps #0 1 3 1154 set Wizard-Desc "The %s may move one space diagonally, or it may leap to a space three ranks and one file or three files and one rank away, as a Camel does." 1155 def Woody_Rook checkleap #0 #1 0 2 or checkleap #0 #1 0 1 1156 def Woody_Rook-Range merge leaps #0 0 1 leaps #0 0 2 1157 set Woody_Rook-Desc "The %s may leap one or two spaces orthogonally. It may pass over another piece when moving two spaces." 1158 def Zebra checkleap #0 #1 2 3 1159 def Zebra-Range leaps #0 2 3 1160 set Zebra-Desc "The %s may leap to any space that is 2 ranks and 3 files or 2 files and 3 ranks away." 1161 def Elephant_Ferz fn Ferz #0 #1 or fn Elephant #0 #1 1162 def Elephant_Ferz-Range merge leaps #0 2 2 leaps #0 1 1 1163 set Elephant_Ferz-Desc "The %s may leap one or two spaces diagonally. It may pass over another piece when moving two spaces." 1164 def Elephant_Wazir fn Wazir #0 #1 or fn Elephant #0 #1 1165 def Elephant_Wazir-Range merge leaps #0 2 2 leaps #0 1 0 1166 set Elephant_Wazir-Desc "The %s may move one space orthogonally, as a Wazir, or leap two spaces diagonally, as an Elephant." 1167 def Kylin fn Ferz #0 #1 or fn Dabbabah #0 #1 1168 def Kylin-Range mergeall leaps #0 1 1 leaps #0 2 0 1169 set Kylin-Desc "The %s may move one space diagonally, or it may leap 2 spaces orthogonally, passing over any pieces in the way." 1170 def Half_Duck fn Ferz #0 #1 or fn Dabbabah #0 #1 or checkleap #0 #1 3 0 1171 def Half_Duck-Range mergeall leaps #0 1 1 leaps #0 2 0 leaps #0 3 0 1172 set Half_Duck-Desc "The %s may move one space diagonally, or it may leap 2 or 3 spaces orthogonally, passing over any pieces in the way." 1173 def Knight_Wazir fn Knight #0 #1 or fn Wazir #0 #1 1174 def Knight_Wazir-Range merge leaps #0 1 2 leaps #0 1 0 1175 set Knight_Wazir-Desc "The %s may move one space orthogonally, as a Wazir, or it may leap as a Knight to any space one file and two ranks or two files and one rank away." 1176 def Frog fn Ferz #0 #1 or checkleap #0 #1 3 0 1177 def Frog-Range merge leaps #0 1 1 leaps #0 3 0 1178 set Frog-Desc "The %s may move one space diagonally or directly leap 3 spaces orthogonally." 1179 def Buffalo fn Knight #0 #1 or fn Camel #0 #1 or fn Zebra #0 #1 1180 def Buffalo-Range mergeall leaps #0 1 2 leaps #0 1 3 leaps #0 2 3 1181 set Buffalo-Desc "The %s Buffalo may leap (1, 2) as a Knight, (1, 3) as a Camel, or (2, 3) as a Zebra." 1182 def @ false 1183 sub attacked start finish 1184 my from piece actual 1185 local movetype 1186 set movetype MOVE 1187 if empty #start 1188 set actual true 1189 move #finish #start 1190 add $old #finish 1191 endif 1192 if isupper space #start 1193 def enemies onlylower 1194 else 1195 def enemies onlyupper 1196 endif 1197 for (from piece) fn enemies 1198 if fn const alias #piece #from #to 1199 if #actual 1200 move #start #finish 1201 endif 1202 return #from 1203 endif 1204 next 1205 if #actual 1206 move #start #finish 1207 endif 1208 return false 1209 endsub 1210 sub fission-attacked start finish 1211 my from piece p1 p2 1212 local movetype 1213 set p1 space #start 1214 set p2 space #finish 1215 set movetype CHECK 1216 if isupper #p1 1217 def enemies onlylower 1218 else 1219 def enemies onlyupper 1220 endif 1221 empty #finish 1222 for (from piece) fn enemies 1223 if fn const alias #piece #from #start 1224 add #p2 #finish 1225 return #from 1226 endif 1227 next 1228 add #p2 #finish 1229 return false 1230 endsub 1231 sub checked king 1232 my from piece 1233 local movetype 1234 set movetype CHECK 1235 if isupper cond empty var king $moved space var king 1236 def enemies onlylower 1237 else 1238 def enemies onlyupper 1239 endif 1240 for (from piece) fn enemies 1241 if fn const alias #piece #from var king and isfunc const alias #piece 1242 return #from 1243 endif 1244 next 1245 return false 1246 endsub 1247 def checked anytrue lambda (fn const alias #0 var key var king) cond isupper space var king (onlylower) (onlyupper) =movetype CHECK =king 1248 def threatened anytrue lambda (fn const alias space #0 #0 var king) elem var king threats =movetype CHECK =king 1249 sub uncheckedpath start finish 1250 my from to piece kingpos 1251 local movetype 1252 set movetype CHECK 1253 if empty #finish 1254 set kingpos #start 1255 else 1256 set kingpos #finish 1257 endif 1258 if isupper space #kingpos 1259 def enemies onlylower 1260 else 1261 def enemies onlyupper 1262 endif 1263 for to path #start #finish 1264 move #kingpos #to 1265 for (from piece) fn enemies 1266 if fn const alias #piece #from #to 1267 move #to #kingpos 1268 return false 1269 endif 1270 next 1271 move #to #kingpos 1272 next 1273 return true 1274 endif 1275 sub uncheckedknightleap start finish 1276 my from to piece kingpos kingpiece checkedpaths 1277 local movetype 1278 set movetype CHECK 1279 if empty #start 1280 set kingpos #finish 1281 else 1282 set kingpos #start 1283 endif 1284 if isupper space #kingpos 1285 def enemies onlylower 1286 else 1287 def enemies onlyupper 1288 endif 1289 set kingpiece space #kingpos 1290 set avenues merge intersection leaps #start 1 0 leaps #finish 1 1 intersection leaps #start 1 1 leaps #finish 1 0 1291 set checkdpaths 0 1292 for to #avenues 1293 if empty #to 1294 move #kingpos #to 1295 else 1296 empty #kingpos 1297 endif 1298 for (from piece) fn enemies 1299 if fn const alias #piece #from #to 1300 inc checkedpaths 1301 break 1302 endif 1303 next 1304 if == space #to #kingpiece 1305 move #to #kingpos 1306 else 1307 add #kingpiece #kingpos 1308 endif 1309 if == checkedpaths 0 1310 break 1311 endif 1312 next 1313 return < var checkedpaths 2 1314 endif 1315 sub castle from to 1316 local coord RPOS RDEST xdir 1317 if not flag #from 1318 die A King may not castle after it moves. 1319 endif 1320 if capture 1321 die A King may not castle to an occupied space. 1322 endif 1323 set xdir sign minus file #to file #from 1324 if not checkaride #from #to #xdir 0 1325 die A King may not castle across any occupied space. 1326 endif 1327 set coord #to 1328 do 1329 set coord where #coord #xdir 0 1330 if flag #coord 1331 break 1332 elseif not onboard #coord 1333 die No piece was found to castle with. 1334 elseif not empty #coord 1335 die The King cannot castle with the piece at #coord 1336 endif 1337 loop 1338 set RPOS #coord 1339 move #to #from 1340 if sub checked #from 1341 die A King may not castle out of check. 1342 endif 1343 store 1344 for coord path #from #to 1345 move #from #coord 1346 if sub checked #coord 1347 die A King may not castle through check. 1348 endif 1349 restore 1350 next 1351 move #from #to 1352 set RDEST where #to neg #xdir 0 1353 move #RPOS #RDEST 1354 return true 1355 endsub 1356 sub castlepos from to 1357 local coord RPOS RDEST xdir safe 1358 verify flag #from 1359 verify empty #to 1360 set xdir sign minus file #to file #from 1361 verify checkaride #from #to #xdir 0 1362 verify not sub checked #from 1363 set coord #to 1364 do 1365 set coord where #coord #xdir 0 1366 if flag #coord 1367 break 1368 endif 1369 verify onboard #coord 1370 verify empty #coord 1371 loop 1372 verify flag #coord 1373 set RPOS #coord 1374 store 1375 for coord path #from #to 1376 move #from #coord 1377 set safe not sub checked #coord 1378 restore 1379 verify #safe 1380 next 1381 move #from #to 1382 set RDEST where #to neg #xdir 0 1383 move #RPOS #RDEST 1384 set safe not sub checked #to 1385 restore 1386 return #safe 1387 endsub 1388 sub castle2 kingfrom kingto rookfrom rookto 1389 local coord xdir king rook 1390 if not flag #kingfrom 1391 die A King may not castle after it moves. 1392 endif 1393 if not flag #rookfrom 1394 die A King may not castle with a piece that has already moved. 1395 endif 1396 if not match @ $lastcaptured $prevcaptured 1397 die Castling to an occupied space is not allowed. 1398 endif 1399 if empty #kingto 1400 die There is nothing on #kingto. Did you move a piece there and then move it away? 1401 endif 1402 if empty #rookto 1403 die There is nothing on #rookto. Did you move a piece there and then move it away? 1404 endif 1405 set king space #kingto 1406 set rook space #rookto 1407 if == #king #rook 1408 die "Castling must be between different pieces. These two are both {#king}. What happened?" 1409 endif 1410 empty #kingto 1411 empty #rookto 1412 add #king #kingfrom 1413 add #rook #rookfrom 1414 set xdir sign minus file #kingto file #kingfrom 1415 if not checkaride #kingfrom #kingto #xdir 0 1416 die A King may not castle across any occupied space. 1417 endif 1418 if not checkaride #rookto #rookfrom #xdir 0 1419 die A Rook may not castle across an occupied space. 1420 endif 1421 if sub checked #kingfrom 1422 die A King may not castle out of check. 1423 endif 1424 store 1425 for coord path #kingfrom #kingto 1426 move #kingfrom #coord 1427 if sub checked #coord 1428 die A King may not castle through check. 1429 endif 1430 restore 1431 next 1432 empty #kingfrom 1433 empty #rookfrom 1434 add #king #kingto 1435 add #rook #rookto 1436 unsetflag #kingfrom #rookfrom 1437 if isupper space #kingto 1438 set Kpos #kingto 1439 else 1440 set kpos #kingto 1441 endif 1442 return true 1443 endsub 1444 sub castlepos2 kingfrom kingto rookfrom rookto 1445 echo "Calling castlepos2" #kingfrom #kingto #rookfrom #rookto 1446 local coord xdir safe 1447 verify flag #kingfrom and flag #rookfrom 1448 echo "Verified flags" 1449 verify empty #kingto or == #kingto #rookfrom 1450 verify empty #rookto or == #rookto #kingfrom 1451 echo "Verified empty destinations" 1452 set xdir sign minus file #kingto file #kingfrom 1453 echo "xdir is {#xdir}" 1454 verify checkride #kingfrom #kingto #xdir 0 1455 echo "Verified checkride {#kingfrom} {#kingto} {#xdir} 0" 1456 verify checkride #rookto #rookfrom #xdir 0 1457 echo "Verified checkride {#kingto} {#kingfrom} {#xdir} 0" 1458 verify not sub checked #kingfrom 1459 echo "Verified not checked" 1460 store 1461 for coord path #kingfrom #kingto 1462 move #kingfrom #coord 1463 set safe not sub checked #coord 1464 restore 1465 verify #safe 1466 next 1467 move #kingfrom #kingto 1468 move #rookfrom #rookto 1469 set safe not sub checked #kingto 1470 restore 1471 return #safe 1472 endsub 1473 sub stalemated kingpos 1474 store 1475 local cspaces friend friends from king piece to movetype np prom promfn 1476 set movetype MOVE 1477 set king alias space #kingpos 1478 if hasupper #king 1479 set friends lambda (onlyupper) 1480 set free lambda (haslower #0 or not hasupper #0) 1481 set pzone lambda (not onboard where #0 0 var pzs) 1482 set cspaces var wcastle 1483 set prom var wprom 1484 else 1485 set friends lambda (onlylower) 1486 set free lambda (hasupper #0 or not haslower #0) 1487 set pzone lambda (not onboard where #0 0 neg var pzs) 1488 set cspaces var bcastle 1489 set prom var bprom 1490 endif 1491 store 1492 for (from piece) fn #friends 1493 set af alias #from 1494 for to fn join const alias #piece "-Range" #from 1495 set at alias #to 1496 if fn const alias #piece #from #to and fn #free alias space #to and onboard #to 1497 set ap alias #piece 1498 move #from #to 1499 if not sub checked cond == #from #kingpos #to #kingpos 1500 set promfn join const alias #piece "-Promote" 1501 if fn #pzone #to and match #piece #promotable 1502 if > count var prom 0 1503 for np var prom 1504 setlegal "{#ap} {#af}-{#at}; {#np}-{#at}" 1505 next 1506 endif 1507 elseif fn #pzone #to and isfunc var promfn 1508 set prom fn var promfn #to 1509 if > count var prom 0 1510 for np var prom 1511 setlegal "{#ap} {#af}-{#at}; {#np}-{#at}" 1512 next 1513 endif 1514 elseif fn #pzone #to and match #piece #promotable 1515 if > count var prom 0 1516 for np var prom 1517 setlegal "{#ap} {#af}-{#at}; {#np}-{#at}" 1518 next 1519 endif 1520 else 1521 setlegal "{#ap} {#af}-{#at}" 1522 endif 1523 endif 1524 endif 1525 restore 1526 next 1527 next 1528 if > count var cspaces 0 1529 for to var cspaces 1530 if sub castlepos #kingpos #to 1531 setlegal "{#king} {#kingpos}-{#to}" 1532 endif 1533 next 1534 endif 1535 setsystem autorules sub describe_rules 1536 return cond count system legalmoves false true 1537 endsub 1538 sub stalemated-quick kingpos 1539 store 1540 local checked checkpos cspaces enemies friend friends from in king piece threats to movetype np prom promfn 1541 set movetype MOVE 1542 set king alias space #kingpos 1543 if hasupper #king 1544 set friends lambda (onlyupper) 1545 set enemies lambda (onlylower) 1546 set free lambda (haslower #0 or not hasupper #0) 1547 set pzone lambda (not onboard where #0 0 var pzs) 1548 set cspaces var wcastle 1549 set prom var wprom 1550 else 1551 set friends lambda (onlylower) 1552 set enemies lambda (onlyupper) 1553 set free lambda (hasupper #0 or not haslower #0) 1554 set pzone lambda (not onboard where #0 0 neg var pzs) 1555 set cspaces var bcastle 1556 set prom var bprom 1557 endif 1558 set krange merge fn join const alias space #kingpos "-Range" #kingpos #kingpos 1559 set threats () 1560 for to #krange 1561 set threats.{#to} () 1562 next 1563 for (from piece) fn #enemies 1564 set in intersection var krange fn join const alias var piece "-Range" var from 1565 for to #in 1566 push threats.{#to} #from 1567 next 1568 next 1569 store 1570 for (from piece) fn #friends 1571 set af alias #from 1572 for to fn join const alias #piece "-Range" #from 1573 set at alias #to 1574 if fn const alias #piece #from #to and fn #free alias space #to and onboard #to 1575 set ap alias #piece 1576 set checkpos cond == #from #kingpos #to #kingpos 1577 set checked false 1578 if count elem var checkpos threats 1579 move #from #to 1580 set checked fn threatened #checkpos 1581 restore 1582 endif 1583 if not #checked 1584 set promfn join const alias #piece "-Promote" 1585 if fn #pzone #to and match #piece #promotable 1586 if > count var prom 0 1587 for np var prom 1588 setlegal "{#ap} {#af}-{#at}; {#np}-{#at}" 1589 next 1590 endif 1591 elseif fn #pzone #to and isfunc var promfn 1592 set prom fn var promfn #to 1593 if > count var prom 0 1594 for np var prom 1595 setlegal "{#ap} {#af}-{#at}; {#np}-{#at}" 1596 next 1597 endif 1598 elseif fn #pzone #to and match #piece #promotable 1599 if > count var prom 0 1600 for np var prom 1601 setlegal "{#ap} {#af}-{#at}; {#np}-{#at}" 1602 next 1603 endif 1604 else 1605 setlegal "{#ap} {#af}-{#at}" 1606 endif 1607 endif 1608 endif 1609 restore 1610 next 1611 next 1612 if > count var cspaces 0 1613 for to var cspaces 1614 if sub castlepos #kingpos #to 1615 setlegal "{#king} {#kingpos}-{#to}" 1616 endif 1617 next 1618 endif 1619 setsystem autorules sub describe_rules 1620 return cond count system legalmoves false true 1621 endsub 1622 sub stalemated2 kingpos 1623 store 1624 local cspaces friend friends from piece to movetype 1625 set movetype MOVE 1626 if isupper space #kingpos 1627 set friends (onlyupper) 1628 set friend (isupper #0) 1629 set cspaces var wcastle 1630 else 1631 set friends (onlylower) 1632 set friend (islower #0) 1633 set cspaces var bcastle 1634 endif 1635 set royal space var kingpos 1636 store 1637 for (from piece) fn #friends 1638 for to fn join const alias #piece "-Range" #from 1639 if fn const alias #piece #from #to and not fn #friend space #to and onboard #to 1640 move #from #to 1641 if not sub checked cond == #from #kingpos #to #kingpos 1642 set ap alias #piece 1643 setlegal "{#ap} {#from}-{#to}" 1644 endif 1645 endif 1646 restore 1647 next 1648 next 1649 if > count var cspaces 0 and flag #kingpos 1650 for mvs var cspaces 1651 if sub castlepos2 #mvs.0 #mvs.1 #mvs.2 #mvs.3 and == #kingpos #mvs.0 1652 set pk alias space #mvs.0 1653 set pr alias space #mvs.2 1654 setlegal "{#pk} {#mvs.0}-{#mvs.1}; {#pr} {#mvs.2}-{#mvs.3}" 1655 endif 1656 next 1657 endif 1658 setsystem autorules sub describe_rules 1659 return cond count system legalmoves false true 1660 endsub 1661 sub fusion-stalemated kingpos 1662 store 1663 local cspaces friend friends from piece to movetype mv ss 1664 set movetype MOVE 1665 set ss join chr 47 chr 47 1666 if isupper space #kingpos 1667 set friends (onlyupper) 1668 set friend (isupper #0) 1669 set cspaces var wcastle 1670 else 1671 set friends (onlylower) 1672 set friend (islower #0) 1673 set cspaces var bcastle 1674 endif 1675 set royal space var kingpos 1676 store 1677 set kp #kingpos 1678 for (from piece) fn #friends 1679 set ap alias #piece 1680 for to fn join const #ap "-Range" #from 1681 if != space #to #piece and match toupper alias space #to K R B N and match toupper alias #piece R B N or not fn #friend space #to and fn const alias #piece #from #to and onboard #to 1682 move #from #to 1683 if match #ap K KR KB KN k kr kb kn 1684 set kp #to 1685 endif 1686 if not sub checked #kp 1687 setlegal "{#ap} {#from}-{#to}" 1688 endif 1689 restore 1690 set kp #kingpos 1691 endif 1692 if not sub checked #from and empty #to and == strlen alias #piece 2 1693 set compound alias #piece 1694 set simple1 leftstr #compound 1 1695 set simple2 rightstr #compound 1 1696 if != not fn #friend space #to and fn const alias #simple1 #from #to 1697 add #simple1 #to 1698 add #simple2 #from 1699 if match #simple1 K k 1700 set kp #to 1701 endif 1702 if not sub checked #kp 1703 setlegal "{#simple1} {#from}-{#to}; {#ss} {#simple2}-{#from}" 1704 endif 1705 restore 1706 set kp #kingpos 1707 endif 1708 if != not fn #friend space #to and fn const alias #simple2 #from #to 1709 add #simple2 #to 1710 add #simple1 #from 1711 if match #simple1 K k 1712 set kp #from 1713 endif 1714 if not sub checked #kp 1715 setlegal "{#simple2} {#from}-{#to}; {#ss} {#simple1}-{#from}" 1716 endif 1717 restore 1718 set kp #kingpos 1719 endif 1720 endif 1721 next 1722 next 1723 if > count var cspaces 0 1724 for to var cspaces 1725 if sub castlepos #kingpos #to 1726 setlegal (#kingpos #to) 1727 endif 1728 next 1729 endif 1730 setsystem autorules sub describe_rules 1731 return cond count system legalmoves false true 1732 endsub 1733 sub describe_rules 1734 my c piecenames notation values val id ref rules desc name codename rangefn 1735 set c.0 join filename 0 rankname 0 1736 set c.1 join filename >> lastfile 1 rankname 1 1737 set c.2 join filename inc >> lastfile 1 rankname 1 1738 set c.3 join filename >> lastfile 1 rankname inc >> lastrank 1 1739 set c.4 join filename inc >> lastfile 1 rankname >> lastrank 1 1740 set c.5 join filename >> lastfile 1 rankname dec lastrank 1741 set c.6 join filename inc >> lastfile 1 rankname dec lastrank 1742 set c.7 join filename lastfile rankname lastrank 1743 foreach p keys $pieces 1744 if isconst alias #p 1745 set codename const alias #p 1746 set name alias #codename 1747 set notation.{#name} alias #p 1748 if match #codename const alias space #kpos const alias space #Kpos 1749 set values.{#name} * 8 count spaces 1750 else 1751 set rangefn join #codename "-Range" 1752 set values.{#name} sum lambda (count fn #rangefn #0) #c 1753 endif 1754 endif 1755 next 1756 set values reverse asort #values 1757 set rules "
" 1758 foreach (name val) #values 1759 set codename realname #name 1760 if == null var #codename 1761 set codename #name 1762 endif 1763 set ref join #codename "-Desc" 1764 set desc str_replace "%s" #name var #ref 1765 set desc str_replace "_" " " #desc 1766 set id realname #notation.{#name} 1767 set rules join #rules "
[pc {#id} {#name}]{#desc}[/pc]
" 1768 next 1769 set rules join #rules "
" 1770 return #rules 1771 endsub 1772 sub findmates side 1773 local enemyking king mates moves mv 1774 if match #side 1 white White first 1775 set king #Kpos 1776 set enemyking #kpos 1777 else 1778 set king #kpos 1779 set enemyking #Kpos 1780 endif 1781 set mates () 1782 ban none 1783 setsystem maxmove 0 1784 store main 1785 setsystem legalmoves () 1786 if not sub stalemated #king 1787 set lglmvs $legalmoves 1788 foreach move #lglmvs 1789 set moves explode chr 59 #move 1790 foreach mv #moves 1791 set mv trim #mv 1792 eval "MOVE: {#mv}" 1793 next 1794 if sub checked #enemyking 1795 setsystem legalmoves () 1796 if sub stalemated #enemyking 1797 push mates #move 1798 endif 1799 endif 1800 restore main 1801 next 1802 endif 1803 setsystem legalmoves #mates 1804 endsub 1805 endlib