I came across FlyWeight Pattern described in the link. In the example provided , I believe only 2 implementations of player objects will be created. Wouldn't the weapons variable be overridden each time a player object is created?
The code as posted on Geeks For Geeks constructs only two mutable objects.
As can be expected, each time PlayerFactory returns a player, it overrides the weapon of one of the two objects.
This can be demonstrated easily:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
public class CounterStrike
{
private static String[] playerType = {"Terrorist", "CounterTerrorist"};
private static String[] weapons = {"AK-47", "Maverick", "Gut Knife", "Desert Eagle"};
public static void main(String args[])
{
List<Player> players = new ArrayList<>();
System.out.println("------- Construction of Players ----------------");
for (int i = 0; i < 10; i++)
{
Player p = PlayerFactory.getPlayer(getRandPlayerType());
p.assignWeapon(getRandWeapon());
p.mission();
players.add(p);
}
System.out.println("------- Printout all players ----------------");
for(Player p : players) {
p.mission();
}
}
public static String getRandPlayerType()
{
// Will return 0 or 1
int randInt = new Random().nextInt(playerType.length);
return playerType[randInt];
}
public static String getRandWeapon()
{
// Will return an integer between 0 inclusive and 5 exclusive
int randInt = new Random().nextInt(weapons.length);
return weapons[randInt];
}
}
interface Player
{
void assignWeapon(String weapon);
void mission();
}
class Terrorist implements Player
{
private final String TASK;
private String weapon;
public Terrorist()
{
TASK = "PLANT A BOMB";
}
#Override
public void assignWeapon(String weapon)
{
this.weapon = weapon;
}
#Override
public void mission()
{
System.out.println("Terrorist with weapon " + weapon + "|" + " Task is " + TASK);
}
}
class CounterTerrorist implements Player
{
private final String TASK;
private String weapon;
public CounterTerrorist()
{
TASK = "DIFFUSE BOMB";
}
#Override
public void assignWeapon(String weapon)
{
this.weapon = weapon;
}
#Override
public void mission()
{
System.out.println("Counter Terrorist with weapon "+ weapon + "|" + " Task is " + TASK);
}
}
class PlayerFactory
{
private static HashMap <String, Player> hm = new HashMap<>();
public static Player getPlayer(String type)
{
Player p = null;
if (hm.containsKey(type)) {
p = hm.get(type);
} else
{
switch(type)
{
case "Terrorist":
p = new Terrorist();
break;
case "CounterTerrorist":
p = new CounterTerrorist();
break;
default :
System.out.println("Unreachable code!");
}
hm.put(type, p);
}
return p;
}
}
The output shows that all Terrorist have the last applied weapon (Maverick) and all CT an AK-47:
Edit: I did not explore this design pattern, but I must say I am not impressed by the code posted in Geeks For Geeks.
From what I see in other examples the extrinsic attributes need to be managed by the factory.
In this case I guess the factory should have a map for terrorist and a map for CT where the key is the weapon:
public class CounterStrike
{
//better use enums
private static String[] playerType = {"Terrorist", "CounterTerrorist"};
private static String[] weapons = {"AK-47", "Maverick", "Gut Knife", "Desert Eagle"};
public static void main(String args[])
{
List<Player> players = new ArrayList<>();
System.out.println("------- Construction of Players ----------------");
for (int i = 0; i < 10; i++)
{
String type = getRandPlayerType();
Player p = type.equals(playerType[0]) ? PlayerFactory.getTerrorist(getRandWeapon()) :
PlayerFactory.getCoubterTerrorist(getRandWeapon()) ;
p.mission();
players.add(p);
}
System.out.println("------- Printout all players ----------------");
for(Player p : players) {
p.mission();
}
}
public static String getRandPlayerType()
{
// Will return 0 or 1
int randInt = new Random().nextInt(playerType.length);
return playerType[randInt];
}
public static String getRandWeapon()
{
// Will return an integer between 0 inclusive and 5 exclusive
int randInt = new Random().nextInt(weapons.length);
return weapons[randInt];
}
}
class PlayerFactory
{
private static HashMap <String, Player> terrorists = new HashMap<>();
private static HashMap <String, Player> cTerrorists = new HashMap<>();
public static Player getTerrorist(String weapon)
{
Player p = null;
if (terrorists.containsKey(weapon)) {
p = terrorists.get(weapon);
} else{
p = new Terrorist(weapon);
}
terrorists.put(weapon, p);
return p;
}
public static Player getCoubterTerrorist(String weapon)
{
Player p = null;
if (cTerrorists.containsKey(weapon)) {
p = cTerrorists.get(weapon);
} else{
p = new CounterTerrorist(weapon);
}
cTerrorists.put(weapon, p);
return p;
}
}
interface Player
{
void mission();
}
class Terrorist implements Player
{
private final String TASK;
private String weapon;
public Terrorist(String weapon)
{
this.weapon = weapon;
TASK = "PLANT A BOMB";
}
#Override
public void mission()
{
System.out.println("Terrorist with weapon " + weapon + "|" + " Task is " + TASK);
}
}
class CounterTerrorist implements Player
{
private final String TASK;
private String weapon;
public CounterTerrorist(String weapon)
{
this.weapon = weapon;
TASK = "DIFFUSE BOMB";
}
#Override
public void mission()
{
System.out.println("Counter Terrorist with weapon "+ weapon + "|" + " Task is " + TASK);
}
}
We can improve the implementation by using enums, and making the player type an intrinsic attribute, rather than a class:
public class CounterStrike
{
public enum PlayerType{
TERRORIST("PLANT A BOMB"), COUNTER_TERRORIST("DIFFUSE BOMB");
private final String task;
PlayerType(String task){
this.task = task;
}
String getTask(){ return task; }
}
public enum Weapon {
AK47("AK-47"), MAVERICK("Maverick"), GUT_KNIFE("Gut Knife"), DESERT_EAGLE("Desert Eagle");
private final String name;
Weapon(String name) { this.name = name; }
String getName(){ return name; }
#Override
public String toString() { return name; }
}
public static void main(String args[])
{
List<Player> players = new ArrayList<>();
System.out.println("------- Construction of Players ----------------");
for (int i = 0; i < 10; i++)
{
Player p = PlayerFactory.getPlayer(getRandPlayerType(), getRandWeapon()) ;
players.add(p);
System.out.println("Created: "+ p);
}
System.out.println("------- Printout all players ----------------");
for(Player p : players) { System.out.println(p); }
}
public static PlayerType getRandPlayerType()
{
int randInt = new Random().nextInt(PlayerType.values().length);
return PlayerType.values()[randInt];
}
public static Weapon getRandWeapon()
{
int randInt = new Random().nextInt(Weapon.values().length);
return Weapon.values()[randInt];
}
}
class PlayerFactory
{
private static HashMap <Weapon, Player> terrorists = new HashMap<>();
private static HashMap <Weapon, Player> cTerrorists = new HashMap<>();
static Player getPlayer(PlayerType type, Weapon weapon) {
return type == PlayerType.TERRORIST ? getTerrorist(weapon) : getCounterTerrorist(weapon);
}
private static Player getTerrorist(Weapon weapon)
{
Player p = null;
if (terrorists.containsKey(weapon)) {
p = terrorists.get(weapon);
} else{
p = new Player(PlayerType.TERRORIST, weapon);
}
terrorists.put(weapon, p);
return p;
}
private static Player getCounterTerrorist(Weapon weapon)
{
Player p = null;
if (cTerrorists.containsKey(weapon)) {
p = cTerrorists.get(weapon);
} else{
p = new Player(PlayerType.COUNTER_TERRORIST, weapon);
}
cTerrorists.put(weapon, p);
return p;
}
}
class Player
{
private final Weapon weapon;
private final PlayerType type;
Player(PlayerType type, Weapon weapon) {
this.type = type;
this.weapon = weapon;
}
Weapon getWeapon() { return weapon; }
PlayerType getType() {return type; }
String getTask() { return type.getTask(); }
#Override
public String toString() {
StringBuilder sb = new StringBuilder(type == PlayerType.TERRORIST ? "Terrorist" : "Counter Terrorist" );
sb.append(" armed with ").append(weapon).append(". Task: ").append(type.getTask());
return sb.toString();
}
}
In the example class diagram given by the Geeks for Geeks author
If I understand this correctly, the game creates one instance of Terrorist, one instance of CounterTerrorist, and n instances of Player created by the PlayerFactory.
The code reflects the diagram. Terrorist and CounterTerrorist implement the Player interface.
Each Player instance created by the PlayerFactory uses the information from the Terrorist or CounterTerrorist instance, depending on which side the player is on. Since there's a Player instance for each player (Usually 10 in CounterStrike, 5 on each side), there's no confusion as to which player is which.
The CounterStrike class manages the Map created by the PlayerFactory.
This simple real-world example minimizes the duplication that would occur if there were just n Player instances. Each Player instance would have to hold the information for both a terrorist and a counter-terrorist.
By creating one instance of Terrorist, one instance of CounterTerrorist, and sharing those instances with the Player instances, the total amount of storage for the game fields is reduced.
The game code is probably easier to debug and manage as well.
The Java code can be found on Geeks For Geeks.
Related
I have the following problem. Five classes are interacting with each other. Two of theme are doing fine. But with the creating of an Object of one class (Ticket) in my main class Event (getting user input from another class (UserInput), an processing this in the costructor) i have now problem to display the results.
Main class Event with main methode
import java.util.ArrayList;
public class Event {
private static String artistName;
private static int artistSalary;
private Language language;
private static ArrayList<String> trackList;
private InputReader inputReader;
private Ticket ticket;
private int amountOfTicketCategories;
private static Object[] ticketList;
private static int index;
public Event() {
}
public Event(Artist artist, Ticket ticket) {
artistName = artist.getArtistName();
artistSalary = artist.getArtistSalary();
trackList = artist.getArrayList();
for (index = 0; index < amountOfTicketCategories; index++) {
ticketList[index] = ticket.getTicket();
ticketList[index].toString();
}
}
public void chooseWhatToDefine() {
language = new Language();
language.whatToSpecify();
}
public void setTicketPrice(String ticketCategory, int ticketPrice) {
}
public void displayArtist(String artistName, int artistSalary) {
language = new Language();
language.displayArtistAndSalary(artistName, artistSalary);
}
public void displayTracklist(ArrayList<String> trackList) {
language = new Language();
language.displayTrackList(trackList);
}
public void displayTickets(Object[] ticketList) {
language = new Language();
language.displayTicket(ticketList);
}
public static void main(String[] args) {
Event event1 = new Event(new Artist(), new Ticket());
event1.displayArtist(artistName, artistSalary);
event1.displayTracklist(trackList);
event1.displayTickets(ticketList);
}
}
Ticket class with constructor that initalize the class with the user input comming from the InputReader class, and creates an object of Strings and Integers.
import java.util.Arrays;
public class Ticket {
private static String ticketCategory;
private static int ticketAmount;
private static int ticketPrice;
private InputReader inputReader;
private int amountOfTicketCategories;
private int index;
private Ticket[] ticketList;
public Ticket(String ticketCategory,int ticketAmount,int ticketPrice) {
}
public Ticket() {
inputReader = new InputReader();
inputReader.specifyTicketCategories();
ticketList = new Ticket[amountOfTicketCategories];
for (index = 0; index < amountOfTicketCategories; index++) {
inputReader.specifyTicket(ticketCategory, ticketAmount, ticketPrice);
ticketList[index] = new Ticket(ticketCategory, ticketAmount, ticketPrice);
}
}
public String toString() {
return("TicketCategory: " + ticketCategory + "Amount of Tickets: " + ticketAmount + "Ticket Price: " +ticketPrice);
}
public Object getTicket() {
return ticketList[index];
}
public int getAmountOfTicketCategories() {
amountOfTicketCategories = inputReader.specifyTicketCategories();
return amountOfTicketCategories;
}
}
InptReader class that processes the user input:
import java.util.ArrayList;
import java.util.Scanner;
public class InputReader {
private Scanner sc;
private Language language;
private ArrayList <String> tracks;
public InputReader() {
tracks = new ArrayList<String>();
language = new Language();
sc = new Scanner(System.in);
}
public int specifyTicketCategories() {
language.defineAmountOfTicketCategories();
return sc.nextInt();
}
public void specifyTicket(String ticketCategory, int ticketAmount, int ticketPrice) {
language.specifyTicketCategory();
ticketCategory = sc.next();
language.specifyTicketAmount();
ticketAmount = sc.nextInt();
language.specifyTicketPrice();
ticketPrice = sc.nextInt();
}
public int amountOfTickets() {
return sc.nextInt();
}
public int ticketPrice() {
return sc.nextInt();
}
public String readName() {
language.specifyArtist();
return sc.nextLine();
}
public int readInteger() {
language.specifyArtistSalary();
return sc.nextInt();
}
public void addTitle() {
int anzahlSongs = 3;
int index = 0;
while (index < anzahlSongs) {
language.specifyTrackList();
tracks.add(sc.nextLine());
index++;
}
}
public ArrayList<String> getArray() {
return tracks;
}
}
Language class that consists of the language statements
import java.util.ArrayList;
public class Language {
public Language () {
}
public void whatToSpecify() {
System.out.println("What would you like to specify fist? For Artist press 1, for Ticket press 2");
}
public void specifyArtist() {
System.out.println("Who is the artist? ");
}
public void specifyArtistSalary() {
System.out.println("How much does the artist earn? ");
}
public void displayTicket(Object[] ticketList) {
System.out.println("Ticketlist: " + ticketList);
}
public void displayArtistAndSalary(String artistName, int artistSalary) {
System.out.println("Artist: " + artistName + " " + "Salary: " + artistSalary);
}
public void displayTrackList(ArrayList<String> trackList) {
System.out.println("Tracklist: " + trackList);
}
public void specifyTicketCategory() {
System.out.println("What is the ticket category? ");
}
public void specifyTicketAmount() {
System.out.println("What ist the amount of tickets? ");
}
public void specifyTicketPrice() {
System.out.println("What is the price for your ticket?");
}
public void specifyTrackList() {
System.out.println("Add title: ");
}
public void defineAmountOfTicketCategories() {
System.out.println("How many ticket categories you like to set up?");
}
public void line() {
System.out.println("***********************************");
}
}
Artist class that that has creates an instance of an artist in the main class (same idea as for ticket) but with other variables and parameters.
import java.util.ArrayList;
public class Artist {
private int artistSalary;
private String artistName;
private InputReader inputReader;
ArrayList <String> trackList;
public Artist() {
inputReader = new InputReader();
artistName = inputReader.readName();
artistSalary = inputReader.readInteger();
inputReader.addTitle();
trackList = inputReader.getArray();
trackList.remove(2);
}
public String getArtistName() {
return artistName;
}
public int getArtistSalary() {
return artistSalary;
}
public ArrayList<String> getArrayList(){
return trackList;
}
}
Output in the console:
Add title:
Hello
Add title:
Hello
How many ticket categories you like to set up?
5
Artist: David Salary: 5000
Tracklist: [, Hello]
Ticketlist: null
First of all, in the Ticket class's constructor, you use the other constructor (The one with the 3 arguments), which has an empty body.
ticketList[index] = new Ticket(ticketCategory, ticketAmount, ticketPrice);
public Ticket(String ticketCategory,int ticketAmount,int ticketPrice) {
//this is empty
}
That means you're creating an object with.. nothing in it (null variables).
Try this:
public Ticket(String ticketCategory,int ticketAmount,int ticketPrice) {
this.ticketCategory = ticketCategory;
this.ticketAmount = ticketAmount;
this.ticketPrice = ticketPrice;
}
Then, your getTicket method is wrong. You never define the "index" integer in your Ticket class.
public Object getTicket() {
return ticketList[index];
}
Where "index" is undefined.
The ticketList should not be in the Ticket class => each time you create a Ticket instance, it will probably not be the same as the previous one.
We want to design a simple tournament that consist of teams with name and citizenship. In this tournament, a set of matches is organized between invited teams and each match opposes two teams. The team with the highest score wins the match. If the result of the match is draw each team gets 1 point, the winning team gets 2 points and no point for the loser. We would like to get the total of points of a team in a tournament to know the winner. The winner is the one with the highest points.
So we managed to create three classes: Team, Match and Tournament and the main class.
In the main class we have this
public class ProgramTournaments {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
//Defining each team
Team frTeam, inTeam, cnTeam;
//Creation of three objects (Teams)
frTeam = new Team("French Blue Team", "French"); // New Means I want to create an Object (frTeams)
inTeam = new Team("Indian Blue Team", "India");
cnTeam = new Team("Chinese Red Team", "China");
//Create a new Tournament
Tournament tournament = new Tournament();
//Invite teams to the tourname
tournament.inviteTeam(frTeam);
tournament.inviteTeam(inTeam);
tournament.inviteTeam(cnTeam);
//Add matches to Tournament
Match m1 = new Match(frTeam, inTeam, true);
Match m2 = new Match(frTeam, cnTeam, true);
Match m3 = new Match(inTeam, cnTeam, true);
tournament.addMatch(m1);
tournament.addMatch(m2);
tournament.addMatch(m3);
//Check If all matches Have been Pleayed
tournament.allMatchPlayed();
}
}
In the team class we did this
public class Team {
//Defining the attributes
private String name; //Private means it is limited only to this Class (team)
private String citizenship;
public String getName() {
return name;
}
public String getCitizenship() {
return citizenship;
}
// Constructor inorder to initialized values
public Team (String name, String citizenship){
this.name = name; //Initializing name of team
this.citizenship = citizenship; //Initializing name of Citizenship of team
}
//Printing to strings
#Override
public String toString() {
return "Team{" + "name=" + name + ", citizenship=" + citizenship + '}';
}
}
In the Match class we did this
public class Match {
private Team team1, team2;
private int scoreTeam1;
private int scoreTeam2;
private int pointTeam1, pointTeam2;
boolean play;
//Constructor
public Match(Team team1, Team team2, boolean play) {
this.team1 = team1;
this.team2 = team2;
this.scoreTeam1 = generateRandomScore();
this.scoreTeam2 = generateRandomScore();
this.play = play;
}
//All Methods
public int getScoreTeam1() {
return scoreTeam1;
}
public void setScoreTeam1(int scoreTeam1) {
this.scoreTeam1 = scoreTeam1;
}
public int getScoreTeam2() {
return scoreTeam2;
}
public void setScoreTeam2(int scoreTeam2) {
this.scoreTeam2 = scoreTeam2;
}
public Team getTeam1() {
return team1;
}
public void setTeam1(Team team1) {
this.team1 = team1;
}
public Team getTeam2() {
return team2;
}
public void setTeam2(Team team2) {
this.team2 = team2;
}
public boolean isPlay() {
return play;
}
public void setPlay(boolean play) {
this.play = play;
}
//Generate Random Score
private int generateRandomScore() {
Random random = new Random();
return random.nextInt(5);
}
public boolean draw() {
if (scoreTeam1 == scoreTeam2) {
pointTeam1 = 1;
pointTeam2 = 1;
return true;
}
return false;
}
public Team matchWinner() {
if (scoreTeam1 > scoreTeam2) {
pointTeam1 = 2;
pointTeam2 = 0;
return team1;
} else {
pointTeam2 = 2;
pointTeam1 = 0;
return team2;
}
}
}
In the Tournament Class we did this
public class Tournament {
private List<Team> ListOfTeams = new ArrayList<>();
private List<Match> ListOfMatches = new ArrayList<>();
//Methods
public void inviteTeam(Team team) { //Inviting Teams
ListOfTeams.add(team);
}
public void addMatch(Match m) {
ListOfMatches.add(m);
}
public boolean allMatchPlayed() {
for (Match match : ListOfMatches) {
if (match.isPlay() == false) {
return false;
}
}
return true;
}
public void tournamentWinner(){
for (Match match : ListOfMatches){
match.decideResult();
}
Comparator <Team> team = new Comparator<Team>(){
#override
public int compare(Team t1, Team t2){
return t1.getScore() - t2.getScore();
}
};
Collections.sort(ListOfTeams, t);
System.out.println("The winner of the tournament is: " + ListOfTeams);
}
}
So please, we are stuck at trying to implement the total points for each teams and to get the winner based on the total points
I would advice to move points member variable from Match to Team. The reason being that each team will have some points at any point of time, so it makes sense that each team has a points field.
Now you would make the following changes to the methods
Team.java
public class Team {
private int points;
// getters and setters for points
/* Rest of your class */
}
Match.java
We should combine your draw() and matchWinner() to one method say decideResult(), as own their own they make no sense.
public void decideResult() {
if (scoreTeam1 == scoreTeam2) {
team1.setPoints(team1.getPoints() + 1);
team2.setPoints(team2.getPoints() + 1);
} else if (scoreTeam1 > scoreTeam2) {
team1.setPoints(team1.getPoints() + 2);
} else {
team2.setPoints(team2.getPoints() + 2);
}
}
To find the winner you can just fetch the score from the respective Team object. For eg : frTeam.getPoints() and compare this with another countries .getPoints()
I am making a multiplayer adventure game for my networking class. I have a client and a server, the server is multithreaded, and kicks off a new thread whenever it gets a new client connected. I have an array list that keeps track of the players to make sure that a new player isn't added. For some reason, when a new client connects, it takes the place of the old one as well as filling a new spot. Here is my code for this part
public class ClientHandler implements Runnable{
private AsynchronousSocketChannel clientChannel;
private static String command[];
private static String name;
private static GameCharacter character;
public ClientHandler(AsynchronousSocketChannel clientChannel)
{
this.clientChannel = clientChannel;
}
public void run(){
try{
System.out.println("Client Handler started for " + this.clientChannel);
System.out.println("Messages from Client: ");
while ((clientChannel != null) && clientChannel.isOpen()) {
ByteBuffer buffer = ByteBuffer.allocate(32);
Future result = clientChannel.read(buffer);
//Wait until buffer is ready
result.get();
buffer.flip();
String message = new String(buffer.array()).trim();
if(message == null || message.equals(""))
{
break;
}
System.out.println(message);
clientChannel.write(buffer);
try {
//Add the character to the routing table and the character table
if (message.contains("connect")) {
System.out.println("I'm here too?");
command = message.split(" ");
name = command[1];
AdventureServer.userInfo.put(name, this);
//Check to see if this game character exists
GameCharacter test;
boolean exists = false;
for(int i=0; i < AdventureServer.characters.size(); i++)
{
test = AdventureServer.characters.get(i);
System.out.println(test.getName());
System.out.println(this.name);
if(this.name.equals(test.getName()))
{
System.out.println("already Here");
exists = true;
}
}
if (exists == true)
{
//This person has connected to the server before
}
else {
//Create a game character
System.out.println("didn't exist before");
character = new GameCharacter(this.name, World.getRow(), World.getCol());
AdventureServer.characters.add(AdventureServer.userInfo.size() - 1, character);
System.out.println(AdventureServer.characters.get(0).getName() + " " +AdventureServer.characters.get(1).getName());
}
}
I understand that the print lines at the bottom will throw an error for the first client that connects, but that is not part of the issue.
And here is the declaration of the server
public class AdventureServer {
public static Map<String, ClientHandler> userInfo = new HashMap<>();
public static World world;
public static List<GameCharacter> characters = Collections.synchronizedList(new ArrayList<>());
public static void main(String args[]) {
//Create the games map that all of the users will exist on
world = new World(args[0]);
System.out.println("Asynchronous Chat Server Started");
try {
AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open();
InetSocketAddress hostAddress = new InetSocketAddress("192.168.1.7", 5000);
serverChannel.bind(hostAddress);
while (true)
{
System.out.println("Waiting for client to connect");
Future acceptResult = serverChannel.accept();
AsynchronousSocketChannel clientChannel = (AsynchronousSocketChannel) acceptResult.get();
new Thread (new ClientHandler(clientChannel)).start();
}
} catch (Exception e) {
System.out.println("error interrupted");
e.printStackTrace();
System.exit(0);
}
}
}
Here is my constructor for game characters
public class GameCharacter {
public static int xpos;
public static int ypos;
private static String name;
private static int rowSize;
private static int columnSize;
static List<String> inventory = new ArrayList<>();
//Constructor
GameCharacter(String n, int rSize, int cSize)
{
xpos = 0;
ypos = 0;
name = n;
rowSize = rSize;
columnSize = cSize;
}
GameCharacter()
{
xpos = 0;
ypos = 0;
name = "billybob";
rowSize = 10;
columnSize = 10;
}
You can try:
public static volatile List<GameCharacter> characters = Collections.synchronizedList(new ArrayList<>());
Update:
The problem is that you are using a non synchronized HashMap userInfo.
Change that line from:
AdventureServer.characters.add(AdventureServer.userInfo.size() - 1, character);
To:
AdventureServer.characters.add(character);
Or make your HashMap Synchronized:
public static Map<String, ClientHandler> userInfo = Collections.synchronizedMap(new HashMap<>());
All those static declarations are making problems, you should remove them. In general you should avoid using static.
ClientHandler:
private static String command[];
private static String name;
private static GameCharacter character;
GameCharacter:
public static int xpos;
public static int ypos;
private static String name;
private static int rowSize;
private static int columnSize;
static List<String> inventory = new ArrayList<>();
Just a side note, this way your Class is more like Java code should look like:
import java.util.ArrayList;
import java.util.List;
public class GameCharacter {
private int xpos;
private int ypos;
private String name;
private int rowSize;
private int columnSize;
private List<String> inventory = new ArrayList<>();
// Constructor
GameCharacter(String n, int rSize, int cSize) {
this.xpos = 0;
this.ypos = 0;
this.name = n;
this.rowSize = rSize;
this.columnSize = cSize;
}
GameCharacter() {
this.xpos = 0;
this.ypos = 0;
this.name = "billybob";
this.rowSize = 10;
this.columnSize = 10;
}
public int getXpos() {
return xpos;
}
public void setXpos(int xpos) {
this.xpos = xpos;
}
public int getYpos() {
return ypos;
}
public void setYpos(int ypos) {
this.ypos = ypos;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getRowSize() {
return rowSize;
}
public void setRowSize(int rowSize) {
this.rowSize = rowSize;
}
public int getColumnSize() {
return columnSize;
}
public void setColumnSize(int columnSize) {
this.columnSize = columnSize;
}
public List<String> getInventory() {
return inventory;
}
public void setInventory(List<String> inventory) {
this.inventory = inventory;
}
}
As a matter of readability, testability, and style, I would also recommend you not directly access data structures belonging to another class. Instead of
Adventureserver.characters.add(blah blah)
I would recommend making characters a private field of Adventureserver, and then creating a method to add or remove characters from it. In fact, I would be inclined not to make characters static -- there is no real advantage, and you might at some point want more than one Adventureserver running.
Sort of like so:
public class AdventureServer {
<...>
private List<GameCharacter> characters = Collections.synchronizedList(new ArrayList<>);
<...>
public void addCharacter(GameCharacter char) {
<... error checking ...>
characters.add(char);
}
public void removeCharacter(GameCharacter char) {
<... implementation ... >
}
public boolean isCharacterHere(GameCharacter char) {
}
public List<GameCharacter> getCharacters() {
<... you could either return characters here, or a copy of it,
depending upon how paranoid you want to be >
I have made a new object called Game:
public class Game {
private String gamenaam;
private String bungeenaam;
private int poort;
private int minplayers;
private int maxplayers;
private static GameState gamestate = GameState.Ingame;
public Game(String naam) {
this.gamenaam = naam;
setAlles();
}
public String getGameNaam() {
return this.gamenaam;
}
public String getBungeeNaam() {
return bungeenaam;
}
public int getPoort() {
return poort;
}
public int getMinPlayers() {
return minplayers;
}
public int getMaxPlayers() {
return maxplayers;
}
public GameState getCurrentState() {
//System.out.print(gamenaam + ":" + MySQL.getGameState(getGameNaam()) + ":" + gamestate);
return gamestate;
}
public void setCurrecntState(GameState state) {
gamestate = state;
}
private void setAlles() {
bungeenaam = MySQL.getBungeeNaam(this.gamenaam);
poort = MySQL.getPoort(this.gamenaam);
minplayers = MySQL.getMinPlayer(this.gamenaam);
maxplayers = MySQL.getMaxPlayer(this.gamenaam);
//gamestate = MySQL.getGameState(this.gamenaam);
}
}
I store everything in an public static HashMap<Location, Game> gameSigns = new HashMap<Location, Game>(); map
Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(Bukkit.getPluginManager().getPlugin("SCGameHost"), new Runnable() {
#Override
public void run() {
for(Map.Entry<Location, Game> entry: Main.gameSigns.entrySet()){
Game game = entry.getValue();
if(game.getGameNaam().equalsIgnoreCase("Heks")) {
System.out.print(game.getGameNaam()+" is changed to FINISHED");
game.setCurrecntState(GameState.Finished);
}else {
game.setCurrecntState(GameState.Maintenance);
}
}
}
}, 10 *20L, 10 *20L);
I have 2 things in the gameSigns HashMap Heks and Snowball.
When I change Heks to GameState.Finished snowball is also being changed.
It is because the variable gamestate is static, so it is shared between all the instances of the Game class. Remove the word static if you want separate values for different instances.
I'm using Java 8, and I want to resolve my problem using List.stream() functionnalities.
Here's my problem :
This is the Score class (Player class does not matter) :
public class Score {
private Player player;
private int score;
public Player getPlayer() {
return player;
}
public void setPlayer(Player player) {
this.player = player;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
At the start of my program, I have a list of players populated :
List<Player> players; // Populated elsewhere
My program then does what it has to do, and I get a variable of this type :
List<List<Score>> scores; // Populated elsewhere
Now i want to print a formatted output such as this for each players :
Player.getName() + " : " + averagedScore;
where averagedScore is the sum of the score.getScore() value for one Player divided by the number of occurences of a Score for this Player in my scores variables.
Now, what I've done so far :
for (Players player : players) {
scores.stream().filter(x -> x.stream().anyMatch(y -> y.getPlayer().equals(player)));
}
But I don't see how to calculate the sum of element.getScore() contained in sublists and filtered by element.getPlayer()
You could use a combination of the groupingBy and averagingInt collectors after having "flatMapped" your list of lists:
Map<Player, Double> scoreByPlayer = scores.stream()
.flatMap(List::stream)
.collect(groupingBy(Score::getPlayer, averagingInt(Score::getScore)));
scoreByPlayer.forEach((p, s) -> System.out.println(p + " : " + s));
Note: requires the following static imports:
import static java.util.stream.Collectors.averagingInt;
import static java.util.stream.Collectors.groupingBy;
For reference, full example:
public static void main(String[] args) {
Player adam = new Player("Adam");
Player pat = new Player("Pat");
Player susie = new Player("Susie");
List<List<Score>> scores = new ArrayList<> ();
scores.add(Arrays.asList(s(adam, 1), s(pat, 2), s(susie, 3)));
scores.add(Arrays.asList(s(adam, 2), s(pat, 4), s(susie, 6)));
scores.add(Arrays.asList(s(adam, 3), s(pat, 6), s(susie, 9)));
Map<Player, Double> scoreByPlayer = scores.stream()
.flatMap(List::stream)
.collect(groupingBy(Score::getPlayer, averagingInt(Score::getScore)));
scoreByPlayer.forEach((p, s) -> System.out.println(p + " : " + s));
}
private static Score s(Player p, int score) { return new Score(p, score); }
public static class Score {
private final Player player;
private final int score;
public Score(Player player, int score) {
this.player = player;
this.score = score;
}
public Player getPlayer() { return player; }
public int getScore() { return score; }
}
public static class Player {
private final String name;
public Player(String name) { this.name = name; }
#Override public String toString() { return name; }
}