Sliding move generation using magic bitboard - chess

This is a question regarding the big picture of how to validate a sliding piece move in chess using magic bitboards. Just to clarify, I am not asking how magic bitboards work internally.
Now, some more details about the question. I'm writing chess board representation using bitboard and I want to validate sliding piece moves using magic bitboards. Can somebody list the main steps of how to achieve that? As an example consider the following board position:
Assume we have all magic bitboard functions and data structures initialised and ready to use. So using only the function signatures for magic bitboards, can you list the steps (pseudo code or any language) to validate a given move for the white rook on g3?

Simply put, magic bitboards are an efficient way to take a position and obtain the legal moves for a sliding piece.
First, you need to find some magic numbers. Some of the code you write to find the magic numbers will also be re-used when you use the magic numbers.
To start off, you need to write 5 functions. These don't need to be particularly fast, because you will only use them when looking for magic numbers and once at program startup before you use your magic numbers. You can use any old technique in these functions.
uint64_t blockermask_rook (int square);
uint64_t blockermask_bishop (int square);
uint64_t moveboard_rook (int square, uint64_t blockerboard);
uint64_t moveboard_bishop (int square, uint64_t blockerboard);
uint64_t blockerboard (int index, uint64_t blockermask);
So you may be asking yourself, da f%q are a blocker mask, move board, and blocker board? Well, I just made the terms up, but here's what I mean by them:
/* Example, Rook on e4:
*
* The blocker mask A blocker board The move board
* 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 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
* 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
* 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0
* 0 1 1 1 0 1 1 0 0 1 1 0 0 0 0 0 0 0 1 1 0 1 1 1
* 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
* 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 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
*/
The blocker mask is all of the squares that can be occupied and block your piece from moving further. The edge squares don't need to be a part of that, because your piece can't move further past that square anyway. The number of 1's in this bitboard determine how large of a lookup table you need for this piece & square combination. In this case, there are 10 ones, so there are 2^10 (1024) possible permutations of pieces that can block an e4 rook.
The blocker board is one of these permutations. In this example, there are pieces on b4, c4, e2, e5, and e7. These are enemy and friendly pieces. A blocker board is always a subset of the blocker mask (it needn't show pieces on other squares (e.g., blockers = occupancy & blockermask;)).
The move board is the resulting available moves for your piece, for a given blocker board. This includes possible captures for your piece. Note that it also includes capturing your own pieces (but you can just AND it with a NOT of your own piece locations to remove those).
So, basically you need to generate the blocker mask on all squares, for both the rook and bishop. And you also need to generate all possible blocker boards on each square, for both the rook and bishop. As you generate the blocker boards, you should also generate the resulting move boards. Store all of this stuff in arrays for later use.
Now that you have that done, for each square/piece combo you try random 64 bit numbers and see if they're magic. You'll know if they're magic by using the magic formula, return ((blockerboard*magic) >> (64-bits));, which will create a magical index from 0..2^bits (0..1024 in the case of the e4 rook). For a certain piece/square, if two blocker boards ever generate the same magical index but these two blocker boards have different move boards, then this is a muggle number, and you should try a new one.
Once you get that down, you'll have 64 magic rook numbers and 64 magic bishop numbers. To use them, at program startup you will initialize all of the blocker masks, blocker boards, and move boards. And now your program can efficiently look up move boards for bishops and rooks on any square (and thus also queens). The code for that will look something like this:
/* Retrieves the move board for the given square and occupancy board. */
uint64_t magic_move_rook (int8_t square, uint64_t occupancy)
{
/* Remove occupants that aren't in the blocker mask for this square. */
occupancy &= Rook.blockmask[square];
/* Calculate the magic move index. */
int index = (occupancy*Rook.magic[square]) >> (64-Rook.bits[square]);
/* Return the pre-calculated move board. */
return Rook.moveboard[square][index];
}

It's good that we can assume magic bitboard functions are available, but in general bitboard move generation functions can accept any technique that produces a bitboard that gives the possible squares to move to. Say RookMoves is such a function, then you would populate the move list as follows:
UInt64 pieceBitboard = Bitboard[SideToMove | Piece.Rook];
UInt64 targetBitboard = ~Bitboard[SideToMove | Piece.All];
while (pieceBitboard != 0) {
Int32 from = Bit.Pop(ref pieceBitboard);
UInt64 moveBitboard = targetBitboard & RookMoves(from, OccupiedBitboard);
while (moveBitboard != 0) {
Int32 to = Bit.Pop(ref moveBitboard);
moveList[index++] = Move.Create(this, from, to);
}
}
where Bit.Pop(ref x) returns the least significant bit in x while simultaneously "popping" (removing) it from x.
To validate a move (I'm interpreting this as confirming move validity), you would either check to see if the move is in the move list, or perform the move and see whether it leaves you in check. Of course, you might need to check whether it obeys the movement rules for the piece but that is trivial.
if ((RookRays[move.From] & Bit.At[move.To]) == 0)
return false;
Int32 side = SideToMove;
position.Make(move);
Boolean valid = position.InCheck(side);
position.Unmake(move);
return valid;

Haha never heard of 'magic bitboard'. Google it and it is exactly what I expected. Although I dont see any magic about it. Anyways to answer your question, you need to generate the available move bit position of the currently selected piece. Not sure what else is needed.
As for psuedo code something like so I guess:
Positions KingChessPiece::getMovablePositions(){
(x,y) = current bit position in the bitboard
availablePosition = [ (x+1,y),(x-1,y),(x,y+1),(x,y-1) ]
for each position in availablePosition
if p_i is occupied then remove it from list
return availablePosition
}
I mean there is nothing hard about this, you just need to make sure you get and set position in a way compatible to the internal structure you are using.
EDIT:
example of a queen:
Position QueenChessPiece::getMovablePosition(){
(x,y) = queens current position
availablePosition = []; //empty list
//check diagonal positions
//move top left diagonal
availablePosition.concat( this.generateAvailablePosition(x,y,-1,1);
//move top right diagonal
availablePosition.concat( this.generateAvailablePosition(x,y,1,1);
//move bottom right diagonal
availablePosition.concat( this.generateAvailablePosition(x,y,1,-1);
//move bottom left diagonal
availablePosition.concat( this.generateAvailablePosition(x,y,-1,-1);
//move straight up
availablePosition.concat( this.generateAvailablePosition(x,y,0,1) )
//move straight down
availablePosition.concat( this.generateAvailablePosition(x,y,0,-1) )
//move left
availablePosition.concat( this.generateAvailablePosition(x,y,-1,0) )
//move right
availablePosition.concat( this.generateAvailablePosition(x,y,1,0) )
return availablePosition;
}
Position QueenChess::generateAvailablePosition(x,y,dx,dy){
availPosition = [];
while( !isSpaceOccupied(x + dx , y + dy))
availPosition.add( position(x + dx ,y + dy) );
x += dx;
y += dy;
endWhile
return availPosition;
}

Related

Difference between 1 and 1'b1 in Verilog

What is the difference between just giving 1 and giving 1'b1 in verilog code?
The 1 is 32 bits wide, thus is the equivalent of 32'b00000000_00000000_00000000_00000001
The 1'b1 is one bit wide.
There are several places where you should be aware of the difference in length but the one most likely to catch you out is in concatenations. {}
reg [ 7:0] A;
reg [ 8:0] B;
assign A = 8'b10100101;
assign B = {1'b1,A}; // B is 9'b110100101
assign B = {1,A}; // B is 9'b110100101
assign B = {A,1'b1}; // B is 9'b101001011
assign B = {A,1}; // B is 9'b000000001 !!!!
So, what's the difference between, say,
logic [7:0] count;
...
count <= count + 1'b1;
and
logic [7:0] count;
...
count <= count + 1;
Not a lot. In the first case your simulator/synthesiser will do this:
i) expand the 1'b1 to 8'b1 (because count is 8 bits wide)
ii) do all the maths using 8 bits (because now everything is 8 bits wide).
In the second case your simulator/synthesiser will do this:
i) do all the maths using 32 bits (because 1 is 32 bits wide)
ii) truncate the 32-bit result to 8 bits wide (because count is 8 bits wide)
The behaviour will be the same. However, that is not always the case. This:
count <= (count * 8'd255) >> 8;
and this:
count <= (count * 255) >> 8;
will behave differently. In the first case, 8 bits will be used for the multiplication (the width of the 8 in the >> 8 is irrelevant) and so the multiplication will overflow; in the second case, 32 bits will be used for the multiplication and so everything will be fine.
1'b1 is an binary, unsigned, 1-bit wide integral value. In the original verilog specification, 1 had the same type as integer. It was signed, but its width was unspecified. A tool could choose the width base on its host implementation of the int type.
Since Verilog 2001 and SystemVerilog 2005, the width of integer and int was fixed at 32-bits. However, because of this original unspecified width, and the fact that so many people write 0 or 1 without realizing that it is now 32-bits wide, the standard does not allow you to use an unbased literal inside a concatenation. {A,1} is illegal.

Understanding Remainder operator

Just doing some basic modulo operations and trying to wrap my head around the below operations with questions marks.
0%5 // 0 - Totally understand
1%5 // 1 ?
2%5 // 2 ?
3%5 // 3 ?
4%5 // 4 ?
5%5 // 0 - Totally understand
Perhaps I'm thinking in the wrong way. For example 1/5 would return a Double of 0.2 and not a single integer so how does it return a remainder of 1?
I understand these. It makes sense but the above I can't wrap my head around.
9%4 // 1
10%2 // 0
10%6 // 4
Be great if someone could explain this. Seems I'm having a brain fart. Source of learning.
From the same Basic Operators page that you link to:
The remainder operator (a % b) works out how many multiples of b will fit inside a and returns the value that is left over (known as the remainder).
Specifically for 1 % 5:
5 doesn't fit in 1, so it fits 0 times.
This means that 1 can be described as
1 = (5 * multiplier) + remainder
Since the multiplier is 0, the remainder is 1
1 = (5 * 0) + remainder
1 = remainder
If we instead look at 6 % 5 the remainder is also 1. This is because 5 fit in 6 one time:
6 = (5 * multiplier) + remainder
6 = (5 * 1) + remainder
6-5 = remainder
1 = remainder
This / the division operator when you say 1/5 if division is in integer it'll give 0 , but this 1.0/0.5 when you make it in Double , it'll give 0.2
but % the modulo operator when you say 1%5 = 1 because you have 1 = 0*5 + 1 which means that 1 has zero number of 5 and the reminder is 1

Lua moving table up causing nil value error

I have a table of tables which represents a 65*65 square grid where each element is integer values. It represents the area around an actor and the actor can move in the four cardinal directions and as they do I need the table to move with them so they remain in the center square 33,33.
Rather than moving the elements of the table I instead have two pointers tableIndex.left and tableIndex.down which store the indexes of the far left column of the bottom row respectively, they both start at 65. I have three helper functions to perform operations on the table, all take the arguments x1,x2,y1,y2 where x1 and y1 are the co-ordinates to start the function at and x2 and y2 are the co ordinates to end the function.
These functions are tableInit which creates tables in all the values between x1 and x2. zero table which fills all of the entries in the specified range with 0 and clear table which sets all the entries in the specified range to nil.
function movetable(direction)
--function to move our probability histogram
-- 0 is up, 1 is right, 2 is down, 3 is left
--as a note robotSpeed = 1
if direction == 0 then
tableIndex.down += robotSpeed
zerotable(tableIndex.left,tableIndex.left+64,tableIndex.down+64,tableIndex.down+64)
cleartable(tableIndex.left,tableIndex.left+64,tableIndex.down-1,tableIndex.down-1)
elseif direction == 1 then
tableIndex.left += robotSpeed
tableInit(tableIndex.left+64,tableIndex.left+64)
zerotable(tableIndex.left+64,tableIndex.left+64,tableIndex.down,tableIndex.down+64)
cleartable(tableIndex.left-1,tableIndex.left-1,tableIndex.down,tableIndex.down+64)
elseif direction == 2 then
tableIndex.down -= robotSpeed
zerotable(tableIndex.left,tableIndex.left+64,tableIndex.down,tableIndex.down)
cleartable(tableIndex.left,tableIndex.left+64,tableIndex.down+65,tableIndex.down+65)
else
tableIndex.left -= robotSpeed
tableInit(tableIndex.left,tableIndex.left)
zerotable(tableIndex.left,tableIndex.left,tableIndex.down,tableIndex.down+64)
cleartable(tableIndex.left+65,tableIndex.left+65,tableIndex.down,tableIndex.down+64)
end
end
The table is called later in the program,in the following section of code, which is where the error is thrown "Attempt to perform arithmetic on field '?' a nil value. This occurs when i and j are 0. This only occurs after the table has last moved up so dir==0 and the error ceases to exist if I comment out the cleartable call in my movetable function for the case when dir==0.
for i=0,64 do
for j=0,64 do
--Robot is at 33 33 so we know there isnt an obstacle here
if i ~= 32 and j ~= 32 then
--This is the equation from the paper which tells us which direction the result is in
local tan = atan2(i-33,j-33)+0.25
if (tan > 1) tan = tan-1
local dInD = flr(360*tan)
--Our polar histogram has sectors ALPHA degrees wide, this rounds the direction down to a multiple of
--the sector size so we can use it as an index
local dir = dInD - dInD%ALPHA
polarHist[dir] += certaintyTable[tableIndex.left+i][tableIndex.down+j]
end
end
As a note I dont have access to the standard lua libraries.
and here is cleartable in case I am doing that wrong
function cleartable(x1,x2,y1,y2)
if x1 == x2 then
for j=y1,y2 do
certaintyTable[x1][j] = nil
end
elseif y1==y2 then
for i=x1,x2 do
certaintyTable[i][y1] = nil
end
else
for i=x1,x2 do
for j=y1,y2 do
certaintyTable[i][j] = nil
end
end
end
end
Thanks for looking at my problem

Quake MAP brushes

Many level editors like Quake or Source games uses implicit plane equation for brush side representation (by 3 points) instead of simple (n.x n.y n.z d).
{
...
( 256 0 0 ) ( 256 0 1 ) ( 256 1 0 ) GROUND1_6 0 0 0 1.0 1.0
( 0 128 0 ) ( 0 128 1 ) ( 1 128 0 ) GROUND1_6 0 0 0 1.0 1.0
...
}
Is there some reason for this? I know it can be easily converted to any form, just wonder why they used this form. Is it some floating point precision stuff?
Quake uses the plane equation, and plane sidedness test, extensively, and so while it seems awkward or annoying if you're just looking to render map geometry, it was likely a pretty easy decision to use this representation. As alluded to above, it allows the map format to use integer coordinates for plane sides. This means the format itself is "lossless" and immune to floating point rounding issues. Vertex coordinates can be calculated at either floating point or full double precision. In fact, newer BSP compilers (q3map2, quemap, etc..) do use double precision for some face splitting calculations.

VB.NET doesn't round numbers correctly?

I'm testing the speed of some functions so I made a test to run the functions over and over again and I stored the results in an array. I needed them to be sorted by the size of the array I randomly generated. I generate 100 elements. Merge sort to the rescue! I used this link to get me started.
The section of code I'm focusing on:
private void mergesort(int low, int high) {
// check if low is smaller then high, if not then the array is sorted
if (low < high) {
// Get the index of the element which is in the middle
int middle = low + (high - low) / 2;
// Sort the left side of the array
mergesort(low, middle);
// Sort the right side of the array
mergesort(middle + 1, high);
// Combine them both
merge(low, middle, high);
}
}
which translated to VB.NET is
private sub mergesort(low as integer, high as integer)
' check if low is smaller then high, if not then the array is sorted
if (low < high)
' Get the index of the element which is in the middle
dim middle as integer = low + (high - low) / 2
' Sort the left side of the array
mergesort(low, middle)
' Sort the right side of the array
mergesort(middle + 1, high)
' Combine them both
merge(low, middle, high)
end if
end sub
Of more importance the LOC that only matters to this question is
dim middle as integer = low + (high - low) / 2
In case you wanna see how merge sort is gonna run this baby
high low high low
100 0 10 0
50 0 6 4
25 0 5 4
12 0 12 7
6 0 10 7
3 0 8 7
2 0 :stackoverflow error:
The error comes from the fact 7 + (8 - 7) / 2 = 8. You'll see 7 and 8 get passed in to mergesort(low, middle) and then we infinite loop. Now earlier in the sort you see a comparison like this again. At 5 and 4. 4 + (5 - 4) / 2 = 4. So essentially for 5 and 4 it becomes 4 + (1) / 2 = 4.5 = 4. For 8 and 7 though it's 7 + (1) / 2 = 7.5 = 8. Remember the numbers are typecasted to an int.
Maybe I'm just using a bad implementation of it or my typecasting is wrong, but my question is: Shouldn't this be a red flag signaling something isn't right with the rounding that's occuring?
Without understanding the whole algorithm, note that VB.NET / is different than C# /. The latter has integer division by default, if you want to truncate decimal places also in VB.NET you have to use \.
Read: \ Operator
So i think that this is what you want:
Dim middle as Int32 = low + (high - low) \ 2
You are correct in your diagnosis: there's something inconsistent with the rounding that's occurring, but this is entirely expected if you know where to look.
From the VB.NET documentation on the / operator:
Divides two numbers and returns a floating-point result.
This documentation explicitly states that , if x and y are integral types, x / y returns a Double. So, 5 / 2 in VB.NET would be expected to be 2.5.
From the C# documentation on the / operator:
All numeric types have predefined division operators.
And further down the page:
When you divide two integers, the result is always an integer.
In the case of C#, if x and y are integers, x / y returns an integer (rounded down). 5 / 2 in C# is expected to return 2.