Solved Intresting problem and Question. Noob v.v

Discussion in 'Plugin Development' started by Tyler Christensen, Aug 15, 2014.

Thread Status:
Not open for further replies.
  1. Sorry, but i need a good way to get all online players (even or odd) push them to a sorting system that divides them into 2 teams, and sets them into hashmaps on a different class. There has to be some way of doing it, i just cant find out how. Thanks Guys :D
     
  2. Offline

    Dealyise

    You can get all players with getServer().getOnlinePlayers();
    Split them by doing getServer().getOnlinePlayers().length / 2 and add them to the first HashMap.
    Then, check again with getServer().getOnlinePlayers(); in a for-loop if a Player is in the HashMap already, if not -> add him into the other HashMap.
    You can avoid Errors by checking getOnlinePlayers().length. If it's greater than 1 , then do /2. If not, cancel it or do whatever you want.
     
  3. Dealyise

    And this would work for an odd amount of players as well?
     
  4. Offline

    Dealyise

    Tyler Christensen
    Like I said, you can check with maths if the amount of players is even or odd.
     
  5. Oki, Thanks for your help! :D
     
  6. Offline

    garbagemule

    There is no reason to make more than one loop through the collection. Adding half to a different collection, then iterating through the entire collection again, constantly checking if each element is a member of the second collection... Too complicated!

    Use a boolean to determine which collection the current player goes into, and toggle it at the end of every iteration of the for-loop. Keep it simple.

    Oh, and to check if an integer is even or odd, use the modulus operator % with a modulus of 2, and check whether the result is 0 (even) or 1 (odd).
     
    Garris0n and Dealyise like this.
  7. @garbagem

    An example maybe? Or try re-explaining it. Im sorry, like i said, im a noob... xD

    Dealyise

    Im sorry, I know im not the best at this, and i am trying but:
    Whenever i try adding their name to a List, its asking my to cast it as a Collection still. How would i label that exactly? Here is my code so far, I've changed it from what i originally had... any Suggestions?

    Code:java
    1. //This method is in my Game class, so when I'm
    2. //ready for my game to start, i type Game.start();
    3. public static void start(){
    4. //hasStarted is a boolean
    5. hasStarted = true;
    6. //This is where i need to sort the players
    7. //into the 2 hashmaps
    8. int players = Bukkit.getServer().getOnlinePlayers().length/2;
    9. //What would i do here?
    10. plist.add(players);
    11. }


    And i do have that list at the top before the Start method.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 9, 2016
  8. Offline

    Dealyise

    Tyler Christensen
    You are trying to add an Integer to a Player List.
    Do this:
    Code:java
    1. Player[] p = getServer().getOnlinePlayers();

    This might work, not sure atm. because I can't use eclipse atm.
     
  9. Dealyise
    I have to change it to this:

    Code:java
    1. Player[] p = Bukkit.getServer().getOnlinePlayers()/2;


    in order for it to pick up thats its getting online players. But it doesnt know what the / is for. I tried putting it like so:

    Code:java
    1. Player[] p = (Bukkit.getServer().getOnlinePlayers())/2;
    2. //and like so:
    3. Player[] p = Bukkit.getServer().getOnlinePlayers()%2;
    4. //and like so:
    5. Player[] p = (Bukkit.getServer().getOnlinePlayers())%2;
    6. //But still no solution, the error is it still cant define
    7. //what / is for as well as %


    And by addind .length at the end, it is trying to change player p to an int.
     
  10. Offline

    Dealyise

    Tyler Christensen
    Wrote a method fast, try to learn from it. I removed some of it so you can figure yourself out how it works.
    Code:java
    1. private static List<Player> list = new ArrayList<Player>();
    2. private static List<Player> list2 = new ArrayList<Player>();
    3. public static void splitPlayers(){
    4. for(Player p : plugin.getServer().getOnlinePlayers()){
    5. //Adding the player to the first list
    6. }
    7. int half = plugin.getServer().getOnlinePlayers().length / 2;
    8. if(use modulo here with half){
    9. for(int i = 0; i < half; i++){
    10. //remove players from first list
    11. }
    12. }else{
    13. half--;
    14. for(int i = 0; i < half; i++){
    15. //remove players from first list
    16. }
    17. }
    18. //Now you got your players splitted
    19. for(Player p : plugin.getServer().getOnlinePlayers()){
    20. if(the first list contains player){
    21. //Adding your source here for adding them into second list.
    22. }
    23. }
    24.  
    25. }
     
    Tyler Christensen likes this.
  11. Dealyise
    I want to make sure i have this right or not, Tell me no if i dont. I want to learn xD Here it is:

    Code:java
    1.  
    2. public static void splitPlayers() {
    3. for (Player p : Bukkit.getServer().getOnlinePlayers()) {
    4. list.add(p);
    5. int half = Bukkit.getServer().getOnlinePlayers().length / 2;
    6. if (half % 2 == 0) {
    7. for (int i = 0; i < half; i++) {
    8. list.remove(p);
    9. }
    10. } else {
    11. half--;
    12. for (int i = 0; i < half; i++) {
    13. list.remove(p);
    14. }
    15. }
    16. for (Player p1 : Bukkit.getServer().getOnlinePlayers()) {
    17. if (list.contains(p1)) {
    18. list.remove(p);
    19. list2.add(p);
    20. }
    21. }
    22. }
    23.  
    24. }
     
  12. Offline

    Garris0n

    It's a Collection now.
     
  13. Offline

    Dealyise

    Tyler Christensen
    Code:java
    1. public static void splitPlayers() {
    2. for (Player p : Bukkit.getServer().getOnlinePlayers()) {
    3. list.add(p);
    4. int half = Bukkit.getServer().getOnlinePlayers().length / 2;
    5. if (half % 2 == 0) { //wrong
    6. for (int i = 0; i < half; i++) {
    7. list.remove(p);
    8. }
    9. } else {
    10. half--;
    11. for (int i = 0; i < half; i++) {
    12. list.remove(p);
    13. }
    14. }
    15. for (Player p1 : Bukkit.getServer().getOnlinePlayers()) {
    16. if (LIST.contains(p1)) {
    17. LIST.remove(p);//wrong
    18. list2.add(p);
    19. }
    20. }
    21. }
    22.  
    23. }
     
  14. Offline

    garbagemule

    I won't spoonfeed code, but I will elaborate. Again, don't do the half + remove/contains/whatever. It's too complicated and much more prone to error.

    Let's first take a look at what we are dealing with - a Collection. The Collection interface extends Iterable, so we can iterate it in an extended for-loop, or we can grab an iterator and construct a loop ourselves. Note that Collection does have a size() method that we can use, but is it really necessary?

    Since there is no weight associated with the players and the teams (a player is associated with a team arbitrarily), it does not matter which order we consider the players, so a simple for-each loop is sufficient. In a real-world scenario, having the players line up behind each other and alternating between saying "left" and "right" would suffice to divide them into two teams, so why not do just that? Since we are dividing the players into two equal (+/- one) size teams, our condition for team selection is binary - a fundamental concept of computer science! We love everything binary! In Java, we have the boolean data type for representing binary values, so that's really all we need.

    As always with state that depends on the iterations of a loop, we have to initialize our teams before we enter the loop. To keep track of which team the current player needs to be assigned to, all we need is a boolean (or a flag). Indeed, we can reduce our team selection decision to an answer to the question of "does this player go on team 1?" which is a yes/no or true/false question. Weee, booleans!

    In each iteration of the for-loop, we ask "does this player go on team 1?" - if yes, we add the player to team 1, and if no, we add the player to team 2. Before the iteration ends, we flip or toggle the boolean by assigning it to its own negation. Sounds confusing? If so, try running this piece of code and try to explain what's going on:
    Code:java
    1. boolean b = true;
    2. System.out.println(b);
    3. b = !b;
    4. System.out.println(b);
    5. b = !b;
    6. System.out.println(b);

    So, your algorithm, in pseudocode, would look like this:
    Code:
    Let P be the collection of online players
    Let L1 and L2 be two new, empty lists
    Let B be a boolean, initially set to true
    for each player p in P {
        if B {
            add p to L1
        } else {
            add p to L2
        }
        toggle B
    }
    That's as close to spoonfeeding code as I'll go. If you don't understand, explain what part you don't understand, and what your current thoughts on the matter are.
     
    leon3001, xTigerRebornx and Gnat008 like this.
  15. i fixed the problem ;] Thanks for your help guys :D Lovin the Bukkit Dev channel ;D
     
  16. Offline

    Dealyise

    garbagemule
    Yep, yours is simplier. Just wanted to show him how it normally works. But yours is better than mine.
    Tyler Christensen
    You're welcome :)
     
  17. Offline

    garbagemule

    Dealyise
    Assuming you wouldn't want to go the simpler route, your code still has serious problems, and I honestly don't think you can justify saying "how it normally works".

    Integer division is always "floored". This is because during integer division, two results are actually computed - the quotient and the remainder. The quotient is the largest integer value you can multiply the divisor with before the result becomes greater than the dividend (essentially the floored result of division of two reals), and the remainder is the result of subtracting the quotient from the dividend, i.e.:
    Code:
    quotient  = floor(a/b)
    remainder = a - quotient
    You can then reconstruct the dividend (a) with the quotient, the remainder, and the divisor (b):
    Code:
    a = (quotient * b) + remainder
    When doing integer division in Java, the quotient is what is returned to you. When using the modulus operator, you get the remainder instead. The problem here is that if the size of your collection is odd, and you divide by 2, you will be given a floored result, disregarding the remainder. In line 8 of your suggestion, you're talking about "modulo with half", and in line 13, you decrement the value of "half". Depending on what you meant by "modulo with half", you will either be decrementing an already floored value, making one team three players smaller than the other (in the odd size case), or two players smaller than the other (in the even size case). I hope it's clear just how important it is to keep things simple...

    Assuming we aren't allowed to use a flag, or if we want the first half of players do be in the first team, and the second half of players in the other, it is still only necessary to loop over the collection once. You can still do it in a single loop, or you can use two loops.
    • In the single loop solution, you would first compute the (floored) half, and then initialize a counter variable to 0 (as with the initializer in normal for-loops). In each iteration, you check if the value of the counter variable is less than or equal to half the size of the collection, and if so, you add to the first list, but if not, you add to the second list. This will create two equal-sized lists, with the second list containing one more player than the first list, in case of an odd collection size.
    • In the dual loop solution, you would have to grab the Iterator of the collection and use it in your loops. The first loop would run from 0 to half, both inclusive (same as less than or equal to in the single loop solution above), and the second loop would run from half to the size of the collection, both exclusive. This is clearly more complicated, and does not really yield any advantages at all.
    The single-loop solution in this case has a possible benefit of reduced branch mispredictions - something you will almost never find a need to optimize for - in comparison to the toggling boolean solution, but it does involve some possibly unnecessary arithmetic and number comparisons that could result in off-by-one errors. I cannot stress enough just how important simplicity is. By keeping your code simple, you make it easier to understand for other people, but also for yourself down the line.
     
Thread Status:
Not open for further replies.

Share This Page