Reputation: 5
Im new to programming and I was making a text based game; more specifically, the player creation. It will ask you to declare the persons name, gender, and type(teen, young adult, adult, or elder) and it will give the person's age based on the players type, e.g. teen could be 13-17 years old. To do this, I asked the user what the type was and that would be the value for setPlayerType. Then, setAge is suppose to use the information from setPersonType to decide what the age should be using an if statement. To test the program to see if the player creation system works I am having it print out the name, how old the player is, and its gender. However, it always prints that the age is 0, and I have been trying to fix it for almost an hour. Sorry if I'm not using the correct naming conventions, I am still trying to get the hang of setters and getters. I hope I explained this well enough for you guys to understand what I am trying to do. Thank you so much in advance!
This is my tester class:
import javax.swing.JOptionPane;
public class PopulationGameTestDrive {
static Person one = new Person();
public static void main(String[] args){
one.setName(JOptionPane.showInputDialog("Name your player"));
one.setGender(JOptionPane.showInputDialog("What is their gender?"));
one.setPersonType(JOptionPane.showInputDialog("Are they a teen, young adult, adult, or elder?"));
String testName = one.getName();
String testGender = one.getGender();
int testAge = one.getAge();
System.out.println(testName + " is " + testAge + " and is a " + testGender);
}
}
And this is the Player class:
import java.util.Random;
public class Person {
private String name; //they choose a name
private String gender; //male or female
private String personsType; //teen, young adult, adult, or elder
int numOfKids = 0;
private int age;
public String getName(){
return name;
}
public void setName(String personsName){
name = personsName;
}
public String getPersonType(){
return personsType;
}
/*
* setPersonType gives age a value based on whether
* the player chose teen, young adult, adult, or elder
*/
public void setPersonType(String personType){
personsType = personType;
}
public String getGender(){
return gender;
}
public void setGender(String personsGender){
gender = personsGender;
}
public int getAge(){
return age;
}
public void setAge(int personsAge){
if(personsType.equals("teen")){
Random num = new Random();
int number = num.nextInt(20);
if(number > 12 & number < 18){
age = number;
} else if(personsType.equals("young adult")){
Random num2 = new Random();
int number2 = num2.nextInt(30);
if(number2 > 17 & number2 < 31){
age = number2;
} else if(personsType.equals("adult")){
Random num3 = new Random();
int number3 = num3.nextInt(50);
if(number3 > 30 & number3 < 50){
age = number3;
}else if(personsType.equals("elder")){
Random num4 = new Random();
int number4 = num4.nextInt(100);
if(number4 > 49 & number4 < 101){
age = number4;
}
}
}
}
}
age = personsAge;
}
}
Upvotes: 0
Views: 1403
Reputation: 334
Mshnik is correct that your test class never actually calls setAge(int), and makes good points about Strings being error-prone to represent data with a finite set of acceptable values. However, even if you call setAge() in the test class and even convert personType to enum, you have some other correctness and robustness issues in your setters. Since you mentioned still trying to get the hang of them, I would like to take the opportunity to mention what jumped out to me before different unexpected behavior pops up.
When you have setters which take objects as arguments you must always ensure that they handle the argument null in an acceptable way.
As your code stands, if the user closes any of the input dialogs, NullPointerException will be thrown when equals() is called, and the stack trace will be unneccessarily complicated to debug as you develop your game. You should decide if each field can ever rationally be set to null, and if not have the setter throw an IllegalArgumentException and handle it appropriately in the code calling your setter.
Secondly, consider if the user enters "TEEN" as the age bracket. Your code won't set age to a random value in the teen range as expected, it will set age to the value passed to setAge(), which I'm assuming is a default and might not rationally relate to their Type. Using equalsIgnoreCase() is better practice when comparing user-entered strings to stored values.
Third, will setAge() ever be called after age is initialized as time passes in the population game, and is that the purpose of the int argument? If so, you will still get unexpected results such as a teen player being 15, calling setAge(16), and the variable actually being set to 14.
My understanding of how to avoid this problem goes down one of two paths. You could change the implementation of setAge(int) to only use random values when age was previously uninitialized, and otherwise set age to its argument. The logic calling setAge would also need to ensure that type is updated when a teen turns twenty, for example.
This requires the setter to perform at least two separate jobs, and therefore my undemanding is that while you're modifying your test it would be valuable to overload setAge in Person. I'd use one with an integer argument that checks for a sane argument value then sets the variable, and one with an AgeBracket enum argument that uses your existing implementation to set the variable to a random int value within the bracket.
Upvotes: 1
Reputation: 7032
I'm not sure your main method actually calls setAge(..) at any point. So the reason getAge() is returning 0 is because 0 is the default value for ints. (Which you never change)
Even if setAge(..) were called, the logic probably doesn't do exactly what you think it does. You have a very detailed if block that assigns varying values to age, depending on the person's type. After that though, whether or not the if block is executed, age is set to personsAge, making the entire if block useless. Perhaps that final statement was supposed to be in an else branch?
The logic of your setAge() function isn't quite right: the else-if branch of personsType.equals("young adult")
is paired with if(number > 12 & number < 18)
, not if(personsType.equals("teen"))
. So I'm fairly confident that the first else-if branch will never be executed, because it is contained within if(personsType.equals("teen"))
, and without personType changing this will always be false within the if branch. Consider this revision of your setAge() function, which I believe achieves a closer logic to what you were hoping:
Based on your comments, don't use the set convention, because you're setting to a random value, not a given value. Also, for debugging purposes, try this code, which has some print statements.
public void setRandomAge(){
System.out.println(personsType); //The type of this person, for debugging purposes to
//make sure it's valid at this point
if(personsType.equals("teen")){
age = (int)(Math.random() * 4) + 13); //random number between [13,17], inclusive
}
else if(personsType.equals("young adult")){
age = (int)(Math.random() * 12) + 18; //random number between [18,30], inclusive
}
else if(personsType.equals("adult")){
age = (int)(Math.random() * 18) + 31; //random number between [31, 49], inclusive
}
else if(personsType.equals("elder")){
age = (int)(Math.random() * 50) + 50; //random number between [50, 100], inclusive
}
else{
age = 0; //Probably should have some default case for
//if the personsType is some other string
}
}
I also agree with Sparrow - adding a call to this method to the setPersonType method is a good idea:
public void setPersonType(String personType){
personsType = personType;
setRandomAge();
}
Finally, Since you're new, its a good point to note that you should look into making an Enum for personType using strings for your personType is clunky and error-prone.
Upvotes: 0
Reputation: 10423
If I use the topic of this question, then the answer would be something like:
class Person {
int age;
String personType;
void setAge(int age) {
this.age = age;
}
void calculateRandomAge() {
Random rand = new Random();
if(personsType.equals("teen")){
int number = rand.nextInt(6);
setAge(number+12);
} else if(personsType.equals("young adult")){
int number = rand.nextInt(14);
this.setAge(number+17);
} ...
(you did not describe what the method should actually do, so I just show how you call a setter in "yourself". You typically not use this.
, but I used it once for illustration.
Upvotes: 0
Reputation: 8652
You do not need to pass any argument in setAge(...) It should be like that :
public void setAge(){
if(personsType.equals("teen")){
Random num = new Random();
int number = num.nextInt(20);
if(number > 12 & number < 18){
age = number;
} else if(personsType.equals("young adult")){
Random num2 = new Random();
int number2 = num2.nextInt(30);
if(number2 > 17 & number2 < 31){
age = number2;
} else if(personsType.equals("adult")){
Random num3 = new Random();
int number3 = num3.nextInt(50);
if(number3 > 30 & number3 < 50){
age = number3;
}else if(personsType.equals("elder")){
Random num4 = new Random();
int number4 = num4.nextInt(100);
if(number4 > 49 & number4 < 101){
age = number4;
}
}
}
}
}
}
And this method should be called either in main or at the end of setPersonType(...):
public void setPersonType(String personType){
personsType = personType;
setAge();
}
Upvotes: 0
Reputation: 127
You are not trying to set the age in your tester class.
Get the age as it will be string and then convert it into int.
find the snippet
String ageString = JOptionPane.showInputDialog("What is your Age?")
try {
int age = Integer.parseInt(ageString);
one.setAge(age);
} catch (NumberFormatException e) {
// Not a number, display error message if entered string is not a valid age...
}
Upvotes: 0