Calling a method originated from a switch case from another class - java

I am relatively new to java and I have been assigned a project. I need to make a rather complicated(for a newbie) battleship game.
Here, I try to call switch cases in class Player from class Tile. Since I've read that one can't directly have access to a switch case, I have made the methods caseSea(), caseShip() e.t.c.
When trying to call them in class Player I get a 'void' type not allowed here error, which I understand but have no idea how to fix!
Any help would be appreciated thanks!
Here is class Tile created to represent one block of a 2D array that will become the battleground board:
public class Tile
{
private int x,y;
static boolean hidden;
public Action tile_action;
public enum Action
{
Sea,
Ship,
Hit,
Miss
}
Action action;
public Tile(Action action)
{
this.action=action;
this.x = x;
this.y = y;
this.tile_action = action;
}
public static void caseSea()
{
System.out.println("~");
}
public static void caseShip()
{
if(hidden == true)
System.out.println("~");
else
System.out.println("s");
}
public static void caseHit()
{
System.out.println("X");
}
public static void caseMiss()
{
System.out.println("O");
}
public static void draw(Action action)
{
switch(action)
{
case Sea:
caseSea();
break;
case Ship:
caseShip();
break;
case Hit:
caseHit();
break;
case Miss:
caseMiss();
break;
}
}
}
Also here is class Player which contains the call to the switch case:
import java.util.Scanner;
public class Player
{
String username; //Variable declaration
static int shotcount;
static int misscount;
static int hitcount;
static int repeatshot;
private int HitPosition[][] = new int[10][10];
public Player(String username)
{
this.username = username;
}
private void placeAllShips()
{
//super.placeAllShips();
}
public void fire(int pos[],int board,boolean hit)
{
if(hit == true)
{
HitPosition[pos[0]][pos[1]] = Tile.draw(Tile.caseHit());
shotcount++;
hitcount++;
}
else
{
HitPosition[pos[0]][pos[1]] = Tile.draw(Tile.caseMiss());
shotcount++;
misscount++;
}
}
}
I get the error that I mention above, in Tile.draw(Tile.caseHit()) and Tile.draw(Tile.caseMiss())

Heh, since this is a relatively simple issue I wanted to stick to comments, but I feel I need to make my voice since the other answers are simply wrong.
What the other guys are suggesting is changing the return type of the methods, and that indeed can work but not with the code you have.
They would ultimately be called twice, and thats not what you want.
The call order would be
caseHit()
pass the caseHit()'s value to draw()
enter a switch inside the draw() method with the Hit enum value and ultimately call caseHit() again.
This is not what you want to do. All you wanna do is call the draw() method with the right argument, which in this case is one of the Action enum values.
So ultimately there is a very easy way to fix your code without much changes and this is changing
Tile.draw(Tile.caseHit());
to
Tile.draw(Tile.Action.Hit);
(and by analogy the other calls of this method)

With Tile.draw(Tile.caseHit()) you are trying to call the caseHit() method and sending the return value of that method as a parameter to the draw() method. The problem is that the caseHit() method isn't returning anything as it has a void return type.
You could fix this by making the caseHit() method return an Action:
public static Action caseHit() {
return Action.Hit;
}

Related

Getting Variables From Java constructor

I'm new to Java programming, sorry if this is a dumb question.
I find it hard to word this question properly, but I have an assignment to create a aircraft class that can make aircraft land, takeoff etc. And need to test it using Testclass. When the new object are entered it automatically assigns a unique ID to the aircraft in the constructor.
I can do this using a instance method fine as it has a return value which is returned to to Testclass. The question wants me to do this in the constructor itself, however, the constructor never returns anything. So the variable never gets sent to the Testclass. I clearly am not understanding OOP properly. Even when I try to just use a getter method to get the ID created in the constructor it gives me the initialized variable before the the constructor has worked on this. This is the code I have so far and its completely wrong I know but if someone could point me in the right direction or tell me how to word this question better it would be a massive help.
// I need to enter 3 aircraft into the system in the testclass
public class Aircraft {
private int aircraftID;
private static int lastID;
private String airportcode;
private int ID = 100;
private int count;
public Aircraft(int a, int b, int c){
// Constructor
// Assign ID
this.ID = a;
lastID = ID;
ID++;
this.ID =b;
lastID = ID;
ID++;
}
}
OK, you want to create an Aircraft that has an automatically-assigned unique identifier, and can take off and land. That implies you need a field for tracking the identifier, a field for tracking whether it's in the air (or not), and methods for the take off and land operations. You also need a static field for generating the unique identifiers. (Note that this implementation isn't thread safe.)
private class Aircraft {
private static int staticId = 0;
private int uniqueId = 0;
private boolean onGround = true; // Aircraft start on the ground in this implementation
public Aircraft(){
this.uniqueId = staticId; // putting this line first makes uniqueId zero-indexed in effect
staticId++;
}
public void land(){
onGround = true;
}
public void takeoff(){
onGround = false;
}
public boolean isFlying(){
return !onGround; // If it's not on the ground, it's flying
}
public int getUniqueId(){
return uniqueId;
}
}
Unit tests checks all of the methods and expected functionality of the class in question:
import org.junit.Test;
import static org.junit.Assert.*;
import Aircraft;
class Testclass {
private final Aircraft aircraft = new Aircraft();
#Test
public void hasId(){
aircraft.getUniqueId() >= 0;
}
#Test
public void canLand(){
assertTrue(aircraft.land());
}
#Test
public void canTakeOff(){
assertTrue(aircraft.takeOff());
}
#Test
public void checkFlightOperationsAreTrackedCorrectly(){
aircraft.land();
assertFalse(aircraft.isFlying());
aircraft.takeOff();
assertTrue(aircraft.isFlying());
}
}
As pointed out a constructor does not return anything (the simplified version is that with new it returns an object instance). I am kinda guessing at what you are trying to acomplish, but I'll have a go anyways. It seems to me that you are trying to cram the construction of 3 objects into one constructor - which is why your constructor has 3 parameters. Also you are playing havoc with the IDs.
I have removed all the variables that I didnt quite understand, leaving only ID that increments with each instantiated Aircraft. The #Override is mainly just for show.
public class Aircraft {
private int aircraftID;
private static int lastID = 0;
#Override
public String toString(){
return "Aircraft_" + this.aircraftID;
}
public Aircraft() {
lastID++;
this.aircraftID = lastID;
}
}
I took the liberty and wrote the TestClass just to see if we have the same thing in mind. Again the printAircraft() method is for show.
public class TestClass {
private List<Aircraft> aircrafts;
public TestClass(){
aircrafts = new ArrayList<>();
}
public void addAircraft(Aircraft a){
aircrafts.add(a);
}
public void printAircraft(){
Iterator<Aircraft> it = aircrafts.iterator();
while(it.hasNext()){
System.out.println(it.next().toString());
}
}
}
and to test it, we create and instance of TestClass add 3 Aircraft instances and print out the contents
public static void main(String[] args) {
TestClass tc = new TestClass();
tc.addAircraft(new Aircraft());
tc.addAircraft(new Aircraft());
tc.addAircraft(new Aircraft());
tc.printAircraft();
}
This would be the case if you are to write the TestClass. If that is given, it would help to know what it looks like - maybe that would help us understand better.

Why won't the if statement detect my game state

I am new to Java and I have come across a "bug" in my code that I am having trouble understanding/fixing. To give you some background knowledge, I set up an Enum that states all the game states (below)
public enum GameState {
IN_LOBBY(true), IN_GAME(false), POST_GAME(false), RESETTING(false);
private boolean canJoin;
private static GameState currentState;
GameState(boolean canJoin) {
this.canJoin = canJoin;
}
public boolean canJoin() {
return canJoin();
}
public static void setState(GameState state) {
GameState currentState = state;
}
public static boolean isState(GameState state) {
return GameState.currentState == state;
}
public static GameState getState() {
return currentState;
}
}
In my main.java class I specify in the onEnable method to set the GameState to IN_LOBBY.
Basically what I am trying to do is in a BlockBreakEvent Listener I want to say is
if (GameState.isState(GameState.IN_LOBBY)) {
Location bLoc = block.getLocation();
ChatUtilties.errorPlayer("You may not break blocks at this time.", player);
bLoc.getBlock().setType(Material.type);
}
In other words I am trying to detect if the GameState is IN_LOBBY and if so make it so that players can not break blocks. But currently two problems have arisen.
For some reason when the GameState is IN_LOBBY the plugin won't even take notice. It just ignores that if statement. It won't even send the message, as if the gamestate was not IN_LOBBY.
I'm not sure how to dynamically change the material based on what block the player broke.
Your setter is wrong:
public static void setState(GameState state) {
GameState currentState = state;
}
You are creating a new local variable currentState here, instead of using the existing field. This happens because you wrote the variable type in front of it, creating a new initialization statement.
Instead use:
public static void setState(GameState state) {
currentState = state;
}
(Since currentState is a static field GameState.currentState = state; would also work in this case)
Edit:
Another problem is with your canJoin method.
public boolean canJoin() {
return canJoin();
}
this method calls itself recursivly without any end condition. So you will get a StackOverflowException if you ever try to call it.
Instead you probably meant to return the canJoin field:
public boolean canJoin() {
return canJoin;
}

Abstract methods without abstract classes

I'm kinda new to Java, and I'm trying to write an RPG of sorts.
Now, in the game the player character would have skills. These could be very diverse, from hurting enemies to healing the player and a lot of other things. It'd make sense to create a Skill class with an abstract applyEffect() method, to be defined on each particular skill.
However, I cannot have a non-abstract class containing abstract methods, and every skill should be an object of the Skill class, so it can't be abstract. The obvious solution is to make the Skill class abstract and create a subclass for every single skill, and then instantiate that into an object to use.
This approach seems a bit redundant. Is there anything else I could conceivably do in this situation?
EDIT: While we're at it, if I want an object that will appear a single time with standard variables, is there any workaround to making a class just for that one object and then instantiating it?
I would not write skills (like 'heal' and 'hide') as classes. I view classes as objects (players), and methods as abilities (skills). Skills like 'heal' or 'hide' are clearly better as methods than classes.
I would simply have one class that has all methods, but only the selected ones are available for use. Having the skills as enums isn't a bad idea either.
enum Skill {
HEAL, HIDE, ATTACK, THROW
}
class Player {
boolean canHeal = false;
boolean canHide = false;
boolean canAttack = false;
boolean canThrow = false;
Player(Skill[] skills) {
for(skill : skills) {
switch(skill) {
case Skills.HEAL: canHeal = true;
break;
case Skills.HIDE: canHide = true;
break;
case Skills.ATTACK: canAttack = true;
break;
case Skills.THROW: canThrow = true;
break;
default: //error
}
}
}
void heal() {
[...]
}
void hide() {
[...]
}
void attack() {
[...]
}
void throw() {
[...]
}
boolean canHeal() {
return canHeal;
}
boolean canHide() {
return canHide;
}
boolean canAttack() {
return canAttack;
}
boolean canThrow() {
return canThrow;
}
}
Now the players can be restricted to only use the methods that should be available to them. What I would do is probably to write a GameHandler-class to take care of everything and do all the checking there.
How about this:
public abstract class Skill {
public abstract void applyEffect();
}
... somewhere else ...
Skill dig = new Skill() {
#Override
public void applyEffect() {
doSomeDigging();
}
};
This one still creates a subclass in the background, but you might like it better.
i would use enums also, you can stuff a bunch of login in them. the maps let each player have whatever skills and stats they need. you can nest enums like this or that.
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
public class So36107587 {
enum Stat {
food,health,magic;
}
enum Skill {
heal,hurt,hunt;
static void apply(Skill skill,double amount,Player player) {
double a=amount*random.nextDouble(),x;
switch(skill) {
case heal:
x=player.stats.get(Stat.health);
player.stats.put(Stat.health,a+x);
break;
case hurt:
x=player.stats.get(Stat.health);
player.stats.put(Stat.health,a-x);
break;
case hunt:
x=player.stats.get(Stat.food);
player.stats.put(Stat.food,a+x);
break;
}
}
static final Random random=new Random();
}
static class Player {
Player() {
init();
}
void init() {
for(Stat stat:Stat.values())
stats.put(stat,1.);
for(Skill skill:Skill.values())
skills.put(skill,1.);
}
void apply(Skill skill,Player player) {
Skill.apply(skill,skills.get(skill),player);
}
#Override public String toString() {
return ""+skills+" "+stats;
}
final Map<Stat,Double> stats=new TreeMap<>();
final Map<Skill,Double> skills=new TreeMap<>();
}
public static void main(String[] args) {
Player player=new Player();
System.out.println(player);
player.apply(Skill.heal,player);
System.out.println(player);
player.apply(Skill.hunt,player);
System.out.println(player);
}
}

How can I access a class other than though passing in a method?

Let us say we have a class called World. Which contains a class called Data. We also have a third class called Input. If Input.clicked(Event event, int x, int y) were to be called I would not be able to access World which means I can't access Data. How do you go about resolving this?
Another way to ask this might be: How can you access something in a method from another class that can't be changed when what you need to access is not final?
Sorry, I am having a hard time explaining this.
Update bit: The world class already exists, can't create a new one. It would be inside the Game class.
Here is a code example, not working code. More pseudo.
public class World {
Data data = new Data();
Input input = new Input();
public void update(float delta) {
input.getInput();
input.makeChangesBasedOnInput();
}
public void render(float delta) {
}
}
public class Data {
public int importantNumber; // Static is not an option
// For me I have to get a user name... but same idea here
public Data() {
Random ran = new Random();
importantNumber = ran.nextInt(1000);
}
}
public class Input {
Button button = new Button();
public Input() { // passing the World class does not work, ex. public Input(World world) {
button.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) { // I can't add world here...
// HERE IS ISSUE
System.out.println(World.Data.importantNumber);
}
}
}
public void getInput() {
// MAGIC
}
public void makeChangesBasedOnInput() {
// MAGIC
}
}
Update 2: Here is another example of what I am trying to do with TextButton & ClickListener from libgdx.
statsButton is a TextButton() from libgdx.
You say passing the World class does not work, well that is probably because you tried to acces a local variable from anonymous function, example:
public Input(World world) {
button.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
// error: world is not final
System.out.println(world.data.importantNumber);
}
}
}
this is what probably happened (if not, please let me know). In Java 8, world would be effectivly final, but in Java 7 or earlier, you would have to declare it final explicitly, like
public Input(final World world) { ... }
Also a common approach is to store your world inside a field:
private World world;
public Input(World world) {
this.world = world;
...
}

How can I make a class implement an interface correctly?

I'm trying to make a class implement an interface correctly but seem to have hit a brick wall. I am not sure if the code I have already written is correct but it was the only way I understood how to approach the task. I have been given an interface with this information:
package mvcchords;
public interface NoteStore {
int getNextNote();
boolean hasNextNote();
void noteAdded(int midicode);
void start(int sortOrder);
}
The application displays piano keys which allow the user to click on them, and it saves the order they were clicked and the midicode of the notes for the specific sound. Then when the user clicks play, it recalls the tune in the order the notes were saved. When a user clicks on a note noteAdded is called. hasNextNote is used to check if it is the end of the saved notes or not. getNextNote is used to get the next note from the array list and start is called when the user clicks the play button. I have been told the integer sortOrder is irrelevant for this part of the task. I have been told that when the play button is clicked it should call the start method and then repeatedly call the getNextNote method until all the notes have been retrieved.
Below is the code I have written so far for a class to implement this interface;
import java.util.*;
import mvcchords.*;
public class MyNoteStore implements NoteStore {
public ArrayList<Integer> Notes;
public void noteAdded(int midicode) {
Notes.add(midicode);
}
public boolean hasNextNote(int k) {
if(Notes.get(k) != null)
return true;
else
return false;
}
public int getNextNote(int k) {
if(hasNextNote(Notes.get(k)) == true)
return Notes.get(k);
else
return 0;
}
public void start(int sortOrder) {
for(int k = 0; k < Notes.size(); k++){
hasNextNote(k);
getNextNote(k);
}
}
}
This code gives me an error saying
MyNoteStore is not abstract and does not override abstract method `hasNextNote()` in `mvcchords.NoteStore`.
I don't know where to go from here and any help would be appreciated. If further information is needed then I will do my best to clarify any points I have made.
Thank you in advance :)
While you have created methods with the correct names you need to have the correct parameters and return types as well. So in this case you need to alter:
int getNextNote(int i);
boolean hasNextNote(int k);
to remove the integer parameters.
Basically you need to keep track of the notes played back so far in the class so that you don't need to pass an integer about all the time. You could either use an Iterator or just store a integer to track the last index played. The below method uses an iterator, maybe you should try and create the one with an integer yourself.
public class MyNoteStore implements NoteStore {
ArrayList<Integer> notes = new ArrayList<Integer>();
Iterator<Integer> playbackIter;
public void noteAdded(int midicode) {
notes.add(midicode);
}
public boolean hasNextNote() {
if (playbackIter != null) {
return playbackIter.hasNext();
}
else {
return false;
}
}
public int getNextNote() {
if (playBackIter != null) {
return playBackIter.next();
}
else {
return -1;
}
}
public void start(int sortOrder) {
playBackIter = notes.iterator();
while(hasNextNote()) {
int note = getNextNote();
//play note
}
}
}
The parameters in the method are different between your implementation and the declaration in the interface.
Well,
your interface defines the methods:
int getNextNote();
boolean hasNextNote();
void noteAdded(int midicode);
void start(int sortOrder);
So,
your class has to implement them with the exact definition, which means with the same return type AND parameters. So you can either change them in the interface declaration or in the class implementation.

Categories