Store and decode values in "binary" as an integer - php

How is the following system called and what would be an easy algorythm to implement a decoding function for the following scenario?
Imagine we have a permission system with the following values. Each permission node gets a number with the following rules:
READ = 1
CREATE = 2
UPDATE = 4
DELETE = 8
To clarify: I'll call the permission itself a permission and the number assigned for it the value. Also, I'll call the sum of all values the level.
When I want to give a user the three permissions READ, CREATE and UPDATE he would have a level of 7. If I calculate these 7 back, I could definitely say, that this user has these exact 3 roles.
My question is: How is this system named and what would be a good situation to calculate this back, meaning: How can I efficiently find out that 7, for example, is made out of 1, 2 and 4 or that a level of 13 is made of 1, 4 and 8? I have absolutely no idea where to start.

This is called a bit map or a bit mask. When used to store permissions, it's called a permission mask.
To test whether a particular value is set, you can use bitwise operators.
$mask = 7;
$perms = array();
if ($mask & READ) {
$perms[] = "READ";
}
if ($mask & CREATE) {
$perms[] = "CREATE";
}
if ($mask & UPDATE) {
$perms[] = "UPDATE";
}
if ($mask & DELETE) {
$perms[] = "DELETE";
}
echo "Permissions are: " . implode(", ", $perms); // prints READ, CREATE, UPDATE

Related

PHPUnit test - Failed asserting that actual size 11935 matches expected size 3

I'm brand new to phpunit and attempting to write a test that asserts that three notes were created, but I'm getting all of the notes from the DB.
/** #test */
public function it_gets_notes()
{
$address = Address::first();
$notes = factory(AddressNote::class, 3)->create(['address_id'
=> $address->id]);
$found = $this->notesClass->getData(['address_id' => $address-
>id]);
$this->assertCount(3, $found);
}
}
The Address and AddressNote models are working properly. I think I'm most confused about the getData method, which I know I need for my code coverage. Anyone see what I'm missing that would generate the error in the title?
If you need to check the difference after running your create method, then save $found before and after adding them, and the subtraction will be your number:
public function it_gets_notes()
{
$address = Address::first();
$found = $this->notesClass->getData(['address_id' => $address->id]);
$notes = factory(AddressNote::class, 3)->create(['address_id' => $address->id]);
$foundAfter = $this->notesClass->getData(['address_id' => $address->id]);
$difference = count($foundAfter) - count($found);
$this->assertEquals(3, $difference);
}
Note that you need to use assertEquals() with 3 and the difference now instead of assertCount(), since you're comparing numbers.
I don't know the whole your story, but I assume that your first mistake was that you did not create a testing database.
So, that would be the first step - in addition to your databaseName (whatever the name) create a databaseName_test.
There are some other steps to do - in your ,env file change the name of the databaseName to databaseName_testing - but only while you're doing your testing (and then immediately rollback to your original databaseName).
Yet, the problem can still persist (PHP Unit is not a perfect tool, just like PHP), and here is the hack that can help.
Instead of:
$this->assertEquals(3, $difference);
write:
$this->assertEquals(11935, $difference); //the number is specific for your case
Yep, it's stupid, but it should work...

PHP Function to generate an infinite unique indentifier

I'm making a new project in Zend 3 that requires me to have a unique ID or HASH which I can use in several places later.
I looked at many examples on Google, and could not find a function that can satisfy my requirements because this needs to be 99% unique all the time, and it needs to be able to generate hundreds, millions of "hashes" unique all the time.
The following function caught my attention:
function uniqidReal($lenght = 13) {
// uniqid gives 13 chars, but you could adjust it to your needs.
if (function_exists("random_bytes")) {
$bytes = random_bytes(ceil($lenght / 2));
} elseif (function_exists("openssl_random_pseudo_bytes")) {
$bytes = openssl_random_pseudo_bytes(ceil($lenght / 2));
} else {
throw new Exception("no cryptographically secure random function available");
}
return substr(bin2hex($bytes), 0, $lenght);
}
A simple test:
echo "<pre>";
for($i = 0; $i < 100; $i++)
{
echo $this->uniqidReal(25) .PHP_EOL ;
}
The result:
a8ba1942ad99d09f496d3d564
5b24746d09cada4b2dc9816bd
c6630c35bc9b4ed0907c803e0
48e04958b633e8a5ead137bb1
643a4ce1bcbca66cea397e85e
d2cd4c6f8dc7054dd0636075f
d9c78bae38720b7e0cc6361f2
54e5f852862adad2ad7bc3349
16c4e42e4f63f62bf9653f96e
c63d64af261e601e4b124e38f
29a3efa07a4d77406349e3020
107d78fdfca13571c152441f2
591b25ebdb695c8259ccc7fe9
105c4f2cc5266bb82222480ba
84e9ad8fd76226f86c89c1ac1
39381d31f494d320abc538a8e
7f8141db50a41b15a85599548
7b15055f6d9fb1228b7438d2a
659182c7bcd5b050befd3fc4c
06f70d134a3839677caa0d246
600b15c9dc53ef7a4551b8a90
a9c8af631c5361e8e1e1b8d9d
4b4b0aca3bbf15d35dd7d1050
f77024a07ee0dcee358dc1f5e
408c007b9d771718263b536e1
2de08e01684805a189224db75
c3838c034ae22d21f27e5d040
b15e9b0bab6ef6a56225a5983
251809396beb9d24b384f5fe8
cec6d262803311152db31b723
95d271ffdfe9df5861eefbaa4
7c11f3401530790b9ef510e55
e363390e2829097e7762bddc4
7ef34c69d9b8e38d72c6db29f
309a84490a7e387aaff1817ca
c214af2927c683954894365df
9f70859880b7ffa4b28265dbb
608e2f2f9e38025d92a1a4f03
c457a54d2da30a4a517edf14c
8670acbded737b1d2febdd954
99899b74b6469e366122b658c
3066408f5b4e86ef84bdb3fb9
010715f4955f66da3402bfa7b
fa01675690435b914631b46e1
2c5e234c5868799f31a6c983c
8345da31809ab2d9714a01d05
7b4e0e507dd0a8b6d7170a265
5aa71aded9fe7afa9a93a98c5
3714fb9f061398d4bb6af909d
165dd0af233cce64cefec12ed
849dda54070b868b50f356068
fe5f6e408eda6e9d429fa34ed
cd13f8da95c5b92b16d9d2781
65d0f69b41ea996ae2f8783a5
5742caf7a922eb3aaa270df30
f381ac4b84f3315e9163f169e
8c2afa1ab32b6fe402bf97ba3
a9f431efe6fc98aa64dbecbc2
8f0746e4e9529326d087f828b
bfc3cbea4d7f5c4495a14fc49
e4bf2d1468c6482570612360e
f1c7238766acdb7f199049487
60ae8a1ffd6784f7bbbc7b437
30afd67f207de6e893f7c9f42
dfa151daccb0e8d64d100f719
07be6a7d4aab21ccd9942401b
73ca1a54fcc40f7a46f46afbd
94ed2888fb93cb65d819d9d52
b7317773c6a15aa0bdf25fa01
edbb7f20f7523d9d941f3ebce
99a3c204b9f2036d3c38342bb
a0585424b8ab2ffcabee299d5
64e669fe2490522451cf10f85
18b8be34d4c560cda5280a103
9524d1f024b3c9864a3fccf75
0e7e94e7974894c98442241bc
4a17cc5e3d2baabaa338f592e
b070eaf38f390516f5cf61aa7
cc7832ea327b7426d8d2b8c2b
0df0a1d4833ebbb5d463c56bf
1bb610a8bb4e241996c9c756a
34ac2fdeb4b88fe6321a1d9c3
f0b20f8e79090dcb65195524c
307252efdd2b833228e0c301f
3908e63b405501782e629ac0b
29e66717adf14fb30c626103d
c8abd48af5f9332b322dffad0
80cd4e162bc7e8fb3a756b48c
825c00cec2294061eb328dd97
106205a2e24609652d149bc17
f1f896657fbc6f6287e7dee20
0fbd16ade658e24d69f76a225
4ab3b5eeeda86fa81afba796a
11d34f3d2ffb61d55da560ddb
013d6151bad187906fcc579a4
4509279a28f34bcf5327dd4c0
3c0eb47b3f9dc5a2f794bb9ad
1e6506906f23542c889330836
e7b1c5012390f3c7c48def9f3
d86caa695cb5fa1e0a2ead4cc
But I cannot confirm that this does guarantee me a 99% success rate for my production environment.
If someone can advise me, or provide me an example I would much appreciate it!
Function random_bytes generates cryptographically secure random bytes
For openssl_random_pseudo_bytes add the crypto_strong paramdeter to ensure the algorithm used is cryptographically strong.
Since your requirement is only 99% unique cryptographically secure random bytes will meet your requirement.
This should be a comment, but its a bit long.
There is some confusion over your use of "unique" and "all the time". A token is either unique or it is not. Using a random number generator to create tokens alone is not sufficient to guarantee uniqueness - the whole point of a random number generator is that you don't know what the next value to be generated will be - meaning you also don't know that the next number won't be the same as a previous number. OTOH, using random_bytes() or openssl_random_pseudo_bytes() to generate a token which is "99% unique all the time" seems like a massive overkill.
To work out how unique this is likely to be we would need to know how many tokens will be considered within the populations at any one time (or to be able to calculate this from the expected rate of creation and the TTL).
That you are using large numbers rather implies you have a very good reason for not using the simplest and most obvious unique identifier - i.e. an incrementing integer. Hence the resistance to guessing an existing identifier is clearly critical to the implementation - but again you've told us nothing about that.
Pasting the title of your post into Google turns up your post as the top result - with PHP's uniqid() function immediately after it - yet for some reason you've either not found uniqid() or have rejected it for some reason.
The title of your post is also an oxymoron - In order to define an infinite set of identifiers, the identifiers would need to be of infinite length.
it needs to be able to generate hundreds, millions of "hashes"
....and you want it all to run within the Zend Framework? - LOL.
But I cannot confirm that this does guarantee me a 99% success rate for my production environment.
Why not? You have sufficient information here to confirm that the bitwise entropy is evenly distributed and should know the planned capacity of the production environment. The rest is basic arithmetic.
We are about 8x10⁹ people. Imagine all us access your site once each second needing a unique identifier during a year. You need about 2,52288×10²³ identifiers. If you think your site will be in production about 1000 years, and population get bigger by a 1000 factor you need about 10²⁹ identifiers; so a 32 bytes auto-incremental string is good enough. Add as suffix a pseudo-random 32 bytes string to get a secure 64 bytes identifier. Doing a bit plus you can hash identifiers to create tokens.
Then is easy to write a function to get them.
Edited 2017/04/13
A small sample:
The first thing you need is a pseudo-random strong keys generator. I'll post the function I'm using currently:
<?php
function pseudoRandomBytes($count = 32){
static $random_state, $bytes, $has_openssl, $has_hash;
$missing_bytes = $count - strlen($bytes);
if ($missing_bytes > 0) {
// If you are using a Php version before 5.3.4 avoid using
// openssl_random_pseudo_bytes()
if (!isset($has_openssl)) {
$has_openssl = version_compare(PHP_VERSION, '5.3.4', '>=')
&& function_exists('openssl_random_pseudo_bytes');
}
// to get entropy
if ($has_openssl) {
$bytes .= openssl_random_pseudo_bytes($missing_bytes);
} elseif ($fh = #fopen('/dev/urandom', 'rb')) {
// avoiding openssl_random_pseudo_bytes()
// you find entropy at /dev/urandom usually available in most
// *nix systems
$bytes .= fread($fh, max(4096, $missing_bytes));
fclose($fh);
}
// If it fails you must create enough entropy
if (strlen($bytes) < $count) {
// Initialize on the first call. The contents of $_SERVER
// includes a mix of user-specific and system information
// that varies a little with each page.
if (!isset($random_state)) {
$random_state = print_r($_SERVER, TRUE);
if (function_exists('getmypid')) {
// Further initialize with the somewhat random PHP process ID.
$random_state .= getmypid();
}
// hash() is only available in PHP 5.1.2+ or via PECL.
$has_hash = function_exists('hash')
&& in_array('sha256', hash_algos());
$bytes = '';
}
if ($has_hash) {
do {
$random_state = hash('sha256', microtime() . mt_rand() .
$random_state);
$bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
} while (strlen($bytes) < $count);
} else {
do {
$random_state = md5(microtime() . mt_rand() . $random_state);
$bytes .= pack("H*", md5(mt_rand() . $random_state));
} while (strlen($bytes) < $count);
}
}
}
$output = substr($bytes, 0, $count);
$bytes = substr($bytes, $count);
return $output;
}
Once you have that function you need a function to create your random keys:
<?php
function pseudo_random_key($byte_count = 32) {
return base64_encode(pseudoRandomBytes($byte_count));
}
As random does not mean unique! you need to merge a unique 32 bytes prefix as I suggested. As big number functions are time-expensive I'll use a chunk-math function using a prefix I suppose generated from time to time using a cron function and stored at an environment DB variable and an auto-incremental index also db-stored
<?php
function uniqueChunkMathKeysPrefix(){
// a call to read your db for prefix
// I suppose you have an environment string-keyed table
// and a couple of dbfunction to read and write data to it
$last18bytesPrefix = dbReadEnvVariable('unique_prefix');
// Also you store your current index wich returns to 0 once you get
// a 99999999999999 value
$lastuniqueindex = dbReadEnvVariable('last_unique_keys_index');
if ($lastuniqueindex < 99999999999999){
$currentuniqueindex = $lastuniqueindex + 1;
$curret18bytesPrefix = $last18bytesPrefix;
}else{
$currentuniqueindex = 0;
$curret18bytesPrefix = dbReadEnvVariable('next_unique_prefix');
// flag your db variables to notify cron to create a new next prefix
dbStoreEnvVariable('next_unique_prefix', 0);
dbStoreEnvVariable('unique_prefix', $curret18bytesPrefix);
// you have the time needed to have site visits and create new
// 99999999999999 keys as a while to run your cron to adjust your
// next prefix
}
// store your current index
dbStoreEnvVariable('last_unique_keys_index', $currentuniqueindex);
// Finally you create the unique index prefix part
$uniqueindexchunk = substr('00000000000000'.$currentuniqueindex, -14);
// return the output
return $curret18bytesPrefix.$uniqueindexchunk;
}
Now you can write a function for unique pseudo-random 64 bytes uniquekeys
<?php
function createUniquePseudoRandomKey(){
$newkey = uniqueChunkMathKeysPrefix() . pseudo_random_key(32);
// to beautify the output make a dummie call
// masking the 0s ties
return md5($newkey);
}

Running PHP & Mysqli queries in Parallel

I'm tying to extract data from thousands of premade sql files. I have a script that does what I need using the Mysqli driver in PHP, but it's really slow since it's one sql file at a time. I modified the script to create unique temp database names, which each sql file is loaded into. Data is extracted to an archive database table, then the temp database is dumped. In an effort to speed things up, I created a script structured 4 scripts similar to the one below, where each for loop is stored in it's own unique PHP file (the code below is only for a quick demo of what's going on in 4 separate files), they are setup to grab only 1/4 of the files from the source file folder. All of this works perfectly, the scripts run, there is zero interference with file handling. The issue is that I seem to get almost zero performance boost. Maybe 10 seconds faster :( I quickly refreshed my PHPmyadmin database listing page and could see the 4 different databases loaded at anytime, but I also noticed that it looked like it was still running more or less sequentially as the DB names were changing on the fly. I went the extra step of creating an unique user for each script with it's own connection. No improvement. Can I get this to work with mysqli / PHP or do I need to look into some other options? I'd prefer to do this all in PHP if I can (version 7.0). I tested by running the PHP scripts in my browser. Is that the issue? I haven't written any code to execute them on the command line and set them to the background yet. One last note, all the users in my mysql database have no limits on connections, etc.
$numbers = array('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20');
$numCount = count($numbers);
$a = '0';
$b = '1';
$c = '2';
$d = '3';
$rebuild = array();
echo"<br>";
for($a; $a <= $numCount; $a+=4){
if(array_key_exists($a, $numbers)){
echo $numbers[$a]."<br>";
}
}
echo "<br>";
for($b; $b <= $numCount; $b+=4){
if(array_key_exists($b, $numbers)){
echo $numbers[$b]."<br>";
}
}
echo "<br>";
for($c; $c <= $numCount; $c+=4){
if(array_key_exists($c, $numbers)){
echo $numbers[$c]."<br>";
}
}
echo "<br>";
for($d; $d <= $numCount; $d+=4){
if(array_key_exists($d, $numbers)){
echo $numbers[$d]."<br>";
}
}
Try this:
<?php
class BackgroundTask extends Thread {
public $output;
protected $input;
public function run() {
/* Processing here, use $output for... well... outputting data */
// Here you would implement your for() loops, for example, using $this->input as their data
// Some dumb value to demonstrate
$output = "SOME DATA!";
}
function __construct($input_data) {
$this->input = $input_data;
}
}
// Create instances with different input data
// Each "quarter" will be a quarter of your data, as you're trying to do right now
$job1 = new BackgroundTask($first_quarter);
$job1->start();
$job2 = new BackgroundTask($second_quarter);
$job2->start();
$job3 = new BackgroundTask($third_quarter);
$job3->start();
$job4 = new BackgroundTask($fourth_quarter);
$job4->start();
// ==================
// "join" the first job, i.e. "wait until it's finished"
$job1->join();
echo "First output: " . $job1->output;
$job2->join();
echo "Second output: " . $job2->output;
$job3->join();
echo "Third output: " . $job3->output;
$job4->join();
echo "Fourth output: " . $job4->output;
?>
When using four calls to your own script through HTTP, you're overloading your connections for no useful reason. Instead, you're taking away spaces for other users who may be trying to access your website.

Golf league payout to six finishing positions

I have a golf league of 40 individuals. We all throw money in a pot and pay out the first 6 places based on final score.
If there were no ties the pay out would be simple but often we have, for example, 2 people tied for first place, 3 people tied for second, 1 person alone in third, etc. The variations seem endless.
I've been trying to automate the calculated payouts for each place using PHP but have not been successful. Any suggestions, help, or pointing in the right direction would be much appreciated. I noticed that someone else tried to ask a similar question on this site but was not successful in framing the question. I'll try to do a better job.
Here is some data I've been playing around with:
$playerNumber=40;
$totalPoints=100;
Payouts:
$pointsFirst=0.6*$totalPoints;
$pointsSecond=0.2*$totalPoints;
$pointsThird=0.15*$totalPoints;
$pointsFourth=0.03*$totalPoints;
$pointsFifth=0.02*$totalPoints;
$pointsSixth=0.01*$totalPoints;
For the example given above and to pay out six places, we would calculate the payouts as follows:
If two people are tied for first place, we add first and second place points and divide by two.
If three people are tied for second place, we add third, fourth and fifth place points and divide by three.
If one person is alone in third, this person would win sixth place points.
I can count the number of players who are in or tied for a certain place.
$countFirst=2;
$countSecond=3;
$countThird=1;
$countFourth=2;
$countFifth=1;
$countSixth=2;
In this example the player scores would be 72, 72, 73, 73, 73, 74, 75, 75, 76, 77, 77.
At first I thought this was an application for nested arrays. Then I thought perhaps using arrays, array slice, etc, may be a way to go. Each time I end up in the woods. I'm not seeing the logic.
I have used conditional statements for paying out three places but to pay out six places with this method puts me deep in the woods.
Example of payout to three places using conditional statements:
$pointsFirst=0.5*$totalPoints;
$pointsSecond=0.3*$totalPoints;
$pointsThird=0.2*$totalPoints;
if($countFirst>2) {
$ptsA=round($totalPoints/$countFirst,2);
}
elseif($countFirst==2) {
$ptsA=round(($pointsFirst+$pointsSecond)/2,2);
if($countSecond>1) {
$ptsB=round($pointsThird/$countSecond,2);
}
elseif($countSecond==1) {
$ptsB=round($pointsThird,2);
}
}
elseif($countFirst==1) {
$ptsA=round($pointsFirst,2);
if($countSecond>1) {
$ptsB=round(($pointsSecond+$pointsThird)/2,2);
}
elseif($countSecond==1) {
$ptsB=round($pointsSecond,2);
if($countThird>1) {
$ptsC=round($pointsThird/$countThird,2);
}
elseif($countThird==1) {
$ptsC=round($pointsThird,2);
}
}
}
I hope I have been clear in my request. I'll be glad to clarify anything. If anyone has any ideas on how to efficiently automate a payout calculation to six places I will be eternally grateful. Thank-you! Mike
Per request:
$scores=array();
$scores[0]=72;
$scores[1]=72;
$scores[2]=73;
$scores[3]=73;
$scores[4]=73;
$scores[5]=74;
$scores[6]=75;
$scores[7]=75;
$scores[8]=76;
$scores[9]=77;
$scores[10]=77;
$payout=array();
$payout[0]=0.6*$totalPoints;
$payout[1]=0.2*$totalPoints;
$payout[2]=0.15*$totalPoints;
$payout[3]=0.03*$totalPoints;
$payout[4]=0.02*$totalPoints;
$payout[5]=0.01*$totalPoints;
$countScores=array();
$countScores[0]=$countFirst;
$countScores[1]=$countSecond;
$countScores[2]=$countThird;
$countScores[3]=$countFourth;
$countScores[4]=$countFifth;
$countScores[5]=$countSixth;
First, there is a problem with your Payouts. If you add them up you get 1.01 not 1
0.6 (1st) + 0.2 (2nd ) + 0.15 (3rd) + 0.03 (4th) + 0.02 (5th) + 0.01 (6th) = 1.01
Second, it is easier if you make your Payouts and Counts into arrays -
change these -
$pointsFirst=0.6*$totalPoints;
$pointsSecond=0.2*$totalPoints;
$pointsThird=0.15*$totalPoints;
$pointsFourth=0.03*$totalPoints;
$pointsFifth=0.02*$totalPoints;
$pointsSixth=0.01*$totalPoints;
$countFirst=2;
$countSecond=3;
$countThird=1;
$countFourth=2;
$countFifth=1;
$countSixth=2;
to these
$payout=array();
$payout[0]=0.6*$totalPoints;
$payout[1]=0.2*$totalPoints;
$payout[2]=0.15*$totalPoints;
$payout[3]=0.03*$totalPoints;
$payout[4]=0.02*$totalPoints;
$payout[5]=0.01*$totalPoints;
$count=array();
$count[0]=2;
$count[1]=3;
$count[2]=1;
$count[3]=2;
$count[4]=1;
$count[5]=2;
Here is the start of one way to do it. Although I would eventually change this into a function so that I can use it again with different payouts, and number of places (see phpfiddle examples below)
I see this in 4 steps-
Step 1
// Add together the payments if there are ties - ie. 2 tied for first $payout[0]+$payout[1], etc
$payout_groups = array(); // start a payout array
$payout_groups_key = 0; // array key count
$payout_groups_count = 0; // array counter, use to match the $count array values
for($w=0;$w<count($payout);$w++){ //
if(array_key_exists($payout_groups_key,$payout_groups)){
$payout_groups[$payout_groups_key] += $payout[$w]; // if there are ties, add them together
}
else{
$payout_groups[$payout_groups_key] = $payout[$w]; // else set a new payout level
}
$payout_groups_count++; // increase the counter
if($payout_groups_count == $count[$payout_groups_key]){ // if we merged all the ties, set a new array key and restart the counter
$payout_groups_key++;
$payout_groups_count = 0;
}
}
Step 2
// basic counter to get how many placers/winners. This makes it possible to have ties for 6th (last) place
$x = 0;
$y = 0;
while($y < count($payout)){
$y += $count[$x]; // the $count array values until we reach the amount of places/payouts
$x++;
}
Step 3
// Create array for winnings per placing
$winnings = array(); // start an array
$placings_count = 0; //
$placings_counter = 0;
for($z=0;$z<$y;$z++){
$winnings[$z] = $payout_groups[$placings_count]/$count[$placings_count];
$placings_counter++;
if($placings_counter == $count[$placings_count]){
$placings_count++;
$placings_counter = 0;
}
}
Step 4
// Assign winnings to scorecard
$scoreboard = array();
for($t=0;$t<count($winnings);$t++){
$scoreboard[$t]['score'] = $scores[$t];
$scoreboard[$t]['payout'] = $winnings[$t];
}
You can see this using your defined values at - http://phpfiddle.org/main/code/a1g-qu0
Using the same code above, I changed the payout amounts, and increased it to 7th places - http://phpfiddle.org/main/code/uxi-qgt

Making the leap from PhP to Python

I am a fairly comfortable PHP programmer, and have very little Python experience. I am trying to help a buddy with his project, the code is easy enough to write in Php, I have most of it ported over, but need a bit of help completing the translation if possible.
The target is to:
Generate a list of basic objects with uid's
Randomly select a few Items to create a second list keyed to the uid containing new
properties.
Test for intersections between the two lists to alter response accordingly.
The following is a working example of what I am trying to code in Python
<?php
srand(3234);
class Object{ // Basic item description
public $x =null;
public $y =null;
public $name =null;
public $uid =null;
}
class Trace{ // Used to update status or move position
# public $x =null;
# public $y =null;
# public $floor =null;
public $display =null; // Currently all we care about is controlling display
}
##########################################################
$objects = array();
$dirtyItems = array();
#CREATION OF ITEMS########################################
for($i = 0; $i < 10; $i++){
$objects[] = new Object();
$objects[$i]->uid = rand();
$objects[$i]->x = rand(1,30);
$objects[$i]->y = rand(1,30);
$objects[$i]->name = "Item$i";
}
##########################################################
#RANDOM ITEM REMOVAL######################################
foreach( $objects as $item )
if( rand(1,10) <= 2 ){ // Simulate full code with 20% chance to remove an item.
$derp = new Trace();
$derp->display = false;
$dirtyItems[$item->uid] = $derp; //# <- THIS IS WHERE I NEED THE PYTHON HELP
}
##########################################################
display();
function display(){
global $objects, $dirtyItems;
foreach( $objects as $key => $value ){ // Iterate object list
if( #is_null($dirtyItems[$value->uid]) ) // Print description
echo "<br />$value->name is at ($value->x, $value->y) ";
else // or Skip if on second list.
echo "<br />Player took item $value->uid";
}
}
?>
So, really I have most of it sorted I am just having trouble with Python's version of an Associative array, to have a list whose keys match the Unique number of Items in the main list.
The output from the above code should look similar to:
Player took item 27955
Player took item 20718
Player took item 10277
Item3 is at (8, 4)
Item4 is at (11, 13)
Item5 is at (3, 15)
Item6 is at (20, 5)
Item7 is at (24, 25)
Item8 is at (12, 13)
Player took item 30326
My Python skills are still course, but this is roughly the same code block as above.
I've been looking at and trying to use list functions .insert( ) or .setitem( ) but it is not quite working as expected.
This is my current Python code, not yet fully functional
import random
import math
# Begin New Globals
dirtyItems = {} # This is where we store the object info
class SimpleClass: # This is what we store the object info as
pass
# End New Globals
# Existing deffinitions
objects = []
class Object:
def __init__(self,x,y,name,uid):
self.x = x # X and Y positioning
self.y = y #
self.name = name #What will display on a 'look' command.
self.uid = uid
def do_items():
global dirtyItems, objects
for count in xrange(10):
X=random.randrange(1,20)
Y=random.randrange(1,20)
UID = int(math.floor(random.random()*10000))
item = Object(X,Y,'Item'+str(count),UID)
try: #This is the new part, we defined the item, now we see if the player has moved it
if dirtyItems[UID]:
print 'Player took ', UID
except KeyError:
objects.append(item) # Back to existing code after this
pass # Any error generated attempting to access means that the item is untouched by the player.
# place_items( )
random.seed(1234)
do_items()
for key in objects:
print "%s at %s %s." % (key.name, key.x, key.y)
if random.randint(1, 10) <= 1:
print key.name, 'should be missing below'
x = SimpleClass()
x.display = False
dirtyItems[key.uid]=x
print ' '
objects = []
random.seed(1234)
do_items()
for key in objects:
print "%s at %s %s." % (key.name, key.x, key.y)
print 'Done.'
So, sorry for the long post, but I wanted to be through and provide both sets of full code. The PhP works perfectly, and the Python is close. If anyone can point me in the correct direction it would be a huge help.
dirtyItems.insert(key.uid,x) is what i tried to use to make a list work as an Assoc array
Edit: minor correction.
You're declaring dirtyItems as an array instead of a dictionary. In python they're distinct types.
Do dirtyItems = {} instead.
Make a dictionary instead of an array:
import random
import math
dirtyItems = {}
Then you can use like:
dirtyItems[key.uid] = x

Categories