Break loop from another class java - java

I'm currently working on somekind text-based 'RPG' game. I made two classes, first one is supposed to simulate road from one town to another and doing so there is a possibility that player will encounter enemy. Fighting logic is placed in another class and when player dies I call method which is supposed to load game from previous save or create new character and that works perfectly fine, but even when player died road is continued instead of breaking loop. LeaveTown class looks like this:
public class WorldMap {
boolean running=true;
public void leaveTown(Character character){
EnemyFactory factory = new EnemyFactory();
PerformAtack atack = new PerformAtack();
StringBuilder sb = new StringBuilder();
Random random = new Random();
int progress = 0;
while(running && progress!=100){
try {
System.out.print(sb.append("#"));
System.out.println(progress+"%");
if (random.nextDouble() * 10 < 2) {
atack.performFight(character,factory.generateRandomEnemy());
}
Thread.sleep(500);
}catch(Exception ex){}
progress = progress+5;
}
}
}
As you can see, I'm using while loop which is supposed to break when running variable is set to false or road is finished. When character dies I call method battleLost:
private void battleLost(Character character){
WorldMap map = new WorldMap();
System.out.println("You are dead.\nWould you like to try AGAIN or LOAD your last save");
System.out.println("Please type AGAIN or LOAD");
while(true) {
String choice = sc.nextLine().toUpperCase();
if (choice.equals("AGAIN")) {
map.running = false;
System.out.println("Create new character?");
break;
} else if (choice.equals("LOAD")) {
map.running = false;
save.readFromFile();
break;
} else
System.out.println("Try again.");
}
}
This method sets running variable in class WorldMap to false, but the while loop is continued instead of breaking. Im aware that problem is probably linked to using map.running = false; in wrong way.
I'd glad if anyone could explain me how this problem should be solved.

boolean running=true;
This variable should be part of Character class.
then, your while will just look like:
while(character.isRunning() && progress!=100)
and, within performFight you can update it to false when died.

I guess battleLost() belongs to PerformAtack class. so the local variable map inside the battleLost() does not affect the object that is controlling the road.
You can do two things:
make running static (and public) and then you can reference it from anywhere by the class name like this WolrdMap.runnning = false but this solution has problems if you decide to do things in parallel (e.g. multiple threads). Remmeber: static data is almost always a pitfall for multi-threaded design!
a better solution is to make atack.performFight return a boolean value and assign that value to the running var: running = atack.performFight(... this is better design in terms of thread safety, but you will have to propagate the boolean value from battleLost() (it too will have to return boolean) to `performFight()' and so on

Well,Change the access modifier for variable boolean running=true; to public static boolean running=true;
once you did that you can change this variable to false without creating an instance in order to break the loop, do something like that
private void battleLost(Character character){
WorldMap map = new WorldMap();
System.out.println("You are dead.\nWould you like to try AGAIN or LOAD your last save");
System.out.println("Please type AGAIN or LOAD");
while(WorldMap.running) {
String choice = sc.nextLine().toUpperCase();
if (choice.equals("AGAIN")) {
map.running = false;
System.out.println("Create new character?");
break;
} else if (choice.equals("LOAD")) {
map.running = false;
save.readFromFile();
break;
} else
System.out.println("Try again.");
}
public void breakTheLoop(){
WorldMap.running=false;
}
because of static is a class variable so it's value will be shared between all classes

Related

Java ArrayList add class object to list if object name is not already in the list?

I have looked through other questions but cant seem to find the answer I am looking for.
I am having trouble figuring out how to create a loop that adds a class object to an ArrayList only if it its name is not used in the list already.
This is the class I have.
package myPackage;
public class Cube {
private int length;
private String name;
public Cube(int initLength, String initName) {
this.length = initLength;
this.name = initName;
}
I would like to create new cubes and add them to a list. Here is the code I am trying to do this with.
In the while loop I can't figure out how to determine if the name has been used or not
package myPackage;
import java.util.ArrayList;
import java.util.Scanner;
public class PartFive {
public static void main(String[] args) {
ArrayList<Cube> cubelist = new ArrayList<>();
Cube oshea = new Cube (13, "oshea");
Cube mike = new Cube (7, "tony");
cubelist.add(oshea);
cubelist.add(mike);
Scanner reader = new Scanner(System.in);
while (true) {
System.out.println("enter cube name (blank quits): ");
String name = reader.nextLine();
if (name.equals("")){
break;
}
System.out.println("enter side length: ");
int length = Integer.valueOf(reader.nextLine());
Cube newcube = new Cube(length, name);
if(cubelist.contains(newcube.name)) {
// dont add to list
}
else {
cubelist.add(newcube);
}
}
reader.close();
System.out.println(cubelist);
}
}
Any constructive criticisms and suggestions are welcomed.
Replace
if(cubelist.contains(newcube.name)) {
dont add to list
}
else {
cubelist.add(newcube);
}
with
boolean found = false;
for(Cube cube: cubelist){
if(cube.getName().equals(name)) {
found = true;
break;
}
}
if(!found) {
cubelist.add(newcube);
}
The idea is to use a boolean variable to track if a cube with the same name as that of the input name already exists in the list. For this, iterate cubelist and if a cube with the same name as that of the input name is found, change the state of the boolean variable and break the loop. If the state of the boolean variable does not change throughout the loop, add the cube to the list.
From the code in your question:
if(cubelist.contains(newcube.name)) {
// don't add to list
}
else {
cubelist.add(newcube);
}
Method contains in class java.utilArrayList is the way to go but you need to be aware that method contains [eventually] calls method equals of its element type. In your case, the element type is Cube. Therefore you need to add a equals method to class Cube. I don't know what determines whether two Cube objects are equal, but I'll guess, according to your question, that they are equal if they have the same name, even when they have different lengths. I will further assume that name cannot be null. Based on those assumptions, here is a equals method. You should add this method to class Cube.
public boolean equals(Object obj) {
boolean areEqual = false;
if (this == obj) {
areEqual = true;
}
else {
if (obj instanceof Cube) {
Cube other = (Cube) obj;
areEqual = name.equals(other.name);
}
}
return areEqual;
}
Now, in method main of class PartFive you can use the following if to add a Cube to the list.
if (!cubelist.contains(newcube)) {
cubelist.add(newcube);
}
You can check for duplicate names in the cubelist array using lambda expressions (for better readability):
boolean isNameAlreadyExisting = cubelist.stream()
.anyMatch(cube -> cube.getName().equals(newcube.getName())); // this is returning true if any of the cubelist element's name is equal with the newcube's name, meaning that the name is already existing in the cubelist
if (!isNameAlreadyExisting) {
cubelist.add(newcube);
}
One thing that you should do is to remove the while(true) instruction which causes an infinite loop.
Another suggestion is to display the name of objects contained by cubelist, to see that indeed the names are not duplicated:
cubelist.stream()
.map(Cube::getName)
.forEach(System.out::println);

Java Passing variables, avoiding toString hash

I know this has been asked before, but not in a way I understood, because I am dumb.
So.
I need to take some variables into a class, compare them against something, and then return the higher of the two. In the long run, I need to compare against a running total, but for my problem, I think the issue is considerably more fundamental. I'm not understanding how to pass a variable BACK to my main class.
import java.io.*;
public class testing123 {
public static void main(String[] args) {
InputStreamReader input = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(input);
Integer a;
Integer b;
Integer numbersCombined;
try {
System.out.println("Please enter a number");
a = Integer.parseInt(reader.readLine());
System.out.println("Please enter a number");
b = Integer.parseInt(reader.readLine());
numbersCombined = (a + b);
testClass Check = new testClass();
System.out.println("Your numbers combined is " +numbersCombined);
System.out.println(Check);
} catch (IOException e){
System.out.println("Error reading from user");
}
}
}
class testClass {
public static Integer testClass (Integer numbersCombined) {
if (numbersCombined > 100) {
numbersCombined = numbersCombined;
}
else {
numbersCombined = 100;
}
System.out.println(numbersCombined);
return numbersCombined;
}
}
If I remove the return, this will print the numbersCombined, but that's all it does. With the return in place, it doesn't execute the print line above the return, and first prints the original numbersCombined (which it shouldn't if you use, say, 10 and 20, since that's less than 100), and then prints testClass#76046e53 rather than the actual value. I know there's a way to override it, but the answers I've found don't work for me.
I know this answer: http://www.google.com/url?q=http%3A%2F%2Fstackoverflow.com%2Fquestions%2F29140402%2Fhow-do-i-print-my-java-object-without-getting-sometype2f92e0f4&sa=D&sntz=1&usg=AFQjCNGIzxlBSH8xIS7hurKe6_Euc7B8RQ
is the basic problem I'm encountering, but the overrides listed aren't really working for me, and I want integer anyway, rather than string.
In the end, what I'm "really" doing is taking a series of 4 numbers from a user, then using this function to compare whether THIS series of numbers is higher than the previous maximum, and if it is, that's the new maximum moving forward, with a loop until the user is done entering serieses of 4 numbers, and then finally printing the maximum.
I was able to write this without ANY functions, all inline, easy as pie. But once I send the comparison to a function, I don't understand how to send it back, and I've spent all day trying to understand the concept. ALL DAY. So, while I know it's going to be a stupid answer, that's because I'm stupid, but not because I didn't try (sorry, kind of defensive. Frustrated).
Fundamentally, I want to send two (this example is just one) variables to a class, compare them, change ONE of them, and return it to the main class. In this example, I'm just trying to send ONE variable, compare it, and the send it back.
You need to call the method within TestClass. Your code is already returning an integer from that method.
Once you instantiate the class run testClass.testClass(numbers)
The way you're throwing around pseudo-global variables between classes is probably the problem. Pass them through the calls like above, rather than implicitly.
Try to do something like this:
import java.io.*;
public class HelloWorld{
public static void main(String []args){
InputStreamReader input = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(input);
Integer a;
Integer b;
Integer numbersCombined;
try {
System.out.println("Please enter a number");
a = Integer.parseInt(reader.readLine());
System.out.println("Please enter a number");
b = Integer.parseInt(reader.readLine());
numbersCombined = (a + b);
testClass Check = new testClass(numbersCombined); // constructor should be like this
System.out.println("Your numbers combined is " + numbersCombined);
System.out.println(Check);
} catch (IOException e){
System.out.println("Error reading from user");
}
}
}
class testClass {
Integer numbersCombined;
// This is a constructor
public testClass (Integer numbersCombined) {
if (numbersCombined > 100) {
this.numbersCombined = numbersCombined; // use this to represent the object
} else {
this.numbersCombined = 100;
}
System.out.println(numbersCombined);
}
// Add method toString()
public String toString() {
return this.numbersCombined.toString();
}
}

Breaking Out Of A Loop Using A Method In Java

I am trying to use a method to double check before a user exits a while loop in my program.
private static Scanner input = new Scanner(System.in);
public static void ays() {
System.out.println("Are you sure?");
String ays = input.nextLine();
if (ays.equals("Yes")) {
break;
} else {
continue;
}
}
Upon running the program, I get the error break outside switch or loop, and continue outside switch or loop. Is there any way to achieve my goal here?
I guess you are invoking ays() inside a while loop. Let the return type of ays() be boolean and let it return either true or false. Invoke ays() from inside the while loop and based on the value returned by ays(), you continue or break out of the loop.
while (true) {
//Do Something
if (ays()) {
continue();
} else {
break();
}
}

Java - Add an object to an arraylist, then adding another to the arraylist causes the first element to be overwritten

I'm currently doing my third year programming project and its a folio tracker. :/ I have crated Stock_API and Portfolio_API interfaces (and implementations of them) and a GUI class which when instantiated takes two parameters as so:
public GUI(Portfolio_API p, Stock s){
tempPort = p;
tempStock = s;
}
I use this constructor as a way of getting implementations of these interfaces into the GUI without exposing the implementation to the GUI (which is one of the main objectives of this project). A portfolio object has a name(string) and an ArrayList. A stock object has a ticker symbol(string), a stock name(string), a share value(float), a number of shares(int) and a value of holding(float).
In the GUI i have a portCollection array list which holds objects of type portfolio_API and this is so the system can keep track of multiple portfolios. Also as mentioned in the block of code above has a tempStock and tempPort object.
Sorry to give u so much detail about the program but i thought it best so i could get the context across. Anyway, the problem at hand. I have a method which uses the GUI to get a ticker symbol, a stock name and a number of shares and adds the stock to the current portfolio open(each portfolio has its own tab). The method looks like this:
public void addStock() {
int num_shares = 0;
float dailyChange = 0.0f;
float stockValue = 0.0f;
boolean succeed = true;
// GUI gets information of stock from user
String ticker = JOptionPane.showInputDialog(frame,
"Enter the ticker symbol:");
String stockName = JOptionPane.showInputDialog(frame,
"Enter the Stock name:");
try {
num_shares = Integer.parseInt(JOptionPane.showInputDialog(frame,
"Enter the number of shares:"));
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(frame,
"Number of shares was not an integer. Try again");
succeed = false;
}
// If parsing was successful...
if (succeed) {
tempStock.setTicker(ticker);
tempStock.setNumberOfShares(num_shares);
tempStock.setStockName(stockName);
// Fetches newest value using the current ticker symbol
boolean succeedUpdate = tempStock.updateShareValue();
if (succeedUpdate) {
tempStock.calculateValueOfHolding();
// Adds to the current portfolio...
String tabName = tabbedPane.getTitleAt(tabbedPane
.getSelectedIndex());
System.out.println(tabName);
findPortfolio(tabName).addStock(tempStock);
findPortfolio(tabName).sort();
// ...Then adds it to the table
JPanel j = (JPanel) tabbedPane.getSelectedComponent()
.getComponentAt(0, 0);
JViewport v = ((JScrollPane) j.getComponent(0)).getViewport();
JTable table = (JTable) v.getComponent(0);
float currentTotal = findPortfolio(tabName).getTotal();
// Updates the total label
((JLabel) j.getComponent(1)).setText("Total: " + currentTotal);
Object[] newStock = { tempStock.getTicker(),
tempStock.getStockName(),
tempStock.getNumberOfShares(),
tempStock.getShareValue(),
tempStock.getValueOfHolding() };
((DefaultTableModel) table.getModel()).addRow(newStock);
}
}
}
When I add more than one stock, the new stock takes place of the old one an effectively overwrites it. I think its the reuse of tempStock that is doing it. Not sure why though as surely if i add the variable to an arraylist it becomes part of that arraylist and needs no association with the tempStock variable?
Methods that are used with the mentioned arraylists :
private Portfolio_API findPortfolio(String name) {
Portfolio_API p = null;
for (int i = 0; i < portCollection.size(); i++) {
if (portCollection.get(i).getName() == name) {
p = portCollection.get(i);
}
}
These two are in the Portfolio class:
#Override
public boolean addStock(Stock_API s) {
if (!doesExist(s)) {
portfolio.add(s);
return true;
} else {
return false;
}
}
#Override
public boolean doesExist(Stock_API s) {
boolean found = false;
for (int i = 0; i < portfolio.size(); i++) {
if (portfolio.get(i).getTicker() == s.getTicker()) {
found = true;
}
}
return found;
}
I've only come here for help because i have hit a brick wall and I really need help. If anyone could give me any suggestions, i'd be eternally in your debt.
Thanks,
Chris
Yes, I think you are right when you say you think it's because you're reusing the tempStock variable. This variable still references the original object so calling setTicker() etc on tempStock also changes the object referenced by your ArrayList because it's the same object. Try reinitialising your tempStock and see if it makes a difference:
// If parsing was successful...
if (succeed) {
tempStock = new Stock(); // or however you instantiate this object
tempStock.setTicker(ticker);
tempStock.setNumberOfShares(num_shares);
tempStock.setStockName(stockName);
Thanks guys for all your input. #oracle certified professor helped with the stock problems after adding an overloaded method for addStock but turned out the same problems plagued portfolio.
What I did was create a makePortfolio method in Portfolio_API to create a new portfolio and return it. That way it avoids any nasty overwrite, gonna add it to stock too just now.
Thanks again guys. Good night! :)

confirming program flow

can someone tell if the code below would work fine?
class CriticalSection{
int iProcessId, iCounter=0;
public static boolean[] freq = new boolean[Global.iParameter[2]];
int busy;
//constructors
CriticalSection(){}
CriticalSection(int iPid){
this.iProcessId = iPid;
}
int freqAvailable(){
for(int i=0; i<
Global.iParameter[2]; i++){
if(freq[i]==true){
//this means that there is no frequency available and the request will be dropped
iCounter++;
}
}
if(iCounter == freq.length)
return 3;
BaseStaInstance.iNumReq++;
return enterCritical();
}
int enterCritical(){
int busy=0;
for(int i=0; i<Global.iParameter[2]; i++){
if(freq[i]==true){
freq[i] = false;
break;
}
}
//implement a thread that will execute the critical section simultaneously as the (contd down)
//basestation leaves it critical section and then generates another request
UseFrequency freqInUse = new UseFrequency;
busy = freqInUse.start(i);
//returns control back to the main program
return 1;
}
}
class UseFrequency extends Thread {
int iFrequency=0;
UseFrequency(int i){
this.iFrequency = i;
}
//this class just allows the frequency to be used in parallel as the other basestations carry on making requests
public void run() {
try {
sleep(((int) (Math.random() * (Global.iParameter[5] - Global.iParameter[4] + 1) ) + Global.iParameter[4])*1000);
} catch (InterruptedException e) { }
}
CriticalSection.freq[iFrequency] = true;
stop();
}
No, this code will not even compile. For example, your "UseFrequency" class has a constructor and a run() method, but then you have two lines CriticalSection.freq[iFrequency] = true; and
stop(); that aren't in any method body - they are just sitting there on their own.
If you get the code to compile it still will not work like you expect because you have multiple threads and no concurrency control. That means the different threads can "step on eachother" and corrupt shared data, like your "freq" array. Any time you have multiple threads you need to protect access to shared variables with a synchronized block. The Java Tutorial on concurrency explains this here http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html
Have you tried compiling and testing it? Are you using an IDE like Eclipse? You can step through your program in the debugger to see what its doing. The way your question is structured no one can tell either way if your program is doing the right or wrong thing, because nothing is specified in the comments of the code, nor in the question posed.

Categories

Resources