Comparing more than 2 variables and making the greater one a new variable

Imagine there being about 3-5 variables that track the player's behavior. What would be the best way to compare all the variables to pick the one with the highest value, and then put that value into a new variable?


Put all the values into a list, sort by whatever (ascending, descending etc.) and then pick the first entry on the list.

E.g.

x=NewStringList(this.sorter)
n=ToString(player.attribute1)
list add(x, n)
n=ToString(player.attribute2)
list add(x, n)
n=ToString(player.attribute3)
list add(x, n)

then sort (or sort descending) and retrieve the first entry

StringListSort(this.sorter)
y=StringListItem (this.sorter, 0)

Then you have to match y back to the attribute it came from. This is messy and I'm sure there's a cleaner way to do it.

if(y=player.attribute1) {
   player.newvariable=player.attribute1
}
etc...

You might need to use ToInt() to get the string back to a number for comparing. Depending on what you want the new variable to do, you might want to set the new variable to the name of attribute1 instead if it's for displaying rather than just keeping track of which is on top.
I haven't tested this, but I think the concept is sound? Happy to be corrected though.


If the attributes you are comparing are all numeric, it seems awkward to convert them all top strings. Not least because sorting like that might put 15 between 1 and 2. (String sorts usually compare the first character of each strong; if those are the same, it compares the second digit, and so on until it finds one that is different)

I would suggest something like this (for the example, I assume that you're trying to find the highest stat of a player who has dnd-like stats in attributes)

highest_stat_name = "none"
highest_stat_value = 0
foreach (attr, Split("strength;intelligence;wisdom;dexterity;constitution;charisma")) {
  if (HasInt (game.pov, attr)) {
    if (GetInt (game.pov, attr) > highest_stat_value) {
      highest_stat_name = attr
      highest_stat_value = GetInt (game.pov, attr)
    }
  }
}

// You can do whatever you want with those variables here,
//     such as putting them in an attribute to refer to later

msg ("Your highest stat is " + highest_stat_name + ", which has a score of " + highest_stat_value + ".")

Oh ok, yeah that makes sense. Didn't realise about 1, 15, 2, though it's obvious in hindsight. That is a much more elegant solution.


Also a little more efficient; because sorting a list involves comparing every element to every other element (well… it's linearithmic, but some principle), when you really only need to compare each element to the highest one found so far. This method also allows you to find which stat was highest, rather than just its value.

If there were situations where you might need to know which is the 4th highest or similar, then sorting would be useful. But in that case I'd probably make it something like…

statistics = NewStringList()
foreach (attr,  Split("strength;intelligence;wisdom;dexterity;constitution;charisma")) {
  value = GetInt (game.pov, attr) + 1000000
  value = Mid (ToString (value) + ";" + attr, 2)
  list add (statistics, value)
}
game.pov.stats_in_order = StringListSortDescending (statistics)

This adds 1000000 onto each stat, the stat name on the end, and then chops off the first character. So the stats_in_order attribute ends up being a list of values that look like 000012;strength. You can then use Split and ToInt to get the actual numbers back.

Alternatively, you could do a somewhat inelegant indirect insertion sort:

sorted = NewStringList()
foreach (attr,  Split("strength;intelligence;wisdom;dexterity;constitution;charisma")) {
  value = GetInt (game.pov, attr)
  newlist = NewStringList()
  found = false
  foreach (comparison, sorted) {
    if (not found) {
      if (GetInt (game.pov, comparison) > value) {
        list add (newlist, comparison)
      }
      else {
        found = true
        list add (newlist, attr)
        list add (newlist, comparison)
      }
    }
    else {
      list add (newlist, comparison)
    }
  }
  sorted = newlist
}
game.pov.sorted_stats = sorted

This is a little inefficient because Quest doesn't provide the usual functions to manipulate lists. But if I got it right off the top of my head, it would give a list of the stat names in order. So ListItem (player.sorted_stats, 0) would be the name of the highest stat; ListItem (player.sorted_stats, 2) would be the one with 2 higher than it, and so on. And GetInt (player, ListItem (player.sorted_stats, 0)) could get the actual value of the highest stat.

Obviously, this is a lot more complex than my earlier suggestion. But I think if you regularly need to know a player's 3rd highest stat or something, it could be useful.

(Oh, note: I used game.pov to refer to the player object in all these examples, because this always works. If somebody finds this post a few months later, I don't want my code to break because they've renamed the player object to Player or ego or something, or have more than one playable character. Doing things the "always works" way to start with is a good habit to get into)

(Also: Sorry for using the word "sorted" to mean "ordered". I think most people will find it easier to read that way)


Log in to post a reply.

Support

Forums