I am a java beginner and I am designing a Nim game for many players to join. I've done some research but I don't know if my implementation is correct. The aim is to check the duplicate object in an array. I've already checked some articles, and I'll reference them in the last part of this article.
For the NimPlayer class. I've created some things.
I've defined the NimPlayer object type.
Using the type, I can initialize the player in the limited space.
I initialize an array for saving player's data by following the steps here: Storing object into an array - Java
public class NimPlayer {
String userName;
String familyName;
String givenName;
NimPlayer [] playerList = new NimPlayer[10]; //set an array here
int id;
//define NimPlayer data type
public NimPlayer(String userName,String surName, String givenName) {
this.userName = userName;
this.familyName = surName;
this.givenName = givenName;
}
//create new data using NimPlayer data type
public void createPlayer(String userName, String familyName, String givenName) {
playerList[id++] = new NimPlayer(userName, familyName, givenName);
}
In the main method, I have created some features for players to use:
addplayer - let the user can add players in the game to compete.
To add the player, the Syntax like this:
$addplayer userName,familyName,givenName
to validate the input, I split the input and store them in the new object.
public static String[] splitName(String inputName) {
String [] splittedLine = inputName.split(",");
String userName = splittedLine[0].trim();
String familyName = splittedLine[1].trim();
String givenName = splittedLine[2].trim();
String [] name = new String[3];
name[0] = userName;
name[1] = familyName;
name[2] = givenName;
return name;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
//create new object to save data
NimPlayer playerData = new NimPlayer(null, null, null);
System.out.print('$');
String commandInput = in.next();
while (true) {
if (commandInput.equals("addplayer")) {
String inputName = in.nextLine();
String[] name = splitName(inputName);
String userName = name[0];
String familyName = name [1];
String givenName = name[2];
playerData.createPlayer(userName, familyName, givenName);
for (int i = 0; i < playerData.playerList.length; i++) {
NimPlayer player = playerData.playerList[i];
System.out.println(player.getUserName()); }
}
So far, I have two questions here.
Every time I enter a set of data, it seems my "playerData" provokes the NullPointerException when looping through the object, but since my name input is multiple, I have to create a new object in the main method for saving input.
For checking if there is the duplicate "userName" in the set of the "inputName", I loop through the objects in an array. How can I access the "userName" in this situation?
for checking duplicate, I've checked:
Java - Loop through instances of a class rather than calling a method for each separate instance
What is a NullPointerException, and how do I fix it?
Java Array, Finding Duplicates
You should address then following things in your design/code:
Since you are creating a player using createPlayer(String userName, String familyName, String givenName), you should make the constructor, NimPlayer(String userName,String surName, String givenName) private so that it can not be called from outside of the class, NimPlayer. Also, declare createPlayer as static so that it doesn't need a NimPlayer object to be called on.
You need to have a static counter to keep track of the number of players and check the value of this counter before adding a new player to playerList.
You should also check the size of the resulting array after inputName.split(","). Similarly, you should check the size of the returned array from splitName before you access any element from it.
Given below is the code incorporating the points mentioned above:
import java.util.Scanner;
class NimPlayer {
private String userName;
private String familyName;
private String givenName;
//...
// public getters and setters of userName, familyName, and givenName
//...
private static int counter = 0;
private static NimPlayer[] playerList = new NimPlayer[10];
private NimPlayer(String userName, String familyName, String givenName) {
this.userName = userName;
this.familyName = familyName;
this.givenName = givenName;
}
public static void createPlayer(String userName, String familyName, String givenName) {
if (counter < 10) {
playerList[counter++] = new NimPlayer(userName, familyName, givenName);
} else {
System.out.println("The list is full.");
}
}
public static int getCounter() {
return counter;
}
public static NimPlayer[] getPlayers() {
return playerList;
}
}
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (true) {
System.out.print('$');
String commandInput = in.next();
if (commandInput.equals("addplayer")) {
String inputName = in.nextLine();
String[] name = splitName(inputName);
if (name != null && name.length == 3) {
NimPlayer.createPlayer(name[0], name[1], name[2]);
}
} else {
break;
}
}
for (int i = 0; i < NimPlayer.getCounter(); i++) {
System.out.println(NimPlayer.getPlayers()[i].getUserName());
}
}
public static String[] splitName(String inputName) {
String[] splittedLine = inputName.split(",");
String[] name = null;
if (splittedLine.length == 3) {
String userName = splittedLine[0].trim();
String familyName = splittedLine[1].trim();
String givenName = splittedLine[2].trim();
name = new String[3];
name[0] = userName;
name[1] = familyName;
name[2] = givenName;
}
return name;
}
}
I didn't understand your another question:
For checking if there is the duplicate "userName" in the set of the
"inputName", I loop through the objects in an array. How can I access
the "userName" in this situation?
Related
I am a beginner, and I am building a classical NimGame. Before, I used to save the project using an array. Now, I modify it to apply the ArrayList to this time. It seems no problem, though, the functions I've made are not working without any errors. I couldn't figure out why.
For now, I tried to add the NimPlayer type into the new playerList, which is the ArrayList. I put the ArrayList in the NimModel, and use the constructor from the NimPlayer to create new players. The Nimsys is the main panel to give commands and receive user inputs. That's why I separate them into three classes.
The command is like this
$addplayer userName,familyName,givenName. And the scanner should process the string and go through the constructor to be a new object.
Any help is highly appreciated, and thank you for your kindness and patience.
Here is my related code Nimsys:
public class Nimsys {
private NimModel nimModel;
public static void main(String[] args) {
Nimsys nimsys = new Nimsys();
nimsys.processCommands();
}
private void processCommands() {
this.nimModel = new NimModel();
Scanner in = new Scanner(System.in);
System.out.println("Welcome to Nim\n");
while (true) {
System.out.print('$');
String commandin = in.nextLine().trim();
if (commandin.equalsIgnoreCase("addplayer")) {
addplayer(in);
}
if (commandin.equalsIgnoreCase("removeplayer")) {
removeplayer(in);
}
}
private String[] splitName(String inName) {
String[] splittedLine = inName.split(",");
String[] name = null;
if (splittedLine.length == 3) {
String userName = splittedLine[0].trim();
String familyName = splittedLine[1].trim();
String givenName = splittedLine[2].trim();
name = new String[3];
name[0] = userName;
name[1] = familyName;
name[2] = givenName;
}
return name;
}
private void addplayer(Scanner in) {
String inName = in.nextLine().trim();
String[] name = splitName(inName);
if (name != null && name.length == 3) {
ArrayList<NimPlayer> playerList = nimModel.getPlayerList();
for (NimPlayer player: playerList) {
if (player.getUserName().contains(name[0])) {
System.out.println("The player already exists.");
return;
} else {
nimModel.createPlayer(name[0], name[1], name[2]);
System.out.println("The player has been created.");
}
}
}
private void removeplayer(Scanner in) {
String removeUserName = in.nextLine().trim();
NimPlayer player = nimModel.removePlayer(removeUserName);
if (player == null) {
System.out.println("The player does not exist");
} else {
System.out.println("Player " + player.getUserName() +
" removed successfully!");
}
}
And the NimModel:
public class NimModel {
private NimPlayer nimplayer;
private ArrayList<NimPlayer> playerList = new ArrayList<>();
public void createPlayer(String userName, String familyName, String givenName) {
NimPlayer player = new NimPlayer(userName, familyName, givenName);
playerList.add(player);
}
public ArrayList<NimPlayer> getPlayerList() {
return playerList;
}
public NimPlayer removePlayer(String userName) {
for (NimPlayer player: playerList) {
String nameCheck = nimplayer.getUserName();
String playerName = player.getUserName();
if (playerName.equals(nameCheck)) {
playerList.remove(player);
break;
}
}
return null;
Lastly, NimPlayer class
public class NimPlayer {
private final String userName;
private String familyName;
private String givenName;
private int gamesPlayed;
private int gamesWon;
private int winRatio;
public NimPlayer(String userName, String familyName, String givenName) {
this.userName = userName;
this.familyName = familyName;
this.givenName = givenName;
this.gamesPlayed = 0;
this.gamesWon = 0;
}
//getters and setters
}
When you use scanner.nextLine() you are asking for a new input to the user. So if you want the format: $addplayer user,firstName,lastName you have to fetch it into a string and use this string:
while (true) {
System.out.print('$');
String commandin = in.nextLine().trim();
if (commandin.split(" ")[0].equalsIgnoreCase("addplayer")) {
addplayer(commandin);
}
}
}
private void addplayer(String commandin) {
String inName = commandin.split(" ")[1];
String[] name = splitName(inName);
....
in a nutschell:
private void addplayer(Scanner in) {
String inName = in.nextLine().trim();
String[] name = splitName(inName);
if (name != null && name.length == 3) {
ArrayList<NimPlayer> playerList = nimModel.getPlayerList();
for (NimPlayer player: playerList) {
if (player.getUserName().contains(name[0])) {
System.out.println("The player already exists.");
return;
}
}
nimModel.createPlayer(name[0], name[1], name[2]);
System.out.println("The player has been created.");
}
Furthermore, your addPlayer() given in Nimsys is defined in your While(true) but I think it's more a typing error.
Personally I would also give a constructor to your model:
import java.util.ArrayList;
public class NimModel {
private NimPlayer nimplayer;
private ArrayList<NimPlayer> playerList;
public NimModel()
{
this.playerList = new ArrayList<NimPlayer>();
}
public void createPlayer(String userName, String familyName, String givenName) {
NimPlayer player = new NimPlayer(userName, familyName, givenName);
playerList.add(player);
}
public ArrayList<NimPlayer> getPlayerList() {
return playerList;
}
public NimPlayer removePlayer(String userName) {
for (NimPlayer player : playerList) {
String nameCheck = nimplayer.getUserName();
String playerName = player.getUserName();
if (playerName.equals(nameCheck)) {
playerList.remove(player);
break;
}
}
return null;
}
}
I've been building a classical Nim game with three java classes. So far, I build almost everything and the last thing I need to do is to rank the player in descending order by winning ratio, which is the score divided by the gamePlayed. What I've tried was to implement the comparables in NimPlayer class. Here is my code:
public class NimPlayer implements Comparable<NimPlayer>{ //initialize comparable
private String userName;
private String familyName;
private String givenName;
static int counter;
private int score;
private int gamePlayed;
private int winRatio = score / (gamePlayed+1); //avoid 0/0, mathmatically wrong
static NimPlayer[] playerList = new NimPlayer[10]; // set an array here
//define NimPlayer data type
public NimPlayer(String userName, String surName, String givenName) {
this.userName = userName;
this.familyName = surName;
this.givenName = givenName;
}
// create new data using NimPlayer data type
public static void createPlayer(String userName, String familyName, String givenName) {
if (counter<10) {
playerList[counter++] = new NimPlayer(userName, familyName, givenName);
} else {
System.out.println("Cannot add more players.");
}
}
public static int getCounter() {
return counter;
}
public static NimPlayer [] getPlayer() {
return playerList;
}
// the getter and the setter of userName, familyName, givenName, score, gamePlayed
#Override
public String toString() {
return winRatio+"% | "+gamePlayed+" games | "+givenName+" "+familyName;
}
#Override
public int compareTo(NimPlayer o) {
return this.winRatio - o.winRatio;
}
}
In the main method, which called Nimsys, I've tried:
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (true) {
System.out.print('$');
String commandin = in.next();
if (commandin.equals("rankings")) {
Arrays.sort(NimPlayer.getPlayer());//sorting with the object type
System.out.println(Arrays.toString(NimPlayer.getPlayer()));
}
}
However, when I have two players in play and their score and gamePlayedare not null, the execution still goes to NullPointerException. Any help is highly appreciated.
The error you are getting is because you are initializating the array with a size of 10. The sort operation will traverse all 10 positions, and some of them will be null. If you create 10 players, then it should work without any problem.
To have a dynamic size, use an ArrayList instead, updating the following:
static List<NimPlayer> playerList = new ArrayList<>();
public static void createPlayer(String userName, String familyName, String givenName) {
if (counter < 10) {
playerList.add(new NimPlayer(userName, familyName, givenName));
counter++;
} else {
System.out.println("Cannot add more players.");
}
}
For sorting the List:
Collections.sort(NimPlayer.playerList);
Besides this, I think you have some flaws in your code.
First, you are initializing the winRatio in the field declaration and, at least from what I can see in your code, is not getting updated never, so it will be always 0. A way to overcome this is to use the getters and setters to trigger the calculation each time you ask for the value.
public Float getWinRatio() {
return Float.valueOf(getScore()) / (getGamePlayed() + 1);
}
Second, you set the winRatio as an int. This will ignore all the decimals in the divisions, so the results won't be accurate.
Also, you seem to be combining the data of players with the logic of the game. You should split the NimPlayer class from the logic containing all the players in the game.
I am creating a simple program which reads data from a text file and displays it in the console. The data that I am displaying is information regarding a student - name, id, subject, marks etc
The program reads the text file, and creates a student object for each user found. I am running into a problem when trying to store these students in a linked list. It seems to create a new list each time and overrides the previous one, so I always just end up with one student in the list.
How can I get it store them without overriding previous lists? Here is some of my code below:
public static boolean readFile(String filename) {
File file = new File(filename);
try {
Scanner scanner = new Scanner(file);
while(scanner.hasNextLine()){
String[] words = scanner.nextLine().split(",");
int id = Integer.parseInt(words[0]);
String firstName = words[1];
String lastName = words[2];
int mathMark1 = Integer.parseInt(words[3]);
int mathMark2 = Integer.parseInt(words[4]);
int mathMark3 = Integer.parseInt(words[5]);
int englishMark1 = Integer.parseInt(words[6]);
int englishMark2 = Integer.parseInt(words[7]);
int englishMark3 = Integer.parseInt(words[8]);
addStudent(id,firstName,lastName,mathMark1,mathMark2,mathMark3,englishMark1,englishMark2,englishMark3);
}
scanner.close();
} catch (FileNotFoundException e) {
System.out.println("Failed to read file");
}
return true;
}
private static void addStudent(int id, String firstName, String lastName,int
mathsMark1, int mathsMark2, int mathsMark3, int englishMark1, int englishMark2,
int englishMark3) {
LinkedList<Student> student = new LinkedList<>();
student.add(new Student(id,firstName,lastName));
LinkedList<AssignmentMarks> mathematicsMarks = new LinkedList<>();
mathematicsMarks.add(new AssignmentMarks("Mathematics",mathsMark1,mathsMark2,mathsMark3));
LinkedList<AssignmentMarks> englishMarks = new LinkedList<>();
englishMarks.add(new AssignmentMarks("English",englishMark1,englishMark2,englishMark3));
}
This code above is in my Main class. The code below is from my Student class:
public class Student {
private int id;
private String firstName;
private String lastName;
private AssignmentMarks mathMarks;
private AssignmentMarks englishMarks;
public Student(int id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public String getFullName() {
return firstName;
}
}
Any help would be appreciated thanks guys!
This variable
LinkedList<Student> student = new LinkedList<>();
needs to declared outside of the method, as a field, or within readFile and passed in as a parameter, otherwise it will be created everytime that you call addStudent
Declare your LinkedList as a member of the class, because here every time you call addStudent() you are creating a new list.
You should instead do something like :
public class Test {
private LinkedList<Student> student = new LinkedList<>();
public static boolean readFile(String filename) {
// ...
addStudent(id,firstName,lastName,mathMark1,mathMark2,mathMark3,
englishMark1,englishMark2,englishMark3);
}
private static void addStudent(int id, String firstName, String lastName,int
mathsMark1, int mathsMark2, int mathsMark3, int englishMark1, int englishMark2,
int englishMark3) {
// ...
// this will now add it to the only instance of the list
student.add(new Student(id,firstName,lastName));
}
}
I have managed to put all objects into arraylist but I am not able to print all values. Only the last one is getting printed, regardless of method used.
It is not getting printed through ArrayList only, which makes me wonder if the objects pushed are the same.
If it is, how do I change that? I have attached the program (run FileInput.java):
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.StringTokenizer;
import javax.swing.text.html.HTMLDocument.Iterator;
//lecture notes(L1) method
public class FileInput {
static String first;
static String second;
static String third;
static String fourth;
static String fifth;
static String sixth;
static int num = 1;
public static void main(String[] args)throws FileNotFoundException, IOException{
Scanner input = new Scanner(new File("player.txt"));
String data = null;
PrintWriter output = new PrintWriter("outfile.txt");
// Player1 user = new Player1();
ArrayList<Player1>listOfPlayers = new ArrayList<>();
Player1 user = new Player1();
// Tokenizing
System.out.println("CSCI213 Players Management System");
while(input.hasNextLine()){
System.out.println("\nPlayer " + num);
data = input.nextLine();
StringTokenizer token = new StringTokenizer(data,"|");
// int t = token.countTokens();
// System.out.println("t is:" + t);
first = token.nextToken().trim();
user.setLoginname(first);
second = new String(token.nextToken("|"));
user.setPassword(second);
third = new String(token.nextToken("|"));
user.setChips(third);
fourth = new String(token.nextToken("|"));
user.setUsername(fourth);
fifth = new String(token.nextToken("|"));
user.setEmail(fifth);
sixth = new String(token.nextToken("|"));
user.setBirthdate(sixth);
// user.display();
listOfPlayers.add(user);
System.out.println("Size is: " + listOfPlayers.size());
// System.out.println(user.loginname);
// System.out.println(listOfPlayers.get(num-1).loginname);
num++;
// output.write(data);
// output.write("\r\n");
}
int x = listOfPlayers.size();
System.out.println("Size is: " + x);
System.out.println(listOfPlayers);
// Display address of required
Player1 p = new Player1();
for(int i = 0; i < x; i++){
p = listOfPlayers.get(i);
System.out.println(p.loginname);
}
for(Player1 e:listOfPlayers){
System.out.println(e.loginname);
System.out.println(e.email);
}
while(input.hasNextLine()){
data = input.nextLine();
output.write(data);
output.write("\r\n");
}
input.close();
output.close();
}
}
// Store all player information
public class Player1 {
static String loginname;
static String password;
static String chips;
static String username;
static String email;
static String birthdate;
/*
public Player1(String loginname, String password,
String username, String email, String birthdate){
this.loginname = loginname;
this.password = password;
this.username = username;
this.email = email;
this.birthdate = birthdate;
}
*/
public Player1() {
// TODO Auto-generated constructor stub
}
public static String getLoginname() {
System.out.print("loginname: ");
return loginname;
}
public static void setLoginname(String loginname) {
Player1.loginname = loginname;
}
public static String getPassword() {
System.out.print("password: ");
return password;
}
public static void setPassword(String password) {
Player1.password = password;
}
public static String getUsername() {
System.out.print("username: ");
return username;
}
public static void setUsername(String username) {
Player1.username = username;
}
public static String getEmail() {
System.out.print("email: ");
return email;
}
public static void setEmail(String email) {
Player1.email = email;
}
public static String getBirthdate() {
System.out.print("birthdate: ");
return birthdate;
}
public static void setBirthdate(String birthdate) {
Player1.birthdate = birthdate;
}
public static String getChips() {
System.out.print("chips: ");
return chips;
}
public static void setChips(String chips) {
Player1.chips = chips;
}
public void display() {
System.out.println("Name: " + this.username);
System.out.println("Email: " + this.email);
System.out.println("Birthdate: " + this.birthdate);
System.out.println("Login ID: " + this.loginname);
System.out.println("Balance Chips: " + this.chips);
}
/*
#Override
public String toString() {
return "toString()=" + this.loginname + "\n";
}
*/
}
Simple:
Player1 user = new Player1();
You are adding the same object again and again. Put that statement into your loop instead. You want to add a completely new Playwer object during each loop iteration!
But even then, things wouldn't work out; because (as Eran figured): your Player class has only static fields. That is like "cheating"; because it means that all Player objects would see the same fields, too (because static fields are shared between all instances of a class!)
In other words: static is an abnormality in good OO design. You don't use it as default; to the contrary: you only make fields static in special corner cases (see here for some examples).
You have two errors :
You are adding the same Player1 instance to the list over and over again. You should move Player1 user = new Player1(); into the loop that adds the players.
Change
Player1 user = new Player1();
// Tokenizing
System.out.println("CSCI213 Players Management System");
while (input.hasNextLine()) {
to
// Tokenizing
System.out.println("CSCI213 Players Management System");
while (input.hasNextLine()) {
Player1 user = new Player1();
The members of the Player1 class are all static, so even if you fix the first issue, all instances of Player1 will share these members. You should change them to non static.
Change
public class Player1 {
static String loginname;
static String password;
static String chips;
static String username;
static String email;
static String birthdate;
to
public class Player1 {
String loginname;
String password;
String chips;
String username;
String email;
String birthdate;
Basically I have a class that has methods which use String arrays and i'm writing a method in the application class to read a file and update an array of object of class Customer. I get errors like:
Line 83: set_address(java.lang.String[]) in Customer cannot be applied to (java.lang.String)
at the line review[i].set_address(st[1]). I understand that it is looking for a string[] and it is receiving a string but is there any way to fix this? Here's the code I'm working with.
import java.io.*;
import java.util.*;
class Customer {
int account_id;
char[] ch1 = new char[20];
String name = new String (ch1);
char[] ch2 = new char[80];
String address = new String (ch2);
char[] ch3 = new char[10];
String phone_number = new String (ch3);
char[] ch4 = new char[8];
String date_of_birth = new String (ch4);
double account_balance;
public int get_accountid(){
return account_id;
}
public String get_address(){
return address;
}
public String get_phone_number(){
return phone_number;
}
public String get_date_of_birth(){
return date_of_birth;
}
public double get_balance(){
return account_balance;
}
public void set_account_id(int num){
account_id = num;
}
public void set_address(String add){
address = add;
}
public void set_phone_number(String phone){
phone_number = phone;
}
public void set_date_of_birth(String dob){
date_of_birth = dob;
}
public void set_balance(double bal){
account_balance = bal;
}
Customer(){ // default constructor
}
// parametrized constructor
Customer(int id, String name, String add, String dob, String num, double bal){
this.account_id = id;
this.name = name;
this.address = add;
this.date_of_birth = dob;
this.phone_number = num;
this.account_balance = bal;
}
}
public class lab2{
public static void main(String args[]){
System.out.println("testing this shit");
}
public static void readFile(String filename){
Customer[] review = new Customer[30];
int i=0;
Scanner scan = new Scanner (new File (filename));
while (scan.hasNext()){
while(i<30){
review[i].set_account_id(scan.nextInt());
String[] st = scan.nextLine().split("=");
review[i].set_address(st[1]);
st = scan.nextLine().spilt("=");
review[i].set_phone_number(st[1]);
st = scan.nextLine().split("=");
review[i].set_date_of_birth(st[1]);
//st = scan.nextLine().split("=");
review[i].set_balance(scan.nextDouble());
scan.nextLine();
i=i+1;
}
}
}
}
Your class Customer looks like a Java bean. I find these declaration suspicious:
String[] name = new String [20];
String[] address = new String [80];
String[] phone_number = new String [10];
String[] date_of_birth = new String [8];
Why do you want a Customer to have 20 names, 80 addresses, 10 phone numbers, and 8 date of birth? I suspect that your intention is saying that a Customer name is at most 20 characters long, his/her address is at most 80 characters long, etc. If this is the case, than you don't want a String[], you may want a char[]!
However, think about making those fields simply String: it seems more natural. I don't see reason why you may want to limit their size.
Just change your method signature:
public void set_address(String add){
address = add;
}
Or other choice: You create a new String[] object based on your String object an pass this: