I have been reading a java book where I came across a piece of code where a fake input is provided in order to test the main class. The fake input is a String and later converted into int primitive type using the Integer.parseInt() method. Following are the two classes:
The main class
public class SimpleDotCom{
int[] locationCells;
int numOfHits = 0;
public void setLocationCells(int[] locs){
locationCells = locs;
}
public String checkYourself(String stringGuess){
int guess = Integer.parseInt(stringGuess);
String result = "miss";
for(int cell : locationCells){
if(guess == cell){
result = "hit";
numOfHits++;
break;
}
}
if(numOfHits == locationCells.length){
result = "kill";
}
System.out.println(result);
return result;
}
}
The test class
public class SimpleDotComTestDrive{
public static void main(String[] args){
SimpleDotCom dot = new SimpleDotCom();
int[] locations = {2,3,4};
dot.setLocationCells(locations);
String userGuess = "4";
String result = dot.checkYourself(userGuess);
}
}
I tried the same example with an int variable and it worked:
public class DotCom{
int[] locationCells;
int numOfHits = 0;
public void setLocationCells(int[] locs){
locationCells = locs;
}
public String checkYourself(int stringGuess){
//int guess = Integer.parseInt(stringGuess);
int guess = stringGuess;
String result = "miss";
for(int cell : locationCells){
if(guess == cell){
result = "hit";
numOfHits++;
break;
}
}
if(numOfHits == locationCells.length){
result = "kill";
}
System.out.println(result);
return result;
}
}
public class DotComTestDrive{
public static void main(String[] args){
DotCom dot = new DotCom();
int[] locations = {2,3,4};
dot.setLocationCells(locations);
int userGuess = 4;
String result = dot.checkYourself(userGuess);
//System.out.println("result2 = "+result);
}
}
I understand the code, but the question is why to have an input as a String where as the same result can be achieved by using an int variable.
I am not sure if I am missing something in understanding or may be my question is completely wrong, but as I tried the same example with an int variable and it worked, I keep wondering when and why to have inputs as a String?
Internally in your program it is recommended to use the strongest possible type, in your case use the int.
But your program has an outside border where data come in and go out, like user input, feedback on the console, I/O operations to files or network, etc. In many cases you have to convert the involved data to or from types which are defined by the interface specification. An XML or json structure transports each data as a string, including numbers and dates. As soon as it passes the border of your application it should be immediately converted to the internally used type (and - of course - checked if the conversion is valid).
The background to this is: Serializing and deserializing (network streams, files) is easier done (better interchangable) using strings. But inside a process (by the CPU) it is better to operate on binary representations of the data.
If the number is large enough and can't be inside the integer or long range.
Also, beneficial for solving these problems in an efficient way
1) When you want to check if a number is a palindrome or not in an
efficient way.
2) When you want to know digits of the number without division
operator.
Few examples Which I am able to recollect now.
Related
This question already has answers here:
Java : Best way to pass int by reference
(7 answers)
Closed 5 years ago.
I have a program which is meant to be a client/server game question game. I've made it as far as accounting various cases of the client/server sending a termination command for the end of the game.
Now, my issue is that I have a set of primitive int points, attempts, correct which are read by the client from the server in a String as below:
N.B. I do know that Java functions pass parameters by value, not reference, and that assigning the value inside of the function will not change the value of the original.
int points = accepted = correct = 0;
String inbound = check (inbound, points, accepted, correct);
System.out.println(points); // Displays value of 0, when expecting > 0
private static String check (String str, int points, int attempts, int correct) {
// Expect Q QuestionString
if (str.substring(0,1).equals("Q")) {
//System.out.println("This is the question.");
return str.substring(2, str.length());
}
String[] input = str.split(" ");
// Expect EX # # #
if (input[0].contains("EX")) {
points = Integer.parseInt(input[1]);
attempts = Integer.parseInt(input[2]);
correct = Integer.parseInt(input[3]);
return "EX";
}
// Expected strings: Correct..., Incorrect.
return str;
}
I am unsure how to workaround this issue without jeopardizing encapsulation or hindering other concepts.
Create a wrapper class to contain those three integer parameters then simply pass an instance of that wrapper to the check method and then modify its contents within the method.
example:
public class Wrapper
{
private int points;
private int attempts;
private int correct;
public int getPoints() {
return points;
}
public void setPoints(int points) {
this.points = points;
}
public int getAttempts() {
return attempts;
}
public void setAttempts(int attempts) {
this.attempts = attempts;
}
public int getCorrect() {
return correct;
}
public void setCorrect(int correct) {
this.correct = correct;
}
}
thus the first part of your code will become:
Wrapper wrapper = new Wrapper();
String inbound = check (inbound, wrapper);
System.out.println(wrapper.getPoints());
and your check method becomes:
private static String check (String str, Wrapper wrapper) {
...
...
if (input[0].contains("EX")) {
wrapper.setPoints(Integer.parseInt(input[1]));
wrapper.setAttempts(Integer.parseInt(input[2]));
wrapper.setCorrect(Integer.parseInt(input[3]));
return "EX";
}
...
...
}
A part of a small program I am coding:
String maxs = "";
int maxi = 0;
At this part I defined two variables as int and String.
public Class(String max){
try {
this.maxi = Integer.parseInt(max);
}catch (Exception e){
this.maxs = max;
}
}
I think this way I will get to define one of both variables, if the String does not parse to int it will be saved as normal String.
Now I need to check what I need to return:
private TypeOfReturn getMax(){
if(this.maxi == 0){
// return maxs (return String)
} else if (this.maxs.equals("")) {
// return maxi (return int)
} else return null;
}
The quastion is, how do I fill the missing parts of the method getMax()?
Is it even possiable in Java?
Use Object instead of TypeOfReturn
You can change the TypeoOfReturn to Object and then return the respective types.
Another way to find out fast if a string is a number or not, which is the main part of your program, is to use the lambda expressions in java 8 like this:
String max = "123";
boolean isNumber = max.chars().allMatch(Character::isDigit);
System.out.println(isNumber);
Which will give you the output
true
Make your TypeOfReturn as String object type and convert the maxi as String and return that String in your else if condition.
Note: you cannot return both the int and String in the Same method.
I decided to create an account in order to ask a question I cant seem to figure out myself, or by some googling, hopefully I didn't just overlook it.
Essentially I am trying to make a text adventure game in Java, and am having a little trouble seeing how I should relate everything in the idea of objects. I have been successful in using XML stax and sending a file to the program, and using attributes and what not, to make it where the user can enter an integer associated with an option, and see if option requires an "item" or gives them an Item. I however did not take an OOP to this.
I want my new program to people able to take a string of user input in, instead of only an integer, and checking it against an array list if it exists. This is closer to the classic MUDs most may be familiar with.
I want to design it in a modular way, so I can slowly add on ideas, and more complexity to go along, so I don't want a "well it works so lets leave it alone" approach either.
Currently I simply want something close to this:
A Room object, which would have: an ID, Description, and interact-able
a Choice object (this one im not sure on) I thought about making an object to hold each rooms possible choices, both for exit, and for interact-ables
if so, the room object may need a Choice Object.
I've thought it over, tried some code, thought it over again, and every time, I keep ending up hard coding more than I feel I should, and making tons more variables than I feel are necessary, which makes me feel like i'm missing something crucial in my thinking.
I also want these rooms to be created through an inputted file, not generated in the code (so essentially the code is a story reader/crafter for any type, not one)
I have also been attempting this too long, and my solutions are becoming worse, but below was my most recent attempt at a rough Idea:
a GameManager class that takes the userInput and checks it some, before passing it along. I havent passed any data because im not sure of the approach. also im not used to regex, so some of that may also be wrong, if it is, maybe point it out, but that is not my focus
import java.util.Scanner;
public class GameManager {
private static final String EXIT_PHRASE = "exit";
public static void main(String[] args) {
Scanner userInput = new Scanner(System.in);
String userStringVal = "";
while(!userStringVal.equals(EXIT_PHRASE)){
userStringVal= userInput.nextLine();
if(checkKeywords(userStringVal)){
System.out.println("matches keyword");
}
else System.out.println("didnt match a keyword");
}
userInput.close();
}
public static boolean checkKeywords(String string){
boolean isKeyword = false;
string.toLowerCase();
if(string.matches("travel.*") || string.matches("search.*")){
System.out.println("passed first check");
String substring = string.substring(6);
if(matchDirection(substring)){
isKeyword = true;
}
}
return isKeyword;
}
public static boolean matchDirection(String string){
boolean hasDirection = false;
if(string.matches(".*\\bnorth|south|east|west|northeast|northwest|southeast| southwest|up|down")){
hasDirection = true;
}
return hasDirection;
}
}
The Room object I thought about as such:
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
public class Room {
private String roomDescription = "";
private int roomID=0;
private int northExit=0;
private int southExit=0;
private int eastExit=0;
private int westExit=0;
private int northeastExit=0;
private int northwestExit=0;
private int southeastExit=0;
private int southwestExit=0;
private int upExit=0;
private int downExit=0;
private String[] interactables = new String[10];
private Options options = new Options();
public Room(XMLStreamReader reader) throws XMLStreamException{
setAttValues(reader);
setRoomDescription(reader);
setUpOptions();
}
public void setinteractables(XMLStreamReader reader){
int count = reader.getAttributeCount();
for(int i = 0; i < count; i++){
interactables[i] = reader.getAttributeValue(i);
}
}
public void setAttValues(XMLStreamReader reader){
int count = reader.getAttributeCount();
for(int i = 0; i < count; i++){
String att = reader.getAttributeLocalName(i);
if(att !=""){
switch(att){
case "North": northExit=Integer.parseInt(att);
case "South": southExit=Integer.parseInt(att);
case "East": eastExit=Integer.parseInt(att);
case "West": westExit=Integer.parseInt(att);
case "NorthEast": northeastExit=Integer.parseInt(att);
case "NorthWest": northwestExit=Integer.parseInt(att);
case "SouthEast": southeastExit=Integer.parseInt(att);
case "SouthWest": southwestExit=Integer.parseInt(att);
case "Up": upExit=Integer.parseInt(att);
case "Down": downExit=Integer.parseInt(att);
case "ID": roomID=Integer.parseInt(att);
}
}
}
}
public void setRoomDescription(XMLStreamReader reader) throws XMLStreamException{
roomDescription = reader.getElementText();
}
public void setUpOptions(){
options.setCardinalPointers(northExit, southExit, eastExit, westExit);
options.setIntercardinalPointers(northeastExit, northwestExit, southeastExit, southwestExit);
options.setElevationPointers(upExit, downExit);
}
}
what can I do to make sure I dont have to state so many directions with so many variables?
here is a quick and rough idea of an Option class that I thought about, but i didn't finish deciding I am already too far in the wrong direction
public class Options {
private int northPointer = 0;
private int southPointer= 0;
private int eastPointer = 0;
private int westPointer = 0;
private int northeastPointer= 0;
private int northwestPointer = 0;
private int southeastPointer = 0;
private int southwestPointer = 0;
private int upPointer = 0;
private int downPointer = 0;
private String northInteractable = "";
private String southInteractable = "";
private String eastInteractable = "";
private String westInteractable = "";
private String northeastInteractable ="";
private String northwestInteractable = "";
private String southeastInteractable = "";
private String southwestInteractable = "";
private String upInteractable = "";
private String downInteractable = "";
public Options(){
}
public void setCardinalPointers(int north, int south, int east, int west){
northPointer = north;
southPointer = south;
eastPointer = east;
westPointer = west;
}
public void setIntercardinalPointers(int northeast, int northwest, int southeast, int southwest){
northeastPointer = northeast;
northwestPointer=northwest;
southeastPointer=southeast;
southwestPointer=southwest;
}
public void setElevationPointers(int up, int down){
upPointer = up;
downPointer = down;
}
public String whatToReturn(String string){
String importantPart = "";
if(string.matches("travel.*")){
String substring = string.substring(6);
}
else {
importantPart = "Interactable";
String substring = string.substring(6);
if (substring.matches("\\bnorth\\b")) {
if(northInteractable!=0){
}
}
else if (substring.matches("\\bsouth\\b"))
else if (substring.matches("\\beast\\b"))
else if (substring.matches("\\bwest\\b"))
else if (substring.contains("northeast"))
else if (substring.contains("northwest"))
else if (substring.contains("southeast"))
else if (substring.contains("southwest"))
else if (substring.contains("up"))
else if (substring.contains("down"))
}
return importantPart;
}
}
I did not see the adventure tag until after I typed this, so I will start perusing through there, but will still post this, so my apologies if there is a good answer to this and I have yet to find it.
as a recap: what would be a good way to relate a few objects to create a room object (that gets its information from a file (XML being what im used to)) having exits, descriptions, and interactions. and the user interacting with these based off keywords that can be inputted freely, and not restricted to say, index values of array's holding keywords.
Im thinking when the user types something like "travel north" to first check if they typed a keyword, in this case being travel, then a direction. Then somewhree else checking if it states travel, check north with a possible northExit a room may or may not have. Then if its another keyword, say like check, to make it easy also have the exact same directions, but check for a different string.
Then if room "northExit" exists, get an option somehow, with a pointer to another roomID. though This thought process causes me issues when thinking about future possibility of requiring items for getting to the next room. Also where to store/acquire these options is causing some difficulties.
There are two things I would like to introduce to you. The first, in the enum. You can think of this as a special kind of class where all the possible options are enumerated in the class definition. This is perfect for things like, in your case, directions. Enums can be simple, where you just list all of the possible options for use in other classes:
public enum Direction {
NORTH, NORTH_EAST, EAST, SOUTH_EAST, SOUTH, SOUTH_WEST, WEST, NOTH_WEST;
}
They can be a bit more complex, if you want them to have methods and attributes of their own:
public enum Direction {
NORTH(true), NORTH_EAST(false), EAST(true), SOUTH_EAST(false), SOUTH(true), SOUTH_WEST(false), WEST(true), NOTH_WEST(false);
private final boolean isCardinal;
private Direction(boolean isCardinal){
this.isCardinal = isCardinal;
}
public boolean isCardinal(){
return isCardinal;
}
public static Collection<Direction> getCardinalDirections(){
return Arrays.asList(Direction.values()).stream().filter(Direction::isCardinal).collect(Collectors.toList());
}
public static Collection<Direction> getIncardinalDirections(){
return Arrays.asList(Direction.values()).stream().filter(x -> !x.isCardinal()).collect(Collectors.toList());
}
}
Please read more about Java enum types here.
The second thing I would like to introduce to you is the data structure known as the Map. Maps are also known as Dictionaries, and that can often help understanding how they work. A Map will take one object and map it to another object, like how a Dictionary maps a word to its definition, or a phonebook maps a person's name to their phone number. We can simplify your Room class a ton by using a Map. I am not going to reproduce all of your code, since I'm focusing on your Room exists right now:
public class Room {
private Map<Direction, Room> exits;
public Room(){
this.exits = new HashMap<>();
}
public void setExit(Direction direction, Room room){
this.exits.put(direction, room);
}
public Room getExit(Direction direction){
return this.exits.get(direction);
}
}
Please read more about the Java Map interface here.
You will, of course, need to adapt your methods which are reading from XML, etc. But, now, your Room class should be greatly simplified.
I hope this points you in a helpful direction.
This question already has answers here:
How to return multiple objects from a Java method?
(25 answers)
Closed 7 years ago.
I am using a simulator to play craps and I am trying to return two values from the same method (or rather I would like to).
When I wrote my return statement I simply tried putting "&" which compiled and runs properly; but I have no way of accessing the second returned value.
public static int crapsGame(){
int myPoint;
int gameStatus = rollagain;
int d1,d2;
int rolls=1;
d1 = rollDice();
d2 = rollDice();
switch ( d1+d2 ) {
case 7:
case 11:
gameStatus = win;
break;
case 2:
case 3:
case 12:
gameStatus = loss;
break;
default:
myPoint = d1+d2;
do {
d1=rollDice();
d2=rollDice();
rolls++;
if ( d1+d2 == myPoint )
gameStatus = win;
else if ( d1+d2 == 7 )
gameStatus = loss;
} while (gameStatus == rollagain);
} // end of switch
return gameStatus & rolls;
}
When I return the value as:
gameStatus=crapsGame();
It appropriately sets the varaible to win or lose but if I try something as simple as following that statement with:
rolls=crapsGame();
It is assigned the same value as gamestatus...a 0 or a 1 (win or lose).
Any way that I can access the second returned value? Or is there a completely different way to go about it?
Create your own value holder object to hold both values, then return it.
return new ValueHolder(gameStatus, rolls);
It's possible to return an array with multiple values, but that's cryptic and it does nothing for readability. It's much easier to understand what this means...
valueHolder.getGameStatus()
than what this means.
intArray[0]
returning gameStatus & rolls means "return the bitwise and of gameStatus and rolls" which probably is not what you want
you have some options here:
return an array
create a class that represents the response with a property for each value and return an instance
use one of the many java collections to return the values (probably lists or maps)
You can return an array of values or a Collection of values.
Is it possible to return more than one value from a method in Java?
No it is not. Java allows only one value to be returned. This restriction is hard-wired into the language.
However, there are a few approaches to deal with this restriction:
Write a light-weight "holder" class with fields for the multiple values you want to return, and create and return an instance of that class.
Return a Map containing the values. The problem with this (and the next) approach is that you are straying into an area that requires runtime type checking ... and that can lead to fragility.
Return an array containing the values. The array has to have a base type that will accommodate the types of all of the values.
If this is a method on an object, then add some fields on the same object and methods that allow the caller to pick up "auxiliary results" from the last call. (For example, the JDBC ResultSet class does this to allow a client to determine if the value just retrieved was a NULL.) The problem is that this makes the class non-reentrant at the instance level.
(You could even return extra results in statics, but it is a really bad idea. It makes the class non-reentrant across all instances, not to mention all of the other badnesses associated with misused statics.)
Of these, the first option is the cleanest. If you are worried about the overhead of creating holder instances, etc, you could consider reusing the instances; e.g. have the caller pass an existing "holder" to the called method into which the results should be placed.
The best practice for an OOP approach is to return an Object. An object that contains all the values you want.
Example:
class Main {
public static void main(String[] args) {
MyResponse response = requestResponse();
System.out.println( response.toString() );
}
private static MyResponse requestResponse() {
return new MyResponse( "this is first arg", "this is second arg" );
}
}
class MyResponse {
private String x, y;
public MyResponse( String x, String y ) {
this.x = x;
this.y = y;
}
#Override
public String toString() {
return "x: " + x + "\t y: " + y;
}
}
If you want an even more scalable approach then you have to use JSON responses. (let me know if you want an example with JSON too)
You can following ways to do this:
Use a Container class, for example
public class GameStatusAndRolls {
String gameStatus;
String rolls;
... // constructor and getter/setter
}
public static GameStatusAndRolls crapsGame(String gameStatus, String rolls) {
return new GameStatusAndRolls(gameStatus, rolls);
}
public static void main(String[] args) {
...
GameStatusAndRolls gameStatusAndRolls = crapsGame(gameStatus, rolls);
gameStatusAndRolls.getGameStatus();
Use List or an array, for example
public static List<Integer> crapsGame(String gameStatus, String rolls) {
return Arrays.asList(gameStatus, rolls);
}
private static final int GAME_STATUS = 0;
private static final int ROOLS = 0;
public static void main(String[] args) {
...
List<Integer> list = crapsGame(gameStatus, rolls);
... list.get(0)...list.get(GAME_STATUS);
... list.get(1)...list.get(ROOLS);
or
public static String[] crapsGame(String gameStatus, String rolls) {
return new String[] {gameStatus, rolls};
}
private static final int GAME_STATUS = 0;
private static final int ROOLS = 0;
public static void main(String[] args) {
...
String[] array = crapsGame(gameStatus, rolls);
... array[0]...array[GAME_STATUS];
... array[1]...array[ROOLS];
Use Map, for example
public static Map<String, String> crapsGame(String gameStatus, String rolls) {
Map<String, String> result = new HashMap<>(2);
result.put("gameStatus", gameStatus);
result.put("rolls", rolls);
return result;
}
public static void main(String[] args) {
...
Map map = crapsGame(gameStatus, rolls);
... map.get("gameStatus")...map.get("rolls");
Sorry if this is answered somewhere due to me missing something obvious, but I've been googling this for days now and it just doesn't seem to make any sense. I've got 3 years of experience in Javascript and am getting into Java now, so I'm not behind on the basic concepts of anything and such.
I'm using IntelliJ for this, but it fails to point out the problem. The communication (access rights and instantiations) between my classes is fine, the code syntax and variable types are as well, etc, so I really can't tell what it is.
I have a Data class, which just holds "read-only" data for the other classes to use.
public class Data {
// snip
public static int[][] specs = {
{6,1,6,40},
{5,2,5,30},
{5,3,4,40},
{4,4,3,60}
};
}
There's another class that has to read this data when it's initialized.
public class Soldier {
// snip
public int range;
public Soldier() {
int x = ...; // user input
range = Data.specs[x][1];
}
}
The specs array itself contains its data as defined (ie the array is not empty), x is valid as an index of the specs array (ie 0 <= x <= 3), its type is int and Test has read access to the specs array (all confirmed with debug output statements). And yet, when it tries to set the value of range (then and only then, at that exact point), I get the "Index out of bounds" error.
Can someone please tell me what's going wrong when trying to read the array? Or am I right in saying that this is really weird and I need to post the entire code?
Note: a small new test also shows that, if I change the code to first output a manually chosen value from the array and then set the value of range, the console prints the error statement (and exits the program) and follows it up by printing the manually picked value, but assigning the value and then asking to output range only throws the error... That makes absolutely no sense at all!
Edit: I've edited the code above. The class called Test is called Soldier in my code (I'm making a text-based game...). Below's the stack trace, if it's any good without the full code (which is way long). The basic structure of my program is this:
1) Boot contains the main method and instantiates a new Game
2) Game instantiates x Teams
3) each Team instantiates an Army
4) each Army instantiates x Soldiers
Each instance of the classes is set as an attribute of the instantiating class (public Army army; and an Army instantiation in the Team constructor, for example). It's essentially a cascade of constructors instantiating subsequent classes and assigning them as their attributes.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at Army.<init>(Army.java:13)
at Team.<init>(Team.java:19)
at Game.<init>(Game.java:22)
at Boot.main(Boot.java:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)5
Edit edit: here's the semi-full code (I'm leaving out the stuff that has absolutely nothing to do with it, including the imports). It's in no particular order and the classes are in separate .java files within the IntelliJ project. The game continues up to the point where a new Soldier asks for its type to be designated (the function performing the user input is working fine and validating the input as proven by a technically identical other part of the game).
public class Boot {
public static void main(String[] args) {
Object[] games = new Object[] {};
if (Lib.userConfirmPrompt("Start the game?") == true) {
do {
games[games.length] = new Game();
}
while (Lib.userConfirmPrompt("Do you want to play again?") == true);
}
System.exit(0);
}
}
public class Game {
public Object[] teams = new Object[] {};
public Game() {
for (int i = 0;i < settings.xbots + 1;i++) {
teams[teams.length] = new Team(this);
}
}
}
public class Team {
public Game game;
public Army army;
public Team(Game p) {
game = p;
army = new Army(this);
}
}
public class Army {
public Team team;
public static Object[] soldiers = new Object[] {};
public Army(Team p) {
team = p;
for (int i = 0;i < team.game.settings.xsoldiers;i++) {
soldiers[soldiers.length] = new Soldier(this);
}
}
}
public class Soldier {
private Army army;
public int sight;
public int range;
public int distance;
public int damage;
public Soldier(Army p) {
army = p;
int type = Lib.userTxtIntOptionsPrompt(Data.isoldiertypes);
// HERE is where it crashes, type is assigned and valid but the array access fails
sight = Data.isoldierspecs[type][0];
range = Data.isoldierspecs[type][1];
distance = Data.isoldierspecs[type][2];
damage = Data.isoldierspecs[type][3];
}
}
public class Data {
public static List isoldiertypes = Arrays.asList("Scout","Private","Machinegunner","Grenadier");
public static int[][] isoldierspecs = {
{6,1,6,40},
{5,2,5,30},
{5,3,4,40},
{4,4,3,60}
};
}
public class Lib {
private static Scanner input = new Scanner(System.in);
// output
// default: 1 query string to print
public static void outBase(String query) {
System.out.print(query);
}
public static void outStd(String query) {
outBase(query + "\n");
}
// end of output
// input
// default: 1 query string to print,
// query and input are in-line (exception: userConfirmPrompt prints query block-wise and default instruction in-line before input),
// keeps user hostage until valid input is given (exception: userPrompt returns blindly)
public static String userPrompt(String query) {
outBase(query);
return input.nextLine();
}
public static String userTxtPrompt(String query) {
String menuinput = null;
do {
if (menuinput != null) {
userHostage();
}
menuinput = userPrompt(query);
} while (menuinput.length() == 0);
return menuinput;
}
public static int userIntPrompt(String query) {
String menuinput = null;
do {
if (menuinput != null) {
userHostage();
}
menuinput = userTxtPrompt(query);
} while(menuinput.matches("^-?\\d+$") == false);
return new Integer(menuinput);
}
// end of input
// options input
// default: takes a List of options as argument,
// prints an enumerated list of these options string-wise,
// prompts for a numeral selection of the desired option and returns the number if valid
public static int userTxtIntOptionsPrompt(List options) {
int choice = 0;
Boolean chosen = false;
do {
if (chosen == true) {
userHostage();
} else {
chosen = true;
}
chosen = true;
for (int i = 0;i < options.size() - 2;i++) {
outStd((i + 1) + ") " + options.get(i) + ",");
}
outStd((options.size() - 1) + ") " + options.get(options.size() - 2) + "\nand " + options.size() + ") " + options.get(options.size() - 1) + ".");
choice = userIntPrompt("Enter the number of the option you'd like to select: ") - 1;
} while(choice < 0 || choice >= options.size());
return choice;
}
// end of options input
// miscellaneous
public static void userHostage() {
outStd("Invalid operation. Please try again.");
}
}
The problem is in your Army class:
public static Object[] soldiers = new Object[] {};
You initialize an empty (length == 0) array named soldiers, but later you access:
soldiers[soldiers.length] = new Soldier(this);
This causes the failure.
By definition, soldiers.length is out of the bound of the array (since the bound is from 0 to soldiers.length-1)
To overcome it - make sure you allocate enough space in the array soldiers or use a dynamic array (ArrayList) instead. You can append elements to an ArrayList using ArrayList.add(), and you don't need to know the expected size before filling it up.
The x should be greater than -1 and less than 4.
The stacktrace does not mention the Solder class, its in the conctructor of the Army class.
Any how, only knowing that the index should be within a range is not enough. As a programmer its your duty to validate the index before trying to access an element at that index.
if(index > 0 && index < array.length) {
//then only acess the element at index
Problem is the array soldiers is of size 0.
This line int x = ...; // user input implies that you are taking input in some fashion from the user and accessing the array with it. Are you checking this value to see that is in range (i.e., between 0 and 3)? If not, this may be why your testing works.
Edit: something like this might solve it for you:
public class Army {
public Team team;
public Vector<Soldier> soldiers;
public Army(Team p) {
soldiers = new Vector<Soldier>()
team = p;
for (int i = 0;i < team.game.settings.xsoldiers;i++) {
soldiers.add(new Soldier(this));
}
}
}
Judging by your other code, this sort of pattern will be useful in your Game object as well.