New user here.
I've been working on a "framework" or draft for a text based adventure game in my object oriented programming class. I showed it to my TA and he said it looked good, but I should try putting the movement in its own private class. Any reason why I should do this? And how I should do it?
Thank you in advance for any help.
Here is my code for my main class:
public class Main {
public static void main(String args[]) {
// This is where we will build rooms
// Load inventory
ArrayList<String> inventory = new ArrayList<>();
// Start game
boolean playing = true;
while (playing) {
String input = Input.getInput();
// Movement commands
if (input.equals("north")) {
if (y > 0) {
y--;
Rooms.print(room, x, y);
} else {
System.out.println("You can't go that way.");
}
} else if (input.equals("south")) {
if (y < HEIGHT - 1) {
y++;
Rooms.print(room, x, y);
} else {
System.out.println("You can't go that way.");
}
} else if (input.equals("east")) {
if (x > 0) {
x--;
Rooms.print(room, x, y);
} else {
System.out.println("You can't go that way.");
}
} else if (input.equals("west")) {
if (x < WIDTH - 1) {
x++;
Rooms.print(room, x, y);
} else {
System.out.println("You can't go that way.");
}
}
// Look commands
else if (input.equals("look")) {
Rooms.print(room, x, y);
}
// Look at item commands
else if (input.equals("look thing")) {
//print item description
}
/* Take command
else if statement
Drop command
else if statement
*/
// Inventory commands
else if (input.equals("i") || input.equals("inv")
|| input.equals("inventory")) {
Inventory.print(inventory);
}
// Quit commands
else if (input.equals("quit")) {
System.out.println("Goodbye!");
playing = false;
// Catch-all for invalid input
} else {
System.out.println("Invalid input");
}
}
System.exit(0);
}
}
One reason that you would want to put the movement in its' own class is to enable what is known as Separation of Concerns. Following this principle, you want to keep your classes as distinct and unique as possible.
This approach makes debugging/developing much easier as your program grows in size and complexity.
As far as making the class private, I don't know that I necessarily agree with that. I would simply make a movement class that handles all the movement related functions and data. Put this in its' own file that is separate from your main file, but within your project.
You can follow the same approach for your game inventory, attacking (if this exists), settings, etc.!
As my comment mentions:
One tip I can give you is to refactor all of your System.out.println("You can't go that way."); into a function and call it. You are repeating this one line a few times and you may want to change it later, easier to do in 1 function, instead of finding every occurrence of that string.
public static void moveError() {
System.out.println("You can't go that way.");
}
A few people in the comments have reccommended transitioning into a switch statement. I agree with this approach; it's not only easier to look at. But easier to maintain as well. You can use specific 'commands' passed as strings/integers/characters that represent specific functions within your code:
switch (direction) {
case "up":
// code to move up and error handle
break;
case "down":
// code to move down and error handle
break;
}
You can also implement specific commands for things like picking up items, adjusting settings, or whatever else you envision.
Maybe the Room Movement functionality that your TA is asking you to enclose within a private class is completely related to your outer class and hence has no significance if existed independently.
Related
Essentially, I've put a switch statement in a for loop. It has not been working as intended. I think it has something to with the break statement.
What I want the loop to do is go to the first element in the array list, execute code based on the 'action' String, then go to the next until the list ends. However, it seems that whenever I run the program it only executes the code in the first index. Here is some code for the BattleManager class:
Scanner input = new Scanner(System.in);
String cmd;
String[] dtct;
Arraylist<BattleAction> turns = new ArrayList<BattleAction>();
public void handle() {
cmd = input.nextLine();
dtct = (cmd.split());
switch(dtct[0]) {
case "attack":
turns.add(new BattleAction("playerattack"));
getenemyaction();
turnsequence();
break;
case "defend":
getenemyaction();
turnsequence()
}
}
public void getenemyaction() {
turns.add(new BattleAction("enemyattack"));
}
public void turnsequence() {
Collections.sort(turns);
print("Size: " + turns.size())
for (int i = 0; i != turns.size(); i ++) {
switch(turns.get(i).action) {
case "playerattack":
playerattack();
break;
case "enemyattack":
enemyattack();
break;
}
}
}
public void playerattack() {
print("Player attack");
}
public void enemyattack() {
print("Enemy attack");
}
When I run the program here is the output I am getting with the attack command:
attack
Size: 2
Player Attack
However when I use the defend command the output is:
defend
Size: 1
Enemy Attack
The desired output would be for turnsequence() to go through turns and do check action for the desired code to be executed, like this:
attack
Size: 2
Player Attack
Enemy Attack
I have done my best to cut out as much unnecessary information at possible to prevent confusion. Thank you so much for reading my post! I really appreciate your help!
I'm struggling with dealing of inventory scan for my game, it basically search for the user inventory if "Flying Broom" if present(it was collected in another method and upload the code is too long), if not it will run the method challengedragon() again; else, it will proceed to the next challenge if the item is present.I was think of inserting method as parameter but it is not possible. This is what I have now. :
public class Main {
String Flyingbroom = "Flying broom";
public static void main(String[] args) {
Player_inventory p = new Player_inventory();
challengedragon();
}
public void challengedragon() {
System.out.println("a Hungarian Horntail dragon! Let's start the battle! You have four options to beat the dragon: ");
System.out.println("1: Fly away with your broom");
System.out.println("2: Fight the dragon");
System.out.println("3: Just run to the egg and get it");
System.out.println("4: Hide behind a rock");
System.out.println("5: Go back to Hogwart");
System.out.println("Your choice is: ");
Scanner in = new Scanner(System.in);
int dragonfightchoice = in .nextInt();
if (dragonfightchoice == 1) {
{
p.Scanitem(Flyingbroom,
"Good choice! You managed to kill the Hungarian Horntail dragon and to get the golden egg",
"You dont have the broom. Try to search for the broom",
playerHP);
proceedtonextchallengelake();
} else if (dragonfightchoice == 2) {
System.out.println("The Hungarian Horntail dragon fired you. - 70HP. ");
playerHP -= 70;
challengedragon();
} else if (dragonfightchoice == 3) {
System.out.println("Bad idea... You lose 100 HP");
playerHP -= 100;
challengedragon();
} else if (dragonfightchoice == 4) {
System.out.println("The dragon found you. You lose 30 HP");
playerHP -= 30;
challengedragon();
} else if (dragonfightchoice == 5) {
Hogwart();
} else {
invalid();
challengedragon();
}
}
For my inventory class:
public void Scanitem(String item, String trueouputext, String textifconditionisnotmet) {
if (inv.contains(item) == true) {
System.out.println(trueouputext);
} else if (inv.contains(item) == false) {
System.out.println(textifconditionisnotmet);
}
public static ArrayList<String> inv = new ArrayList<String>();
Do you guys have any recommendation?
Are there additional steps to populate the inventory (variable inv)?
Also, wouldn't you want ScanItem to answer true or false, depending on whether the item was found? Then you would have something like this:
public boolean scanitem(String item) {
return ( inv.contains(item) );
}
if ( p.scanItem(flyingBroom) ) {
System.out.println("Good choice! You managed to kill the Hungarian Horntail dragon and to get the golden egg");
} else {
System.out.println("You dont have the broom. Try to search for the broom");
}
That will get you closer to what you want. However, there are two other issues which you'll need to put into your code:
You will need a loop of some sort, instead of calling challengeDragon from inside of itself.
Somehow, the return value from scanItem must be used to decide whether to loop.
Currently, you do a nested call of a method each time the player does something, this means that sooner or later you'll run out of the stack. A better idea for the framework for your text-based adventure is to have some kind of a description of the current game's state. The state could be represented as an object that contains the following information:
where's the player currently at (on which step, at which "crossing" etc.)
the player's stats (HP, available skills etc.)
the contents of the player's inventory
some previously made choices affecting the game
Then, the code could be written as a simple loop that does the following:
process player's input
change the state according to the player's input
present the player with available options according to the new state
wait for the next input
repeat
I'm really scratching my heard on this one. I'm new at java, and I'm having the strangest thing happen.
It's homework and I'm taking it one step at a time. My issue is the loop just keeps going and stops asking for input, just keeps looping until it terminates. My comments are largely for myself. I tried to extract what was causing my problem and post it here.
Look at the "hatColor" switch, you'll notice the way I'm making sure the user enter only from the options I have allotted. Should I be using a exception handler or something?
Anyway, in short, the problem is that if I enter something with spaces, the loop skips asking for my next input. Like, if I entered "y y y y y " to the scanner when first prompted, the program will terminate and not give me the chance to enter something else.
Please, anyone that understands this, I would really appreciate your help.
import java.util.Scanner;
public class Testing
{
static String hatColor;
public static void main(String[] args) {
gameStart();
}
public static void gameStart()
{
Scanner userInput = new Scanner(System.in);
boolean keepLooping = true;
int loopCounter = 0;
System.out.println("The game begins. You must choose between 3 different colored hats."
+ " You can type white, black, or gray.");
while (keepLooping == true)
{
hatColor = userInput.next();
switch(hatColor)
{
case "white":
System.out.println("You have chosen the path of well intentioned decisions.");
walletDrop();
//the two items below are only there in case the wallet drop somehow completes without calling another method
keepLooping = false; // stops the while loop from looping again.
break; // breaks out of the switch
case "gray":
System.out.println("You have chosen the path of free will.");
walletDrop();
keepLooping = false;
break;
case "black" :
System.out.println("You have chosen the path of personal gain.");
walletDrop();
keepLooping = false;
break;
default : //we could just copy this default chunk for later switch statements
if (loopCounter >= 3)//end program on them
{
System.exit(0);
}
System.out.println("You didn't enter a usable answer. Try again");
loopCounter++;
if (loopCounter == 3)
{
System.out.println("This program will self destruct if you enter another invalid response.");
}
}//end of switch
}//end of while
}//end of game start method
public static void walletDrop()
{
System.out.println("wallet drop successful");
}
}
So I have actually solved this right after posting. In case someone else needs to look here for help:
The issue I was experiencing was due to using the scanner method
variableToAssign = scannerName.next();
instead of
variableToAssign = scannerName.nextLine();
I've a little problem.
Myself and a few friends were playing poker yesterday but we didn't have chips so I decided to start writing a program for that [Without Cards, just Chips].
In my code I have two main variables in the Game Object.
private int id;
private long bank;
I have a different file called Aside in which I can do different calculations.
In the code below I am trying to compare all instance bank variables to see if all the banks matched [In this case this will mean a new card can be drawn, otherwise users will have to keep to either raise or fold].
Is there a way of writing this in an easier term:
package poker;
import java.util.ArrayList;
public class Aside
{
public boolean compareBanks(ArrayList<Game> x)
{
ArrayList<Game> players = new ArrayList(x);
if(players.get(0).getBank() == players.get(1).getBank() && players.get(0).getBank() == players.get(2).getBank()
&& players.get(1).getBank() == players.get(2).getBank())
{
return true;
}
return false;
}
}
Later I use this here:
while(aside.compareBanks(players))
But the loop keeps going.
I'm fairly intermediate in programming so go easy on me with mistakes.
Thank you for your time.
P.S: This is NOT a code dump.
while(aside.compareBanks(players))
{
for(Game x : players)
{
if(x.hasPayedBid() == true)
{
System.out.println("Player : " + x.getName() + " [Call, Raise, Fold]:");
action = in.nextLine();
if(action.equalsIgnoreCase("call"))
{
break;
}else if(action.equalsIgnoreCase("raise"))
{
System.out.println("How much are you raising? $");
int raise = in.nextInt();
table += raise;
x.raise(raise);
}else
{
x.fold();
}
}
}
in.nextLine();
for(Game x : players)
{
System.out.println(x.toString() + "\n");
}
}//End While
You can do it using java-8 Stream API something like this
return players.stream().allMatch(p -> p.getBlank().equals( players.get(0).getBalnk()))
However if you will use while(aside.compareBanks(players)) and all elements of the list have equal blank value, your while loop will never stop. It is the same as while(true). So in this case you probably need to use if(aside.compareBanks(players)) or in case of equal blank values change them.
Try this
long bankValue=0;
For(Game player: players){
bankValue+=player.getBank();
}
if(bankValue==(players.get(0).getBank()*players.size)){
return true;}
else return false;
I've been working on a small project trying to learn some basics, I'm trying to make a clone of space invaders. I'm not really experienced (which is why I'm doing this) and I've run into something I've never had a problem with before.
My problem is with loops, I've used basic loops but I'm using some nested loops now and it's giving me some problems. Here is the code that breaks my project
public void moveLevel(int l, ArrayList ms){
switch(l){
case 1:{
centerX = 60;
centerY = 35;
alienArray = ms;
moveRight = true;
while(moveRight == true){
x += 1;
}
}
case 2:{
}
}
}
I can show more code if anybody thinks it would help, but basically, this block gets the level number (l) passed to it as well as an array list which holds about 15 'alien' objects. The line 'x+=1' is what moves the aliens (the location of each alien is x).
This code is called from another function which is constantly called from a swing timer.
What is happening, is that when the code reaches this point, the program seems to freeze. I have a button on the JPanel that doesn't react, I have a hotkey to close the application which doesn't react, and exiting the application with the mouse does nothing (I've included a DefaultCloseOperation(EXIT_ON_CLOSE) in the JFrame which works without this while loop).
if I replace the word 'while' with 'if', like below the code works fine.
public void moveLevel(int l, ArrayList ms){
switch(l){
case 1:{
centerX = 60;
centerY = 35;
alienArray = ms;
moveRight = true;
if(moveRight == true){
x += 1;
}
}
case 2:{
}
}
}
I've also tried a do, while loop.
I have no idea what the problem is, I assume it's a logic error but it seems fairly straightforward to me. Again, if anybody would like to see the rest of the code I can post it. Otherwise, if anybody has any suggestions I would appreciate it. I'm open to specific advice or just general advice on code efficiency. Thanks
ANSWER
Okay I've gotten my code moving forward thanks to Ted Hopp, who commented below. Looks like an infinite loop was being executed within the case statement.
Here is my fix for any who are curious, I've included the function that calls the function from the original post.
public void move(int l, ArrayList ms){
level = l;
alienArray = ms;
moveLevel(level, alienArray);
centerX += horizontal;
centerY += vertical;
x += horizontal;
y += vertical;
if(moveRight == true){
horizontal = 1;
vertical = 0;
System.out.println(centerX);
}
else x -= 1;
}
public void moveLevel(int l, ArrayList ms){
switch(l){
case 1:{
alienArray = ms;
moveRight = true;
if(moveRight == true){
if (centerX > 300){
moveRight = false;
}
if(moveRight == false){
if(centerX < 100){
}
}
}
}
break;
case 2:{
}
}
}
This just basically moves all of the aliens to the right and stops so far, but I've moved past the original issue.
You have an infinite loop:
moveRight = true;
while(moveRight == true){
x += 1;
}
because moveRight enters the loop as true and will never become false by repeatedly executing x += 1;.
It looks like you're trying to get something to animate continuous motion to the right. However, this is not the way to do it because your loop won't let any other part of your code (including the rendering) to execute. Without knowing more about your code structure, it's hard to provide specific advice, but I suggest you read up on animation loops. There are lots of tutorial resources on the web on the subject. Look for things like java swing animation loop.
Also, it looks like you need a break; statement at the end of each case.
You loop, as in its current state, is infinite. You'll need to have a condition where your boolean variablemoveRight will be set to false.