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;
}
Related
i recently asked a question on how to code my statemachine in a clean way. normally i code for PLC`s so im no expert in java.
i got an helpfull answer to model the states as an enum, and encapsulate the transition logic inside the enums, like this:
public enum State {
s00_StandBy {
#Override
public State nextState() {
// if...
return ...;
}
},
s10_DetermineOperation {
#Override
public State nextState() {
// if ...
return ....;
}
},
public abstract State nextState();
}
But i am having trouble implementing this myself.
First thing is why cant i use certain conditions inside the enum cases?
example:
boolean resetBtn,startBtn;
State currentState;
//Transition logic
public enum State {
//if state is s00_standBy and startBtn is true proceed to s10
s00_StandBy {
#Override
public State nextState() {
if(startBtn){ // Cant use startBtn here? how to use conditions from outside the enum case?
return s10_DetermineOperation;
}
}
};
public abstract State nextState();
}
//Main
public void main() throws Exception {
//while in this state do stuff
if(currentState.equals(State.s00_StandBy)) {
//when done or condition is met go to next state
currentState.nextState();
}
}
second problem im up against is, how do you code the enum encapsulated transitions to have multiple conditions to proceed to a single new state?
like normally i would program the transition sort of like this:
//state
if (currentState.equals(s10_DetermineOperation) && resetBtn = true)
Or (currentState.equals(s20_normalOperation) && resetBtn=true)
Or (currentState.equals(s30_someOtherState) && resetBtn=true){
return state.s00_StandBy;}
but to my understanding wih the encapsulated enums you can only jump from a certain state to another and every transition have to be coded seperately?
so you get this for the above example:
boolean resetBtn,startBtn;
State currentState;
//Transition logic
public enum State {
//if state is s00_standBy and startBtn is true proceed to s10
s10_DetermineOperation {
#Override
public State nextState() {
if(startBtn){ // Cant use startBtn here? how to use conditions from outside the enum case?
return s00_StandBy;
}
}
},
s20_normalOperation {
#Override
public State nextState() {
if(resetBtn){ // Cant use startBtn here? how to use conditions from outside the enum case?
return s00_StandBy;
}
}
},
s30_normalOperation {
#Override
public State nextState() {
if(resetBtn){ // Cant use startBtn here? how to use conditions from outside the enum case?
return s00_StandBy;
}
}
},
public abstract State nextState();
}
this gets out of hand fast when you have a lot of transitions, what am i doing wrong here?
There could be several solutions.
Instead of only one method for doing the transition, you could have one for evvery trigger, buttons in your case.
For example:
public abstract State startButtonPressed();
public abstract State resetButtonPressed();
And implement this methods in every state.
Another way, is to encapsulate the fields you need to access in a class, for example Context, an add it as an argument to the state transition method(s).
public abstract State nextState(Context context);
public State nextState(Context context) {
if(context.startBtn){
return s00_StandBy;
}
}
Of course, both solutions can be combined.
Edit
An example using context:
The context class:
public class Context {
private boolean bool1;
private boolean bool2;
public Context() {
}
public boolean isBool1() {
return bool1;
}
public void setBool1(boolean bool1) {
this.bool1 = bool1;
}
public boolean isBool2() {
return bool2;
}
public void setBool2(boolean bool2) {
this.bool2 = bool2;
}
}
The enum:
public enum State {
s00_StandBy {
#Override
public State nextState(Context context) {
if (context.isBool1()) {
return s99_otherState;
} else {
return s20_someOtherState;
}
}
},
s20_someOtherState {
#Override
public State nextState(Context context) {
if (context.isBool2()) {
return s99_otherState;
} else {
return s00_StandBy;
}
}
},
s99_otherState {
#Override
public State nextState(Context context) {
return s00_StandBy;
}
};
public abstract State nextState(Context context);
}
An example main method:
public class Main {
public static void main(String... args) {
Context context = new Context();
State currentState = State.s00_StandBy;
context.setBool1(true);
currentState = currentState.nextState(context);
System.out.println(currentState);
}
}
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;
}
I'm using preferences to save the sound settings in my game as a boolean value. However, when I first start the game, the boolean initializes to false (sound off), because I'm not initializing it elsewhere. I could initialize it to true in the create method, but then the game would just start with sounds on every time you start the game, and that would just defeat the purpose of preferences.
Otherwise it works fine, it's just that I want the boolean to initialize to true the first time you start the game and not every time you restart it.
Is there a way to do this with preferences or do I have to use some other kind of saving method?
Note: this is a desktop application
public Preferences getPreferences() {
if (preferences == null) {
preferences = Gdx.app.getPreferences("myPrefs");
}
return preferences;
}
private void generatePreferences() {
getPreferences().clear();
getPreferences().putBoolean("soundEnabled", true).flush();
getPreferences().putBoolean("notFirstLaunch", true).flush();
}
public void loadPreferences() {
if (!getPreferences().getBoolean("notFirstLaunch")) {
generatePreferences();
} else {
//read the prefs and do your stuff
}
}
I would suggest you a slightly different approach:
Firstly, I think that the perfect place to initialize prefs is create method of the main game class (the one that extends Game):
public void create () {
Prefs.initPrefs();
....other initialization....
}
Then, initPrefs method looks like:
private static final String MUSIC_ON = "music_on";
private static final String LANG = "lang";
public static void initPrefs() {
boolean needChange = false;
if (!pref.contains(MUSIC_ON)) {
pref.putBoolean(MUSIC_ON, true);
needChange = true;
}
//if no lang - select system default
if (!pref.contains(LANG)) {
String language = Locale.getDefault().getLanguage();
pref.putString(LANG, language);
needChange = true;
}
if (needChange) {
pref.flush();
}
}
And finally to toggle the music:
public static boolean isMusicOn() {
return pref.getBoolean(MUSIC_ON);
}
public static void toggleMusic() {
pref.putBoolean(MUSIC_ON, !isMusicOn());
pref.flush();
}
I know this is a few years old now but just in case anyone else was wondering.
I think what you need to do is add a default value to your getBoolean() method without calling flush().
In my game i have a method called isSoundOn() which i call when my sound button is created. The very first time you start your game after installing it, you probably wont have saved a preference which means that the method below has to default to something. if you add true to the getBoolean method then your game should initialize to true.
public boolean isSoundOn() {
return preferences.getBoolean("soundOn", true);
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I am writing this code in Netbeans for a java class, but I am having a few errors and would really appreciate some help. The assignment is:
Design and implement a stringed musical instrument class using the following guidelines:
Data fields for your instrument should include number of strings, an array of string names representing string names (e.g. E,A,D,G), and boolean fields to determine if the instrument is tuned, and if the instrument is currently playing. You are welcome to add additional data fields if you like.
A constructor method that set the tuned and currently playing fields to false.
Other methods
to tune the instrument
to start the instrument playing, and
to stop the instrument from playing.
Other methods as you see fit (Add at least one unique method).
Create a UML class diagram using a diagram tool (e.g. PPT, Visio) of your choice. Prepare the diagrams and place them in a word document along with a brief description of each of your classes.
Create Java classes for your instruments. Be sure that your code matches your design specifications and some minimal functionality is included. For example, if you called the violin.play() method, you should at least print that the violin is playing. Similar functionality should be supplied when you stop playing, tune or call any of your methods. For example:
public void playviolin() {
System.out.println("The violin is now playing.");
}
Write the output from your Instrument class methods to a text file that a user entered from the command line arguments (e.g. java Mynamep3tst myfilename.txt). This allows your program to accept filenames from the user via a command line argument.
Finally, create a Java test class that simulates using your instrument class. In your test class be you should at a minimum: a) Construct 10 instances of your instrument, b) tune your instruments, c) Start playing your instrument, d) Call your unique method, and e) Stop playing your instruments. (Hint: Arrays and Loops will make your job easier and result in more efficient code!)
So here is my code currently:
package andrewrubinfinalproject;
/**
*
* #author Andy
*/
public class AndrewRubinFinalProject {
public static void main(String[] args) {
//fields to determine if the instrument is isTuned,
private boolean isTuned;
//and if the instrument is currently isPlaying.
private boolean isPlaying;
private String name;
private int numberOfStrings = 4; // number of strings
private String nameofStringsInInstrument[] = {"E", "C", "D", "A"}; //an array of string names
//A constructor method that set the isTuned and currently isPlaying fields to false.
public AndrewRubinFinalProject() {
this.isTuned = false;
this.isPlaying = false;
}
public String getNameOfInstrument() {
return name;
}
public void setNameOfInstrument(String nameOfInstrument) {
this.name = nameOfInstrument;
}
// Other methods
public boolean isPlaying() {
return isPlaying;
}
public void setPlaying(boolean playing) {
this.isPlaying = playing;
}
public boolean isTuned() {
return isTuned;
}
public void setTuned(boolean isTuned) {
this.isTuned = isTuned;
}
public void startPlayInstrument() {
System.out.println("The Instrument is now Playing.");
isPlaying = true;
}
public void stopPlayInstrument() {
System.out.println("The Instrument is not Playing anymore.");
isPlaying = false;
}
public void startTuneInstrument() {
System.out.println("The Instrument is Tuned.");
isTuned = true;
}
public void stopTuneInstrument() {
System.out.println("The Instrument is not Tuned.");
isTuned = false;
}
public int getNumberOfStrings() {
return this.numberOfStrings ;
}
public String[] getStringNames() {
return nameofStringsInInstrument;
}
}
You didn't close your main method. You should insert } before you begin to write other methods.
It's a bad habit to use magic numbers in your code, such as private int numberOfStrings = 4;, what if you change the array? You'll have to change this number too.
Instead, it's better to use .length that returns the size of the array.
It seems your assignment is given to check your OOP concepts.
See the code below, I've given a little touch to your code.
package andrewrubinfinalproject;
/**
*
* #author Andy
*/
public class AndrewRubinFinalProject {
//fields to determine if the instrument is isTuned,
private boolean isTuned;
//and if the instrument is currently isPlaying.
private boolean isPlaying;
private String name;
private int numberOfStrings = 4; // number of strings
private String nameofStringsInInstrument[] = {"E", "C", "D", "A"}; //an array of string names
//A constructor method that set the isTuned and currently isPlaying fields to false.
public AndrewRubinFinalProject() {
this.isTuned = false;
this.isPlaying = false;
}
public String getNameOfInstrument() {
return this.name;
}
public void setNameOfInstrument(String nameOfInstrument) {
this.name = nameOfInstrument;
}
// Other methods
public boolean isPlaying() {
return this.isPlaying;
}
public void setPlaying(boolean playing) {
this.isPlaying = playing;
}
public boolean isTuned() {
return this.isTuned;
}
public void setTuned(boolean isTuned) {
this.isTuned = isTuned;
}
public void startPlayInstrument() {
System.out.println("The Instrument is now Playing.");
this.isPlaying = true;
}
public void stopPlayInstrument() {
System.out.println("The Instrument is not Playing anymore.");
this.isPlaying = false;
}
public void startTuneInstrument() {
System.out.println("The Instrument is Tuned.");
this.isTuned = true;
}
public void stopTuneInstrument() {
System.out.println("The Instrument is not Tuned.");
this.isTuned = false;
}
public int getNumberOfStrings() {
return this.numberOfStrings ;
}
public String[] getStringNames() {
return this.nameofStringsInInstrument;
}
}
The problem is with the positioning of your main method.
First write a class as in the above code.
Then in your main method, make an instance of AndrewRubinFinalProject class by calling the constructor.
public static void main(String[] args){
AndrewRubinFinalProject andrewsObject= new AndrewRubinFinalProject();
// you can call any method in your class with respect to andrewsObject
// e.g.
// andrewsObject.setNameOfInstrument("Violin");
// String x= andrewsObject.getNameOfInstrument()
}
What you must know is that the main method does not necessarily be in the class you are writing. It can be somewhere else in your program.
First you should make at least 2 classes. One is Instrument with all its fields and methods. And another is your main project class that contains main() method and created and uses instruments.
The code that you posted will not be compiled as you opened and not closed the main method.
When first starting out in Object Oriented Programming, write up a small description of the problem, or at least think about it in terms that have enough detail.
Initially, the nouns should become your classes. Abstract groups of nouns might be good candidates for interfaces, and the verbs should become methods belonging to the class that is "closest" to the verb. By closest, I mean that performing the verb will require more access to the attributes in the class.
I'm trying to mimic the following abstract class, designed to enable only one lazy initialization, without using logic statements. I'm ignoring the synchronization elements necessary for thread safety for simplicity's sake.
abstract class Thunk<T>
{
private boolean initiated = false;
private T value;
public T get()
{
if(!initiated) // not using (value == null)
{
value = compute();
initiated = true;
}
return value;
}
abstract protected T compute();
}
Can an instance of the following abstract class be hacked by a child to initialize the same variable more than once?
abstract class Thunk<T>
{
private T value;
private Computer<T> computer;
public Thunk()
{
computer = new Computer<T>(this);
}
public T get()
{
value = computer.getValue();
return value;
}
abstract protected T compute();
private class Computer<T>
{
private static final String TAG = "Computer";
private Thunk<T> thunk;
private T value;
private Computer<T> computer;
public Computer(Thunk<T> thunk)
{
Log.d(TAG, "constructed");
this.thunk = thunk;
computer = this;
}
public T getValue()
{
Log.d(TAG + ".getValue()", "");
value = computer.computeValue();
return value;
}
protected T computeValue()
{
Log.d(TAG + ".computeValue()", "");
value = thunk.compute();
computer = new DumbComputer<T>(thunk, value);
return value;
}
//this is for maximal encapsulation
private class DumbComputer<T> extends Computer<T>
{
private static final String TAG = "DumbComputer";
private T value;
public DumbComputer(Thunk<T> thunk, T value)
{
super(thunk);
Log.d(TAG + ".contructed()", "booki");
this.value = value;
}
//overriding so that value will be calculated only once.
#Override
protected T computeValue()
{
Log.d(TAG + ".computeValue()", "");
return value;
}
}
}
}
Yes, by overriding the get method.
To fix that you can make the get into a final method. That will prevent overriding and give you singleton-like behaviour.
Note that the code you have written is not thread safe.
You could achieve thread safety by making the method synchronized (don't worry about performance until you know you gave a problem and that the method is the hotspot, because slow correct code is better than fast incorrect code, and the JVM is very good at optimising locks. If you find a specific lock for this class to be excessively hot, you can use a number of tricks to speed it up... but don't worry about that just yet)
Also worth pointing out the resource holder inner class pattern for lazy init (not applicable to your use case as this class need. It be used for only singletons) can be used if you wan the best lazy init of singletons.
update (responding to comment as comments don't support formatting)
Do this:
abstract class Thunk<T>
{
private boolean initiated = false;
private T value;
public synchronized final T get()
{
if(!initiated) // not using (value == null)
{
value = compute();
initiated = true;
}
return value;
}
abstract protected T compute();
}
That is the simplest code that can possibly work. Don't even dream of trying to "improve" that code. It can be improved, but the improvements will differ depending on how the class is being used, and the complexity of the improvement will hide what your code is trying to do. Start with the simplest thing that can work, and go from there.
Keep It Simple Stupid
And don't solve problems you don't have yet
The pattern
public final void f() {
...
X x = ...;
g(x);
...
}
abstract protected void g(X x);
is quite usefull in contractual programming:
to impose a behaviour (body of f), and
to provide a local context (x).
A behaviour often is realized by holding a state (like your initiated).
So yes, it is fine for lazy evaluation. Though lazy evaluation can be achieved on field level, for instance by the seldom seen jewel Future<>.
Your second example does not work as (probably) intended, as you create a new DumbComputer each time you call Thunk.get. You can achieve your goal as follows (but I do not think it's good design, and I really do not see where the advantage compared to an easier solution shuld be):
abstract class Thunk<T> {
T value;
Computer<T> computer;
protected abstract T doCompute ();
private interface Computer<T> {
Computer getComputer ();
T compute ();
}
public Thunk<T> () {
// initialize computer with a calculating one
computer = new Computer<T> () {
Computer getComputer () {
// return a dumb computer
return new Computer<T> () {
Computer getComputer () { return this; }
T compute () { return value; }
}
}
T compute () { value = doCompute (); return value; }
};
}
public T getValue () {
T v = computer.compute (); computer = computer.getComputer (); return v;
}
}