Hello!
I've been busy passing exams, but now I'm free to code around again.
So, in my usual style!

The goal:
I've been playing some Battlefield 3 during study breaks, and I've often been pissed off by BF3's autobalance mechanism. It's bad. Horrible. It makes me sad. I usually have to watch cat videos for an hour to recover from being autobalanced.
But, it gave me the idea to code my own autobalancer! :D

The problem:
To me, my logic seems fine, but the code breaks when I try to call the methods and objects in my main class.

The code (Player.class):

package autobalance;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

public class Player {

    private Random R = new Random();
    private String name;
    private int team;
    private int score;
    List<Player> allPlayers;

    public Player() {
        this.name = "Soldier ";
        this.score = this.R.nextInt(10000);
        this.team = this.R.nextInt(2) + 1;
    }

    public Player addPlayer(String soldierName) {
        this.allPlayers = new ArrayList<>();
        Player P = new Player();
        P.setName(this.name + soldierName);
        allPlayers.add(P);
        return P;
    }

    public void showTeam(int T) {
        Iterator<Player> IT = this.allPlayers.iterator();
        while (IT.hasNext()) {
            Player temp = IT.next();
            if (temp.getTeam() == T) {
                System.out.println(temp.getName() + "-" + temp.getScore());
            }
        }
    }


    public void setName(String name) {
        this.name = name;
    }   

    public String getName() {
        return name;
    }

    public int getScore() {
        return score;
    }

    public int getTeam() {
        return team;
    }
}

The code (main Autobalance.class):

package autobalance;
public class Autobalance {
    public static void main(String[] args) {

        Player P = new Player();

        P.addPlayer("Mirza");
        P.addPlayer("Asmir");
        P.addPlayer("Ljubo");
        P.addPlayer("Slađo");
        P.addPlayer("Khan");
        P.addPlayer("Vpa");
        P.addPlayer("Marin");

    System.out.println("Team 1:");
        P.showTeam(1);
        System.out.println("Team 2:");
        P.showTeam(2);
    }
}

Error report:
No red lines in the code, but when I run it, this happens:

Exception in thread "main" java.lang.RuntimeException: 
Uncompilable source code - constructor Player in class autobalance.
Player cannot be applied to given types;
  required: no arguments
  found: java.lang.String
  reason: actual and formal argument lists differ in length
    at autobalance.Autobalance.main(Autobalance.java:5)
Java Result: 1
BUILD SUCCESSFUL (total time: 0 s

It says line 5 in Autobalance.class is broken, does that mean all of Player.class is broken? :S
I'd really appreaciate gurus' help. :)

This is the output that I recieved after running your code.

Team 1:
Soldier Marin-6431
Team 2:
BUILD SUCCESSFUL (total time: 0 seconds)

and then on another run

Team 1:
Team 2:
Soldier Marin-9910
BUILD SUCCESSFUL (total time: 0 seconds)

I have no errors.... this is strange

Autobalance.java

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package autobalance;

/**
 *
 * @author Patrick
 */
public class Autobalance {
    public static void main(String[] args) {

        Player P = new Player();

        P.addPlayer("Mirza");
        P.addPlayer("Asmir");
        P.addPlayer("Ljubo");
        P.addPlayer("Slađo");
        P.addPlayer("Khan");
        P.addPlayer("Vpa");
        P.addPlayer("Marin");

    System.out.println("Team 1:");
        P.showTeam(1);
        System.out.println("Team 2:");
        P.showTeam(2);
    }
}

Player.java

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package autobalance;

/**
 *
 * @author Patrick
 */
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

public class Player {

    private Random R = new Random();
    private String name;
    private int team;
    private int score;
    List<Player> allPlayers;

    public Player() {
        this.name = "Soldier ";
        this.score = this.R.nextInt(10000);
        this.team = this.R.nextInt(2) + 1;
    }

    public Player addPlayer(String soldierName) {
        this.allPlayers = new ArrayList<>();
        Player P = new Player();
        P.setName(this.name + soldierName);
        allPlayers.add(P);
        return P;
    }

    public void showTeam(int T) {
        Iterator<Player> IT = this.allPlayers.iterator();
        while (IT.hasNext()) {
            Player temp = IT.next();
            if (temp.getTeam() == T) {
                System.out.println(temp.getName() + "-" + temp.getScore());
            }
        }
    }


    public void setName(String name) {
        this.name = name;
    }   

    public String getName() {
        return name;
    }

    public int getScore() {
        return score;
    }

    public int getTeam() {
        return team;
    }
}

That is the same exact code that you posted, therefore the only conclusion is that your computer doesn't like you.

EDIT: I notice that the player's name never changes, you may want to look into that.

Edited 3 Years Ago by pbj.codez: noticed that players names never changes

hey Pobunjenik, sta ima? Alright, I am not sure I understand exactly what it is you are having problems with, but I think I found another bug in your code. This method:

public Player addPlayer(String soldierName) {
    this.allPlayers = new ArrayList<>();
    Player P = new Player();
    P.setName(this.name + soldierName);
    allPlayers.add(P);
    return P;
}

initializes your allPlayers list everytime it is invoked. Therefore, at any time it only has one player - not more.

Comments
Evo ništa, vježbam kod malo. :D

Weird. :S
I've reworked parts off my initial code. And now I get a different error message.

Autobalance.class:

package autobalance;
public class Autobalance {
    public static void main(String[] args) {

        Player P = new Player();

        P.addPlayer("Mirza");
        P.addPlayer("Ljubo");
        P.addPlayer("Asmir");
        P.addPlayer("Slađo");
        P.addPlayer("Goran");
        P.addPlayer("Marin");
        P.addPlayer("Mlađo");

        System.out.println("Team 1:");
        P.showTeam(1);
        System.out.println("Team 2:");
        P.showTeam(2);
    }
}

Player.class:

package autobalance;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

public class Player {

    private Random R = new Random();
    private String name;
    private int team;
    private int score;
    List<Player> allPlayers;

    public Player() {
        this.allPlayers = new ArrayList<>();
    }

    public void addPlayer(String name) {
        Player P = new Player();
        P.setName("Soldier " + name);
        P.setScore(this.R.nextInt(10000));
        P.setTeam(this.R.nextInt(2) + 1);
        this.allPlayers.add(P);
        System.out.println("Added " + name + "!");
    }

    public void showTeam(int T) {
        Iterator<Player> IT = this.allPlayers.iterator();
        while (IT.hasNext()) {
            Player temp = IT.next();
            if (temp.getTeam() == T) {
                System.out.println(temp.getName() + " - " + temp.getScore());
            }
        }
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setScore(int score) {
        this.score = score;
    }

    public void setTeam(int team) {
        this.team = team;
    }    

    public String getName() {
        return name;
    }

    public int getScore() {
        return score;
    }

    public int getTeam() {
        return team;
    }
}

Error report:

run:
Exception in thread "main" java.lang.UnsupportedOperationException: Not yet implemented
    at autobalance.Player.<init>(Player.java:26)
    at autobalance.Autobalance.main(Autobalance.java:5)
Java Result: 1
BUILD SUCCESSFUL (total time: 0 seconds)

I think the new code is much better then the old one, but it is still wrong!

ArrayList is still broken.
Every time you call new Player() you execute the default constructor and start a new ArrayList. That's perfectly good logic considering that the ArrayList is an instance member - one ArrayList per Player, but I doubt very much that it's what you want. Presumably you want one list for the whole game, comtaining all the Players. The purist solution is to have that list as an instance member in some kind of Game class, but if there is only one game happening at a time you could simply make the list static and initialise it when you declare it. The same argument applies to the showTeam method - either it belongs in a Game class or it should be a static method in Player (or maybe there's a case for a Team class?).

Your main method is also pretty bizarre. You create an instance of Player, then keep adding Players to it. What does it mean to "add a player to another player"? Is that just an attempt to work round the non-static ArrayList?

Hint 1:
Personally I'd dump the no-args Playerconstructor, and turn addPlayer into a constructor (because that's what it does - creates a new Player with a given name)

Hint 2:

Iterator<Player> IT = this.allPlayers.iterator();
while (IT.hasNext()) {
   Player temp = IT.next();

is the long and harder and more error-prone way to code

for (Player temp : allPlayers) {

Edited 3 Years Ago by JamesCherrill

hey Pobunjenik, I am not getting that exception. I complied your code and it compiled and ran with no exception arising. However, you may get that UnsupportedOperationException is for example you try invoking method add() on an array ([]), but you won't get that when you invoke add() on a list. seek for some method invokation in an object that does not support that method inside your code, although I doubt you'll find that in the code you have posted above.

I've changed the code according to James' instructions and now it looks like this:

Autobalance.java

package autobalance;

public class Autobalance {

    public static void main(String[] args) {
        Game G = new Game();
        Player P = new Player();

        P.addPlayer("Pobunjenik");
        P.addPlayer("Smorko");
        P.addPlayer("Staycool");
        P.addPlayer("Pekmez");
        P.addPlayer("Džukac");
        P.addPlayer("Debil");
        P.addPlayer("Mrgud");
        P.addPlayer("Khan");
        P.addPlayer("Dude");
        P.addPlayer("Liaf");
        P.addPlayer("Stupid Kid");
        P.addPlayer("Idiot");
        P.addPlayer("Coco");

        System.out.println("\nTEAM 1:");
        G.showTeam(1);
        System.out.println("\nTEAM 2:");
        G.showTeam(2);
    }
}

Player.java:

package autobalance;

import java.util.Random;

public class Player {

    private Random R = new Random();
    private String name;
    private int team;
    private int score;
    Game G = new Game();

    public void addPlayer(String name) {
        Player P = new Player();
        P.name = name;
        P.score = this.R.nextInt(10000);
        P.team = this.R.nextInt(2) + 1;
        Game.allPlayers.add(P);
        System.out.println("Added " + name + "!");        
    }

    public String getName() {
        return name;
    }

    public int getScore() {
        return score;
    }

    public int getTeam() {
        return team;
    }
}

Game.java:

package autobalance;

import java.util.ArrayList;
import java.util.List;

public class Game {

    static List<Player> allPlayers = new ArrayList<>();

    public void showTeam(int T) {
        for (Player temp : Game.allPlayers) {
            if (temp.getTeam() == T) {
                System.out.println(temp.getName() + " - " + temp.getScore());
            }
        }
    }
}

But then I got this error: java.lang.RuntimeException: Uncompilable source code
I googled around, and found the solution, which is to uncheck "Compile on save" setting in the project properties (Build -> Compiling).

And now the code works!

Output:

Added Pobunjenik!
Added Smorko!
Added Staycool!
Added Pekmez!
Added Džukac!
Added Debil!
Added Mrgud!
Added Khan!
Added Dude!
Added Liaf!
Added Stupid Kid!
Added Idiot!
Added Coco!

TEAM 1:
Pekmez - 7277
Mrgud - 2640
Khan - 3576
Dude - 1043
Liaf - 7151
Stupid Kid - 6050
Idiot - 5960
Coco - 5960

TEAM 2:
Pobunjenik - 1248
Smorko - 4193
Staycool - 7662
Džukac - 9575
Debil - 9405
BUILD SUCCESSFUL (total time: 0 seconds)

Can I get comments on the new code? Could something have been done more efficiently maybe?
The next step is to sort the players based on score (I'll use insertSort), and then to balance the teams, based on score. :)

Disabling compile on save just means you are running the old version of your code. It's a really bad idea for you (it exists for very large programs that take long time to compile). You must fix all your compile errors before trying to run.

The Game class is a good way to go, but you are creating a whole load of Game instances, which only works because the ArrayList is static. What you should do is to create a single instance of Game in main, then pass that to all the Players as they are constructed, so every Player has a reference to the same Game instance. Then the arraylist can be / should be an instance variable, not static.

Finally, you still have the "dummy" Player that only exists so you can call addPlayer. It's horrible. Change addPlayer to be an ordinary constructor and simplify the code:eg

    main...
       Game g = new Game();
       new Player(g, "James");
       ...

  class Player..
    Player(Game g, String name) { // a constructor
       this.game = g;
       this.name = name;
       g.allPlayers.add(this);
       etc

ps: Java naming convention is that variables should start with a lower case, so g or p, not G or P

Edited 3 Years Ago by JamesCherrill

Oh now I see what you're talking about!
I've done what you said and the code runs perfectly!

Tomorrow I'll sort the teams and balance the players based on score.
Any tips?

Ummm... How do I sort a list?
I know how to sort an array, but object Player I've got multiple variables (name, team, score), and I need to sort the list based on score.

I've googled around for it, but I just can't seem to get my head around it!

You need a Comparator (see API doc) - it's a small interface with a method that compares two Players to see which sorts first (ib your case by comparing their scores). You pass that to Collections.sort with your list and that's it.

Edited 3 Years Ago by JamesCherrill

I love you man. :D

Here is how I did it:

// in main:
    Collections.sort(g.allPlayers, new sortTeam());
// end of main

class sortTeam implements Comparator<Player> {
    @Override
    public int compare(Player a, Player b) {
        return a.getScore() > b.getScore() ? -1 : a.getScore() == b.getScore() ? 0 : 1;
    }
}

Output:

run:
TEAM 1:
Pobby - 5149
Smorko - 2348
Pekmez - 1532
Džukac - 4664
Debil - 7785
Liaf - 1798
Idiot - 8576

TEAM 2:
Stycool - 2443
Mrgud - 1614
Khan - 8596
Dude - 1454
Idiot - 4872
Coco - 1383

SORTED!

TEAM 1:
Idiot - 8576
Debil - 7785
Pobby - 5149
Džukac - 4664
Smorko - 2348
Liaf - 1798
Pekmez - 1532

TEAM 2:
Khan - 8596
Idiot - 4872
Stycool - 2443
Mrgud - 1614
Dude - 1454
Coco - 1383
BUILD SUCCESSFUL (total time: 0 seconds)

I googled this, and then I learned the mechanics via Comparator's javadoc.

The feeling is mutual! - seriously, it's great when you point someone in the right direction and they have enough smarts and initiative to make the journey for themselves.
Just one very small suggestion: "teamSort" is bad namimg convention, plus it doesn't tell you much - suppose you later have another one for sorting teams in alphbetical order? What would you call that? I would want to call it something quite explicit like PlayerComparatorByScore, so when I use it I won't need any comments to explain it.

Edited 3 Years Ago by JamesCherrill

I'm making a program that balances two teams of players based on player scores.
Later on, I'll implement squads and then I'll sell the code to Electronic Arts for 100 million dollars.
Simple. :D

This article has been dead for over six months. Start a new discussion instead.