phparraysmultidimensional-arrayleaderboardreward-system

PHP Reward points to leaderboard and account for ties


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.


Solution

  • 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
            )
    
    )