Health counter for game - java

I am having an issue with a health counter in my battleship game. What I need is that when the method is called, it will take 1 off of health. So let's say that the health is at 3, the method is called when the players ship takes a hit. Then I need it to go health-1, and keep that value. Then when the health=0, the game will end.
Any questions and improvements to this code is welcome, as well as criticism.
UPDATED:
public static void enemyShoot (int row, int col)
{
int shot1;
int shot2;
int health = 3;
Random enemyshot = new Random();
shot1 = enemyshot.nextInt(5)+1;
shot2 = enemyshot.nextInt(5)+1;
if (shot1 == row && shot2 == col)
{
System.out.println("You Have Been Hit");
health = Health(health);
}
}
public static int Health (int health)
{
if (health == 0){
System.out.println("You dead");
System.exit(0);
}
health = health-1;
return health;
}

You are initializing health to 0
int health = 0;
Then when your shot hits the target you
Health(health);
Which subtracts 1 and then tests for 0
health = health-1;
if (health == 0)
your health is now at -1 so it never == 0
You should set health to some positive value and or change your test to
if (health <= 0)

When you pass health as a parameter to Health method, it makes a copy to use in this method. So, when you decrement and analyse it, the copy gets decremented to 2 (if you initially passed 3), but the original variable is still equal to 3. So, in fact, the health counter is never decremented.
It's called "passing argument by value", you can check out this question: What's the difference between passing by reference vs. passing by value?
The right thing to do is to decrement the value inside your method and then return the result. You should also call your method like this:
health = Health(health);
Also, arsendavtyan91 is right, you start with health = 0... you might want to pass the actual value to the method enemyShoot

You were close with your Health method, what you would want is something like this:
public static void hit() {
this.health--;
if (health <= 0) {
System.out.println("You died.");
System.exit(0);
}
}
Java is a pass-by-reference so you need to update the health of the object that just got hit. In this case I am assuming your Health() is inside of that object.
Otherwise you start with your health = 3; and every time it gets hit it will become health = 2; but the object that is being hit will always stay at 3 health. Again, without seeing any more of your code I can't tell exactly the best way to do this, so I had to assume a few things.
It should be noted that this will exit the program very quickly and you won't even see the You died message.

You need not subtract if health is equal to zero.
The game will continue since you always initialize health on the line int health = 3; in the enemyShoot() method, right before going to call the Health() method.
So I suggest you declare health inside the class (like a global variable) and initialise it by passing it to the a constructor like this:
int health;
public ClassName(int health){//this is a constructor with the `health` argument
this.health = health;
}
public static void enemyShoot (int row, int col)
{
int shot1;
int shot2;
Random enemyshot = new Random();
shot1 = enemyshot.nextInt(5)+1;
shot2 = enemyshot.nextInt(5)+1;
if (shot1 == row && shot2 == col)
{
System.out.println("You Have Been Hit");
health = Health(health);
}
}
public static int Health (int health)
{
if (health == 0){
System.out.println("You dead");
System.exit(0);
}
health = health-1;
return health;
}

First, you should really read more about the basics of object oriented programming. My answer is based on that little snippet of code you provided, so I'm not sure if there already is a proper implementation...
However, I think what you want is to create a Battleship Object, which has initial health as a member variable. You could define coordinates, orientation etc with parameters, but I'll leave them out from this example. After you have managed to create this object, use enemyShoot method to calculate if battleship has been hit and decrease health that is the case. Which comes out something like this:
public class Battleship {
int m_health;
public BattleShip() {
m_health = 3;
}
public enemyShoot(int x, int y) {
// TODO: calculate if hit
if (hit == true) {
m_health--;
if (m_health == 0)
System.out.println("You dead");
System.exit(0);
}
}
}
So to use the code above I would put it in a file called Battleship.java and create a main method which would initialize the objects I wish to use
public static void main(String ... args) {
Battleship bs = new Battleship(); // <-- Creates a new Battleship object
bs.enemyShoot(0,0); // <-- shoot the battleship
bs.enemyShoot(0,0);
bs.enemyShoot(0,0); // <--At this point battleship would be destroyed, if hit
}
The problem with the Health method you provide is that is takes primitive data type int as parameter (initially set as 0) which gets assigned -1 every time Health is called. Callign this method does not have affect on health value inside enemyShoot method, since this is NOT an Object but a inner method variable of primitive data type.
Hope this helps you to get on with your assignment. :)

Related

Java recursive function below what is the problem?

public static int score(int[][] array, int win, int turn) {
int score = 0;
if (GamePrinciples.gameEnd(array, win)) {
if (GamePrinciples.draw(array)) {
score = 0;
} else if (GamePrinciples.winningBoard(array, win)[0] == 1) {
score = 1;
} else {
score = -1;
}
} else {
for (int[][] i : children(array, win, turn)) {
score += score(i, win, GamePrinciples.nextPlayer(turn));
}
}
return score;
}
briefly this program is part of my minimax algorithm. So the problem is that I get a stack over flow. Where am I going wrong?
if an array is in ending mode then if it is a draw it gives a score of zero if player one wins then a score of one and if player two wins it gives a score of two.
if the array is however not in the ending state we get the children of the array (immediate children that is the boards that result from the current board with only one move). The score of the board will be the sum of the score of each of its children. The logic seems okay and the other methods such as children, nextPlayer, winningBoard, draw all work fine with testing. So I am guessing there is problem with this kind of recursive implementation. Can anyone help? Thanks in advance
Your code seems wrong in the loop:
for (int[][] i : children(array, win, turn)) {
I haven’t tested, but you should call the method children() outside the for.
By calling the method within the for clause, you are always returning the initial array instead of iterating through it.
So try putting the children() method return to a variable and iterate through this variable.
Something like:
… c = children(…)
for(int[][] i : c) {
…

Random number guessing game with limitations after each guess

I am making a number guessing game:
The computer generates a number inside an interval
I try to guess it and receive a reply whether it's higher/lower than my guess or equals to my guess and I've won
There is an interval in which I can guess, as well as a guess attempt limit
The trick is, however, that I need to implement another condition: each guess should "shrink" the interval in which I'm able to guess. For example: computer generates 50, I guess 25, computer replies "The random number is larger.". Now knowing that, I should not guess anything lower than 25 again, it's unreasonable. In case I guess i.e. 15, the computer should reply "The guess doesn't make sense.". I understand that I somehow need to save each guess value to a new variable, but nothing seems to work. I'm a beginner, please bear with the following code, I've tried a lot of things:
public String guess(int guess)
{
int lowerBound = 0;
int upperBound = 99;
Set<Integer> lowerGuesses = new TreeSet<>();
Set<Integer> higherGuesses = new TreeSet<>();
if (gameOver) {
return "The game is over.";
}
if (guess < 0 || guess > 99) {
return "The guess is out of bounds.";
}
if (guessCount < maxGuessCount) {
if (guess < secretNumber) {
if (lowerGuesses.contains(guess)) {
return "The guess doesn't make sense.";
}
else {
guessCount++;
lowerBound = guess;
lowerGuesses.add(guess);
return "The random number is larger.";
}
}
if (guess > secretNumber) {
if (higherGuesses.contains(guess)) {
return "The guess doesn't make sense.";
}
else {
guessCount++;
upperBound = guess;
higherGuesses.add(guess);
return "The random number is smaller.";
}
}
if (lowerGuesses.contains(guess)) {
return "The guess doesn't make sense.";
}
if (higherGuesses.contains(guess)) {
return "The guess doesn't make sense.";
}
}
if (guess < lowerBound || guess > upperBound) {
return "The guess doesn't make sense.";
}
if (guessCount == maxGuessCount) {
gameOver = true;
victorious = false;
return "Ran out of guess attempts.";
}
guessCount++;
gameOver = true;
victorious = true;
return "You won.";
}
Thank you in advance!
First, to avoid confusion, let's rename the method in order to make sure that its name is not an exact match with its parameter, so this is how it should look like:
public String makeGuess(int guess)
avoid naming different entities in the same name space with the exact same name (local variables being present in different methods or parameters having similar names with data members for the purpose of initialization are an exception). From now on, you will call the method as makeGuess(25), for example.
Now, to the actual problem. You have an incorrect assumption. You assume that you need to keep track of past intervals. That's not the case. You can just change the edges of the intervals. Also, your code is superfluous, I advise you to refactor it. Finally, you always initialize upper bounds, local bounds and higher and lower guesses as local variables, so they will never be kept track of. Instead of this, you need to perform the following simple measures in order to make this work:
Define the bounds and limit as data members
protected int lowerBound = 0;
protected int higherBound = 99;
protected int lb = 0;
protected int hb = 99;
protected int limit = 5;
protected int guessCount = 0;
protected int randomizedNumber; //Initialize this somewhere
Note that I have hard-coded some values. You might want to make this dynamic with initialization and stuff like that, but that's outside the scope of the answer. lowerBound, higherBound, limit are game settings. while lb, hb, guessCount represent the game state. You could separate this logic into another class, but for the sake of simplicity, even though I would program differently, I will leave them here in this case.
Have a method that initializes the game
public void initialize() {
lb = lowerBound;
hb = higherBound;
guessCount = 0;
}
So you separate your concern of game initialization from the outer logic of starting and maintaining a game.
Implement makeGuess in a simplistic way
public String makeGuess(int guess) {
if (++guessCount >= limit) return "The game is over.";
else if ((lb > guess) || (hb < guess)) return "The guess doesn't make sense";
else if (randomizedNumber == guess) return "You won.";
else if (guess < randomizedNumber) {
hb = guess;
return "The random number is smaller.";
} else {
lb = guess;
return "The random number is larger.";
}
}
NOTE: I dislike mixing up the logic with the output layer, the reason I did it in the method above was that you have mentioned you are a beginner and my intention is to make this answer understandable for the person who just begun programming and is very confused. For the purpose of actual solutions, you should return a state and in a different layer process that state and perform the console/UI operations you need. I will not go through the details now, as it would also be outside of scope, but for now, please have some success with the solution above, but THEN you should DEFINITELY look into how you need to code, because that is almost as important as making your code work.

Creating a Vehicle Program

Right now I'm doing some tasks from a java e-book that I've acquired, and unfortunately, I'm stuck. The main thought of this program is to create a Vehicle class, which along with a test program can increase, decrease and break the current speed.
The starting speed should be 0. I want the user to specify what speed the car should drive to (for an example 90 km/h). After hitting the speed(90 in this case) I want the program to ask the user if he wants to decrease the speed to a given value, stay at the same speed, or break to 0. Should all of this be done in the testprogram, or should it be implemented into the Vehicle class?
I'm supposed to create a program from the following UML: https://i.stack.imgur.com/01fgM.png
This is my code so far:
public class Vehicle {
int speed;
//Constructor
public Vehicle () {
this.speed = 0;
}
public void increaseSpeed (int differenceInc) {
this.speed += differenceInc;
}
public void decreaseSpeed (int differenceDec) {
this.speed -= differenceDec;
}
public void brake() {
}
public int getSpeed () {
return this.speed;
}
}
And this is my empty test class.
public class VehicleTest {
public static void main(String[] args) {
Vehicle golf = new Vehicle();
//Speed which should be accelerated to:
Vehicle myHybrid = new Vehicle();
System.out.println("You've hit the given speed. Do you want to stay at this speed, break, or decrease to another given speed?");
}
}
Well , first of all, welcome to Stack Overflow.
If you want a method to accept arguments (parameters) then you must declare said arguments and the arguments' types in the mehtod declaration:
public void increaseSpeed (int augmentValue) {
this.speed += augmentValue;
}
You're also asking about software design: "should the component (Vehicle) user or client be able to set the augment value of the increaseSpeed mehtod?" . The answer relies on the design of said component. If your method will accept an argument then perhaps the method should also validate the input value and establish pre and post conditions.
Hope this helps.
Probably the idea is to take an int for increaseSpeed(), so that you can increase the speed by that given integer. Also add the logic for hitting the speed limit in your increaseSpeed method.
So...
public void increaseSpeed (int amount) {
if (speed + amount < MAX_SPEED) { // Where MAX_SPEED is a static final int of value 90
this.speed += amount;
} else {
System.out.println("Max speed reached. Want to exceed (y/n)?");
Scanner scanner = new Scanner(System.in);
char c = scanner.next().charAt(0);
if (c == 'y') {
this.speed += amount;
}
}
}
You can do the same for decreaseSpeed(), of course. Don't forget to check if decreasing the speed doesn't result in a negative speed (unless, you consider a negative value of speed to be driving in reverse.
By the way, here I have hard-coded MAX_SPEED for simplicity. This is, of course, dependent on the road you are driving, so it is probably better to do this differently (e.g., a Road class that includes the particular attributes of a given road, or by passing both an integer for the amount you want to speedup with and an integer for the maximum speed).

Battleship stuck on battle board implementation

we recently somewhat learned Object Oriented Programming and already have a project on it due soon, so I am not too familiar with OOP. However, we were assigned a project of creating a Battleship game.
I have created a ship, square, and battle board class. I have tested all three, and all tests have also passed except for one method on Battleboard classs. To test each class, I used a toString method. This is in my battle board's toString method:
for (int i = 0; i < squares.length; i++) {
Just a couple of problems that I spotted, there can be more as the code is still incomplete:
A. In the very beginning of
public boolean addShip(int length, boolean isHorizontal, int startRow, int startCol) {
there is
square = new Square();
It seems logical to check whether a ship exists at the square to which you add it, but instead you check whether it exists in a brand new square. We don't have Square code, but I assume that it does not have a ship initially.
B. In the same method there is the following code:
if (isHorizontal == true) {
ship = new Ship(length, isHorizontal, startRow, startCol);
for (int i = 0; i < ship.getLength(); i++) {
if (startCol > numberOfColumns) {
return false;
} else {
square.addShip(ship);
startCol++;
}
}
}
So the ship is being repeatedly added to the same brand new square which is not related to the board. Later, that square is not added anywhere and now used anyhow.
I'm not sure how to fix this, but probably all the squares should have been inialized before this method is called, no squares should been created in this method; instead, you need to find a square corresponding to the current iteration`.
C. The following code
} else if (!square.hasBeenHit() && square.hasShip()) {
//Returns length of ship if there is a ship that hasn't been hit
if (ship.getLength() == 1) {
toString += "1 ";
} else if (ship.getLength() == 2) {
toString += "2 ";
} else if (ship.getLength() == 3) {
toString += "3 ";
} else if (ship.getLength() == 4) {
toString += "4 ";
}
}
uses the same ship on all iterations, so it behaves in the same way on all the iterations (appends 1). The correct thing would be to find a ship belonging to the current square (i, j), if it exists, and use it.
D. A brand new square is created on each loop, again, although you are iterating over squares! It would be more logical to write square = squares[i][j] instead of square = new Square().
I'd recommend you to use a debugger to see what happens in your code.

checkDeath() not being called

I am working on a Tower Defense project and I am running into a little issue.
public void loseHealth(int amo) {
health -= amo;
checkDeath();
}
public void checkDeath() {
if(health == 0) {
deleteMob();
}
}
This works, but when I try the following the health reaches zero and the mob does not get deleted. I have been trying to get this working for about 2 days and cannot seem to get it right. I have been unsuccessful at finding something to read that could help but I may not be looking in the right place.
public void loseHealth(int amo) {
shot = Value.damage[0] += amo;
health -= shot;
checkDeath();
}
public void checkDeath() {
if(health == 0) {
deleteMob();
}
}
I declared an array and that consists of:
public static int[] damage = {5, 10};
The reason I have two here is because I have two towers I am trying to have do different damage. Right now I just want to get it working I can do the part for the different towers. If there is more information you need please let me know.
That is because your health variable is getting decreased below 0. Therefore, health == 0 will always return false. Try the following instead:
public void checkDeath() {
if(health <= 0) {
deleteMob();
}
}
It looks possible that your loseHealth method could produce a negative value for health. If this is the case then your checkDeath method would have to use if(health <=0) for the condition.
Your problem is that you're checking explicitly if your health integer is at 0. Most likely, the mob's health counter is a negative number after getting inflicted damage.
Use
if(health <= 0)
Instead of
if(health == 0)

Categories

Resources