Java Console Game Development | Methods [closed] - java

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
Alright, allow me to elaborate on my dilemma.
I'm making a Console Game with Java. It's not going to be super simple, but I don't want it to be really advanced either. I'm just trying to test my skills using the basics that I've learned. I've started a few times, but constantly ran into the same "problem".
It's not exactly a problem though, just something I could do better. The best way to explain it is to just show some example code.
Here is my Main class. We'll call it "Main.java".
package com.mattkx4.cgamedev.main;
public class Main {
public static void main(String[] args) {
}
}
Ok, now let's make a new method in our Main.java. We'll call this method "Start". Our Main class now looks like so:
package com.mattkx4.cgamedev.main;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
}
public static void start() {
System.out.println("This is the start.");
Scanner s = new Scanner(System.in);
System.out.println("Enter \"NEXT\" to continue.");
String in = s.nextLine();
if(in.equalsIgnoreCase("NEXT")) {
}else{
System.out.println("Please input \"NEXT\".");
start();
}
}
}
Now we'll add two more methods. We'll call them "middle" and "end". Our finished class now looks like so:
package com.mattkx4.cgamedev.main;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
start();
}
public static void start() {
System.out.println("This is the start.");
Scanner s = new Scanner(System.in);
System.out.println("Enter \"NEXT\" to continue.");
String in = s.nextLine();
if(in.equalsIgnoreCase("NEXT")) {
middle();
s.close();
System.exit(0);
}else{
System.out.println("Please input \"NEXT\".");
start();
}
}
public static void middle() {
System.out.println("This is the middle.");
System.out.println("Let's move on to the end.");
end();
}
public static void end() {
System.out.println("This is the end.\nFinishing up, and heading back to the start() method to close program.");
}
}
What I've written here is in my opinion a very inefficient program. Inefficient to code with that is. There's has to be another way to doing this program, rather than calling methods inside of other methods to move along the program.
A summary of my question: Is the above code the most efficient way to write a console game?
Thanks in advance! If you have any questions I'll be happy to answer them.
-Matthew

There are many kinds of answers to your question. I'll just enumerate some basic things.
Your design is linear and completely rigid. Unflexible. Most applications like this, rather than chaining any methods or the like, store a state somehow. This is often achieved with an enum. It's important to understand how state-based programming works. So you might have something like:
public enum GameState {
LOAD, START, STOP, BEGIN, MIDDLE, END, GAME_OVER // ... and so on
}
You're using a bunch of static methods. This is certainly not what you want to do. It completely abandons any object-orientation. If you're making a game world, you will, ideally, have a class for every distinct object in your world, and they will be arranged in a logical hierarchy, by extends-ing each other or implements-ing different interfaces.
You will need to learn concurrency. Your user input will almost necessarily come asynchronously to the rendering of your game, if it has any sophistication at all. At the very, very least, you'll probably at least need Swing to create a GUI.
So, just with those three very basic notes, you will need to study up on object-orientation, polymorphism, concurrency, and all the various data structures available to you. Your example, to be frank, has the sophistication of a Java 101 project. (I'm not saying that to be mean.) If you plan to make a real game, you'll need a lot more of the basics under your belt before you can make real headway.
It's good that you're thinking big, and it's good that your goals for programming are big. But break that big dream up into manageable chunks. It will get your farther, faster, and it will also prevent you from getting discouraged.
Best of luck to you!
As a side note, if you start coding up some simple games (even something as simple as a console-based Hangman or Tic-Tac-Toe), please come around to the Code Review Beta. We'll be more than happy to give you a detailed review of your code and help you along the path to becoming a veteran programmer! It's a good community with a lot of very constructive criticism. I've both helped people there (with Java) and received a good amount of help as I learned Python.

Well, I don't quite get what this has to do with performance or optimization. But normally you use classes and methods to structure your program.
That being said, there is a huge mistake in your start method. You should axoid the unnecessary recursion and use a loop instead, and remove the exit call:
public static void start() {
System.out.println("This is the start.");
Scanner s = new Scanner(System.in);
System.out.println("Enter \"NEXT\" to continue.");
String in = s.nextLine();
if(in.equalsIgnoreCase("NEXT")) {
middle();
s.close();
System.exit(0);
}else{
System.out.println("Please input \"NEXT\".");
start(); // <-- recursion!
}
}
Better do it like this:
public static void start() {
System.out.println("This is the start.");
Scanner s = new Scanner(System.in);
System.out.println("Enter \"NEXT\" to continue.");
while ( !s.nextLine().equals("NEXT")) {
System.out.println("Please input \"NEXT\".");
}
middle();
// you probably also want to put "end();" here - it is not called in the original code
s.close();
}

I guess what you are trying to build up is an main skeleton of the application. I suggest to search for "Game Loop". There a lots of good articles down there about that.
For a general solution, the algorithm is, at big scales, more or less like this:
while (notExit()) {
event = getNextEvent(); // this can be the user keyboard input or mouse
renderGame(); // display the graphics on the screen
doGameLogic(event); // do the game logic according to the events occurred
}
Later, you must take into account how many times per seconds you draw on the screen (FPS) and how many times you compute changes (Physic Frames per second).
Any analogy to the GUI programming is just pure coincidence. I was joking, it is not coincidence, is a fact that GUI and Game Programming shared a thread that fulfill the role of event dispatch thread.
For more information i suggest to read this tutorials : http://sol.gfxile.net/gp/index.html.
Hope it helps!

It really depends on the type of application/game how you want to structure it.
In this case, you may find it useful to have some kind of control method which runs the functions in the correct order and has your "flow" logic.
In a more complicated game this method would deal with user input that directs them to different rooms/levels/etc. And you may even have smaller control methods that deal with sub parts.
For instance,
You could have a playGame method that calls registerPlayer(), which would process getting the player's name and any other information. When that method returns then playGame would call a levelOne() method and so on and so forth.
Just try to break it up into logical units for your game!

solution from top of my head,
create class
class Location{
public Location( String locationId, String desctiption, List<String> exit){
//populate fields
}
private final String locationId;
private final String desctiption;
private final List<String> exits;
//getters ommited
}
then you could have 3 locations;
start = new Location("START","This is the start.",Arrays.asList("middle"));
middle= new Location("middle","This is the middle.\nLet's move on to the end.",Arrays.asList("end"));
end= new Location("end","This is the end.",null);
now your launcher class
public class Game {
Map locations = new HashMap();
public Game() {
locations.put("START", new Location("START", "This is the start.",
Arrays.asList("middle")));
locations.put("middle",
new Location("middle",
"This is the middle.\nLet's move on to the end.",
Arrays.asList("end")));
locations.put("end", new Location("end", "This is the end.", null));
}
public static void main(String[] args) {
Game game = new Game();
game.start();
}
private void start() {
visitLocation(locations.get("START"));
}
public void visitLocation(Location location) {
System.out.println(location.getDescription());
if (location.getExits().isEmpty()) {
return;
}
Scanner s = new Scanner(System.in);
String in = "";
do {
System.out.println("Choose exit from location : ");
for (String exit : location.getExits())
System.out.print(exit + " ");
in = s.nextLine();
} while (!location.getExits().contains(in));
s.close();
visitLocation(locations.get(in));
}
}
this is still not best but i think it will give you some ideas,

Related

Why do I get 'Bash (input): command not found' error when using a string for the input, but when I change that part of the code to integers, it works?

I have this program that I'm writing that mainly runs similar to a simple choose your own adventure game. It's a trouble shooting guide for rocketry, that mainly for personal use. It has simple value inputs, y/n, a,b,c,d, and so on. After a few different segments I decided to ask the user (incase I give it to friends or something) if they would like to hear a tip, if they said yes, the tip would be printed out, if not, the program would continue running. When I tested it, i got the error message: 'bash y: command not found'.
All of the syntax is correct (that was the best answer I could find to try to correct the problem, didn't apply), and I don't know what bash is, and I'm using replit, incase that matters.
I get this error in two different areas, but here is an example of one:
//problem code
class A{
public static void tip(){
Scanner scan = new Scanner(System.in);
System.out.println("Would you like to hear a tip? (y/n)");
String tipA = scan.nextLine();
if (tipA.equals("y")){
System.out.println("blahblahblah");
}
}
}
//there was a typo in this post but not in the actual code, wish it was the actual problem, thanks for pointing it out
Then I changed it to this:
//the 'fixed' code
class A{
public static void tip(){
Scanner scan = new Scanner(System.in);
System.out.println("Would you like to hear a tip? (y(1)/n(2))");
int tipA = scan.nextInt();
if (tipA == 1){
System.out.println("blahblahblah");
}
}
}
It works, but as you can see in the 'fixed' code, the y/n doesn't look as nice, and I am also curious as to why, because I could not find any answers pertaining to this scenario.
The other area is similar, but instead of "y/n", it is 'A, B, C, D' choices.
I have my current workaround, but it would be nice to have a solution to polish the program a bit.
Any help is much appreciated.
It sounds like your problem is confusion about what nextLine does. It doesn't do what 99% of java programmers (and most tutorials) think it does. It's not a bug - it does exactly what the javadoc says, but, it's not what you'd expect.
See This answer that explains precisely what to do. Boils down to:
public static void tip() {
Scanner scan = new Scanner(System.in);
scan.useDelimiter("\\R");
System.out.println("Would you like to hear a tip? (y/n)");
String tipA = scan.next();
if (tipA.equals("y")) {
System.out.println("blahblahblah");
}
Generally you'd want to make a scanner exactly once (in your main method perhaps), create a new instance of your Main class, set up the Scanner as a field of it, and then reuse it in all your methods. This saves typing, is easier to test, more flexible, etc:
public class ExampleMain {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
s.useDelimiter("\\R");
ExampleMain app = new ExampleMain();
app.scanner = s;
app.go();
}
private Scanner scanner;
private boolean running;
void go() {
running = true;
while (running) {
tip();
// whatever other commands and such you'd like go here
}
}
void tip() {
System.out.println("Would you like to....");
}
}
This also lets you do things like write a method that repeatedly asks for a specific kind of input (say, an integer between 1 and 9, as you're showing a menu with 9 options), and, using a while loop, keep asking if the user fails to enter appropriate responses. Otherwise you have to copy/paste a ton of code which is naturally not how you should be programming.

Java Is okay to put input/output only in main method?

I'm new to Java Programing.
Lately I am doing the Java assignment.
I sew this method in user-defined class
public void intputRank( Scanner s) {
salary = s.nextInt();
}
I was confused because I always want put I/O in main method (like in C++ I only write cin cout in main function). I have 2 reasons for doing this:
It's easy for me to see where my program accept input. When there is something wrong about I/O, I just need to debug the main method.
Scanner is a more complicated Class, use it as parameter would make unknown wrong.
So, kind Stack Overflowers, is it just a bad example or I understand something wrongly?
If it is the latter? Why not
public void inputRank( int asalary) {
salary = asalary;
}
//in main method
Scanner reader = new Scanner(System.in);
int asalary = reader.nextInt();
//then pass the asalary as parameter
If your program needs to be robust, e.g. when prompting for an integer it'll validate the input and re-prompt if bad, then having reusable helper methods is a good thing.
This means that you'll need multiple methods that use Scanner. Now, you can pass the Scanner object in as a parameter, or you can put it in a field, that's entirely up to you.
But the main point is that having code in a method that uses a Scanner is perfectly fine, and it really is a must for robust code, otherwise you'll ruin the DRY (Don't Repeat Yourself) principle.
Example:
public static int promptNonNegativeInt(Scanner sc, String prompt) {
for (;;) {
System.out.print(prompt + ": ");
if (! sc.hasNextInt()) {
System.out.println("** Not a valid number, please try again");
sc.nextLine(); // discard bad input
continue;
}
int value = sc.nextInt();
sc.nextLine(); // discard any extra text on the line
if (value < 0) {
System.out.println("** Number cannot be negative, please try again");
continue;
}
return value;
}
}
Example use
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int value = promptNonNegativeInt(sc, "Enter number");
System.out.println("You entered: " + value);
}
Even more complex is if you need to prompt for an object with multiple fields. Isolating the code that does this is good programming (separation of concern), so writing a promptMyObject(Scanner sc) method is a good thing.
Especially if you need to prompt for various objects. If you leave all prompting code in the main() method, it'll be huge and unreadable. It would be a God method, a variation of the God object:
A God object is an object that knows too much or does too much. The God object is an example of an anti-pattern.
In general, I prefer to write methods that take simpler types over more complicated types. This makes them easier to compose and reuse later on.
In your example, the method that takes an int could be considered better than taking a Scanner, because int is simpler and more common than a Scanner. That being said, the name inputRank kind of implies it's doing to read / receive input, so I would be tempted to rename it to something like applyRank in this case.

Restarting program from a certain point after an if

I started studying Java not too long ago, I am currently trying to make a little game to see if I got the things I saw right.
I want to make a "game" that let's you choose between two dialogue options which have different consequences.
This is the code I used:
package programs;
import java.util.Scanner;
public class Programma1_0 {
public static void main(String[] args) {
System.out.println(
"You wake up in a laboratory. You don't remember ever being there. You actually don't remember anything.");
System.out.println("A door opens, a girl comes towards you.");
System.out.println("Girl:<<Hi, I see you woke up. How are you feeling?>>");
System.out.println("(Write Good or Bad)");
Scanner first = new Scanner(System.in);
String firstch = first.nextLine();
if (firstch.equals("Good")) {
System.out.println("Great, we have a lot to explain.");
} else if (firstch.equals("Bad")) {
System.out.println("You should be alright in an hour or so. You've slept for a long time.");
} else {
System.out.println("(I told you to write Good or Bad)");
}
}
}
So far it's working as intended. The only problem is that if I write something other than Good or Bad i get the message "(I told you to write Good or Bad)" and the program terminates. Is there a way to automatically restart it? If i put more choices in, I want the program to automatically restart from the question where it terminated (So I don't play through half of the game, get a question wrong and have to restart the program from the start), is that possible?
Thanks.
You can accomplish this by putting this before your if statement.
while (true) {
if (firstch.equals("Good") || firstch.equals("Bad"))
break;
else {
System.out.println("(I told you to write Good or Bad)");
firstch = first.nextLine();
}
}
Then you can also remove the last else part of your if statement.
Now it will continue asking for a new input till it gets either "Good" or "Bad"
You can simply put your if-else statement inside the do-while loop, that way you can loop through until you get correct response
int i = 0;
do {
System.out.println("(Write Good or Bad)");
firstch = first.nextLine();
if (firstch.equals("Good")) {
System.out.println("Great, we have a lot to explain.");
i = 0;
} else if (firstch.equals("Bad")) {
System.out.println("You should be alright in an hour or so. You've slept for a long time.");
i = 0
} else {
System.out.println("(I told you to write Good or Bad)");
i = 1;
}
} while (i == 1);
You can partition your program into separate methods. Here I created a method called retrieveAnswer() which its only task to create a Scanner and get input. This method will return a String as seen in the public static String header.
Another method I created was entitled getResult() which takes a String argument and will now compare the String passed from
String firstch = retrieveAnswer();
getResult(firstch);
If the result goes to the else block, it will call retrieveAnswer() and pass the value returned to getResult() as seen in getResult(retrieveAnswer()) which will then restart the whole process.
There are multiple solutions to this, but I just took the recursion route instead. Good luck with Java! If you are confused, look more into methods as they are VERY essential in programming.
import java.util.Scanner;
public class Source {
public static void main(String[] args) {
System.out.println(
"You wake up in a laboratory. You don't remember ever being there. You actually don't remember anything.");
System.out.println("A door opens, a girl comes towards you.");
System.out.println("Girl:<<Hi, I see you woke up. How are you feeling?>>");
System.out.println("(Write Good or Bad)");
String firstch = retrieveAnswer();
getResult(firstch);
}
public static String retrieveAnswer(){
Scanner first = new Scanner(System.in);
String firstch = first.nextLine();
return firstch;
}
public static void getResult(String firstch){
if (firstch.equals("Good")) {
System.out.println("Great, we have a lot to explain.");
} else if (firstch.equals("Bad")) {
System.out.println("You should be alright in an hour or so. You've slept for a long time.");
} else {
System.out.println("(I told you to write Good or Bad)");
getResult(retrieveAnswer());
}
}
}

Abbreviation Decoder Script in Java

I am working on a program that is supposed to pull abbreviated text meanings from a list that is created from if-else statements. I am running into trouble with the logic of making the program see an incorrect input and provide a suggestion from the supported list. Here is the code we were given to edit.
import java.util.Scanner;
public class TweetDecoder {
public static void main(String[] args) {
Scanner scnr = new Scanner(System.in);
String origTweet = "";
System.out.println("Enter abbreviation from tweet: ");
origTweet = scnr.next();
if (origTweet.equals("LOL")) {
System.out.println("LOL = laughing out loud");
}
else if (origTweet.equals("BFN")) {
System.out.println("BFN = bye for now");
}
else if (origTweet.equals("FTW")) {
System.out.println("FTW = for the win");
}
else if (origTweet.equals("IRL")) {
System.out.println("IRL = in real life");
}
else {
System.out.println("Sorry, don't know that one.");
}
return;
}
}
This is for a class so I would like to know if someone can push me in the right direction rather than give the full answer or the string that I should be using. I feel like is should be something to do with String Comparison or String Access Operations but I cant seem to get it nailed down. If someone can assist I would greatly appreciate it. Thank you in advance!
it wouldn't let me add a comment, so i suppose here will do.
I would suggest looking into the .startsWith method. Its a method contained in the String class.
For example,
if(origTweet.startsWith("L")) //
System.out.println("Perhaps you meant LOL");
sorry if this isn't what you meant / wanted

Java declaration/ variable scope issues

I'm relatively new to java, and after much searching, I just can't pair up any solutions of related issues to mine. I'm trying to implement a very simple method to write to/ read from an array, and it's not being recognized by the compiler. "Keyboard" is a "variable not recognized" either. Here's a declaration of the array, with the method a bit further down that works on it... (first time long time btw :) Many thanks in advance...
private static void loadMakeModelYear()
import java.util.Scanner;
String [][] makeModelYear = {{"Make", "Model", "Year"},{"Blank", "Blank", "Blank"}};
private static void loadMakeModelYear()
{
for (int i = 0; i < 3; i++)
{
System.out.println("Please enter a " + makeModelYear[i][0]);
makeModelYear [i][1] = keyboard.nextLine();
}
}
This is just a guess, but your code appears to use keyboard with a lowercase k, while your error message uses Keyboard with a capital K. Check the case of your variables.
I juste rewrote your example as it may explain things better here.
import java.util.Scanner;
class SomeClass
public static void main(String...args) {
loadMakeModelyear();
}
static String[][] makeModelYear = new String[][] {
{"Make", "Model", "Year"},
{"Blank", "Blank", "Blank"}
};
private static void loadMakeModelYear() {
Scanner keyboard = new Scanner(System.in);
for (int i = 0; i < 3; i++) {
System.out.println("Please enter a " + makeModelYear[0][i]);
makeModelYear [1][i] = keyboard.nextLine();
}
}
}
There are a lot more resources for Java than there is for C#. One site that is often very useful (to me at least) is Real's howto (check out the Java index).
What IDE are you using for this? NetBeans does a decent job of providing most VS2010 functionality.
I do not see keyboard declared. Do you declare it elsewhere?
"keyboard" is not a special object in Java giving you access to the real life keyboard, if that helps.
My My My ..... Oh my dear, you're grossly confused in the way Java language operates. Lets look at your code more closely.
1.) Firstly, import statement should be the first statement in your file. The only statement which can come before import is the package statement.
but the glaring mistake which you're doing is by declaring methods like this. In java the scope of any method is bound to a class. This is not declarative style programming, where you can declare a stand-alone method. The same argument holds for your array as well, this array and method must be part of some class, even if they are static.
3.) Secondly, you are using a variable keyboard, but you have not declared it anywhere.
I hope you do realize that you're just using the wrong paradigm. Say this after me, "Java is purely OO "
Regards
AViD
I think I see your problem. This is just a guess, and I'm not sure if you have already done this. In the case that you haven't you might want to set your reference variable keyboard to the Scanner class. This can be done by:
Scanner keyboard = new Scanner(System.in);

Categories

Resources