Domanda

Okay I've been beating my head over this one for a while and google searching trying to find anything to lead me in the right direction to no avail.

So I have a ranked leaderboard array like so:

[1] = array('points' => '99', 'rank' => '1');
[2] = array('points' => '90', 'rank' => '2');
[3] = array('points' => '90', 'rank' => '2');
[4] = array('points' => '80', 'rank' => '4');
[5] = array('points' => '70', 'rank' => '5');
[6] = array('points' => '70', 'rank' => '5');

Then I have a reward point system with a predefined array to award points based on rank:

[1]=10;
[2]=9;
[3]=8;
[4]=7;
[5]=6;
[6]=5;

If it weren't for ties I'd just match the two arrays up and award points as so based off of the array keys. But, since I'm allowing for ties I'm trying to split the tied reward points between all tied users. So with the references above players 2 and 3 who are tied at 2nd would split the rewards point 9 and 8... so both would be awarded 8.5 points.

So the end result I'm looking for when merging both arrays would be:

[1] = array('points' => '99', 'rank' => '1', 'reward' => '10');
[2] = array('points' => '90', 'rank' => '2', 'reward' => '8.5');
[3] = array('points' => '90', 'rank' => '2', 'reward' => '8.5');
[4] = array('points' => '80', 'rank' => '4', 'reward' => '7');
[5] = array('points' => '70', 'rank' => '5', 'reward' => '5.5');
[6] = array('points' => '70', 'rank' => '5', 'reward' => '5.5');

The leaderboard can constantly change until the end of the day so I'm trying not to make it too complicated. I'm just wondering if anyone can point me to something they've seen that would help me out or if they had any implementation ideas.

I the part I'm struggling with the most in my attempt is looping through the leaderboard array and continuously looking forward for the 'rank' to be the same to then know what I need to sum up and split out, while also knowing I can skip the array ahead instead of performing this same test on the next item that I just went through in my lookahead. Sorry If I'm confusing, but I'm obviously confused.

È stato utile?

Soluzione

This is probably what you want:

Code

$persons = array(
    array('points' => '99', 'rank' => '1'),
    array('points' => '90', 'rank' => '2'),
    array('points' => '90', 'rank' => '2'),
    array('points' => '80', 'rank' => '4'),
    array('points' => '70', 'rank' => '5'),
    array('points' => '70', 'rank' => '5')
);

$ranks = array(
    1 => 10,
    2 => 9,
    3 => 8,
    4 => 7,
    5 => 6,
    6 => 5
);

foreach($persons as $person => $prop) {
    $reward = $ranks[$prop['rank']];

    if (isset($persons[$person+1])) {
        if ($persons[$person+1]['rank'] == $prop['rank']) {
            $reward = $reward - 0.5;
        }
    }

    if (isset($persons[$person-1])) {
        if ($persons[$person-1]['rank'] == $prop['rank']) {
            $reward = $reward - 0.5;
        }
    }

    $persons[$person]['reward'] = $reward;
}

echo '<pre>';
print_r($persons);
echo '<pre>';

What happens here is you create the reward key and fill it with the person's rank based on the index in the $ranks array. This example is not safe tho. You might want to do a check first if the key even exists in the $ranks array.

This example is very "raw" and probably isn't flawed with different rankings, so you have to do the final tests yourself.

Output

Array
(
    [0] => Array
        (
            [points] => 99
            [rank] => 1
            [reward] => 10
        )

    [1] => Array
        (
            [points] => 90
            [rank] => 2
            [reward] => 8.5
        )

    [2] => Array
        (
            [points] => 90
            [rank] => 2
            [reward] => 8.5
        )

    [3] => Array
        (
            [points] => 80
            [rank] => 4
            [reward] => 7
        )

    [4] => Array
        (
            [points] => 70
            [rank] => 5
            [reward] => 5.5
        )

    [5] => Array
        (
            [points] => 70
            [rank] => 5
            [reward] => 5.5
        )

)

Altri suggerimenti

if more then 2 person can have the same rank like

$persons = array(
    array('points' => '99', 'rank' => '1'),
    array('points' => '90', 'rank' => '2'), // <---
    array('points' => '90', 'rank' => '2'), // <---
    array('points' => '90', 'rank' => '2'), // <---
    array('points' => '70', 'rank' => '5'),
    array('points' => '70', 'rank' => '5')
);

then this @Allendar algorithm will give you wrong results (will give reward of 8.5 than 8 and 8.5 points to persons with rank 2 in input above).

if there is always the same number of persons and number of defined ranking (like 6 in this case) you could use something like this:

$persons = array(
    array('points' => '99', 'rank' => '1'),
    array('points' => '90', 'rank' => '2'),
    array('points' => '90', 'rank' => '2'),
    array('points' => '90', 'rank' => '2'),
    array('points' => '70', 'rank' => '5'),
    array('points' => '70', 'rank' => '5')
);

$ranks = array(
    1 => 10,
    2 => 9,
    3 => 8,
    4 => 7,
    5 => 6,
    6 => 5
);

$current_ranks = $ranks;
$rank_pool = array();
$rank_counter = array();

$i = 1; // person counter, start with 1 because $ranks start with 1

// distribute reword equally for all ranks
foreach($persons as $person => $prop) {
  if(!isset($ranks[$i])){
    exit("no reword for this much persons [$i]");
  }

  $rank = $prop['rank'];
  if(!isset($rank_pool[$rank])){
    $rank_pool[$rank] = 0;
  }
  $rank_pool[$rank] += $ranks[$i];
  if(!isset($rank_counter[$rank])){
    $rank_counter[$rank] = 0;
  }
  $rank_counter[$rank]++;

  $i++;
}

// set reword according to equally distributed reword
// points for all ranks
foreach($persons as $person => $prop) {
  $rank = $prop['rank'];
  if(!isset($rank_pool[$rank]) || !isset($rank_counter[$rank])){
    exit('something is wrong!');
  }
  $persons[$person]['reword'] = $rank_pool[$rank]/$rank_counter[$rank];
}


echo '<pre>';
print_r($rank_counter);
print_r($rank_pool);
print_r($persons);
echo '<pre>';

and with input as above you'll get:

$rank_counter=
Array
(
  [1] => 1// --- 1 with rank 1
  [2] => 3// --- 3 with rank 2
  [5] => 2// --- 2 with rank 5
)

$rank_pool
Array
(
  [1] => 10// --- 10 points for persons with rank 1
  [2] => 24// --- 24 points for persons with rank 2
  [5] => 11// --- 11 points for persons with rank 5
)

and you get reword points per person by simple division of total points for each rank and count of each rank

10/1 = 10 points for each person with rank 1
24/3 = 8 points for each person with rank 2
and
11/2 = 5.5 points for each person with rank 5
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top