Ranking System Help

Twine Version: Twine 1.x
Story Format: Sugarcube2

Hi, this is my first post so appologies if I do something stoopid.

I’m trying to make a ranking system for a game I’m working on.

Say for instance, we have 4 contestants, one of which is the player character who we can say is P4 (my game will have more if that matters).

P1 scores 30pts
P2 scores 35pts
P3 scores 40pts
P4 scores 40pts

I need to work out their positions and any ties.

I thought I could start with something like:

<<if $p1pts gte $p2pts and $p1pts gte $p3pts and $p1pts gte $p4pts>><<set $p1rank = 1>><<set $rank1 = $rank1 + 1>><</if>>

Which finds if anyone beat p1, if true then sets p1 as rank 1 and adds 1 to the number of players at rank 1.
I can then do the same for the other players to see if anyone else is in joint 1st place…

…but then (if not before) I get lost.

Please help! :pleading_face:

One simple technique you can use to sort the points is to temporarily store a copy of those points in a nested Array, and then use JavaScript’s <array>.sort() function combined with a custom ‘descending order’ comparer to sort the elements within the array.

note: Your example didn’t show where the P1, P2, etc String values were sourced from, so I am hard-coding them in my example. I have also add two <<for>> macro calls to follow to demostrate that the scores have been sorted, both of these <<for>> macros can be removed.

/* Temporarily store each player's points within a nested Array. */
<<set _scores to [
	['P1', $p1pts],
	['P2', $p2pts],
	['P3', $p3pts],
	['P4', $p4pts]
]>>
Unsorted Scores:
<ul>
<<for _item range _scores>>
	<li>_item[0] scores _item[1]pts</li>
<</for>>
</ul>

/* Sort the nested Array, descending order. */
<<run _scores.sort(function(a, b) {
  return b[1] - a[1];
})>>

Ranked Scores:
<ul>
<<for _item range _scores>>
	<li>_item[0] scores _item[1]pts</li>
<</for>>
</ul>

You can change the above variable names to whatever makes sense for your project.

Sorry Greyelf, I wrestled with this for 4 days but it is functioning now that I realise the variables $p(1-4)pts are no longer functional and just needed swapping with numerical values! (i.e. 30, 35, 40 and 40).

P1 to P4 weren’t supposed to be string values. I just meant players 1 to 4 and was using $p(1-4)pts to track each player’s score. Sorry if that was confusing.

Perhaps I ought to have put:

$p1pts = 30
$p1pts = 35
$p1pts = 40
$p1pts = 40

But the way you’ve done it using P1-4 as string values works (unsurprisingly you know what you’re talking about). I didn’t realise you could also attribute values to values – that’s handy.

Now it looks like:

<<set _scores to [

['P1', 35],

['P2', 30],

['P3', 40],

['P4', 40]

]>>

In the unsorted and ranked scores for macros, two temporary variables; ‘_item’ and ‘_scores’ appear (to me) to be used like a ‘Property access, dot notation’ variable denoting ‘index’ and ‘value’ (as stated in the documentation under for macros) but maybe I’m very wrong.

If _scores is a temp variable under which are the string values denoting player (P1-4) and those string values in turn hold their subjective score in numerical form, what then is the function of _item?

Would you explain to me how ‘_item[0]’ and ‘_item[1]pts’ function on the list items please?

Finally, between the unsorted scores and the ranked scores is the run macro which does the actual sorting.

Would you explain what this code means or drop me a link please?

Much obliged, Greyelf. You’ve saved me again. Hip hip array.

Just to be clear, _scores is an array of arrays. Each element of the _scores array is another array with two elements, the 0th element in the sub-arrays is the string name of the player, and the 1st element is a numerical value (not a string).

The <<for>> macro, when used with the range parameter, loops through each element of the variable which is listed after the range parameter, and stores that element within the variable that’s named before the range parameter.

In other words, before _scores is sorted, in the first loop of the <<for>> macro, _item is set to ['P1', 35], in the second loop _item is set to ['P2', 30], etc. until it’s gone the whole way through the _scores array. Thus, in the first loop, _item[0] is 'P1' and _item[1] is 35 (the “pts” at the end just makes it display as 35pts).

Check this link for the explanation of the Array.sort() method (which Greyelf linked you to earlier).

Hope that helps clear things up! :slight_smile: