Search code examples
arraysvectorchess

how to mathematically have array border without actually increasing the array size?


So I have a game board represented by a 1d array of 64 squares and I wish to know when a piece is trying to escape the borders.

So for example: Assume a king in the game of chess is on the X:

0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 X 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

it is easy to calculate the attacked squares with a direction vector:

-9, -8, -7,
-1,      1,
 7,  8,  9

0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0
0 0 0 1 X 1 0 0
0 0 0 1 1 1 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

also if he is on the upper or lower edges of the board: I just add an if that checks if the square + directionvector[i] > 63 or square + directionvector[i] < 0

so:

0 0 0 1 X 1 0 0
0 0 0 1 1 1 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

The problem then comes when it sits on the side edges:

0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1
1 0 0 0 0 0 1 X
1 0 0 0 0 0 1 1
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

This is what will happen it will "jump" to the wrong place as you see above.

Do you know of any way of checking this? thanks


Solution

  • At the beginning of your program, you can precompute the legal moves for every piece and every square and store them somewhere.

    Assuming that your squares are numbered from 0 to 63, then KING_MOVES[i] will store the legal moves for a king on square i (where i ranges from 0 to 63). For example, KING_MOVES[0] = { 1, 8, 9 } and KING_MOVES[31] = { 22, 23, 30, 38, 39 }. Similarly, for a knight in the corner, KNIGHT_MOVES[0] = { 10, 17 }.

      0  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
    

    The number of legal moves is different from every square (a king has 8 moves in the center, but only 3 in the corner). You can store the number of legal moves separately (such as NUM_KING_MOVES[31] = 5) or you can terminate each list with a special value like -1 or 64.

    To precompute these lists, you can convert each 1-D number to a pair of (row, column) coordinates and generate moves naively, with boundary checks. For a king on square 31, you convert 31 to (row 3, column 7). When moving to the right, you end up on (row 3, column 8), which is illegal, so you discard this move. When moving to the top-left, you end up on (row 2, column 6), which is legal, so you convert that back to a 1-D representation: 2 * 8 + 6 = 22. You append this move to KING_MOVES[31] and so forth.

    This gives you the best of both worlds: faster and shorter code for move generation with no wasted memory on every board due to padding. The downside is a few kilobytes of extra memory.

    If you're going down this path, you could also take a look at bitboards for even faster move generation.