I have problem with my integer arrays, for example one. I have class with objects, and i have different class, where these objects are incremented after button click, but I got "null" values and NullPointerExpection. I had this all working, when i hade just, for example "int Money;", but my codes was 12000 lines, and i tried to make it easier to read, etc. But now with array they don't work. I got working this thing with For Loops , but how I understand, i can't make it with loops, because i want to later load these values from savefile.
CarMainClass (This one doesn't work) :
package Clicker;
public class MainHolder {
public Integer main[] = new Integer[8];
public MainHolder(){
}
public void MainMaker(int k){
}
public void MakeMain(){
MainMaker(0); // Money
MainMaker(0); // Money Clicks
MainMaker(0); // Boxes
MainMaker(0); // Boxes Clicks
MainMaker(1); // Boxes Level
MainMaker(1); // Player Level
MainMaker(1); // Garage Level
MainMaker(0); // Garage Slots
}
}
CarMainClass (That works, with for loop) :
package Clicker;
public class MainHolder {
public Integer main[];
public MainHolder(){
main = new Integer[8];
for(int i=0; i <8;i ++){
if(i ==4 || i ==5 || i ==6){
MainMaker(1,i);
}else{
MainMaker(0,i);
}
}
}
public void MainMaker(int k,int p){
main[p] = k;
}
public void MakeMain(){
}
}
And button :
//Money Button Click
if(ae.getSource() == jbtnMoney) {
CarMain.main[0] += 1;
MoneyLabel.setText("Money: " + CarMain.main[0]);
CarMain.main[1] += 1;
MoneyClicksLabel.setText("Money Clicks: " + CarMain.main[1]);
}
Application GUI when working : WorkingImage
Application GUI when dosn't work + error : NoWorkingImage
Is it a full code of CarMainClass? It seems that the method MainMaker doesn't contain any executable code so it doesn't do anything when you call it. The button click is ok.
The initialised array is empty - contains only null values and that is why it returns null - when you reference the value on the GUI.
You need to change it to this (I assume that each number describes object):
package Clicker;
public class MainHolder {
public Integer main[] = new Integer[8];
public MainHolder(){
MakeMain();
}
public void MainMaker(int k,int p){
main[p] = k;
}
public void MakeMain(){
MainMaker(0,0); // Money
MainMaker(0,1); // Money Clicks
MainMaker(0,2); // Boxes
MainMaker(0,3); // Boxes Clicks
MainMaker(1,4); // Boxes Level
MainMaker(1,5); // Player Level
MainMaker(1,6); // Garage Level
MainMaker(0,7); // Garage Slots
}
}
But your solution to use loops make actually more sense. Why you can't store it into a file? You should define the the integers which you use to describe the application as constants - final Integer money = 0 and so on.
You can store the values into a file and use the index to map the values to the corresponding values. Or store it as map.
Related
I am making a replica of a Subway restaurant where you would receive an order in a certain sequence and check if the sequence is valid and if the ingredients are in the menu.
The right order is: 1 bread, 0 to 1 meat, 1 cheese, 1 to 3 extras, 1 to 3 sauces.
Meaning that an order can have a minimum of 4 ingredients (bread, cheese, 1 extra, 1 sauce) and a maximum of 9 ingredients (bread, meat, cheese, 3 extras, 3 sauces).
My question is if there is a more optimized/smarter method to go about validating each and every ingredient than mine?
Code:
// Example order
HashMap<String, HashSet<String>> menu = new HashMap<>();
public static void main(String[] args) {
// Example order
List<String> ingredients = Arrays.asList("Wheat", "Veal",
"Yellow", "Cucumbers", "Onions");
if (!isValid(ingredients)) {
// throw exc;
}
boolean isValid(List<String> ingredients) {
if (ingredients.size() < 4 || ingredients.size() > 9) {
return false;
}
int i = 0;
// Bread
if (!Restaurant.menu.get("Bread")
.contains(ingredients.get(i++))) {
System.out.println("Bread");
return false;
}
// Meat
if (!(Restaurant.menu.get("Meat")
.contains(ingredients.get(i)))
&& !Restaurant.menu.get("Cheese")
.contains(ingredients.get(i))) {
System.out.println("Meat");
return false;
}
if (Restaurant.menu.get("Meat")
.contains(ingredients.get(i))) { // Meat case
if ((!Restaurant.menu.get("Cheese")
.contains(ingredients.get(++i)))) {
System.out.println("Cheese");
return false;
}
}
for (int j = ++i; j < ingredients.size(); j++) {
if ((!Restaurant.menu.get("Extras")
.contains(ingredients.get(j)))) { // Extras
if (j == i) {
return false;
} else {
if ((!Restaurant.menu.get("Sauces")
.contains(ingredients.get(j)))) { // Sauces
return false;
}
}
}
}
return true;
}
Note 1: I know about the rule "If it works, don't touch it" but I feel like this code is getting in the territory of spaghetti code with a bunch of ifs essentially checking similar things with lots of cases and just wanted a second opinion if there is a more optimized way I can't think of right now.
Note 2: I chose HashSet over ArrayList for the menu because it is faster to search.
First, there is nothing really wrong with your general approach.
Having said that, there are some errors.
You are referencing your hashMap as a static value via Restaurant where it isn't declared static.
you are calling isValid() from within a static context (Main) but the method is not declared static.
This is how I might approach it. And it's not to say it is the best approach or style either.
I chose to use an enum to hold details about each menu item, and a class to process the order. Enum's easily lend themselves to this type of requirement. I recommend you read up on them (they are too involved to explain them in detail here). But because they are static they are best served in holding values that are not likely to change.
Each item has two arguments are are processed in the enum's constructor.
so each item has a separate range of its item (the ingredient)
the enum also has a validate method to check to see if a supplied count of items meets the requirements.
The actual order is in the MyOrder class.
it contains a map to hold the counts of each ingredient.
an add method to add the current quantity to the map for a given ingredient.
and a display method to print informative information about the order.
enum Menu {MEAT(0,1), BREAD(1,1), CHEESE(1,1), EXTRAS(1,3), SAUCES(1,3);
private int min;
private int max;
private Menu(int min, int max) {
this.min = min;
this.max = max;
}
public int getMax() {
return max;
}
public int getMin() {
return min;
}
public boolean validate(int count) {
return count >= min && count <= max;
}
}
class MyOrder {
private EnumMap<Menu, Integer> counts = new EnumMap<>(Menu.class);
public void display() {
for (Menu item : Menu.values()) {
int count = counts.get(item);
System.out.printf("%-7s: %d (%d,%d) %s%n",item.name(), count, item.getMin(), item.getMax(),
item.validate(count) ? "" : "Item count out of range.");
}
}
public boolean add(Menu item, int quantity) {
return item.validate(counts.merge(item, quantity, Integer::sum));
}
}
public class Restaurant {
public static void main(String[] args) {
boolean isValid;
MyOrder order = new MyOrder();
isValid = order.add(Menu.BREAD,2);
isValid &= order.add(Menu.MEAT,1);
isValid &= order.add(Menu.CHEESE,2);
isValid &= order.add(Menu.EXTRAS,3);
isValid &= order.add(Menu.SAUCES,2);
if (isValid) {
System.out.println("Your order is accepted.");
} else {
System.out.println("Order is not in compliance");
order.display();
}
}
}
prints
Order is not in compliance
MEAT : 1 (0,1)
BREAD : 1 (1,1)
CHEESE : 2 (1,1) Item count out of range.
EXTRAS : 3 (1,3)
SAUCES : 2 (1,3)
Also remember that the result of any if statement is a boolean. So the inequality can be assigned to a boolean and then tested later (if it makes sense to do so). Also notice that I don't check for a legitimate order until the end. Some might prefer to signal a bad order as soon as it occurs. This is a design choice.
For more information check.
Enum
EnumMap
Map.merge
The problem I see with your proposed solution is that it is trying to solve all problems at once, instead of solving them separately. That makes your code hard to read and understand, in my opinion. While it may work, the more business rules you add, the harder this will get.
So what can you do about it? Separate the concerns.
The first concern is cassifying an ingredient: is it bread, cheese, meat, extra, sauce? You could e.g. create a class Menu with a method getCategory() (instead of just using a HashSet for menu) that returns the category, and the return value could be an Enum.
The seond concern is order. You could check the order of the list using a custom Comparator. See this question for details.
The third concern is number of ingredients of a certain category. Given that you can find out the category of an ingredient, you can count how many you have and check if it is the right amount.
There are more things to be said about how to achieve any of this, I just wanted to point you in a possible direction.
I'm having an issue that has been giving me a an error saying java.lang.StackOverflowError: null. My program is sort of like a lottery, a random number is chosen, and based off the number, your item is chosen from a array. Now this works all handy and dandy, but when i try to insert the item received into an inventory. I get that error. Im pretty sure i set up my class wrong but i don't know how to construct an array in a separate class that receives data from another class, and returns the data back to the same class. Enough chit chatting, heres what my code looks like so far. (please dont mind the extra variables as this is a cropped portion of my code)
public class inventory {
private int inventorymain;
public String[] inventorymain() {
String[] inventorymain;
return inventorymain();
}
}
import java.util.Scanner;
import java.util.Random;
public class glue {
public static void main(String [] args) {
inventory inv = new inventory();
allskins a = new allskins();
Scanner s = new Scanner(System.in);
int selection = 0;
int invcount = -1;
Random rand = new Random();
do {
System.out.println(d.menue());
selection = s.nextInt();
if (selection == 1) {
invcount++;
int random = rand.nextInt(208);
System.out.println("You opend a: ");
System.out.println(a.allskins()[random]);
System.out.println("Your item has been put in your inventory, select inventroy from the menue to view all items.");
System.out.println("");
inv.inventorymain()[invcount] = (a.allskins()[random]);
}
}while (selection != 6);
}
}
Thank you
You're entering infinite recursive loop calling inventorymain()
public class inventory {
private int inventorymain;
public String[] inventorymain() {
String[] inventorymain;
return inventorymain(); // recursive call here without escape condition
}
}
It's better to keep the method name and variable name different to avoid such cases.
I have to do my homework in Greenfoot.
This part means that I have to save the position of Chess and then click reset.
Then, I have to choose load to put back the pieces of chess in the position they had before reset.
Since I don't know the exact size of the array, I know I can use List but it isn't allowed in the homework.
Nothing showed up on the screen but there is no error message.
Assume I have a class called Chess.
static Actor[] allChess;
public void save() // this is the save
{
Actor[] allChess = GWorld.getAllObjects("Chess");
}
public void load() // this is the load
{
if (allChess != null)
{
for (int i=0; i < allChess.length; i++)
{
Chess ch = (Chess) allChess[i];
GWorld.addOneObject(new Chess(ch.color, ch.rank), ch.getX(), ch.getY());
}
}
}
Thanks a lot!
allChess is redeclared as a local variable in save(). Do like this :
public void save() // this is the save
{
allChess = GWorld.getAllObjects("Chess");
}
I'm trying to take one parameter from the parent class of Car and add it to my array (carsParked), how can i do this?
Parent Class
public class Car
{
protected String regNo; //Car registration number
protected String owner; //Name of the owner
protected String carColor;
/** Creates a Car object
* #param rNo - registration number
* #param own - name of the owner
**/
public Car (String rNo, String own, String carColour)
{
regNo = rNo;
owner = own;
carColor = carColour;
}
/** #return The car registration number
**/
public String getRegNo()
{
return regNo;
}
/** #return A String representation of the car details
**/
public String getAsString()
{
return "Car: " + regNo + "\nColor: " + carColor;
}
public String getColor()
{
return carColor;
}
}
Child Class
public class Carpark extends Car
{
private String location; // Location of the Car Park
private int capacity; // Capacity of the Car Park - how many cars it can hold
private int carsIn; // Number of cars currently in the Car Park
private String[] carsParked;
/** Constructor for Carparks
* #param loc - the Location of the Carpark
* #param cap - the Capacity of the Carpark
*/
public Carpark (String locations, int room)
{
location = locations;
capacity = room;
}
/** Records entry of a car into the car park */
public void driveIn()
{
carsIn = carsIn + 1;
}
/** Records the departure of a car from the car park */
public void driveOut()
{
carsIn = carsIn - 1;
}
/** Returns a String representation of information about the carpark */
public String getAsString()
{
return location + "\nCapacity: " + capacity +
" Currently parked: " + carsIn +
"\n*************************\n";
}
}
Last Question Method
public String getCarsByColor (String carColour)
{
for (int num = 0; num < carsParked.length; num++)
{
if ( carColour.equals(carsParked[num]) )
{
System.out.print (carsParked[num]);
}
}
return carColour;
}
I have this so far so that if "red" is put in the parameters, it would list all the cars with the color red and it's corresponding information but does not seem to work ~_~.
You seem to have the wrong relationship here: a car park is not a car. I would recommend against using inheritance in either direction between these classes. And Carpark should probably just have an array or collection of cars.
Also note that the parameter carsIn isn't necessary - just get the length of the array of cars (or size() if it's a Collection).
Edit: Okay, ignoring the inheritance part, it seems like it makes sense to add cars when driveIn is called, and remove them when driveOut is called.
driveIn should probably take a Car as an argument, so the method can access the parameter you want to store (personally I would just store Car references, but fine). Since we're going to be adding and removing these parameters, it'll be much easier to use a List that can resize itself instead of an array, like ArrayList. For example:
private final List<String> carsRegNosParked = new ArrayList<String>();
public void driveIn(Car car) {
carsRegNosParked.add(car.getRegNo());
}
It's less clear what driveOut should do. It could take a specific registration number to remove:
public void driveOut(String regNo) {
carsRegNosParked.remove(regNo);
}
Or it could just indiscriminately remove a car, say the first car added:
public void driveOut() {
if (!carsRegNosParked.isEmpty()) {
carsRegNosParked.remove(0);
}
}
Note the difference between remove(Object) and remove(int).
First change carsParked to a list. So:
private String[] carsParked;
becomes
private List<String> carsParked;
Then in you constructor initialize it to an empty list by doing:
carsParked = new ArrayList();
Then in your drive in method, make it take a car parameter and pull the param you want:
public void driveIn(Car car) {
carsParked.add(car.getRegNo());
}
Also you do not need to keep track of the number of cars this way. Since you could always do carsParked.size() to find out.
Now I would probably change that list to be List<Car> instead of string and just dump the whole car in there. Sure you may only need one item right now, but who knows down the road, maybe you will need something else.
EDIT:
Sure you could do it with an simple array. The issue with that is sizing. Say you initially create an array of size 5, when you go to add the 6 item you will need to create a new larger array, copy the original data, then add the new item. Just more work. Now if the idea is you have a carpark, and it can have X number of spots then you initilize your array to that size from the begining.
public Carpark (String locations, int room){
location = locations;
capacity = room;
//this creates an array with the max number of spots
carsParked = new String[capacity];
//also good idea to init
carsIn = 0; //initial number of cars parked
}
then in your driveIn() method:
public void driveIn(Car car) {
carsParked[carsIn] =car.getRegNo();
carsIn=carsIn+1;
}
now driveOut()
public void driveOut(Car car) {
//loop through the array until we find the car
for (int i=0; i < carsParked.length; i=i+1){
if (car.getRegNo().equals(carsParked[i])){
//we found the car, so set the space null
carsParked[i] = null;
carsIn=carsIn-1;
//stop looping now
break;
}
}
}
Looks nice doesn't it. Well no it is not. Now the driveIn will not work, since we have null spots scattered all over the place. How do we fix it:
public void driveIn(Car car) {
//loop through the array until we find a null spot,
//then park the car
for (int i=0; i < carsParked.length; i=i+1){
if (carsParked[i] == null){
//we found the car, so set the space null
carsParked[i] = car.getRegNo();
carsIn=carsIn+1;
//stop looping now
break;
}
}
}
It could still be improved further. I would probably still change String[] carsParked to Car[] carsParked as to not throw away information.
I would also change the driveIn and driveOut methods to return booleans to indicate if the successfully parked or un-parked a car.
Final Edit:
Okay, if you want to keep track of what cars are parked in the car park and which spot they are in you need to know enough about each car to make it unique. In your case you may only need regNo. So when you call driveIn or driveOut you have to pass that information so we can store it at the appropriate index (parking spot) in the array. Otherwise all you will know is a car was parked somewhere, or that a car left. Not which spots are open.
So in short the parameter Car car in those two methods contain the information needed to uniquely identify each car that is being parked, or is leaving. Without it the car park instance would have no clue who is currently parked, or where they are parked.
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.