PHP Game weapon accuracy - php

I'm trying to come up with a way for players to fire their weapons and only hit for a certain percentage. For example, one gun can only hit 70% of the time while another only hits 34% of the time.
So far all I could come up with is weighted arrays.
Attempt 1:
private function weighted_random(&$weight)
{
$weights = array(($weight/100), (100-$weight)/100);
$r = mt_rand(1,1000);
$offset = 0;
foreach($weights as $k => $w)
{
$offset += $w*1000;
if($r <= $offset)
return $k;
}
}
Attempt 2:
private function weapon_fired(&$weight)
{
$hit = array();
for($i = 0; $i < $weight; $i++)
$hit[] = true;
for($i = $weight; $i < 100; $i++)
$hit[] = false;
shuffle($hit);
return $hit[mt_rand(0,100)];
}
It doesn't seem that the players are hitting the correct percentages but I'm not really sure why.
Any ideas or suggestions? Is anything glaringly wrong with these?
Thanks

private function weapon_fired($weight)
{
return mt_rand(0, 99) < $weight;
}

Related

Gaussian elimination has to give back multiple solutions php

I want to use gaussian elimination to solve the following matrix Matrix and this is the answer I'm expecting. I would like to get back an equation in the form as is displayed in answer but i can't figure out how to do it.
public function gauss($A, $x) {
# Just make a single matrix
for ($i=0; $i < count($A); $i++) {
$A[$i][] = $x[$i];
}
$n = count($A);
for ($i=0; $i < $n; $i++) {
# Search for maximum in this column
$maxEl = abs($A[$i][$i]);
$maxRow = $i;
for ($k=$i+1; $k < $n; $k++) {
if (abs($A[$k][$i]) > $maxEl) {
$maxEl = abs($A[$k][$i]);
$maxRow = $k;
}
}
# Swap maximum row with current row (column by column)
for ($k=$i; $k < $n+1; $k++) {
$tmp = $A[$maxRow][$k];
$A[$maxRow][$k] = $A[$i][$k];
$A[$i][$k] = $tmp;
}
# Make all rows below this one 0 in current column
for ($k=$i+1; $k < $n; $k++) {
$c = -$A[$k][$i]/$A[$i][$i];
for ($j=$i; $j < $n+1; $j++) {
if ($i==$j) {
$A[$k][$j] = 0;
} else {
$A[$k][$j] += $c * $A[$i][$j];
}
}
}
}
# Solve equation Ax=b for an upper triangular matrix $A
$x = array_fill(0, $n, 0);
for ($i=$n-1; $i > -1; $i--) {
$x[$i] = $A[$i][$n]/$A[$i][$i];
for ($k=$i-1; $k > -1; $k--) {
$A[$k][$n] -= $A[$k][$i] * $x[$i];
}
}
return $x;
}
I hope someone can help me to rewrite this code so it gives the solution i've provided or recommend a library which is capable of doing this.
I've searched for possible solutions on Google but haven't been able to find one yet.
Thanks in advance.

Convert GMP integer to a sum of power of two (2n)

I'm using GMP library of php to solve a problem of formulary.
public function gmp_sum($aRessource)
{
// Avec le while
$i = 0;
$nb_ressource = count($aRessource);
while ($i < $nb_ressource)
{
if ($i == 0)
{
$tmp = gmp_init($aRessource[$i]);
}
else
{
$tmp = gmp_add(gmp_init($aRessource[$i]),$tmp);
}
$i++;
}
return $tmp;
}
The variable $aRessource is equal to : array(1,2,4,8);
so my function gmp_sum is returning 15.
I want to create an algorithm who does the reverse operation, the function take the integer 15 and return me an array who contains 1 2 4 8. But I do not know where to start.
Thanks for the help
Solution :
Decompose integer to power of 2 in php
public function gmp_reverse($gmp_sum)
{
$res = array();
$i = 1;
while ($i < 64) // 64 bytes
{
$tmp = $gmp_sum & $i; // check if bytes equal to 1
if ($tmp != 0)
{
array_push($res,$i);
}
$i = $i * 2;
}
return $res;
}
Assuming you want an array which adds up to the sum, you want a reverse of that. This function assumes, you have a perfect input, so for example, 17 will not work.
Try it out.
function reversegen($gmpsum)
{
$stack = array();
$limit = $gmpsum;
$cur = 1;
for($sum = 0; $sum < $limit; )
{
echo $cur. "<br>";
array_push($stack,$cur);
$sum = $sum + $cur;
$cur = 2 * $cur;
}
return($stack);
}
$stack = reversegen(15);
print_r($stack);
15 above is for representative purpose. You can use, 31, 63, 127 etc and it will still work fine.

To find out whether every letter in word B appear in word A, which is the fastest func in php

I got three funcs:
_sort, _strpos, _array_int
<?php
class timer{
private $_start;
private $_end;
public function program_begin(){
$this->_start = microtime(true);
}
public function program_end(){
$this->_end = microtime(true);
}
public function get_time(){
$time_use = ($this->_end - $this->_start)*1000;
echo $time_use."ms\n";
}
};
$t = new timer();
$test_cnt = $argv[1];
$s_len1 = $s_len2 = $argv[2];
$t->program_begin();
for($j = 0; $j<$test_cnt; $j++){
for($i = 0; $i < $s_len1; $i++)
$s1 .= chr(rand()%26+97);
for($i = 0; $i < $s_len2; $i++)
$s2 .= chr(rand()%26+97);
$flag = call_user_func($argv[3],$s1, $s2);
$s1=$s2="";
}
$t->program_end();
$t->get_time();
function _sort($s1, $s2){
for($i = 0; $i < strlen($s1); $i++)
$arr[] = $s1[$i];
sort($arr);
for($i = 0; $i < strlen($s2); $i++)
if(!search_part($arr, $s2[$i]))
return false;
return true;
}
function search_part($arr, $key){
$s = 0;
$e = count($arr)-1;
while($s<=$e){
$m = (int)(($s+$e)/2);
if($arr[$m] > $key)
$e = $m-1;
if($arr[$m] < $key)
$s = $m+1;
if($arr[$m] == $key)
return true;
}
return false;
}
function _strpos($s1, $s2){
for($i = 0; $i < strlen($s2); $i++)
if(strpos($s1,$s2[$i]) === false)
return false;
return true;
}
function _array($s1, $s2){
for($i = 0; $i < strlen($s1); $i++)
$arr[$s1[$i]] = 1;
for($i = 0; $i < strlen($s2); $i++)
if(!isset($arr[$s2[$i]]))
return false;
return true;
}
function _array_int($s1,$s2){
for($i = 0; $i < strlen($s1); $i++)
$arr[ord($s1[$i])] = 1;
for($i = 0; $i < strlen($s2); $i++)
if(!isset($arr[ord($s2[$i])]))
return false;
return true;
}
I thought the time complexity:
_sort(as func A) : O(nlgn)
_array_int(as func B): O(n)
_strpos(as func C): O(n^2)
thus speed seems to be B>A>C
but the test result is: C>B>A
I could not explain why C is fastest.
test it like this php test.php test_count word_lenght test_func
One of the reasons your O(n^2) might have performed faster than the others, is because it contains a bug.
if(!strpos($s1,$s2[$i]))
return false;
This effectively means "if there is no character $s2[$i] in $s1 OR it is the FIRST character in $s1, return false.", since string index starts at 0. And that's probably not what you intended, as it will instantly return false in O(1) when both strings start with the same character, for example. (you can fix this by using instead if(strpos($s1,$s2[$i]) === false))
Secondly, the input you use to test is critical for the results you obtain. Since O(10*n) is still O(n), there is no guarantee that for small inputs, an O(n) algorithm will execute faster than a O(n²) and so on. This guarantee is on the asymptotic result as n grows sufficiently large. Besides, peculiarities in the algorithms can also lead to different performance in specific cases, as opposed to the "worst case". For example, your quadratic function could result in very different performances compared to itself by simply passing the arguments in swapped order ($s2, $s1), if one of the strings is significantly smaller than the other, or other special conditions are met, particularly because you allow your algorithms to quickly return false as soon as possible, without necessarily processing both strings all the way to the end.
In the end, your O(n) algorithm should generally perform the best among the 3, especially as the input size increases, but it is not necessarily guaranteed that it will perform better at every input.
if you simply use str_split to match if a string is part of another string. Your code seems unnecessarily complex.
$string1 = "ABCD";
$string2 = "AABCDEF";
$origin = str_split($string1);
$other = str_split($string2);
foreach ($origin as $char) {
if (in_array($char, $other)) {
//char found
} else {
//char not found
}
}

php - shifting variable value by if else simplification

I'm trying to make something like this to my variable data value...
$maxvalue = 0;
$basevalue = 0;
if($basevalue == 0) {$maxvalue = 0;}
else if ($basevalue == 1) {$maxvalue = 884;}
else if ($basevalue == 2) {$maxvalue = 1819;}
else if ($basevalue == 3) {$maxvalue = 2839;}
and so on.. i believe there is no exact computation on how the $maxvalue shifts as the basevalue increase. Can someone suggest me a simplier way to do this? thanks in advance!
$maxvalues = array(0, 884, 1819, 2839, ...);
$maxvalue = $maxvalues[$basevalue];
It looks like there's a pattern, almost like a faculty, but also with some other calculations. All numbers are multiples of 17. The following function returns the numbers you provided, so I think it might work for the higher numbers too:
function getMaxValue($base)
{
// Factor of $base = 51 + $base^2 + Factor($base - 1). You
// could solve that in a recursion, but a loop is generally better.
$factor = 0;
for ($i = 1; $i <= $base; $i++)
$factor += 51 + ($i * $i);
return $factor * 17;
}
// Test
for ($i = 0; $i < 100; $i++)
{
echo "$i -- " . getMaxValue($i) . "<br>\n";
}
Here's the solution that prevented me putting all of them in an array..
$maxvalue = 17/6*(2*($basevalue*$basevalue*$basevalue)+3
($basevalue*$basevalue)+307*$basevalue);
Thanks for all the help

PHP Get Experience by Level

I have this piece of code that loops 1 through 99 and is a formula.
function getExperienceByLevel ($maxLevel)
{
$levels = array ();
$current = 0;
for ($i = 1; $i <= $maxLevel; $i++)
{
$levels[$i - 1] = floor ($current / 4);
$current += floor($i+300*pow(2, ($i/9.75)));
}
return $levels;
}
First you initiate it like so $aLevels = getExperienceByLevel(99); then to see how much EXP you need to get to level 6 you do this echo $aLevels[5]; since it's an array.
Now I'm trying to do reverse. Get Level by EXP.
function getLevelByExp($exp)
{
$myLevel = 0;
$aLevels = getExperienceByLevel(99);
for ($i = 1; $i < 100; $i++)
{
if ($exp > $aLevels[$i-1])
{
return $myLevel;
}
}
}
When called upon getLevelByExp(1124); or any number inside, it seems to return a zero. But it seems to work when you put echos inside that statement.
Like instead of return $myLevel do echo "You are up to level $i<br />"; and it will go all the way up to the current level you've gained EXP for.
But still.. doesn't work when I want to simply return a number.
This seems to work better than your function:
function getLevelByExp($exp)
{
$aLevels = getExperienceByLevel(99);
for ($i = 0; $i <= 99; ++$i)
{
//echo "cmp $exp >= aLevels[$i]={$aLevels[$i]}\n";
if ($exp <= $aLevels[$i])
return $i - 1;
}
return -1;
}
It needs improvement for the edge cases, such as when $exp is zero.
Return $i instead because it always '0'
if ($exp > $aLevels[$i-1]) {
return $i;
}
You never change $myLevel, so it will always stay at 0.
Try returning $i instead of $myLevel, as $i is actually changing:
function getLevelByExp($exp) {
$aLevels = getExperienceByLevel(99);
for ($i = 1; $i < 100; $i++) {
if ($exp > $aLevels[$i-1]) {
return $i;
}
}
}

Categories