• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Sorting integers

Status
Not open for further replies.
Level 13
Joined
Mar 24, 2013
Messages
1,105
So I am trying to check the points of players at the end of a round to see who won said round. However, I am running into a problem when it is a tie, I am not sure exactly how to deal with such an occurrence.

Currently I have:

  • Set CurrentIndex = 1
  • For each (Integer TempInteger) from 1 to 11, do (Actions)
    • Loop - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • TotalPoints[CurrentIndex] Less than TotalPoints[TempInteger]
        • Then - Actions
          • Set CurrentIndex = TempInteger
        • Else - Actions
With the above what happens is, if Player 1 is tied with Player 2, Player 1 is credited the win because Player 2's is not larger than ones, but instead equal to.

I am having a hard time wrapping my head around this problem, because if I add another condition that checks for equality first I am not sure what that means because two people could be equal scores but both have a smaller score than another.
 
Level 13
Joined
Mar 24, 2013
Messages
1,105
@DMIF
So I am looking at your sorter, and I must not be understanding it properly, because I think it wants the largest and smallest at the onset. The problem with that is...I am trying to figure out which value is the largest atm so there doesn't seem to be much use in using this.

I must not be explaining my issue too well. I have a list of numbers by player: 50, 175, 200, 100, 200.

I want to enumerate through this list finding which is the largest all the while checking to see if this seemingly largest term is truly larger than all the terms. Because should one term not be truly larger, as in they are equal in the case above (200 vs 200), currently the player who is checked first is awarded the win despite it being a tie. I want both to win in this context.

However, at the end when I check who won the game I do not want both players to win/be tied I want to be able to play a tie-breaker so I need to detect this. Both of which I am not sure how to do.

Even doing something to the effect of:
PlayerPoints[1] = PlayerPoints[2]
PlayerPoints[1] = PlayerPoints[3]

This would be a lot of code since I have 11 players, and it would presuppose Player 1 is the one with the most points unless I had already checked to see if Player 1 is less than the others which..I just am getting so lost in the seemingly large number of combinations.

@Tickles
That sounds like something that might work, but also seems like I would have some enormous condition blocks. But I'll think on it for a little.

What you said also made me think of whether or not it would be possible to simply track the person in 1st place the whole time...But I have no idea how I would do that.
 
One way to approach it is to construct an array of "leaders", such that:
leaders[1] => winner
leaders[2] => tied player (if a tie exists)
leaders[3] => tied player (if a 3-way tie exists)
etc.

In a case where there is 1 winner, leaders[] would only contain leaders[1]. If there is a 2-way tie, only leaders[1] and leaders[2] would be filled. In a 3-way tie, leaders[1], leaders[2], and leaders[3] would all be filled. And so forth.

Next, we want to consider what determines a tie. In this case, equal scores determines a tie. Therefore, we can map the highest score to the number of "leaders" using a hashtable (you can also use an array if you know TotalPoints[] will be between 0-8192).
  • Set Leaders[1] = 1
  • For each (Integer TempInteger) from 1 to 11, do (Actions)
    • Loop - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • TotalPoints[Leaders[1]] Less than or Equal to TotalPoints[TempInteger]
        • Then - Actions
          • Set PointIndex = ((Load 0 of TotalPoints[TempInteger] in PointHash) + 1)
          • Set Leaders[PointIndex] = TempInteger
          • Hashtable - Save PointIndex as 0 of TotalPoints[TempInteger] in PointHash
        • Else - Actions
In this case, Leaders[1] acts as CurrentIndex, since it should always point to the player with the highest score. Now note what happens in the case of a tie--since I changed the condition to "Less than or equal to", it will go to "then" on ties. In this case, since they have the same amount of points, PointIndex + 1 will actually go to 2. So it'll end up storing to Leaders[2]. And it'll work for 3-way ties, 4-way ties, etc. If you are going to run this trigger multiple times, make sure you clear the hashtable when you are done getting the ties.

Now, to check if there is a tie, you simply need to check:
  • (Load 0 of TotalPoints[TempInteger] in PointHash) Greater than 1
If that condition is true, then there is a tie. Then you can loop from 1 to that value to deal with ties:
  • Set WinningPlayers = (Load 0 of TotalPoints[TempInteger] in PointHash)
  • For each (TempInteger) from 1 to WinningPlayers, do (Actions)
    • Loop - Actions
      • <Actions>
Hopefully this all makes sense. Don't worry too much about understanding how to come up with that solution, but make sure you understand how it works. As death said, an easier method would be to sort, but that is rather slow in GUI. The method above is guaranteed to work in 12 iterations, whereas a simple bubble sort could go through as many as 144.
 
Level 13
Joined
Mar 24, 2013
Messages
1,105
Hey Purge, I really appreciate you typing out such a lengthy response, I am having a hard time figuring out how to print out the proper names now that it has found the proper and highest value.

To answer your question, TotalPoints[] is from 1-11 and each index corresponds to the GUI player number of each.

This is what I think I know/understand

The first If statement is deciding who has the most points by starting with Player 1s, and checking if anyone has higher points, should they have higher points they are set as the new person to check everyone else's against, and increments an integer should there be a tie. And should there be a lower bound tie it is seemingly changed to the upper one.

Then should there be a tie, PointIndex will be larger than 1 so we can loop through and show as many statements as we need. But the problem I have here is I need to know who the tie is between to first give them both credit and to print their name. As you referenced earlier, the 2nd place person is in the Leaders[2] and so on, but I loop from 1 to WinningPlayers and try to get it to print out accordingly. however it gives me the same name of the Player, in this case Player 5 (seemingly the last person to have their score checked) So it will show here Player 5 has won 2 times.

Also another problem I am having is, should I fire this trigger again, it goes from detecting a 2 way tie, to solely giving Player 5 the win, PointIndex becomes only equal to 1 for some reason. And I am not sure why or how.


  • Actions
    • Game - Display to (All players) the text: fire
    • Set TotalPoints[1] = 0
    • Set TotalPoints[2] = 0
    • Set TotalPoints[3] = 50
    • Set TotalPoints[5] = 50
    • Set Leaders[1] = 1
    • For each (Integer TempInteger) from 1 to 11, do (Actions)
      • Loop - Actions
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • TotalPoints[Leaders[1]] Less than or equal to TotalPoints[TempInteger]
          • Then - Actions
            • Set PointIndex = ((Load 0 of TotalPoints[TempInteger] from PointHash) + 1)
            • Game - Display to (All players) the text: (String(PointIndex))
            • Set Leaders[PointIndex] = TempInteger
            • Hashtable - Save PointIndex as 0 of TotalPoints[TempInteger] in PointHash
          • Else - Actions
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • PointIndex Greater than 1
      • Then - Actions
        • Set WinningPlayers = PointIndex
        • For each (Integer TempInteger) from 1 to WinningPlayers, do (Actions)
          • Loop - Actions
            • Game - Display to (All players) the text: (RealNames[Leaders[WinningPlayers]] + has won.)
      • Else - Actions
        • Game - Display to (All players) the text: No Tie Detected
        • Game - Display to (All players) the text: (String(TotalPoints[Leaders[1]]))
        • Game - Display to (All players) the text: (RealNames[Leaders[1]] + won)
    • Hashtable - Clear PointHash
 
In this part of your code:
  • For each (Integer TempInteger) from 1 to WinningPlayers, do (Actions)
    • Loop - Actions
      • Game - Display to (All players) the text: (RealNames[Leaders[WinningPlayers]] + has won.)
It should use TempInteger within the loop:
  • For each (Integer TempInteger) from 1 to WinningPlayers, do (Actions)
    • Loop - Actions
      • Game - Display to (All players) the text: (RealNames[Leaders[TempInteger]] + has won.)
Hopefully that would fix the issue.

As for the repetition issue, I am guessing it is because the flushing the hashtable actually destroys it. You would have to create it again:
  • Hashtable - Clear PointHash
  • Hashtable - Create a hashtable
  • Set PointHash = (Last created hashtable)
Alternatively, if you don't want to keep recreating the hashtable, you can switch the parent and child keys so that it saves as TotalPoints[] of 0, and then clear the 0 parent key at the end of the trigger. But it is up to you.

Anyway, let me know if it works. I just wrote that code off the top of my head, so it may have some issues. :p
 
Status
Not open for further replies.
Top