You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: posts/visualizing-chess-bitboards.md
+23-21Lines changed: 23 additions & 21 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,7 +7,7 @@ description: "Brief introduction to chess bitboards and move generation with ani
7
7
8
8
When simulating board games on a computer, one of the challenges is keeping track of the game pieces. Bitboards are an efficient way to store game state in (usually) 64-bit integers. There are 64 positions on a chess board so we can use each bit as an on/off switch.
9
9
10
-
Let's say I want to describe a board where `f5` is occupied. For that, we can use the number `67108864`. In decimal notation, it doesn't seem much like a chessboard. In hex, we can see that there's some structure: `0x0000000004000000`.
10
+
Let's say I want to describe a board where `f5` is occupied. For that, we can use the number `67108864`. In decimal notation, it doesn't look that much like a chessboard. In hex, we can see that there's a little more structure: `0x0000000004000000`.
11
11
12
12
For me, it starts to make more sense when representated as a binary number with 64 digits.
13
13
@@ -24,12 +24,12 @@ For me, it starts to make more sense when representated as a binary number with
24
24
25
25
We can't pack an _entire_ game's state into a number (e.g. piece color, piece type, castling rights) so we use groups of numbers.
26
26
27
-
We can use _bitwise_ operations on these numbers to manipulate individual bits using operators like `AND`, `OR`, `XOR`, `NOT`, and bit shifts. These operations are fast (they're directly executed by the CPU in a single clock cycle with no need for complex computation or memory access).
27
+
We can use _bitwise_ operations on these numbers to manipulate individual bits using operators like `AND`, `OR`, `XOR`, `NOT`, and bit shifts. These operations are are among the fastest operations a CPU can perform. Bitboards are also cache-friendly since they pack data into fewer memory locations.
28
28
29
29
In order to move a piece at `f5` forwards we can shift the bitboard left by 8 bits.
30
30
31
31
```js
32
-
pieceOnF5 =0x0000000004000000n;
32
+
pieceOnF5 =0x0000000004000000;
33
33
// Move one rank forward (from f5 to f6)
34
34
pieceOnF5 <<8n; // 0x0000000400000000n
35
35
```
@@ -40,19 +40,19 @@ Why 8? Well, if you picture all of a chessboard's squares lined up in one long r
40
40
41
41
A mask is a bitboard used to isolate, modify, or test specific squares using bitwise operations.
42
42
43
-
An example of a mask might be the `A` file: `0x0101010101010101`. To check if there are any pieces there we can use bitwise `AND`.
43
+
An example of a mask might be the `A` file: `0x0101010101010101`. To check if there are any pieces on the `A` file, we can use bitwise `AND`.
44
44
45
45
```js
46
-
if (pieces &0x0101010101010101n) {
47
-
//There is at least one piece on the A file
46
+
if (pieces &0x0101010101010101) {
47
+
//At least one piece on the A file
48
48
}
49
49
```
50
50
51
-
Even though I know a little bit about bitboards, I still find them fairly confusing and unintuitive. I'm also prone to mistakes while working with them.
51
+
Even though I know a little bit about bitboards, I still find them confusing and unintuitive. I'm also prone to mistakes while working with them.
52
52
53
53
I've found that visual examples (and interactive debugging tools) can be very helpful. Let's take a look at how we can generate the initial white pawn attacks.
54
54
55
-
Two numbers will probably stick out; `7` and `9`. If you picture that long row of chessboard squares I mentioned before, think about how many squares you'd have to move to be diagonally forwards or backwards from your starting position.
55
+
Two numbers will probably stick out in the below example; `7` and `9`. If you picture that long row of chessboard squares I mentioned before, think about how many squares you'd have to move to be diagonally forwards or backwards from your starting position.
@@ -61,19 +61,19 @@ Without bitboards, a program has to perform many more (magnitudes more!) instruc
61
61
```js
62
62
attacks = [];
63
63
for (i =0; i <64; i++) {
64
-
piece =board.getPiece(i);
65
-
if (piece ==="P") { // White pawn
66
-
67
-
// Check left attack (forward-left)
68
-
if (!board.isOnFileA(i)) {
69
-
attacks.push(i +7);
70
-
}
71
-
72
-
// Check right attack (forward-right)
73
-
if (!board.isOnFileH(i)) {
74
-
attacks.push(i +9);
75
-
}
64
+
piece =board.getPiece(i);
65
+
if (piece ==="P") { // White pawn
66
+
67
+
// Check left attack (forward-left)
68
+
if (!board.isOnFileA(i)) {
69
+
attacks.push(i +7);
70
+
}
71
+
72
+
// Check right attack (forward-right)
73
+
if (!board.isOnFileH(i)) {
74
+
attacks.push(i +9);
76
75
}
76
+
}
77
77
}
78
78
```
79
79
@@ -83,10 +83,12 @@ I've got one more example where we generate a knight's attacks. We start with th
83
83
84
84
Inside a chess engine, we would then use more bitwise operations to see if those positions were occupied so we could evaluated the strength of each potential move.
85
85
86
-
The "not file" masks here are used to prevent invalid wraparounds.
86
+
The "not file" masks here are used to prevent invalid wraparounds. From `g5`, these masks stop the knight from moving to `l6` and `l4` (which aren't real squares).
87
87
88
88
<divclassName="bitboards"id="knightAttack"></div>
89
89
90
+
In practice, chess engines often pre-compute and store attack masks in lookup tables for even better performance, rather than calculating them on the fly like this – as well as other sophisticated techniques like [zobrist hashing](https://www.chessprogramming.org/Zobrist_Hashing) and [magic bitboard](https://www.chessprogramming.org/Magic_Bitboards).
91
+
90
92
I hope this helps show how bitboards can be the building blocks of any kind of chess computation.
91
93
92
94
For further reading, I've found the [Chess Programming Wiki](https://www.chessprogramming.org/Bitboards) and the source code for `python-chess` (e.g. [calculating attack masks](https://github.com/niklasf/python-chess/blob/ffa04827e325de5b4d39a67eee3528474b814285/chess/__init__.py#L875)) to both be very useful.
0 commit comments