So, I'm trying to make a gladiator game, where the players will be lanistas. I'm going for realism, so the gladiators will die in the arena, making a big influx of new "recruits" necessary.
For now, each newly created gladiator has 21 attributes, ranging from numerical values for things such as strength and agility, to text for faction and name. These are calculated by random functions. Names and factions I'm picking randomely from arrays with (at least for names) a relatively big list of realistic names. Numerical values are simply rand(x,y).
Before I added the name and faction arrays, I tried several times running the file that create gladiators with a while loop creating 10000 gladiators, without any clones emerging, as far as I could see. Now, with picking names too from random (as described above), everything works fine if I create a small number of gladiators, but once I use a number of a couple of hundred for my while loop, or if I run the file a few times in a row with as low a number as 50 in my while loop, I get clones.
With 21 attributes, 100 different values+ for most of them, getting clones doesn't happen by chance. Can anyone tell me what's wrong? This can kill my game, and I was just getting optimistic after overcoming a few (easy) challenges.
Oh, and yeah, the gladiators with the attributes are put into a mysql database automatically.
Edit (update):
I went back in my stuff, removed the naming and faction random functions, and set all to "s". Created 10000 gladiators named s s from faction s, and it seems there are excactly 0 clones - nobody with the exact same stats.
Reactivated the random name functions. Ran the file, creating 200 gladiators. Couldn't see clones. Ran it again. One clone for each gladiator. And again. Now two clones for the gladiators.
This random function isn't random at all, is it?
Edit (update 2):
Tested it again, with one of the previously excluded random functions activated one at a time. It seems its the firstname and surname functions that are screwing things up. Also, from my last test, it seems like there's a pattern, with gladiator id 209 being equal to 737, 77 being equal to 605 and 1133, 148 equal to 676, 772 equal to 244, and so on.
737-209, 605-77, 1133-605, 676-148, 772-244 all have one thing in comon. They all equal 528.
This isn't much random at all.
The function I use for getting names goes something like:
$surname=surname($faction) //surname is a function, using the variable $faction
function surname($faction) {
if ($faction=="Roman") {
$nomen = array("Aburius", "Accius", [...]);
$cognomen = array("Zeno", "Zonsimus", [...]);
$randnomen=array_rand($nomen,1);
$randcognomen=array_rand($cognomen,1);
$merge=array($nomen[$randnomen],$cognomen[$randcognomen]);
$surname=implode(" ",$merge);
return $surname;
}
To clarify: The [...] in the $nomen and $cognomen arrays is there in place of hundreds of roman names, to save space and your time.
array_rand seems to have a problem with randomness see here.
I prefer to use mt_rand myself.
The following function can create random names with either1,2 or three parts.
function randomName(){
$numargs = func_num_args();
$first = func_get_arg(0);
$one = count($first)-1;
$name = $first[mt_rand( 0,$one)]; //count($array)-1
if($numargs > 1){
$middle = func_get_arg(1);
$two = count($middle)-1;
$name .=" ". $middle[mt_rand( 0,$two)];
}
if($numargs > 2){
$last = func_get_arg(2);
$three = count($last)-1;
$name .= " ".$last[mt_rand( 0,$three)];
}
return $name;
}
USE
$var= randomName($first,$middle,$last);// 3 names
$var= randomName($first,$last);// 2 names
etc
WHERE $first,$middle,$last are arrays
With only ~100 values for an attribute and 1000s of gladiators, there may be many with the same name attribute, for example.
If you mean that there may be multiple gladiators where all 21 attributes are the same, then the only way to guard against that is to check newly created gladiators against the existing ones and if there is a match regenerate the new one.
Just like you would when someone registers for a site, normally username and email address must be unique per user, so you have to check first.
The easiest and most performant in this case might be to generate a "hash" of each gladiator's properties and check if it exists before generating a new gladiator. This will make them all unique, so you also need to consider how unique do you want them? Can 2 or more gladiators have 20 properties in common? How about 15, etc?
Related
I've made a script that pretty much loads a huge array of objects from a mysql database, and then loads a huge (but smaller) list of objects from the same mysql database.
I want to iterate over each list to check for irregular behaviour, using PHP. BUT everytime I run the script it takes forever to execute (so far I haven't seen it complete). Is there any optimizations I can make so it doesn't take this long to execute...? There's roughly 64150 entries in the first list, and about 1748 entries in the second list.
This is what the code generally looks like in pseudo code.
// an array of size 64000 containing objects in the form of {"id": 1, "unique_id": "kqiweyu21a)_"}
$items_list = [];
// an array of size 5000 containing objects in the form of {"inventory: "a long string that might have the unique_id", "name": "SomeName", id": 1};
$user_list = [];
Up until this point the results are instant... But when I do this it takes forever to execute, seems like it never ends...
foreach($items_list as $item)
{
foreach($user_list as $user)
{
if(strpos($user["inventory"], $item["unique_id"]) !== false)
{
echo("Found a version of the item");
}
}
}
Note that the echo should rarely happen.... The issue isn't with MySQL as the $items_list and $user_list array populate almost instantly.. It only starts to take forever when I try to iterate over the lists...
With 130M iterations, adding a break will help somehow despite it rarely happens...
foreach($items_list as $item)
{
foreach($user_list as $user)
{
if(strpos($user["inventory"], $item["unique_id"])){
echo("Found a version of the item");
break;
}
}
}
alternate solutions 1 with PHP 5.6: You could also use PTHREADS and split your big array in chunks to pool them into threads... with break, this will certainly improve it.
alternate solutions 2: use PHP7, the performances improvements regarding arrays manipulations and loop is BIG.
Also try to sort you arrays before the loop. depends on what you are looking at but very oftenly, sorting arrays before will limit a much as possible the loop time if the condition is found.
Your example is almost impossible to reproduce. You need to provide an example that can be replicated ie the two loops as given if only accessing an array will complete extremely quickly ie 1 - 2 seconds. This means that either the string your searching is kilobytes or larger (not provided in question) or something else is happening ie a database access or something like that while the loops are running.
You can let SQL do the searching for you. Since you don't share the columns you need I'll only pull the ones I see.
SELECT i.unique_id, u.inventory
FROM items i, users u
WHERE LOCATE(i.unique_id, u inventory)
I am making a way to organize user into groups and need a way to check them. For example I have a method to check gender, which return true if there is no gender imbalance and false if there is. I also have similar methods to check age distribution and to check genders. For each of these methods I have a method which makes an optimized array of groups.
I.e. i have a method which optimizes groups based on gender. I would only call one of these methods if the respective check returns false. The problem I am running into is that when I optimize the groups based on a specific criterion i.e. gender, there is a chance that the new optimized groups have messed up another check criterion.
For example, if I check age, gender and skill level (my third check) and I find that there is an imbalance in age, proceed to optimize the groups with respect to age, then I could potentially mess up gender or skill level distributions. My solution to this problem was that If I could find a way call all variations of the check methods and break if a check all method returned true (all checks return true, all groups have good balances of age, gender and skill level).
Ex:
Let A, B and C be check methods and optimize_A, optimize_B, optimize_C be the make optimized group methods. I need some way loop through the check methods 3! times (because there are 3 check methods and I need to run ABC, ACB, BAC, BCA, CAB, CBA). OR I could do a while loop and break if the method check all () returns true (all checks return true, all have good distributions) and break once I have run the all the combinations of the check methods.
Could anyone help me with this problem? Please bear in mind I am a novice programmer and have never done anything like this before. Thanks
Edit:
How could I do something like this JavaScript code snippet in php?
var arr = [check1, check2, check3],
rand = Math.floor(Math.random() * arr.length),
func = arr[rand];
func();
Here is my attempt:
<?php
$checks_to_run = array('check_gender','check_age','check_skill_level');
$rand = floor(rand(0, count($checks_to_run) - 1));
$func = $checks_to_run[$rand];
echo $this->.$func.($tmp); // $tmp is an array of groups
?>
You almost had it, just remove the dots at the end.
$checks_to_run = array('check_gender','check_age','check_skill_level');
$rand = floor(rand(0, count($checks_to_run) - 1));
$func = $checks_to_run[$rand];
echo $this->$func($tmp); // $tmp is an array of groups
I have an Array of product types in PHP, it looks pretty much like this:
$types = [
0 => "cars",
1 => "motorbikes",
2 => "boats",
3 => "airplanes"
];
So that when then user wants to get or save it, I can use the ID of the category to insert or get it from the database, like this:
select * from items where type = 0;
now, My doubt is the following: if I am using integer index keys, would it not be the same to use the following?
$types = ["cars", "motorbikes", "etc."];
Since PHP will give an integer auto-ordering.
Which one would you consider to be best practice in this case? The advantage of the first example seems to only be the fact that I can assign different keys, like for private categories or such, but I don't know really.
It is also important to consider that the values will need to be translated so, should I consider even just using IDs? like
$types = ["t1", "t2", "etc."];
and then insert the translation somewhere else?
There are 2 possible options.
Your current option 1 with manually set indexes.
A way better one - a table in the DB, holding these categories, which allow editing categories without losing the association between keys and names.
Your current option 2 is not an option at all - it will break the order the same moment you insert or delete a category
Here you set the index:
$types = [
3 => "airplanes"
index ^ ^ value
So, if you delete cars from the list, the index remain associated with it's value:
$types = [
1 => "motorbikes",
2 => "boats",
3 => "airplanes"
];
While if you don't set indexes manually
$types = ["motorbikes", "boats", "airplanes"];
airplanes will lose it's association, and become boats. It's not ht magic we expect from the web application
It all depends on the project. If I'm working with an array of items from the database I like the key to be the id from the database so it's available should I need it. If there's no need for the ids then there is no need to define a key. It will start at 0 anyways.
I think your first approach is a good one. You could even do it as default translation:
$types["en"] = []
Of course if you have a default language variable, you can use it from the start, and it will be much easier in the future to translate it further and expand
The arrays will be seen as the same so you can order it and take key as ID but it's not the best practice, all depends on how you design your relationship between arrays, php and database.
I might be missing your question but the array in PHP is ordered hash map basically. So ["cars", "motorcycles", "etc."] is guaranteed to preserver ordering (and have keys 0, 1, 2). But you might instead consider do the following
class AutoTypes {
const TYPE_CAR = 0;
const TYPE_MOTORCYCLE = 1;
const TYPE_BOAT = 2;
public static function getLabels() {
return array(self::TYPE_CAR => 'Car', self::TYPE_MOTORCYCLE => 'Motorcycle', self::TYPE_BOAT => 'Boat');
}
}
This way you can refer to the auto type by AutoTypes::CONSTANT. Because if you want to remove motorcycle at some point, not using clear indexes in the array, removing an item will brake your logic.
In my opinion, in this circumstance it's better to use
$types = ["cars", "motorbikes", "etc."];
As you say, PHP automatically assigns integer indexes starting from 0; so there's no need to specify the index that it would be assigned anyway.
It's up to you however, if you feel that it isn't clear enough just to declare an array without specifying the indexes manually then that's up to you. But personally I feel that it's obvious to any competent programmer and so therefore it's a waste of time and hard disk space to manually specify those indexes.
I am kind of new in programming generally and I found it a good idea to ask here first.
So, let's say I have about 900 sets of 6 numbers stored somewhere (maybe in arrays?). I want each time to generate a random set of 6 numbers that is different than the other 900. If it is the same (check with the other 900), then don't accept it and generate a new. I thought of using arrays and check the new set with the others each time, but I think it's a little "painful" to have 900 arrays before.
Any ideas would be appreciated! Thanks!
Honestly, I failed to imagine the task you need this for. )) But usually when you need to ensure a uniqueness of some sort of sets, you use hashes.
Let's say, for example, we have 900 arrays of the following structure:
$arr1 = [n1, n2, n3, n4, n5, n6];
$arr2 = [m1, m2, m3, m4, m5, m6];
...
And we need another array, which shouldn't be the same as any of these.
The solution, I think, is to create a metastructure for storing these arrays alongside its hashes. Something like...
$arrayCollection = array(
hash($arr1) => $arr1,
hash($arr2) => $arr2,
...
);
Then, when a new set is created, I'd generate its hash too - and just check whether the element with the same hash already exists in my collection. Like this:
do {
$newArr = generateArray();
$newArrHash = hash($newArr);
} while (isset($arrayCollection[$newArrayHash]));
It would be quite fast, much faster then just comparing these sets again and again. )
As for hash function, it can be as simple as...
function hash(array $arr) {
return implode('|', $arr);
}
... or you may need to wrap it into some digest function (md5($x, true) will do just fine, I suppose), if $arr may contain some very large strings/numbers.
I have any array
$num_list = array(42=>'0',44=>'0',46=>'0',48=>'0',50=>'0',52=>'0',54=>'0',56=>'0',58=>'0',60=>'0');
and I want to change specific values as I go through a loop
while(list($pq, $oin) = mysql_fetch_row($result2)) {
$num_list[$oin] = $pq;
}
So I want to change like 58 to 403 rather then 0.
However I always end up getting just the last change and non of the earlier ones. So it always ends up being something like
0,0,0,0,0,0,0,0,0,403
rather then
14,19,0,24,603,249,0,0,0,403
How can I do this so it doesn't overwrite it?
Thanks
Well, you explicititly coded that each entry should be replaced with the values from the database (even with "0").
You could replace the values on non-zero-values only:
while(list($pq, $oin) = mysql_fetch_row($result2)) {
if ($pq !== "0") $num_list[$oin] = $pq;
}
I don't get you more clear, i thought your asking this only. Check this
while(list($pq, $oin) = mysql_fetch_row($result2)) {
if($oin==58) {
$num_list[$oin] = $pq;
}
}
In my simulated tests (although You are very scarce with information), Your code works well and produces the result that You want. Check the second query parameter, that You put into array - namely $pg, thats what You should get there 0,0,0,0,0...403 OR Other thing might be that Your $oin numbers are not present in $num_list keys.
I tested Your code with mysqli driver though, but resource extraction fetch_row is the same.
Bear in mind one more thing - if Your query record number is bigger than $numlist array, and $oin numbers are not unique, Your $numlist may be easily overwritten by the folowing data, also $numlist may get a lot more additional unwanted elements.
Always try to provide the wider context of Your problem, there could be many ways to solve that and help would arrive sooner.