So some background information, I'm new to programming and am still learning, so I apologize for my trivial error making. I am making my own text based game just to further practice etc.
Here is the link to everything on dropbox for more context:
https://www.dropbox.com/sh/uxy7vafzt3fwikf/B-FQ3VXfsR
I am currently trying to implement the combat system for my game, and I am running into the issue of the combat sequence not ending when required. The 'combat sequence' is a while loop as follows:
public void startCombat()
{
inCombat = true;
while(inCombat != false)// && herohealth > 0 && monsterhealth > 0)
{
checkAlive();
heroHitMonster();
checkAlive();
monsterHitHero();
}
attackinghero.setHeroHealth(herohealth);
attackedmonster.setMonsterHealth(monsterhealth);
}
where the checkAlive() method is as follows:
public void checkAlive()
{
if(herohealth <= 0)
{
System.out.println("You have died.");
attackinghero.clearInventory();
inCombat = false;
}
else if(monsterhealth <= 0)
{
System.out.println("You have killed the "+attackedmonster.getmonsterName()+"!");
inCombat = false;
combatlocation.removeMonster(attackedmonster.getmonsterName());
}
else
{
//
}
}
I am trying to get it to end the combat sequence when either the 'hero' or 'monster' health become <= 0,
however it is currently finishing the while loop and therefore producing the result of the hero being hit even if he killed the monster in his first hit.
This is what is currently being 'printed to screen'
rat loses 5 health!
You have killed the rat!
Hero loses 1 health!
Any help is much appreciated, thanks in advance.
checkAlive shouldn't be void it should be Boolean and should return inCombat, and in your function startCombat you should do inCombat=checkAlive();
The while loop will only evaluate after both actions. You need a way to break the loop after the hero hits the monster. I would personally change the checkAlive method to return a boolean, and put the hit methods in if statements in the while loop:
if(checkAlive())
{
heroHitMonster();
}
if(checkAlive())
{
monsterHitHero();
}
You should end the loop at the end of the checkAlive instead of changing the boolean value.
If you killed the monster at first hit, you still execute the monsterHitHero() even, if the monster is killed. The function to hit should be conditioned to the life of heroes/monster.
Related
So I am making a game where there are waves of enemies. The Wave class contains an update method that updates all the enemies in an arraylist of enemies contained in the Wave class. The Wave class also has a boolean called beat that decides whether or not the player has beaten the current wave. I am now have been trying however to start the next wave after the player beats the first. All waves in the arraylist start out with their beat variable as true except for the first. There are currently only two waves. I do not know why this is not working. Thank You for any help.
for(int i = 0; i < 1;i++)
{
if(!w.get(i).beat)
w.get(i).update(g2d);
else if(w.get(i).beat)
{
if(i-1 != -1)
{
if(w.get(i-1).beat && w.get(i).beat)
{
w.get(i).beat = false;
}
}
}
}
Your loop will increment i to the next wave after setting the current wave's beat setting to false, and miss calling the update method for that case. It looks like you should either call its update method immediately after setting beat = false, or perform the if test in the opposite order like this:
for(int i = 0; i < numWaves;i++) // upper range should be the number of waves
{
if(w.get(i).beat)
{
if(i>0) // this can be simplified to "if (i>0)"
{
if(w.get(i-1).beat) // no need to check w.get(i).beat here
{
w.get(i).beat = false;
}
}
}
else
w.get(i).update(g2d);
}
I don't know why you'd initialize a wave's beat state to true then set it to false when its turn comes. Why not just initialize all to false since they really haven't been beat yet?
I'm not sure that I understand your code but I can tell you 2 things. First of all, your loop never loops because as soon as the index is 1, it ends without executing the code a second time. Secondly
if(i-1 != -1)
{
if(w.get(i-1).beat && w.get(i).beat)
{
w.get(i).beat = false;
}
}
is always false due to what I said.
I have made a for loop with a nested if block. On exit of the loop I want the object to perform an action by calling a method. At the moment I am struggling to find how to do this. Could anyone make any suggestions?. Below is the code I have made.
public void goLoop()
{
for (int i = 1; i <= getAmountOfLoops(); i++ )
{
if (getPosition() => 25)
{
this.setPosition(4);
}
else
{
this.keepLooping();
this.setTotalAmountOfLoops(getTotalAmountOfLoops() + 2);
}
jump(); // Do I put the action to perform on exit of loop here?
}
Just call it after the loop:
for (... ) {
}
action();
BTW change getPosition() => 25 to getPosition() >= 25.
Note: It's always better to be aware of the logic of your program before you start coding, however if you start coding and suddenly encounter a trivial situation like this, just give it a try! and check if it produces the desired result or not.
If the die shows a 6, the player doesn't move at all on this turn and also forfeits the next turn.
To accomplish this, I have tried an integer type warning marker variable for the player and an integer type time counter variable.
If the die shows 6, I want to increment the warning marker variable by 1 during the first run(and have the while loop do nothing), then keep the value at 1 during the second run (while loop will not work), then lower it back down to 0 for the third run of the while loop (so the while loop will work). The marker will stay at zero unless the die shows a 6 again, after which the same process will repeat.
I have a while loop like this:
while the warning marker is equal to 0 {
Do Stuff
if the die shows a 6, the warning marker increases by 1.
the time counter also increases by 1.
}
How do I manipulate the variables to get the result that I need? Or is my partially complete method absolutely off in terms of logic?
Thanks.
Can u tell me if this works for you?
flag=true;
while condition{
if flag==true{
if die == 6
{
flag=false;
continue;}
}
else { Do STUFF }
} else
{
flag==true;
}
}
I think you want to reword this problem.
This is what I understood. You have a warning marker.
You have a loop that checks whether the marker is 0, if it is then you do something.
If the die is a six, you will increase the warning marker. If its new value is 3, then you will reset it to 0. Meanwhile, the time counter is always increasing.
If this is correct, I think you want something like:
int warningMarker = 0;
int timeMarker = 0;
while (true) {
if (die == 6) {
++warningMarker;
if (warningMarker == 3) {
warningMarker = 0;
}
}
if (warningMarker == 0) {
doSomething();
}
++timeMarker;
}
Java is Object-Oriented Pragramming language. Use this feature.
See following pseudocode and let me know if you have problem in undestanding it.
Create a class Player as following:
class Player
{
boolean skipChance = false;
... // Other fields
... //
}
Change your while as following:
while(isGameOn())
{
Player p = getCurrentPlayer();
if( ! p.skipChance)
{
int val = p.throwDice();
if(val == 6)
{
p.skipChance = true;
continue; // control moves to while.
}
// Do stuff
}
else
{
p.skipChance = false;
}
}
I have the following code
#EventHandler
public void onPlayerQuit(PlayerQuitEvent event){
Player player = event.getPlayer();
final Player[] playerlist = getServer().getOnlinePlayers();
if (playerlist.length <=1) { // if no players are online
getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable(){
// this is a scheduler.
public void run(){
if(playerlist.length <=1){
getServer().shutdown();
}
}
}, 6000L); // runs every 6000 ticks, which is every 300 seconds, which is every 5 minutes.
}
}
Which when a player leaves, it checks to see if he was the last one on, if he was, then it after 5 minutes, it checks again, and if still no one is on its supposed to stop the server.
In this line here:
if (playerlist.length <=1) { // if no players are online
I HAVE to have it as <=1 or it doesnt work at all, but it will also stop the server if I leave, and join back and im the only one on. When I had it at =0 and just <1 it didnt work.
Any ideas?
Here is my update code (Still doesnt work):
#EventHandler
public void onPlayerQuit(PlayerQuitEvent event){
Player player = event.getPlayer();
final Player[] playerlist = getServer().getOnlinePlayers();
if (playerlist.length <=1) { // if no players are online
getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable(){
// this is a scheduler.
public void run(){
final Player[] playerlist = getServer().getOnlinePlayers();
if(playerlist.length <=1){
getServer().shutdown();
}
}
}, 500L); // runs every 6000 ticks, which is every 300 seconds, which is every 5 minutes.
}
}
The reason why what you have written does not work is your use of <=. If someone logs off and no one is left, the task is scheduled. If someone logs back on within 5 minuets or less and remains online, when the scheduled task checks to see if the server should be shutdown, 1 <= 1 is true so the server shuts down.
You mentioned that just using = did not work, this is because in boolean statements, == must be used to check for equality.
Try using this:
if (playerlist.length == 0) { // if no players are online
// Do stuff
}
Update (Discussed in comments):
I do not know the Bukkit API very well, but this is what I assume is happening then: The online player list is updated after onPlayerQuit() is executed. Try this: Inside of your onPlayerQuit() method, try checking playerlist.length == 1 and inside of your task, check playerlist.length == 0
I do not know if you have already solved this problem, but I think part of the problem is that you are trying to re-initialize an already initialized final variable...Again, like some of the others in the replies, I do not know Bukkit API as I am trying to learn it, but you cannot re-initialize a final variable...So I would either recommend taking away the final part, or if it must remain, I would make a new array for the run() method...as you are checking for a second time to see if anyone is online...it will not matter if you change arrays, because you are changing amount of players online presumably anyways...because it is final, it will always be 1 when you re-run the length of the final array of playerlist...
You code doesn't refresh the playerlist variable when the delayed task in run, never detecting if someone has joined when the task is actually run.
A better implementation of the code would be:
#EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
boolean playersOnServer = false;
for(Player p : getServer().getOnlinePlayers()) {
if(p==player) continue;
playersOnServer = true;
break;
}
if (!playersOnServer) {
getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable(){
public void run(){
//Redo players check
boolean playersOnServer = false;
for(Player p : getServer().getOnlinePlayers()) {
playersOnServer = true;
break;
}
if(!playersOnServer){
getServer().shutdown();
}
}
}, 6000L);
}
}
Inside the above code, I used a for loop instead of a simple check to see if there are any players online, to make it work with the old player array from the old bukkit, and the new collections method from the new bukkit.
This kind of detection still has its bugs, for example if the last person quits, then directly joins, and then waits 4 minutes and 59 seconds before leaving again, it will shut down the server directly when he has left.
You never cancel the task when someone logs back on. Since you never cancel the task it will execute even if someone logs back on within the 5m time frame.
So I have what I think is pretty good code for a sudoku solver in java but I need some help with this method. It gives me a stack overflow when I embed it in a main method. The problem is that my method doesn't know how to turn around and fix its mistakes. I need a boolean flag (one that, unlike the one used in the code below, actually works preferably) or something to let it know when it should turn back and when it can again go forwards and continue solving the game. Thanks for any help you can give
public void play(int r, int c){//this method throws the StackOverflowError
if(needAtLoc(r,c).size()==9){
int num=1+generator.nextInt(9);
setCell(r,c,num,this);
if(c<8){
System.out.println(this);///////////////
play(r, c+1);
}
else{
play(r+1, 0);
}
}
else{
if(needAtLoc(r,c).size()==0){//no possible moves THIS IS THE PROBLEM LINE!!!
if(c>0){
play(r, c-1);//play last cell, in column to left
}
else{
if(r==0){
play(r,c);//first square, so must play again (can't go back)
}
else{
play(r-1, 8);/*first cell of row so must go to previous row and
the end column*/
}
}
}
else{//if there are possible moves
int num=needAtLoc(r,c).remove(generator.nextInt(needAtLoc(r,c).size()));
setCell(r,c,num,this);//set the value of the cell
System.out.println(this);//////////////
if(r==8 && c==8){//the end of the cell has been reached so must end recursive call
return;
}
else{
if(c<8){
play(r, c+1);//normal, next cell
}
else{
play(r+1, 0);/*last cell in row so we go to next one
in the first column ("return" button)*/
}
}
}
}
}
Rather than solve this for you I would make a few suggestions in how to tackle this. 9 hours is ample.
1) Your code is hard to read. Try to space it out a bit. Give your variables meaningful names that are clear (this helps you and other people read your code). You may have made a simple mistake and clean code will make these easier to spot. Try to break it into smaller methods since this will make it more readable and more maintainable.
2) Stack overflows are caused (generally I believe) when you make too many nested method calls and are typical in recursive code. Therefore make your recursion clear. Make sure you have a base case that will terminate.
Sorry to not give you "the answer" but since this sounds like homework I think there's more value in learning how to solve this yourself. Hope that seems fair.
I think your problem is where you have:
if(r==0)
{
play(r,c);//first square, so must play again (can't go back)
}
That's because you don't seem to modify any state here and you pass the same values in that made you come to this step in the first place. Seems like infinite recursion for me.
Also please align your code correctly as it is too hard to read when it is misaligned and maybe provide some clues what the other methods do. Good luck!
Your code is throwing stack over flow exception because you never reach a terminating condition that ends your recursion, or at least it is not obvious you to see you have a recursion terminating condition by reading your code.
Your code is not well structure, hence you will have a hard time debugging it. Try to restructure your code, it will help you rethink the problem. Also, please comment your code :)
You are recursively calling play without ever returning and it looks as if you are initialising a new set of variables each time at the top of the function.
Try splitting out the initialisation from the recursive part. You also need a clear end condition to end the recursion e.g. (if(isBoardFilled()==true)) return.
Also structure it so that you add a number to the board, test it against the contraints and if it passes add another number (recurse) or backtrack by removing the last number and try again.
I think u are calling play() recursively .Try to check if there is a stopping condition to ur recursive call.
I agree with Tom, but here is a hint.
There is no condition and return statement to end the recursive calls.
I've managed to be more concise and more clear but it still won't run... I just need a push over the edge and I'm home free. I've dumped so many wasted hours into this project:
public ArrayList<Integer> needAtLoc(int r, int c){
int bc=c/3;//the column within the SudokuBoard
int blc;
/*The two posibilities for the column within each SudokuBlock:*/
if(c>=0 && c<3) {
blc=c;
}
else {
blc=c%3;
}
int br=r/3; //the row within the SudokuBoard
int blr;
/*The two possiblities for the row within each SudokuBlock:*/
if(r>=0 && r<3) {
blr=r;
} else {
blr=r%3;
}
ArrayList<Integer> needR = new ArrayList<Integer>();
needR=checkR(r);//
needR.trimToSize();
System.out.println(needR);//////////////
ArrayList<Integer> needC=new ArrayList<Integer>();
needC=checkC(c);
needC.trimToSize();
System.out.println(needC);/////////////
ArrayList<Integer> needBl=new ArrayList<Integer>();
needBl=this.board[br][bc].updateMissing(); //that method updates and returns an ArrayList
needBl.trimToSize();
ArrayList<Integer> poss=new ArrayList<Integer>();
poss.clear();
for(Integer e: needBl){
if(needC.contains(e) && needR.contains(e)){
poss.add(e);
}
}
return poss;
}
//this method throws the StackOverflowError
public void play(int r, int c){
int bc=c/3; //the column within the SudokuBoard
int blc;
/*The two posibilities for the column within each SudokuBlock:*/
if(c>=0 && c<3) {
blc=c;
} else {
blc=c%3;
}
int br=r/3; //the row within the SudokuBoard
int blr;
/*The two possiblities for the row within each SudokuBlock:*/
if(r>=0 && r<3) {
blr=r;
} else {
blr=r%3;
}
if(needAtLoc(r,c).size()==9){
int num=1+generator.nextInt(9);
this.board[br][bc].setValue(blr, blc, num);
if(c<8){
System.out.println(this);///////////////
play(r, c+1);
} else{
play(r+1, 0);
}
} else{
if(needAtLoc(r,c).size()==0){ //no possible moves
if(c>0){
bc=(c-1)/3;
if(c>0 && c<4) {
blc=c-1;
} else {
blc = (c-1) % 3;
}
this.board[br][bc].setValue(blr, blc, 0);
play(r, c-1);
}
else{
blc=0;
bc=0;
if(r==0){
blr=0;
br=0;
this.board[br][bc].setValue(blr, blc, 0);
play(r,c);
}
else{
br=(r-1)/3;
if(r>0 && r<4) {blr=r-1;}
else {blr=(r-1)%3;}
this.board[br][bc].setValue(blr, blc, 0);
play(r-1, 8);
}
}
}
else{//if there are possible moves
int num=needAtLoc(r,c).remove(generator.nextInt(needAtLoc(r,c).size()));
this.board[br][bc].setValue(blr, blc, num);
System.out.println(this);//////////////
if(r==8 && c==8){
return;
}
else{
if(c<8){
play(r, c+1);
}
else{
play(r+1, 0);
}
}
}
}
}