0
\$\begingroup\$

I have a local multiplayer game with an end of round screen that pops up after each round. I'm trying to figure out the logic to calculate the 1st, 2nd, 3rd place from a maximum of 4 players. I also want draw/tie conditions. It's possible for 2 or 3 players to get the same score. The score is just an int for each player. I've been struggling with this for a while... Any help appreciated, even if its just some pseudo code to point me in the right direction. Also, I'd like to avoid using Linq if possible, as I've heard it doesn't play nice with Unity. Thanks

Edit:

Below is what I've managed to come up with for determining the draw conditions. Doesn't seem to hold up in all cases though... Surely there's a simpler approach?

         PlayerScore[] orderedScores = m_scores.OrderByDescending(ps => ps.score).Take(4).ToArray();


        _1stPlacePlayers.Add(orderedScores[0].playerNumber);

        if (orderedScores[0].score == orderedScores[1].score)
        {
            // 2 player draw 1st place
            _1stPlacePlayers.Add(orderedScores[1].playerNumber);
            if(orderedScores[0].score == orderedScores[2].score)
            {
                // 3 player draw 1st place
                _1stPlacePlayers.Add(orderedScores[2].playerNumber);
                if(orderedScores[0].score == orderedScores[3].score)
                {
                    // 4 player draw 1st place
                    _1stPlacePlayers.Add(orderedScores[3].playerNumber);
                }
            }else if (orderedScores[1].score == orderedScores[2].score)
            {
                // 2 player draw 2nd place
                _2ndPlacePlayers.Add(orderedScores[2].playerNumber);
                if (orderedScores[1].score == orderedScores[3].score)
                {
                    // 3 player draw 2nd place
                    _2ndPlacePlayers.Add(orderedScores[3].playerNumber);
                }
            }
            else if (orderedScores[2].score == orderedScores[3].score)
            {
                // 2 player draw 3rd place
                _3rdPlacePlayers.Add(orderedScores[3].playerNumber);
            }
        }

        else if (orderedScores[1].score == orderedScores[2].score)
        {
            // 2 player draw 2nd place
            _2ndPlacePlayers.Add(orderedScores[2].playerNumber);
            if (orderedScores[1].score == orderedScores[3].score)
            {
                // 3 player draw 2nd place
                _2ndPlacePlayers.Add(orderedScores[3].playerNumber);
            }
        }
        else if (orderedScores[2].score == orderedScores[3].score)
        {
            // 2 player draw 3rd place
            _3rdPlacePlayers.Add(orderedScores[3].playerNumber);
        }
\$\endgroup\$
3
  • \$\begingroup\$ Presumably you've tried putting the players in a list and sorting the list by score. Did you run into a specific problem making that do what you need? \$\endgroup\$
    – DMGregory
    Commented Nov 1, 2018 at 3:35
  • \$\begingroup\$ Hi, yes I've managed to sort the players in a list. My main problem is testing for all the possible draw conditions e.g. P1 and P3 having same score, P1, P2, P4 having same score etc. \$\endgroup\$
    – mossy321
    Commented Nov 1, 2018 at 3:48
  • \$\begingroup\$ For the most part, Linq plays fine with Unity. However, advice from both Microsoft and Unity is to avoid it where performance is a concern, since it generates garbage that the GC needs to clean up. An end of round screen doesn't really need to concern itself with performance. Some might consider OrderByDescending Linq because it is part of the namespace, after all. \$\endgroup\$ Commented Nov 2, 2018 at 12:56

1 Answer 1

1
\$\begingroup\$

Avoid looking at specific permutations with a branching tree structure of IFs and use a set-based definition of 1st, 2nd, 3rd that can handle arbitrary multiplicity. For example:

PlayerScore[] orderedScores = m_scores.OrderByDescending(ps => ps.score).Take(4).ToArray();
int[] uniqueScores = orderedScores.Select(ps => ps.score).Distinct().ToArray();
_1stPlacePlayers.AddRange( orderedScores.Where(ps => ps.score == uniqueScores[0] ).Select(ps => ps.playerNumber) );
if( uniqueScores.Length > 1 )
   _2ndPlacePlayers.AddRange( orderedScores.Where(ps => ps.score == uniqueScores[1] ).Select(ps => ps.playerNumber) );
if( uniqueScores.Length > 2 )
   _3rdPlacePlayers.AddRange( orderedScores.Where(ps => ps.score == uniqueScores[2] ).Select(ps => ps.playerNumber) );

I think you can simplify this down to a one or two-liner if you replace the hard-coded _NthPlacePlayers collections with an indexable array of collections.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .