How to iterate over a bit value? - php

I want to build a chessboard via bitboard system.
Starting with 12 bitboards i want to display a table (chessboard), during loop/iteration a piece must be drawn.
How do i loop through all bitvalues?
I was thinking of something like:
for(i=0;i<64;i++)
draw table / build array / draw empty square
These are my my values to start a game:
function init_game($whitePlayer,$blackPlayer)
{
$WhitePawns = '0000000000000000000000000000000000000000000000001111111100000000';
$WhiteKnights = '0000000000000000000000000000000000000000000000000000000001000010';
$WhiteBishops = '0000000000000000000000000000000000000000000000000000000000100100';
$WhiteRooks = '0000000000000000000000000000000000000000000000000000000010000001';
$WhiteQueens = '0000000000000000000000000000000000000000000000000000000000010000';
$WhiteKing = '0000000000000000000000000000000000000000000000000000000000001000';
$BlackPawns = '0000000011111111000000000000000000000000000000000000000000000000';
$BlackKnights = '0100001000000000000000000000000000000000000000000000000001000010';
$BlackBishops = '0010010000000000000000000000000000000000000000000000000000100100';
$BlackRooks = '1000000100000000000000000000000000000000000000000000000000000000';
$BlackQueens = '0000100000000000000000000000000000000000000000000000000000000000';
$BlackKing = '0001000000000000000000000000000000000000000000000000000000000000';
$WhitePieces = $WhitePawns|$WhiteKnights|$WhiteBishops|$WhiteRooks|$WhiteQueens|$WhiteKing;
$BlackPieces = $BlackPawns|$BlackKnights|$BlackBishops|$BlackRooks|$BlackQueens|$BlackKing;
}
Some people asked me: why bitboard appoach?
Answer:
About bitboard
A bitboard, often used for boardgames such as chess, checkers and othello, is a specialization of the bitset data structure, where each bit represents a game position or state, designed for optimization of speed and/or memory or disk use in mass calculations. Bits in the same bitboard relate to each other in the rules of the game often forming a game position when taken together. Other bitboards are commonly used as masks to transform or answer queries about positions. The "game" may be any game-like system where information is tightly packed in a structured form with "rules" affecting how the individual units or pieces relate.

First you have to check if your PHP version supports 64bit integers, otherwise you will have strange results.
Just run:
echo PHP_INT_MAX;
and if result is 9223372036854775807 then it should work.
You're using strings and I suppose that when you'll do $string | $string in form like you're doing it above then it will be cast as integer with base 10, so the result won't be what you want. Since PHP 5.4 you can use 0b000 notation, for lower PHP version you'll need to keep it in hexadecimal or base 10 format. If you're storing values in DB or somewhere like that and you'll receive value as string or you just want to keep it in format presented above, then you have to use intVal($value, 2) first to cast it properly.
To iterate over the value you can use just for loop (as you suggested):
$value = intVal($WhitePieces,2);
for ($i = 0 ; $i < 64 ; ++$i) {
if ((pow(2,$i) & $value)) {
// draw piece
}
}

You do not have bitvalues, you do have strings. And strings should be difficult to or.
How do you loop? Use an array and foreach.
How do you use 64bit values? Use PHP 5.4 and the binary number format: 0b00001111 => 16 - alternatively express the integer value as hex or decimal, which should be completely ok for a game setup routine that will not change because the rules are known for centuries.
Remember that you have to use a 64Bit system to execute your code, otherwise PHP will be unable to support 64Bit integers, and either treat them as float values, or shorten them to 32Bit values, depending on what you actually do.
Because of all this, I'd suggest NOT to use bit fields for the solution. They seem like a great idea to program more assembler-like, but you are not writing assembler, and will probably pay for this approach with non-optimal performance compared to anything else.

Related

PHP pack: do not really understand

I posted this (php pack: problems with data types and verification of my results) and found that I had two problems.
So here again only one issue (I solved the other one) Hopefully this is easy to understand:
I want to use the PHP pack() function.
1) My aim is to convert any integer number info a hex one of length 2-Bytes.
Example: 0d37 --> 0x0025
2) Second aim is to toggle high / low byte of each value: 0x0025 --> 0x2500
3) There are many input values which will form 12-Bytes of binary data.
Can anyone help me?
You just have to lookup the format table in the pack() manual page and it is quite easy.
2 bytes means 16 bits, or also called a "short". I assume you want that unsigned ... so we get n for big endian (high) and v for little endian (low) byte order.
The only potentially tricky part is figuring out how to combine the format and parameters, as each format character is tied to a value argument:
bin2hex(pack('nv', 34, 34)) // returns 00222200
If you need a variable number of values, you'll need agument unpacking (a PHP language feature, not to be confused with unpack()):
$format = 'nv';
$values = [34, 34];
pack($format, ... $values); // does the same thing
And alternatively, if all of your values should be packed with the same format, you could do this:
pack('v*', $values); // will "pack" as many short integers as you want

PHP array keys changes to negative value between certain number range

By coincidence I ran into a very bizarre behaviour regarding PHP arrays and its keys. Consider this creation of an PHP array.
$arr[2250572483]=1;
//dump the array
var_dump($arr);
//Result:
array(1) { [-2044394813]=> int(1) }
Somehow the array key has changed its value to a completely different negative number. This led me to some further investigation which is still inconclusive.
In below example I loop between the number range 2250572300 and 2250572500. Time is scarces for me so I did not manage to pinpoint at what number this phenomenon starts occurring because I run out of memory looping through large range of numbers. I think it should be somewhere between 2100000000 and 4300000000.
$arr2 = array();
for($i=2250572300; $i<= 2250572500; $i++){
$arr2[$i]=$i;
}
echo "<pre>".var_export($arr2,true)."</pre>";
My question is: does anyone know how and why this is happening and is there anything that is currently being done to fix the problem?
Essentially this is a major design flaw within PHP and could potentially make PHP useless when you are working with numbers in arrays, examples being supplier, invoice, item numbers etc.
Thanks
You're using an integer value as the array key. All integers in PHP are signed integers and on 32-bit systems, the maximum value is 232 - 1 (given by PHP_INT_MAX). If the integer value is greater than PHP_INT_MAX then it wraps over and gives $key % PHP_INT_MAX as the result.
To confirm:
echo 2250572483 % PHP_INT_MAX; // => -2044394813
The solution would be to use the key as a string, i.e. $arr['2250572483']=1;. This shouldn't be a problem on 64-bit systems, though (where the upper limit is 264 - 1).
That has something to do with how integers are saved. The first bit (from the left side) say if you are positiv + or negativ - and with this behavior the result with big ints will be how you discribted it. That you have a negativ Integer.

What is the PHP numeric array key limit

I am having a problem with an array changing the value of keys on me. In the example I'm providing below it starts out ok, but at some point php is turning my string into an integer and changing that integer when inserting it into another array as a key.
Code
-----------------
$fund = '01';
$division = '1';
$gl_transactions[$fund] = array();
$glint = array($division=>array('gl_cash_account'=>'1800001040000000'));
print chr(10).'1:'.chr(10);
print_r($glint);
$gl = $glint[$division]['gl_cash_account'];
print chr(10).'2:'.chr(10);
print $gl;
$gl_transactions[$fund][$gl]['description'] = 'MTS DISBURSEMENTS';
print chr(10).'3:'.chr(10);
print_r($gl_transactions);
Expected output
---------------
1:Array([1] => Array([gl_cash_account] => 1800001040000000 ))
2:1800001040000000
3:Array([01] => Array([1800001040000000] => Array([description] => MTS DISBURSEMENTS)))
Actual output
---------------
1:Array([1] => Array([gl_cash_account] => 1800001040000000 ))
2:1800001040000000
3:Array([01] => Array([1721082880] => Array([description] => MTS DISBURSEMENTS)))
notice the index changed from 1800001040000000 to 1721082880
Obsticles
These big numbers are G/L Account numbers and cannot be changed to smaller numbers. We have tens of thousands of pieces of code, over a million lines of code in our product and cannot go through every bit of it to find where this may be an issue and rewrite it. This is just a generic example of something that we do in many places, building multidimensional arrays using data from a database. I can simply cast the variable as a string when inserting into the array to fix the above example, but backfilling 1M+ lines of code is not a viable option.
On my development machine I run php 5.3 MSSQL, Windows, and IIS. I do not get this error with the above code but I do get it when simply setting a variable as an integer and then inserting it into an array as a key. i.e. $gl = 1800001040000000; $ar[$gl] = 1; print_r($ar); Now we don't cast a variables to integers in our software, but in the first example php converts it on it's own at some point when it's building the last array when ran on some of our clients systems.
So my questions are:
What is the exact limit of a numeric array key.
Is there a way to increase this.
Has this been fixed or increased in later versions of php beyond 5.2
Other notes
Our software works with several databases, several browsers, window and linux, apache and IIS. We have hundreds of customers using the software all with their own unique setup. Most of our customers are on php 5.2 currently and upgrading them is not possible at this point because of deprecated functions used in our software.
My guess is that you are limited by the maximum value of an integer since PHP will automatically cast strings with valid integer values being used as array keys to integers. The PHP manual indicates the limits for integers will vary by system, but the big issue is 32-bit systems vs. 64-bit systems in determining upper limit.
http://php.net/manual/en/language.types.integer.php
The maximum integer value on a system can be read from PHP_INT_MAX constant.
I see there is no accepted answer here, and certainly the OP has moved on from this. I was losing my keys in an array like this (from Snowmed CT):
static function getNemsisProcedures() {
$nemsis[445828009] = 'Assessment Advanced Spinal Assessment (i.e., spinal clearance)';
$nemsis[425058005] = 'Assessment Orthostatic Vital Signs';
// etc....
$nemsis[89666000] = 'Cardiac CPR, Manual';
$nemsis[450661000124102] = 'Cardiac Defibrillation, AED'; // TAKE NOTE
$nemsis[426220008] = 'Cardiac Defibrillation, Manual';
// a lot more etc...
The issue was with "Cardiac Defibrillation, AED" because the key as an integer 450661000124102 was greater than PHP_MAX_INT (2147483647 in my case).
Solution: Use string keys where applicable.
In my case, I did not require the keys to be integers, and to prevent a large commit in git, I simply gave the affected Snowmed CT Procedure values keys with type string by quoting them:
static function getNemsisProcedures() {
$nemsis[445828009] = 'Assessment Advanced Spinal Assessment (i.e., spinal clearance)';
$nemsis[425058005] = 'Assessment Orthostatic Vital Signs';
// etc....
$nemsis[89666000] = 'Cardiac CPR, Manual';
// KEY IS GREATER THAN PHP_MAX_INT - USE QUOTES:
$nemsis['450661000124102'] = 'Cardiac Defibrillation, AED';
$nemsis[426220008] = 'Cardiac Defibrillation, Manual';
// a lot more etc...

Php rand vs Perl rand

I am trying to port a piece of code from perl to php. The perl code snippet is part of akamai's video on demand link generation script. The script generates seed based on the location / URL of the video file (which will always be constant for a single URL). And then it is used in generating serial ID for stream (which is basically a random number between 1 and 2000 using the seed). Here is the perl code.$seed=6718;
srand($seed);
print(int(rand(1999)) + 1); // return 442 every time And the converted PHP code is:$seed=6718;
srand($seed);
echo(rand(0, 1999) + 1); //returns 155 every time
Does php rand behaves differently than perl one?
Yes. You can't depend on their algorithms being the same. For perl, which rand is used depends on what platform your perl was built for.
You may have more luck using a particular algorithm; for instance, Mersenne Twister looks to be available for both PHP and Perl.
Update: trying it produces different results, so that one at least won't do the trick.
Update 2: From the perl numbers you show, your perl is using the drand48 library; I don't know whether that's available for PHP at all, and google isn't helping.
[clippy]It looks like your trying to hash a number, maybe you want to use a hash function?[/clippy]
Hash functions are designed to take an input and produce a consistently repeatable value, that is in appearance random. As a bonus they often have cross language implementations.
Using srand() with rand() to get what is basically a hash value is a fairly bad idea. Different languages use different algorithms, some just use system libraries. Changing (or upgrading) the OS, standard C library, or language can result in wildly different results.
Using SHA1 to get a number between 1 and 2000 is a bit overkill, but you can at least be sure that you could port the code to nearly any language and still get the same result.
use Digest::SHA1;
# get a integer hash value from $in between $min (inclusive) and $max (exclusive)
sub get_int_hash {
my ($in, $min, $max) = #_;
# calculate the SHA1 of $in, note $in is converted to a string.
my $sha = Digest::SHA1->new;
$sha->add( "$in" );
my $digest = $sha->hexdigest;
# use the last 7 characters of the digest (28 bits) for an effective range of 0 - 268,435,455.
my $value = hex substr $digest, -7;
# scale and shift the value to the desired range.
my $out = int( $value / 0x10000000 * ( $max - $min ) ) + $min;
return $out;
}
print get_int_hash(6718, 1, 2000); #this should print 812 for any SHA1 implementation.
Just seeing this snippet of code it is impossible to say if it is the same.
At first you need to knew that even a random generator like the rand() function is not really random. It calculates a new value with a mathematical formula from the previous number. With the srand() function you can set the start value.
Calling srand() with the same argument each time means that the program always returns the same numbers in the same order.
If you really want random numbers, in Perl you should remove the initialization of srand(). Because Perl automatically sets srand() to a better (random) value when you first call the rand() function.
If your program really wants random numbers, then it should also be okay for PHP. But even in PHP i would look if srand() is automatically set and set to a more random value.
If your program don't work with random numbers and instead really want a stream of numbers that is always the same, then the snipet of code are probably not identical. Even if you do the same initialization with srand() it could be that PHP uses another formula to calculate the next "random" number.
So you need to look at your surrounding code if you code really wants random numbers, if yes you can use this code. But even then you should look for a better initialization for srand().

How to compare two 64 bit numbers

In PHP I have a 64 bit number which represents tasks that must be completed. A second 64 bit number represents the tasks which have been completed:
$pack_code = 1001111100100000000000000011111101001111100100000000000000011111
$veri_code = 0000000000000000000000000001110000000000000000000000000000111110
I need to compare the two and provide a percentage of tasks completed figure. I could loop through both and find how many bits are set, but I don't know if this is the fastest way?
Assuming that these are actually strings, perhaps something like:
$pack_code = '1001111100100000000000000011111101001111100100000000000000011111';
$veri_code = '0000000000000000000000000001110000000000000000000000000000111110';
$matches = array_intersect_assoc(str_split($pack_code),str_split($veri_code));
$finished_matches = array_intersect($matches,array(1));
$percentage = (count($finished_matches) / 64) * 100
Because you're getting the numbers as hex strings instead of ones and zeros, you'll need to do a bit of extra work.
PHP does not reliably support numbers over 32 bits as integers. 64-bit support requires being compiled and running on a 64-bit machine. This means that attempts to represent a 64-bit integer may fail depending on your environment. For this reason, it will be important to ensure that PHP only ever deals with these numbers as strings. This won't be hard, as hex strings coming out of the database will be, well, strings, not ints.
There are a few options here. The first would be using the GMP extension's gmp_xor function, which performs a bitwise-XOR operation on two numbers. The resulting number will have bits turned on when the two numbers have opposing bits in that location, and off when the two numbers have identical bits in that location. Then it's just a matter of counting the bits to get the remaining task count.
Another option would be transforming the number-as-a-string into a string of ones and zeros, as you've represented in your question. If you have GMP, you can use gmp_init to read it as a base-16 number, and use gmp_strval to return it as a base-2 number.
If you don't have GMP, this function provided in another answer (scroll to "Step 2") can accurately transform a string-as-number into anything between base-2 and 36. It will be slower than using GMP.
In both of these cases, you'd end up with a string of ones and zeros and can use code like that posted by #Mark Baker to get the difference.
Optimization in this case is not worth of considering. I'm 100% sure that you don't really care whether your scrip will be generated 0.00000014 sec. faster, am I right?
Just loop through each bit of that number, compare it with another and you're done.
Remember words of Donald Knuth:
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
This code utilizes the GNU Multi Precision library, which is supported by PHP, and since it is implemented in C, should be fast enough, and supports arbitrary precision.
$pack_code = gmp_init("1001111100100000000000000011111101001111100100000000000000011111", 2);
$veri_code = gmp_init("0000000000000000000000000001110000000000000000000000000000111110", 2);
$number_of_different_bits = gmp_popcount(gmp_xor($pack_code, $veri_code));
$a = 11111;
echo sprintf('%032b',$a)."\n";
$b = 12345;
echo sprintf('%032b',$b)."\n";
$c = $a & $b;
echo sprintf('%032b',$c)."\n";
$n=0;
while($c)
{
$n += $c & 1;
$c = $c >> 1;
}
echo $n."\n";
Output:
00000000000000000010101101100111
00000000000000000011000000111001
00000000000000000010000000100001
3
Given your PHP-setuo can handle 64bit, this can be easily extended.
If not you can sidestep this restriction using GNU Multiple Precision
You could also split up the HEx-Representation and then operate on those coresponding parts parts instead. As you need just the local fact of 1 or 0 and not which number actually is represented! I think that would solve your problem best.
For example:
0xF1A35C and 0xD546C1
you just compare the binary version of F and D, 1 and 5, A and 4, ...

Categories