-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMoves.cs
More file actions
605 lines (546 loc) · 36.8 KB
/
Moves.cs
File metadata and controls
605 lines (546 loc) · 36.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
// TODO: use stringbuilder instead for the list and hist.
// strinbuilders do not have indexof and startswith method, might need?
// stringbuilder is going to be faster
// DONE: reverse bits faster
//
// Algo for sliders
// ' = reverse: o = occupied: r = rook:
// lineAttacks = ( o - 2r ) ^ reverse( o'- 2r')
// o - r removes the piece
// o -r again borrows from the next peice (attacks) and fills the traversed fields with 1s
// doing the same but reversing everything makes the slider go right (towards most least significant bit) ( board is from A8 = 1st bit H1 = 64th bit )
// https://www.chessprogramming.org/Hyperbola_Quintessence
//
using System;
// using System.Collections.Generic;
// using System.Linq;
using System.Text;
using System.Threading.Tasks;
// using System.Globalization;
namespace ChessBitboard{
public class Moves{
public static UInt64 fileA = 0x101010101010101; // 1 on every field on A file
public static UInt64 fileH = 0x8080808080808080; // 1 on H file
public static UInt64 fileAB = 0x303030303030303; // 1 on file A & B
public static UInt64 fileGH = 0xC0C0C0C0C0C0C0C0; // 1 on file H & H
public static UInt64 rank1 = 0xFF00000000000000;
public static UInt64 rank4 = 0xFF00000000;
public static UInt64 rank5 = 0xFF000000;
public static UInt64 rank8 = 0xFF;
public static UInt64 center = 0x1818000000;
public static UInt64 centerBig = 0x3C3C3C3C0000;
public static UInt64 kingSide = 0xF0F0F0F0F0F0F0F;
public static UInt64 queenSide = 0xF0F0F0F0F0F0F0F0;
public static UInt64 notMyPieces; // every piece that the side can not capture including oppesit side king to stop illegal capture
public static UInt64 empty; // every field empty
public static UInt64 occupied;
public static UInt64 notMyPiecesAndOccu;
public static char[] Zero2 = new char[4] {'0', '4', '0', '2'};
public static char[] Zero6 = new char[4] {'0', '4', '0', '6'};
public static char[] Seven2 = new char[4] {'7', '4', '7', '2'};
public static char[] Seven6 = new char[4] {'7', '4', '7', '6'};
public static UInt64[] Rankmasks8 = new UInt64[]{
0xFF,0xFF00,0xFF0000,0xFF000000,0xFF00000000,0xFF0000000000,0xFF000000000000,0xFF00000000000000
};
public static UInt64[] Filemasks8 = new UInt64[]{
0x101010101010101,0x202020202020202,0x404040404040404,0x808080808080808,0x1010101010101010,0x2020202020202020,0x4040404040404040,0x8080808080808080
};
public static UInt64[] Diagonalmasks8 = new UInt64[]{
0x1, 0x102, 0x10204, 0x1020408, 0x102040810, 0x10204081020, 0x1020408102040,
0x102040810204080, 0x204081020408000, 0x408102040800000, 0x810204080000000,
0x1020408000000000, 0x2040800000000000, 0x4080000000000000, 0x8000000000000000
};
public static UInt64[] AntiDiagonalmasks8 = new UInt64[]{
0x80, 0x8040, 0x804020, 0x80402010, 0x8040201008, 0x804020100804, 0x80402010080402,
0x8040201008040201, 0x4020100804020100, 0x2010080402010000, 0x1008040201000000,
0x804020100000000, 0x402010000000000, 0x201000000000000, 0x100000000000000
};
public static UInt64 makeMove(UInt64 board, char[] moves, char type, int start, int end){
if ( Tools.IsCharDigit(moves[3])){ //if last digit of move string is digit then its a normal move
//int end = (((moves[2] - '0') * 8) + (moves[3] - '0'));
if (((board >> start) & 1) == 1) {
board = board & ~((UInt64)1 << start); // remove piece from start
board = board | ((UInt64)1 << end); // add the piece to the end
}
else{
board = board & ~((UInt64)1 << end); // remove piece if it got attacked
}
}else if(moves[3] == 'P'){ // if last char in move string is P its a promotion
int startp, endp;
if (char.IsUpper(moves[2])){ // if 3 char is upper case then its white promoting a piece
startp = Tools.trailingZerosRight(Filemasks8[moves[0] - '0'] & Rankmasks8[1]); // get start position by ANDing rank and file - i only have start file and end file - i know a promotion for white can only happen from rank 7 to 8
endp = Tools.trailingZerosRight(Filemasks8[moves[1] - '0'] & Rankmasks8[0]);
}else{
startp = Tools.trailingZerosRight(Filemasks8[moves[0] - '0'] & Rankmasks8[6]);
endp = Tools.trailingZerosRight(Filemasks8[moves[1] - '0'] & Rankmasks8[7]);
}
if(type == moves[2]) { // if the promote is the same as the pieceboard making moves, add the promoted piece to board on endp location
board = board | ((UInt64)1 << endp); // add the piece to the end
}else {
board = board & ~((UInt64)1 << startp); // remove piece from start
board = board & ~((UInt64)1 <<endp);
}
}
else if (moves[3] == 'E'){ // if last char is E the move is en passant // moves[0] and moves[1] is file from and file to
int starte, ende;
if (moves[2] == 'W'){ // if 3 char is W then its white en passant
starte = Tools.trailingZerosRight(Filemasks8[moves[0] - '0'] & Rankmasks8[3]); // get start position
ende = Tools.trailingZerosRight(Filemasks8[moves[1] - '0'] & Rankmasks8[2]); //
board = board & ~(Filemasks8[moves[1] - '0'] & Rankmasks8[3]); // remove taken pawn - file is move to and rank is the startering rank which is the rank opponent will be at
}else{
starte = Tools.trailingZerosRight(Filemasks8[moves[0] - '0'] & Rankmasks8[4]);
ende = Tools.trailingZerosRight(Filemasks8[moves[1] - '0'] & Rankmasks8[5]);
board = board & ~(Filemasks8[moves[1] - '0'] & Rankmasks8[4]); // remove taken pawn
}
if (((board >> starte) & 1 ) == 1 ){ // if pieceBoard is equal to start location
board = board & ~((UInt64)1 << starte); // remove piece from start location
board = board | ((UInt64)1 << ende); // add pawn to end location (behind taken pawn)
}
}
return board;
}
public static UInt64 CastleMove(UInt64 Rook, UInt64 King, char[] Cmoves, char type, int start){
if (((King >> start) & 1) == 1){
if (Tools.ArrC(Cmoves, Zero2) || Tools.ArrC(Cmoves, Zero6) || Tools.ArrC(Cmoves, Seven2) || Tools.ArrC(Cmoves, Seven6)){
string move = new string(Cmoves);
if(type == 'R'){
switch(move){
case "7472":
Rook = Rook & ~((UInt64)1 << 56); // remove piece from start
Rook = Rook | ((UInt64)1 << 59); // add the piece to d1 sq
break;
case "7476":
Rook = Rook & ~((UInt64)1 << 63); // remove piece from start
Rook = Rook | ((UInt64)1 << 61); // add the piece to f1 sq
break;
}
} else if (type == 'r') {
switch(move){
case "0402":
Rook = Rook & ~((UInt64)1); // remove piece from start
Rook = Rook | ((UInt64)1 << 3); // add the piece to f8 sq
break;
case "0406":
Rook = Rook & ~((UInt64)1 << 7); // remove piece from start
Rook = Rook | ((UInt64)1 << 5); // add the piece to d1 sq
break;
}
}
}
}
return Rook;
}
public static UInt64 makeMoveEP(UInt64 board, char[] moves, int start){
if ((Tools.Abs(moves[0] - moves[2]) == 2) && (((board >> start) & 1) == 1)){ // if moved 2 forward on file and pawnboard shifted with start location is 1 then its a pawn
return Filemasks8[moves[1] - '0'];
}
return (UInt64)0;
}
public static UInt64 HandVMoves(int square){
UInt64 bitboardSq = (UInt64)1 << square;
UInt64 revO = Tools.reverseBit(occupied);
UInt64 revBitSq = Tools.reverseBitSingle(bitboardSq) * 2;
int rank = square / 8;
int file = square % 8;
//turn square number into binary bitboard representing piece
// use ( o - 2r ) ^ reverse( reverse(o) - 2 * reverse(r)) for horizontal attacks
// first part is attack toward MSB (right)
UInt64 possibleH = (occupied - 2 * bitboardSq) ^ Tools.reverseBit(revO - revBitSq);
// use ( o - 2r ) ^ reverse( reverse(o) - 2 * reverse(r)) same but with masksing occupied with the file the piece is on for vertical attacks
UInt64 possibleV = ((occupied & Filemasks8[file]) - (2 * bitboardSq)) ^ Tools.reverseBit(Tools.reverseBit(occupied & Filemasks8[file]) - revBitSq);
return (possibleH & Rankmasks8[rank]) | (possibleV & Filemasks8[file]); // & with masks and | to combine vertial and horizontal
}
public static UInt64 DandAntiDMoves(int square){
int rank = square / 8;
int file = square % 8;
UInt64 bitboardSq = (UInt64)1 << square;
UInt64 revBitSq = Tools.reverseBitSingle(bitboardSq);
UInt64 possibleD = ((occupied & Diagonalmasks8[rank + file]) - (2 * bitboardSq)) ^ Tools.reverseBit(Tools.reverseBit(occupied & Diagonalmasks8[rank + file]) - (2 * revBitSq));
UInt64 possibleAntiD = ((occupied & AntiDiagonalmasks8[rank + 7 - file]) - (2 * bitboardSq)) ^ Tools.reverseBit(Tools.reverseBit(occupied & AntiDiagonalmasks8[rank + 7 - file]) - (2 * revBitSq));
return (possibleD & Diagonalmasks8[rank + file]) | (possibleAntiD & AntiDiagonalmasks8[rank + 7 - file]);
}
private static StringBuilder list = new StringBuilder();
public static string possibleMovesW(UInt64 bKB, UInt64 bQB, UInt64 bRB, UInt64 bBB, UInt64 bNB, UInt64 bPB, UInt64 wKB, UInt64 wQB, UInt64 wRB, UInt64 wBB, UInt64 wNB, UInt64 wPB, UInt64 EPB, bool castleWKside, bool castleWQside, bool castleBKside, bool castleBQside){
notMyPieces=~(wKB|wQB|wRB|wNB|wBB|wPB|bKB); // or'd every white piece and black king to indicate what the white pieces cant capture, also black king to avoid illegal capture
occupied = bKB|bQB|bRB|bBB|bNB|bPB|wKB|wQB|wRB|wBB|wNB|wPB; // or all pieces together to get occupied
empty = ~occupied;// indicates empty fields with a 1 with flip ~ of occupied
notMyPiecesAndOccu = notMyPieces & occupied;
list.Clear();
possibleWP(wPB, bPB, EPB);
possibleB(occupied, wBB);
possibleR(occupied, wRB);
possibleQ(occupied, wQB);
possibleN(occupied, wNB);
possibleK(occupied, wKB);
possibleCW(bKB, bQB, bRB, bBB, bNB, bPB, wKB, wQB, wRB, wBB, wNB, wPB, castleWKside, castleWQside);
return list.ToString();
}
public static string possibleMovesB(UInt64 bKB, UInt64 bQB, UInt64 bRB, UInt64 bBB, UInt64 bNB, UInt64 bPB, UInt64 wKB, UInt64 wQB, UInt64 wRB, UInt64 wBB, UInt64 wNB, UInt64 wPB, UInt64 EPB, bool castleWKside, bool castleWQside, bool castleBKside, bool castleBQside){
notMyPieces=~(bKB|bQB|bRB|bNB|bBB|bPB|wKB);
occupied = bKB|bQB|bRB|bBB|bNB|bPB|wKB|wQB|wRB|wBB|wNB|wPB; // or all pieces together to get occupied
empty = ~occupied; // indicates empty fields with a 1 with flip ~ of occupied
notMyPiecesAndOccu = notMyPieces & occupied;
list.Clear();
possibleBP(bPB, wPB, EPB);
possibleB(occupied, bBB);
possibleR(occupied, bRB);
possibleQ(occupied, bQB);
possibleN(occupied, bNB);
possibleK(occupied, bKB);
possibleCB(bKB, bQB, bRB, bBB, bNB, bPB, wKB, wQB, wRB, wBB, wNB, wPB, castleBKside, castleBQside);
return list.ToString();
}
public static void possibleCW(UInt64 bKB, UInt64 bQB, UInt64 bRB, UInt64 bBB, UInt64 bNB, UInt64 bPB, UInt64 wKB, UInt64 wQB, UInt64 wRB, UInt64 wBB, UInt64 wNB, UInt64 wPB, bool castleWKside, bool castleWQside){
if (castleWKside){ // check if king has moved or rook on king side moved
if ((occupied & (((UInt64)1 << 61) | ((UInt64)1 << 62))) == 0 && ((wRB & ((UInt64)1 << 63)) != 0)){ // sq in between are empty
UInt64 unsafeSq = unsafeWhite(bKB, bQB, bRB, bBB, bNB, bPB, wKB, wQB, wRB, wBB, wNB, wPB);
if((unsafeSq & ((wKB | ((UInt64)1 << 61)) | ((UInt64)1 << 62))) == 0){ // king is not in check and field it moves over are not under attack
list.Append("7476");
}
}
}
if (castleWQside){ // check if king has moved or rook on queen side moved
if ((occupied & (((UInt64)1 << 57) | ((UInt64)1 << 58) | ((UInt64)1 << 59))) == 0 && ((wRB & ((UInt64)1 << 56)) != 0)){ // sq in between are empty
UInt64 unsafeSqWQ = unsafeWhite(bKB, bQB, bRB, bBB, bNB, bPB, wKB, wQB, wRB, wBB, wNB, wPB);
if((unsafeSqWQ & ((wKB | ((UInt64)1 << 58)) | ((UInt64)1 << 59))) == 0){ // king is not in check and field it moves over are not under attack
list.Append("7472");
}
}
}
}
public static void possibleCB(UInt64 bKB, UInt64 bQB, UInt64 bRB, UInt64 bBB, UInt64 bNB, UInt64 bPB, UInt64 wKB, UInt64 wQB, UInt64 wRB, UInt64 wBB, UInt64 wNB, UInt64 wPB, bool castleBKside, bool castleBQside){
if (castleBKside){ // check if king has moved or rook on king side moved
if ((occupied & (((UInt64)1 << 5) | ((UInt64)1 << 6))) == 0 && ((bRB & ((UInt64)1 << 7)) != 0)){ // sq in between are empty
UInt64 unsafeSq = unsafeBlack(bKB, bQB, bRB, bBB, bNB, bPB, wKB, wQB, wRB, wBB, wNB, wPB);
if((unsafeSq & ((bKB | ((UInt64)1 << 5)) | ((UInt64)1 << 6))) == 0){ // king is not in check and field it moves over are not under attack
list.Append("0406");
}
}
}
if (castleBQside){ // check if king has moved or rook on queen side moved
if ((occupied & (((UInt64)1 << 1) | ((UInt64)1 << 2) | ((UInt64)1 << 3))) == 0 && ((bRB & (UInt64)1) != 0)){ // sq in between are empty
UInt64 unsafeSqBQ = unsafeBlack(bKB, bQB, bRB, bBB, bNB, bPB, wKB, wQB, wRB, wBB, wNB, wPB);
if((unsafeSqBQ & ((bKB | ((UInt64)1 << 2)) | ((UInt64)1 << 3))) == 0){ // king is not in check and field it moves over are not under attack
list.Append("0402");
}
}
}
}
public static void possibleN(UInt64 occupied, UInt64 N){
UInt64 i = N & ~(N-1); // get first knight to check for moves
UInt64 possible;
while(i != 0){
int iLocation = Tools.trailingZerosRight(i); // get number of zeroes until first 1 from left to right - the number is equal to the index on board of knight
possible = Span.Knight[iLocation] & notMyPieces; // put location in index of array with all 64 possible knight locations // turns out to not be faster than calculating possible location on the spot
UInt64 k = possible & ~(possible-1); // get one of the possiblities
while (k != 0){ // goes trough each of the possibilies
int index = Tools.trailingZerosRight(k); // get index of move to
list.Append(iLocation / 8).Append(iLocation % 8).Append(index / 8).Append(index % 8); // iLocation where the knight is and index where the knight can move to
possible = possible & ~k; // remove the move from possibiliies that was just listed
k = possible & ~(possible-1); // get the next move possible
}
N = N & ~i; // remove the knight that was checked for all moves
i = N & ~(N-1); // get the next knight to check for all moves
}
}
public static void possibleK(UInt64 occupied, UInt64 K){
int iLocation = Tools.trailingZerosRight(K); // get number of zeroes until first 1 from left to right - the number is equal to the index on board of knight
UInt64 possible = Span.King[iLocation] & notMyPieces; // put location into index of array with all possible kingspans
UInt64 i = possible & ~(possible-1); // get one of the possiblities
while (i != 0){ // goes trough each of the possibilies
int index = Tools.trailingZerosRight(i); // get index of move to
list.Append(iLocation / 8).Append(iLocation % 8).Append(index / 8).Append(index % 8); // iLocation where the knight is and index where the knight can move to
possible = possible & ~i; // remove the move from possibiliies that was just listed
i = possible & ~(possible-1); // get the next move possible
}
}
public static void possibleQ(UInt64 occupied, UInt64 Q){
UInt64 i = Q & ~(Q-1); // get first queen to check for moves
UInt64 possible;
while(i != 0){
int iLocation = Tools.trailingZerosRight(i); // get number of zeroes until first 1 from left to right - the number is equal to the index on board of queen
possible = (DandAntiDMoves(iLocation) | HandVMoves(iLocation)) & notMyPieces; // get diagonal and antidiagonal moves for the selected piece and with not my pieces
UInt64 k = possible & ~(possible-1); // get one of the possiblities
while (k != 0){ // goes trough each of the possibilies
int index = Tools.trailingZerosRight(k); // get index of move to
list.Append(iLocation / 8).Append(iLocation % 8).Append(index / 8).Append(index % 8); // iLocation where the Queen is and index where the Queen can move to
possible = possible & ~k; // remove the move from possibiliies that was just listed
k = possible & ~(possible-1); // get the next move possible
}
Q = Q & ~i; // remove the Queen that was checked for all moves
i = Q & ~(Q-1); // get the next Queen to check for all moves
}
}
public static void possibleB(UInt64 occupied, UInt64 B){
UInt64 i = B & ~(B-1); // get first bishop to check for moves
UInt64 possible;
while(i != 0){
int iLocation = Tools.trailingZerosRight(i); // get number of zeroes until first 1 from left to right - the number is equal to the index on board of bishop
possible = DandAntiDMoves(iLocation)¬MyPieces; // get diagonal and antidiagonal moves for the selected piece and with not my pieces
UInt64 k = possible & ~(possible-1); // get one of the possiblities
while (k != 0){ // goes trough each of the possibilies
int index = Tools.trailingZerosRight(k); // get index of move to
list.Append(iLocation / 8).Append(iLocation % 8).Append(index / 8).Append(index % 8); // iLocation where the bishop is and index where the bishop can move to
possible = possible & ~k; // remove the move from possibiliies that was just listed
k = possible & ~(possible-1); // get the next move possible
}
B = B & ~i; // remove the bishop that was checked for all moves
i = B & ~(B-1); // get the next bishop to check for all moves
}
}
public static void possibleR(UInt64 occupied, UInt64 R){
UInt64 i = R & ~(R-1); // get first rook to check for moves
UInt64 possible;
while(i != 0){
int iLocation = Tools.trailingZerosRight(i); // get number of zeroes until first 1 from left to right - the number is equal to the index on board of rook
possible = HandVMoves(iLocation)¬MyPieces; // get hori and verti moves for the selected piece and with not my pieces
UInt64 k = possible & ~(possible-1); // get one of the possiblities
while (k != 0){ // goes trough each of the possibilies
int index = Tools.trailingZerosRight(k); // get index of move to
list.Append(iLocation / 8).Append(iLocation % 8).Append(index / 8).Append(index % 8); // iLocation where the rook is and index where the rook can move to
possible = possible & ~k; // remove the move from possibiliies that was just listed
k = possible & ~(possible-1); // get the next move possible
}
R = R & ~i; // remove the rook that was checked for all moves
i = R & ~(R-1); // get the next rook to check for all moves
}
}
public static void possibleWP(UInt64 wPB, UInt64 bPB, UInt64 EPB){
//x1,y1,x2,y2
UInt64 pMoves = (wPB>>7) & notMyPiecesAndOccu & ~rank8 & ~fileA; // shift everything to the right by 7 to indicate capture right, and there is black piece and not on rank8 and not file H to stop capture one the other side of board
/* gets the first pawn-bit-move and puts into possibleMoves (if any) in a bitboard alone to put into moves list:
* possibleMoves =
* pMove = 10100011
* -1 ~ = 01011101
* & = 00000001
* then later the tested pawn-bit is removed like so:
* possibleMoves =
* pMove = 10100011
* & ~ = 11111110
* = 10100010 == moved that was put into list is removed others remain
* */
UInt64 possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves); // puts the index to the first pawn by counting number of 0's to the right
list.Append(index/8+1).Append(index%8-1).Append(index/8).Append(index%8); //add move cords to list // first index +1 to get back to startlocation in the internal rank representation
pMoves &= ~(possibleMoves); // the listed move is removed from pMoves
possibleMoves = pMoves & ~(pMoves-1); // gets the next move alone in a bitboard
}
pMoves = (wPB>>9) & notMyPiecesAndOccu & ~rank8 & ~fileH; // shift everything to the right by 9 to indicate capture left, and there is black piece and not on rank8 and not file A to stop capture on the other side of board
possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index/8+1).Append(index%8+1).Append(index/8).Append(index%8); //add move cords to list
pMoves &= ~(possibleMoves);
possibleMoves = pMoves & ~(pMoves-1);
}
pMoves = (wPB>>8) & empty & ~rank8; // shift everything to the right by 8 to indicate move forward by one, and there is empty field and not on rank8
possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index/8+1).Append(index%8).Append(index/8).Append(index%8); //add move cords to list
pMoves &= ~(possibleMoves);
possibleMoves = pMoves & ~(pMoves-1);
}
pMoves = (wPB>>16) & empty & (empty>>8) & rank4; // shift everything to the right by 16 to indicate move forward and field is empty and field infront is empty and it is rank 4(meaning only when rank2 posistion can it move this way)
possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index/8+2).Append(index%8).Append(index/8).Append(index%8); //add move cords to list
pMoves &= ~(possibleMoves);
possibleMoves = pMoves & ~(pMoves-1);
}
// y1, y2, promotype, "P"
pMoves = (wPB>>7) & notMyPiecesAndOccu & rank8 & ~fileA; // shift everything to the right by 7 to indicate capture right, and there is black piece and not on rank8 and not file H to stop capture one the other side of board
possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index%8-1).Append(index%8).Append("QP").Append(index%8-1).Append(index%8).Append("RP").Append(index%8-1).Append(index%8).Append("NP").Append(index%8-1).Append(index%8).Append("BP");
pMoves &= ~(possibleMoves);
possibleMoves = pMoves & ~(pMoves-1);
}
pMoves = (wPB>>9) & notMyPiecesAndOccu & rank8 & ~fileH; // shift everything to the right by 9 to indicate capture left, and there is black piece and not on rank8 and not file A to stop capture on the other side of board
possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index%8+1).Append(index%8).Append("QP").Append(index%8+1).Append(index%8).Append("RP").Append(index%8+1).Append(index%8).Append("NP").Append(index%8+1).Append(index%8).Append("BP");
pMoves &= ~(possibleMoves);
possibleMoves = pMoves & ~(pMoves-1);
}
pMoves = (wPB>>8) & empty & rank8; // shift everything to the right by 8 to indicate move forward by one, and there is empty field and not on rank8
possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index%8).Append(index%8).Append("QP").Append(index%8).Append(index%8).Append("RP").Append(index%8).Append(index%8).Append("NP").Append(index%8).Append(index%8).Append("BP");
pMoves &= ~(possibleMoves);
possibleMoves = pMoves & ~(pMoves-1);
}
// y1, y2 E
// en passant to the right
possibleMoves = (wPB << 1) & bPB & rank5 & ~fileA & EPB; // location of enemy pawn that is inside the en passant mask(EPB)
if (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index%8-1).Append(index%8).Append("WE"); // file from and to
}
// en passant to the left
possibleMoves = (wPB >> 1) & bPB & rank5 & ~fileH & EPB;//
if (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index%8+1).Append(index%8).Append("WE"); // file from and to
}
}
public static void possibleBP(UInt64 bPB, UInt64 wPB, UInt64 EPB){
//x1,y1,x2,y2
UInt64 pMoves = (bPB<<7) & notMyPiecesAndOccu & ~rank1 & ~fileH;// shift everything to the right by 7 to indicate capture right, and there is black piece and not on rank8 and not file H to stop capture one the other side of board
UInt64 possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves); // puts the index to the first pawn by counting number of 0's to the right
list.Append(index/8-1).Append(index%8+1).Append(index/8).Append(index%8); //add move cords to list // first index +1 to get back to startlocation in the internal rank representation
pMoves &= ~(possibleMoves); // the listed move is removed from pMoves
possibleMoves = pMoves & ~(pMoves-1); // gets the next move alone in a bitboard
}
pMoves = (bPB<<9) & notMyPiecesAndOccu & ~rank1 & ~fileA; // shift everything to the right by 9 to indicate capture left, and there is black piece and not on rank8 and not file A to stop capture on the other side of board
possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index/8-1).Append(index%8-1).Append(index/8).Append(index%8); //add move cords to list
pMoves &= ~(possibleMoves);
possibleMoves = pMoves & ~(pMoves-1);
}
pMoves = (bPB<<8) & empty & ~rank1; // shift everything to the right by 8 to indicate move forward by one, and there is empty field and not on rank8
possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index/8-1).Append(index%8).Append(index/8).Append(index%8); //add move cords to list
pMoves &= ~(possibleMoves);
possibleMoves = pMoves & ~(pMoves-1);
}
pMoves = (bPB<<16) & empty & (empty<<8) & rank5; // shift everything to the right by 16 to indicate move forward and field is empty and field infront is empty and it is rank 4(meaning only when rank2 posistion can it move this way)
possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index/8-2).Append(index%8).Append(index/8).Append(index%8); //add move cords to list
pMoves &= ~(possibleMoves);
possibleMoves = pMoves & ~(pMoves-1);
}
// y1, y2, promotype, "P"
pMoves = (bPB<<7) & notMyPiecesAndOccu & rank1 & ~fileH; // shift everything to the right by 7 to indicate capture right, and there is black piece and not on rank8 and not file H to stop capture one the other side of board
possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index%8+1).Append(index%8).Append("qP").Append(index%8+1).Append(index%8).Append("rP").Append(index%8+1).Append(index%8).Append("nP").Append(index%8+1).Append(index%8).Append("bP");
pMoves &= ~(possibleMoves);
possibleMoves = pMoves & ~(pMoves-1);
}
pMoves = (bPB<<9) & notMyPiecesAndOccu & rank1 & ~fileA; // shift everything to the right by 9 to indicate capture left, and there is black piece and not on rank8 and not file A to stop capture on the other side of board
possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index%8-1).Append(index%8).Append("qP").Append(index%8-1).Append(index%8).Append("rP").Append(index%8-1).Append(index%8).Append("nP").Append(index%8-1).Append(index%8).Append("bP");
pMoves &= ~(possibleMoves);
possibleMoves = pMoves & ~(pMoves-1);
}
pMoves = (bPB<<8) & empty & rank1; // shift everything to the right by 8 to indicate move forward by one, and there is empty field and not on rank8
possibleMoves=pMoves&~(pMoves-1);
while (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index%8).Append(index%8).Append("qP").Append(index%8).Append(index%8).Append("rP").Append(index%8).Append(index%8).Append("nP").Append(index%8).Append(index%8).Append("bP");
pMoves &= ~(possibleMoves);
possibleMoves = pMoves & ~(pMoves-1);
}
// y1, y2 BE
// en passant to the right
possibleMoves = (bPB >> 1) & wPB & rank4 & ~fileH & EPB; // piece location to move, no destination put in hist - does not try and grab moves one by one because there should only be one possible per round
if (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index%8+1).Append(index%8).Append("BE");
}
// en passant to the left
possibleMoves = (bPB << 1) & wPB & rank4 & ~fileA & EPB;// piece to move no destination put in hist
if (possibleMoves != 0){
int index = Tools.trailingZerosRight(possibleMoves);
list.Append(index%8-1).Append(index%8).Append("BE");
}
}
public static UInt64 unsafeWhite(UInt64 bKB, UInt64 bQB, UInt64 bRB, UInt64 bBB, UInt64 bNB, UInt64 bPB, UInt64 wKB, UInt64 wQB, UInt64 wRB, UInt64 wBB, UInt64 wNB, UInt64 wPB){
UInt64 unsafeSq;
occupied = bKB|bQB|bRB|bBB|bNB|bPB|wKB|wQB|wRB|wBB|wNB|wPB;
//pawn
unsafeSq = ((bPB << 7) & ~fileH); // pawn capture right
unsafeSq = unsafeSq | ((bPB << 9) & ~fileA); // pawn capture left
UInt64 possible;
//knight
UInt64 i = bNB & ~(bNB-1);
while(i != 0){
possible = Span.Knight[Tools.trailingZerosRight(i)]; // put location in index of array with all 64 possible knight locations // turns out to not be faster than calculating possible location on the spot
unsafeSq = unsafeSq | possible; // add knight attack squares to unsafeSq var
bNB = bNB & ~i;
i = bNB & ~(bNB-1);
}
//bishop and queen
UInt64 QandB = bQB|bBB;
i = QandB & ~(QandB-1);
while(i !=0){
int iLocation = Tools.trailingZerosRight(i);
possible = DandAntiDMoves(iLocation);
unsafeSq = unsafeSq | possible;
QandB = QandB & ~i;
i = QandB & ~(QandB-1);
}
//rook and queen
UInt64 QandR = bQB|bRB;
i = QandR & ~(QandR-1);
while(i !=0){
int iLocation = Tools.trailingZerosRight(i);
possible = HandVMoves(iLocation);
unsafeSq = unsafeSq | possible;
QandR = QandR & ~i;
i = QandR & ~(QandR-1);
}
//king
possible = Span.King[Tools.trailingZerosRight(bKB)]; // put location into index of array with all possible kingspans
unsafeSq = unsafeSq | possible; // add knight attack squares to unsafeSq var
return unsafeSq;
}
public static UInt64 unsafeBlack(UInt64 bKB, UInt64 bQB, UInt64 bRB, UInt64 bBB, UInt64 bNB, UInt64 bPB, UInt64 wKB, UInt64 wQB, UInt64 wRB, UInt64 wBB, UInt64 wNB, UInt64 wPB){
UInt64 unsafeSq;
occupied = bKB|bQB|bRB|bBB|bNB|bPB|wKB|wQB|wRB|wBB|wNB|wPB;
//pawn
unsafeSq = ((wPB >> 7) & ~fileA); // pawn capture right
unsafeSq = unsafeSq | ((wPB >> 9) & ~fileH); // pawn capture left
UInt64 possible;
//knight
UInt64 i = wNB & ~(wNB-1);
while(i != 0){
possible = Span.Knight[Tools.trailingZerosRight(i)]; // put location in index of array with all 64 possible knight locations // turns out to not be faster than calculating possible location on the spot
unsafeSq = unsafeSq | possible; // add knight attack squares to unsafeSq var
wNB = wNB & ~i;
i = wNB & ~(wNB-1);
}
//bishop and queen
UInt64 QandB = wQB|wBB;
i = QandB & ~(QandB-1);
while(i !=0){
int iLocation = Tools.trailingZerosRight(i);
possible = DandAntiDMoves(iLocation);
unsafeSq = unsafeSq | possible;
QandB = QandB & ~i;
i = QandB & ~(QandB-1);
}
//rook and queen
UInt64 QandR = wQB|wRB;
i = QandR & ~(QandR-1);
while(i !=0){
int iLocation = Tools.trailingZerosRight(i);
possible = HandVMoves(iLocation);
unsafeSq = unsafeSq | possible;
QandR = QandR & ~i;
i = QandR & ~(QandR-1);
}
//king
possible = Span.King[Tools.trailingZerosRight(wKB)]; // put location into index of array with all possible kingspans
unsafeSq = unsafeSq | possible; // add knight attack squares to unsafeSq var
return unsafeSq;
}
}
}