Related
I'm currently working on a game for browsers strictly built with php, html, sql & js atm. It's just a fun project i'm working on. Yet I have come to a spot where a function is not working as intended and maybe some help can help me find where I am going wrong. So with that said I have a page where you can fight enemies. Now once you hit the attack button it calculates a formula then updates the enemy health according to the enemies current health - so called formula. Now that works as intended. I moved on to then make the opposite (when an enemy attacks me) and it is not working as intended. It always, no matter what, sets the character health to 0 instead of running the correct formula etc. $enemy & $my_character are arrays.
$enemy = Array ( [level] => 1 [cur_health] => 104 [max_health] => 108 [cur_mana] => 36 [max_mana] => 36 [defense] => 30 [attack_power] => 16 [spell_power] => 3 [image] => images/enemies/demon_1.png [name] => Demon [battleback] => images/battlebacks/cave1.png )
$my_character = Array ( [name] => rackemup [level] => 1 [next_level] => 2 [avatar] => 05.png [class] => Knight [race] => Human [max_health] => 135 [current_health] => 135 [max_mana] => 9 [current_mana] => 9 [next_level_xp] => 100 [current_xp] => 30 [sp] => 0 [gold] => 115 [tokens] => 0 [ac] => 0 [defense] => 18 [attack_power] => 20 [spell_power] => 1 )
Controller:
if ($action == "attack") {
charAttack($enemy,$my_character);
enemyAttack($enemy,$my_character);
header("Location: ?route=$route&msg=2#attack");
exit;
}
Model:
function enemyAttack($enemy,$my_character) {
$dmg = $enemy['attack_power'] - $my_character['defense'];
if ($dmg <= 0) {
$dmg = 1;
}else{
$dmg = ceil($dmg);
}
$cur_hp = $my_character['cur_health'] - $dmg;
updateCharacter($_SESSION['char'],"health",$cur_hp);
updateLog("Enemy Attack","The Enemy Hit You For ".number_format($dmg)." Damage!");
}
function charAttack($enemy,$my_character) {
$dmg = $my_character['attack_power'] - $enemy['defense'];
if ($dmg <= 0) {
$dmg = 1;
}else{
$dmg = ceil($dmg);
}
$cur_hp = $enemy['cur_health'] - $dmg;
updateEnemy($_SESSION['char'],"health",$cur_hp);
updateLog("User Attack","Your Attack Hit The Enemy For ".number_format($dmg)." Damage!");
}
Try $my_character['current_health'] instead of $my_character['cur_health'] in enemyAttack? ;-)
I am trying to calculate the winning order of golfers when they are tied in a competition.
These golf competitions are using the "stableford" points scoring system, where you score points per hole with the highest points winning. Compared to normal golf "stroke play" where the lowest score wins (though this also has the countback system, only calculating the lowest score in the event of a tie...)
The rules are to use a "countback". i.e., if scores are tied after 9 holes, the best placed of the ties is the best score from the last 8 holes. then 7 holes, etc.
The best I can come up with is 2 arrays.
An array with all the players who tied in a given round. ($ties)
One which has the full score data in (referencing the database playerid) for all 9 holes. ($tie_perhole)
I loop through array 1, pulling data from array 2 and using the following formula to create a temporary array with the highest score:
$max = array_keys($array,max($array));
If $max only has 1 item, this player is the highest scorer. the loop through the first array is "by reference", so on the next iteration of the loop, his playerid is now longer in the array, thus ignored. this continues until there is only 1 playerid left in the first array.
However, it only works if a single player wins in each iteration. The scenario that doesn't work is if a sub-set of players tie on any iterations / countbacks.
I think my problem is the current structure I have will need the original $ties array to become split, and then to continue to iterate through the split arrays in the same way...
As an example...
The $ties array is as follows:
Array
(
[18] => Array
(
[0] => 77
[1] => 79
[2] => 76
[3] => 78
)
)
The $tie_perhole (score data) array is as follows:
Array
(
[18] => Array
(
[77] => Array
(
[9] => 18
[8] => 16
[7] => 14
[6] => 12
[5] => 10
[4] => 8
[3] => 6
[2] => 4
[1] => 2
)
[79] => Array
(
[9] => 18
[8] => 17
[7] => 15
[6] => 14
[5] => 11
[4] => 9
[3] => 7
[2] => 5
[1] => 3
)
[76] => Array
(
[9] => 18
[8] => 16
[7] => 14
[6] => 12
[5] => 10
[4] => 8
[3] => 6
[2] => 4
[1] => 2
)
[78] => Array
(
[9] => 18
[8] => 17
[7] => 15
[6] => 13
[5] => 11
[4] => 9
[3] => 7
[2] => 5
[1] => 3
)
)
)
So in this competition, player's 78 and 79 score highest on the 8th hole countback (17pts), so 1st and 2nd should be between them. Player 79 should then be 1st on the 6th hole countback (14pts, compared to 13pts). The same should occur for 3rd and 4th place with the 2 remaining other players.
There are other scenarios that can occur here, in that within a competition, there will likely be many groups of players (of different amounts) on different tied points through the leaderboard.
Also note, there will be some players on the leaderboard who are NOT tied and stay in their current outright position.
The basics of the working code I have is:
foreach ($ties as $comparekey => &$compareval) {
$tie_loop = 0;
for ($m = 9; $m >= 1; $m--) {
$compare = array();
foreach ($compareval as $tie) {
$compare[$tie] = $tie_perhole[$comparekey][$tie][$m];
}
$row = array_keys($compare,max($compare));
if (count($row) == 1) {
$indexties = array_search($row[0], $ties[$comparekey]);
unset($ties[$comparekey][$indexties]);
// Now update this "winners" finishing position in a sorted array
// This is a multidimensional array too, with custom function...
$indexresults = searchForId($row[0], $comp_results_arr);
$comp_results_arr[$indexresults][position] = $tie_loop;
$tie_loop++;
}
// I think I need conditions here to filter if a subset of players tie
// Other than count($row) == 1
// And possibly splitting out into multiple $ties arrays for each thread...
if (empty($ties[$comparekey])) {
break;
}
}
}
usort($comp_results_arr, 'compare_posn_asc');
foreach($comp_results_arr as $row) {
//echo an HTML table...
}
Thanks in advance for any helpful insights, tips, thoughts, etc...
Robert Cathay asked for more scenarios. So here is another...
The leaderboard actually has more entrants (player 26 had a bad round...), but the code i need help with is only bothered about the ties within the leaderboard.
Summary leaderboard:
Points Player
21 48
21 75
20 73
20 1
13 26
This example produces a $tie_perhole array of:
Array
(
[21] => Array
(
[75] => Array
(
[9] => 21
[8] => 19
[7] => 16
[6] => 14
[5] => 12
[4] => 9
[3] => 7
[2] => 5
[1] => 3
)
[48] => Array
(
[9] => 21
[8] => 19
[7] => 16
[6] => 13
[5] => 11
[4] => 9
[3] => 8
[2] => 5
[1] => 3
)
)
[20] => Array
(
[73] => Array
(
[9] => 20
[8] => 18
[7] => 16
[6] => 13
[5] => 11
[4] => 8
[3] => 6
[2] => 5
[1] => 3
)
[1] => Array
(
[9] => 20
[8] => 17
[7] => 16
[6] => 14
[5] => 12
[4] => 9
[3] => 7
[2] => 4
[1] => 2
)
)
)
In this example, the array shows that players 75 and 48 scored 21 points that player 75 will eventually win on the 6th hole countback (14pts compared to 13pts) and player 48 is 2nd. In the next tied group, players 73 and 1 scored 20 points, and player 73 will win this group on the 8th hole countback and finishes 3rd (18 pts compared to 17 pts), with player 1 in 4th. player 26 is then 5th.
Note, the $tie_loop is added to another array to calculate the 1st to 5th place finishing positions, so that is working.
Hopefully that is enough to help.
Ok, so I don't understand golf at all... hahaha BUT! I think I got the gist of this problem, so heres my solution.
<?php
/**
* Author : Carlos Alaniz
* Email : Carlos.glvn1993#gmail.com
* Porpuse : Stackoverflow example
* Date : Aug/04/2015
**/
$golfers = [
"A" => [1,5,9,1,1,2,3,4,9],
"B" => [2,6,4,2,4,4,1,9,3],
"C" => [3,4,9,8,1,1,5,1,3],
"D" => [1,5,1,1,1,5,4,5,8]
];
//Iterate over scores.
function get_winners(&$golfers, $hole = 9){
$positions = array(); // The score numer is the key!
foreach ($golfers as $golfer=>$score ) { // Get key and value
$score_sub = array_slice($score,0,$hole); // Get the scores subset, first iteration is always all holes
$total_score = (string)array_sum($score_sub); // Get the key
if(!isset($positions[$total_score])){
$positions[$total_score] = array(); // Make array
}
$positions[$total_score][] = $golfer; // Add Golpher to score.
}
ksort($positions, SORT_NUMERIC); // Sort based on key, low -> high
return array(end($positions), key($positions)); // The last shall be first
}
//Recursion is Awsome
function getWinner(&$golfers, $hole = 9){
if ($hole == 0) return;
$winner = get_winners($golfers,$hole); // Get all ties, if any.
if(count($winner[0]) > 1){ // If theirs ties, filter again!
$sub_golfers =
array_intersect_key($golfers,
array_flip($winner[0])); // Only the Worthy Shall Pass.
$winner = getWinner($sub_golfers,$hole - 1); // And again...
}
return $winner; // We got a winner, unless they really tie...
}
echo "<pre>";
print_R(getWinner($golfers));
echo "</pre>";
Ok... Now ill explain my method...
Since we need to know the highest score and it might be ties, it makes no sense to me to maintain all that in separate arrays, instead I just reversed the
golfer => scores
to
Tota_score => golfers
That way when we can sort the array by key and obtain all the golfers with the highest score.
Now total_score is the total sum of a subset of the holes scores array. So... the first time this function runs, it will add all 9 holes, in this case theres 3 golfers that end up with the same score.
Array
(
[0] => Array
(
[0] => A
[1] => B
[2] => C
)
[1] => 35
)
Since the total count of golfers is not 1 and we are still in the 9th hole, we run this again, but this time only against those 3 golfers and the current hole - 1, so we are only adding up to the 8th hole this time.
Array
(
[0] => Array
(
[0] => B
[1] => C
)
[1] => 32
)
We had another tie.... this process will continue until we reach the final hole, or a winner.
Array
(
[0] => Array
(
[0] => C
)
[1] => 31
)
EDIT
<?php
/**
* Author : Carlos Alaniz
* Email : Carlos.glvn1993#gmail.com
* Porpuse : Stackoverflow example
**/
$golfers = [
"77" => [2,4,6,8,10,12,14,16,18],
"79" => [3,5,7,9,11,14,15,17,18],
"76" => [2,4,6,8,10,12,14,16,18],
"78" => [3,5,7,9,11,13,15,17,18]
];
//Iterate over scores.
function get_winners(&$golfers, $hole = 9){
$positions = array(); // The score numer is the key!
foreach ($golfers as $golfer => $score) { // Get key and value
//$score_sub = array_slice($score,0,$hole); // Get the scores subset, first iteration is always all holes
$total_score = (string)$score[$hole-1]; // Get the key
if(!isset($positions[$total_score])){
$positions[$total_score] = array(); // Make array
}
$positions[$total_score][] = $golfer; // Add Golpher to score.
}
ksort($positions, SORT_NUMERIC); // Sort based on key, low -> high
return [
"winner"=> end($positions),
"score" => key($positions),
"tiebreaker_hole" => [
"hole"=>$hole,
"score"=> key($positions)],
]; // The last shall be first
}
//Recursion is Awsome
function getWinner(&$golfers, $hole = 9){
if ($hole == 0) return;
$highest = get_winners($golfers,$hole); // Get all ties, if any.
$winner = $highest;
if(count($winner["winner"]) > 1){ // If theirs ties, filter again!
$sub_golfers =
array_intersect_key($golfers,
array_flip($winner["winner"])); // Only the Worthy Shall Pass.
$winner = getWinner($sub_golfers,$hole - 1); // And again...
}
$winner["score"] = $highest["score"];
return $winner; // We got a winner, unless they really tie...
}
echo "<pre>";
print_R(getWinner($golfers));
echo "</pre>";
Result:
Array
(
[winner] => Array
(
[0] => 79
)
[score] => 18
[tiebreaker_hole] => Array
(
[hole] => 6
[score] => 14
)
)
I have a script that builds an array of week numbers for the last 12 weeks like so:
$week_numbers = range(date('W'), date('W')-11, -1);
However, if the current week number is 1, then this will return an array like so:
Array
(
[0] => 1
[1] => 0
[2] => -1
[3] => -2
[4] => -3
[5] => -4
[6] => -5
[7] => -6
[8] => -7
[9] => -8
[10] => -9
[11] => -10
)
But I need this array to look like this instead:
Array
(
[0] => 1
[1] => 52
[2] => 51
[3] => 50
[4] => 49
[5] => 48
[6] => 47
[7] => 46
[8] => 45
[9] => 44
[10] => 43
[11] => 42
)
Can anyone see a simple solution to this?
I have thought about doing something like this (not tested):
$current_week_number = date('W');
if($current_week_number<12){
// Calculate the first range of week numbers (for current year)
$this_year_week_numbers = range(date('W'), 1, -1);
// Calculate the next range of week numbers (for last year)
$last_year_week_numbers = range(52, 52-(11-$current_week_number), -1);
// Combine the two arrays to return the week numbers for the last 12 weeks
$week_numbers = array_merge($this_year_week_numbers,$last_year_week_numbers);
}else{
// Calculate the week numbers the easy way
$week_numbers = range(date('W'), date('W')-11, -1);
}
one idea
$i = 1;
while ($i <= 11) {
echo date('W', strtotime("-$i week")); //1 week ago
$i++;
}
if you arent scared of loops you can do this:
$week_numbers = range(date('W'), date('W')-11, -1);
foreach($week_numbers as $key => $value) { if($value < 1) $week_numbers[$key] += 52; }
You can do a modulo % trick:
$week_numbers = range(date('W'), date('W')-11, -1);
foreach ($week_numbers as $i => $number) {
$week_numbers[$i] = (($week_numbers[$i] + 52 - 1) % 52) + 1;
}
// -1 +1 is to change the range from 0-51 to 1-52
I've found that using modulo like this is often useful for date calculations, you can something similar for months, using 12.
Well, I think the easiest way is to create array after getting dates:
$week_numbers = array_map(function($iDay)
{
return ($iDay+52)%52?($iDay+52)%52:52;
}, range(date('W'), date('W')-11));
-note, that you can not do just % since 52%52 will be 0 (and you want 52)
I have the following array:
array('16 HOURS','13.3 HOURS','10.6 HOURS AGO','8 HOURS AGO','5.3 HOURS AGO','2.6 HOURS AGO','CURRENT')
I want to insert empty cells ('') between every string until the desired length is reached. I have tried various loops, for i etc but always end up with white spaces behind CURRENT or before 16 HOURS, thanks in advance.
Try this.
$array = array('16 HOURS','13.3 HOURS','10.6 HOURS AGO','8 HOURS AGO','5.3 HOURS AGO','2.6 HOURS AGO','CURRENT');
$i = 1;
foreach($array as $val) {
$tempArray[] = $val;
if($i < count($array)) {
$tempArray[] = '';
}
$i++;
}
print_r($tempArray);
Result
Array
(
[0] => 16 HOURS
[1] =>
[2] => 13.3 HOURS
[3] =>
[4] => 10.6 HOURS AGO
[5] =>
[6] => 8 HOURS AGO
[7] =>
[8] => 5.3 HOURS AGO
[9] =>
[10] => 2.6 HOURS AGO
[11] =>
[12] => CURRENT
)
$myArray = array(
'16 HOURS',
'13.3 HOURS',
'10.6 HOURS AGO',
'8 HOURS AGO',
'5.3 HOURS AGO',
'2.6 HOURS AGO',
'CURRENT'
);
$newArray = array_combine(
range(0,12,2),
$myArray
) +
array_fill_keys(
range(1,12,2),
''
)
;
ksort($newArray);
var_dump($newArray);
Assume that selected date from Canlender is 02/09/2011. To store weekly date into array from 20/09/2011 is
for($i=0; $i<7; $i++)
{
$WeeklyDate[] = date("Y-m-d", strtotime(2011-09-02) - 86400*$i);
}
My question is how to store monthly date into array from the selected date.
Many thanks
---Update----------
The final result of monthlyDate should look like the following:
$monthlyDate= array{2011-08-03, 2011-08-04, 2011-08-05, 2011-08-06, 2011-08-07 ....2011-08-31, 2011-09-01, 2011-09-02}
First, calculate the number of days in a month using cal_days_in_month and then proceed as you are doing with weeks eg:
$days = cal_days_in_month(CAL_GREGORIAN, 9, 2011);
for($i = 0; $i <= $days; $i++)
{
$MonthlyDate[] = date("Y-m-d", strtotime(2011-09-02) - 86400*$i);
}
Notice that CAL_GREGORIAN is a built-in constant.
Working Example
Whenever programs are incrementing a date using 86400 there is a risk of unexpected output because of DST.
By using strtotime() with a unit larger than hours (like days, weeks, months, etc.) preventing any DST hiccups. Note: a DateTime object approach can be used but for this case, it is unnecessary overhead.
The following is an adjusted form of a one-liner date range function I developed.
Here is the online demo for this case.
function getDatesFromRange($a,$b,$x=0,$dates=[]){
while(end($dates)!=$b && $x=array_push($dates,date("Y-m-d",strtotime("$a +$x day"))));
return $dates;
}
$date='2011-09-02';
$monthlyDate=getDatesFromRange(date("Y-m-d",strtotime("$date -1 month +1 day")),$date);
var_export($monthlyDate);
output as desired/expected:
array (
0 => '2011-08-03',
1 => '2011-08-04',
2 => '2011-08-05',
3 => '2011-08-06',
4 => '2011-08-07',
5 => '2011-08-08',
6 => '2011-08-09',
7 => '2011-08-10',
8 => '2011-08-11',
9 => '2011-08-12',
10 => '2011-08-13',
11 => '2011-08-14',
12 => '2011-08-15',
13 => '2011-08-16',
14 => '2011-08-17',
15 => '2011-08-18',
16 => '2011-08-19',
17 => '2011-08-20',
18 => '2011-08-21',
19 => '2011-08-22',
20 => '2011-08-23',
21 => '2011-08-24',
22 => '2011-08-25',
23 => '2011-08-26',
24 => '2011-08-27',
25 => '2011-08-28',
26 => '2011-08-29',
27 => '2011-08-30',
28 => '2011-08-31',
29 => '2011-09-01',
30 => '2011-09-02',
)