I'm making (my own version of)roulette with Java, and one of the types of bets a player can make is to choose the color that is going to be rolled. (Even is black, odd is red). Is there a way I can use a switch statement to compare a string against an enum?
private enum colors{red, black};
private String colorGuess;
private boolean colorVerify = false;
public void getColorGuess(){
do{
Scanner in = new Scanner(System.in);
colorGuess = in.nextLine();
switch(colors){
case red:
colorVerify = true;
break;
case black:
colorVerify = true;
break;
default:
System.out.println("Invalid color selection!");
break;
}while(colorVerify = false);
This is what i'm trying to get but it's not letting me use the enum 'colors' in a switch statement.
You must have an instance of an enum type (its member) on which you switch. You are trying to switch on the Enum class itself, which is a meaningless construct. So you probably need
colors col = colors.valueOf(colorGuess);
switch (col) ...
BTW the name should be Colors, not colors to respect the very important and non-optional Java naming convention.
You can get an enum from a string with Enum.valueOf(). Take care here, the other answers fail to mention that Enum.valueOf() will throw an IllegalArgumentException if passed an string which isn't a valid member of the enum.
Be sure to properly format and indent your code, it helps us (and you!) read it and understand what's going on:
// note the capitalization, and the singular 'Color'
private enum Color {RED, BLACK};
// At least with the code provided, you don't need colorGuess or colorVerify to be
// instance variables, they can be local to the method. Limiting the amount of
// time a variable lives for (its scope) is critical for quality, maintainable code
public Color getColorGuess() {
Scanner in = new Scanner(System.in); // this should be outside the while loop
while(in.hasNextLine()) {
// .toUpperCase() lets you type "red" or "RED" and still match
String line = in.nextLine().toUpperCase();
try {
// Enum.valueOf() throws an exception if the input is not valid
Color guess = Color.valueOf(line);
switch(guess) {
case RED:
return guess; // return, rather than break, to exit the method
case BLACK:
return guess;
// As long as your switch statement covers all cases in your enum, you
// don't need a default: case, you'll never reach it
}
} catch (IllegalArgumentException e) {
System.out.println("Invalid color selection!");
}
}
}
Note that we now return guess in both cases, which is somewhat redundant. At least with the example code you provided, you don't actually need to track colorVerify at all, because the method will keep looping forever until a valid color is entered. You could replace the whole switch statement in my method with simply return guess; as you know it's a valid guess as soon as Color.valueOf() returns a value.
In other words, you could clean your code up to:
public static Color getColorGuess() {
try (Scanner in = new Scanner(System.in)) {
while(in.hasNextLine()) {
try {
return Color.valueOf(in.nextLine().toUpperCase());
} catch (IllegalArgumentException e) {
System.out.println("Invalid color selection!");
}
}
}
}
Notice that the method is static now, and uses a try-with-resources block to close the Scanner once you're done with it.
Related
I am a very new, relatively inexperienced Java programmer. The project I am working is just a test of my current skills, and my goal is to write as efficient a program as possible.
In essence, I have three classes: A, B, and C. B extends A and C extends B, but I want a Scanner object in C to be used in a switch statement (part of a larger method) in A.
The reason I want this is because I do not want to overload the method in A (copy-pasting the same code with different parameters is not ideal), and I do not want to combine all of my classes into one (the code is simple enough to do this, but I want to test my knowledge of object creation and use).
Here is some of the code:
import java.time.LocalDateTime;
public class WatchFace {
// MASTER TIME
LocalDateTime dateTimeObject = LocalDateTime.now();
int hour = dateTimeObject.getHour();
int minute = dateTimeObject.getMinute();
// WATCH FACE METHOD
public void watchFaceMethod() {
// Code I'd like to utilize; this is my question for StackOverflow
// switch (userInput) {
// case 1:
// // Intentionally do nothing
// break;
//
// case 2:
// // Change minute and hour to some values obtained by timezone stuff
// break;
//
// case 3:
// // Change both minute and hour to -1
// break;
// }
// Basically, the rest of this code just prints something different to the Windows CLI depending on the
// hour and minute variables' current values (i.e. beyond the intended switch statement).
}
}
import java.time.format.DateTimeFormatter;
public class Watch extends WatchFace {
static void watchMethod() {
// Code printing some Strings is here.
WatchFace watchFaceObject = new WatchFace();
watchFaceObject.watchFaceMethod();
// Code printing some more Strings is here.
DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("hh:mm a 'on' EEEE, MMMM dd, yyyy");
String dateTimeDisplay = watchFaceObject.dateTimeObject.format(dateTimeFormat);
System.out.print("\nIt is currently " + dateTimeDisplay + "\n");
if (watchFaceObject.hour == 11 && watchFaceObject.minute == 11) {
System.out.println("Make a wish!");
}
}
}
import java.util.Scanner;
public class InteractiveWatch extends Watch {
public static void main(String[] args) {
// WATCH OBJECT
Watch watchObject = new Watch();
// STARTUP
System.out.println("Welcome to Interactive Watch!\n");
System.out.println("What would you like to do?");
System.out.println("[1] See local time.");
System.out.println("[2] See local time in a particular place.");
System.out.println("[3] See something special.\n");
Scanner scannerObject = new Scanner(System.in);
// INPUT
boolean loopBreak = true;
while (loopBreak) {
loopBreak = false; // loopBreak set to false
String userInput = scannerObject.nextLine(); // User inputs some string
switch(userInput) {
case "1":
watchObject.watchMethod(); // watchFaceMethod ideally detects userInput == 1
break;
case "2":
watchObject.watchMethod(); // watchFaceMethod ideally detects userInput == 2
break;
case "3":
watchObject.watchMethod(); // watchFaceMethod ideally detects userInput == 3
break;
default:
loopBreak = true; // loopBreak set to true; while loop reinitiates
System.out.println("\nPlease enter a valid key.\n");
break;
}
}
}
}
I learned everything I have from w3schools' Java course, but I still have much more to learn. Let me know if what I want is even possible, or anything else that would make this code more efficient. Thank you!
The short answer is no. You cannot access an object belonging to a subtype.
The long answer: The watchFaceMethod does not know that the call came from an InteractiveWatch. Think about it this way; what if we made a new class OtherWatch, which also extends Watch. Suppose OtherWatch does not have a Scanner object. Now what is watchFaceMethod() going to do when it's told to invoke a method of your Scanner object? It can't do anything, because the Scanner object does not exist. I'm not sure I understand why you're trying to access the Scanner object in watchFaceMethod in the first place, though. You already got the input from the user. You don't want to get more input, so you really want access to the string that the nextLine() method returned. I would approach this by simply passing the string up the hierarchy as a parameter to the watchMethod() and watchFaceMethod() methods. It's not "inefficient" to pass parameters to another method. You would end up with methods something like these:
public void watchMethod(String userInput) {
...
WatchFace watchFaceObject = new WatchFace();
watchFaceObject.watchFaceMethod(userInput);
...
}
and
public void watchFaceMethod(String userInput) {
switch (userInput) {
case "1":
...
break;
case "2":
...
break;
case "3":
...
break;
}
...
}
Another option is to make userInput a public, static variable, and then just reference it from watchFaceMethod(), but I would advise against this as you could quickly lose track of what methods are accessing and mutating that variable.
One more little thing I noticed about your code; you use \n for your line separators, which produces a linefeed character. This is the standard line separator on UNIX systems, but Windows uses a carriage return together with a linefeed, and OSX uses just the carriage return, so if you want your returns to show up on all platforms, you should use %n, which produces the correct platform-specific line separator.
No, it's not possible.
superclass does not have access to members of its subclasses in Java. But the subclass has access to all non-private members of its superclass.
I am a java beginner, and in this particular problem I practiced making a program that converts any given string to lowercase string. Is there a a better way to achieve this goal in java (in terms of design)?
Also, how does the "else" (after "else if") catches or waits for me to make an input. Somehow that part does not make sense to me, even though I achieved what I wanted. How is the value of "ans" from input transferred to the entire loop and used until the loop is closed?
After many attempts and failures, I used a separate method for the conversion part. My second question is a bit too complicated to be researched.
import static java.lang.System.out;
import java.util.Scanner;
public class MyClass {
public static Scanner s = new Scanner(System.in);
public static String ans;
public static void main(String args[]) {
Conversion();
do {
ans = new String(s.nextLine());
if (ans.equalsIgnoreCase("Y")) {
Conversion();
} else if (ans.equalsIgnoreCase("N")) {
out.println("Thank you for using this program!");
break;
} else {
out.println("Invalid entry!");
out.println("Would you like to convert another string?\n(Please type 'Y' for yes, or 'N' for no.)");
}
} while (ans != "N");
}//END MAIN
public static void Conversion() {
out.println("Please enter string to be converted to lowercase: ");
String str = new String(s.nextLine());
out.println("Your new string is: " + str.toLowerCase());
out.println("Would you like to convert another string? (Y/N)");
}
}
I notice a few issues; Conversion looks like a class-name (Java naming convention would be conversion) and ans != "N" is using == instead of .equals - and wouldn't ignore case (!ans.equalsIgnoreCase("N")). Globals (e.g. static) are bad (pass the Scanner to the methods that need it), and the static import just makes the code more difficult to reason about (in my opinion). Your current loop doesn't really follow a conventional form, I would extract the prompt and loop for "another" conversion to a new method and if you must print a thank you I'd do so after the "main loop". Something like,
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
do {
conversion(sc);
} while (another(sc));
System.out.println("Thank you for using this program!");
}
public static void conversion(Scanner s) {
System.out.println("Please enter string to be converted to lowercase: ");
System.out.printf("Your new string is: %s%n", s.nextLine().toLowerCase());
}
public static boolean another(Scanner s) {
while (true) {
System.out.println("Would you like to convert another string? (Y/N)");
String ans = s.nextLine();
if (ans.equalsIgnoreCase("Y")) {
return true;
} else if (ans.equalsIgnoreCase("N")) {
return false;
}
System.out.println("Invalid entry!");
System.out.println("(Please type 'Y' for yes, or 'N' for no.)");
}
}
Answering your first question:
There are many design patterns and practices so many people can argue what I would recommend you to do. It's basically the same for all programming languages. Let's take your function "Conversion". The name itself says that you use it to convert stuff. Not to display, not to prompt - to convert. In this case, the only actual thing it should do is to convert upperCase to lowercase. In fact, you might want to specify what type of conversion it has in the name of the function (convertToLowerCase?). In fact, in Java, we use lowerCamelCase for all function names and UpperCamelCase for classes.
If you accept my previous suggestion, you could break the Conversion function into multiple ones like promptUserForInput, WrongInputHandler and so forth.
If I understood your second question correctly, you wonder about the way the code executed and how the variable ans is transferred further into the loop. Let's take a look at your code and what variables do:
You initialize your variable in the class MyClass by making it accessible to all methods in the class;
You prompt the user for the input to assign to this variable inside the do..while loop with this line ans = new String(s.nextLine()); which saves the value of the variable and, again, which can be accessed inside the whole class so its value is changed.
It goes into the if..else if...else statement. The way it works, it goes line by line - if the first if-statement fails, it goes on until it finds a truthy statement and it doesn't go any further. In your case, if the ans is not equal to either y/Y/ it will go to else if statement and if it's not n/N, it will go to else (so basically whatever except y/Y/n/N) and will be executed. After that, it jumps into the while (ans!= "N"); line where it compares your class-member variable ans and if it's not equal to "N" it starts over the loop right after the do{ part until you type in the "N".
I hope that makes sense. Whenever the program is asking you for input, it does not execute code further but is stuck until you provide any input. The value from input itself isn't passed throughout the loop and the program. The reason why you can use it because you created a higher-scope variable ans where you saved the result of your input.
IMPORTANT: if you've declared the ans inside the do..while loop, you would've not been able to have accessed it in the while (ans...) because it will 'die' right before the curly brace between do { ...here} while(). If you want to learn more about the scope and variables in general, you can read this article.
Here is my code example:
public static void main(String args[]) {
//declare before entering the loop to have higher scope
String ans = "y";
do {
//we get the given string to convert from the user
String str = promptForString();
//we convert the string
str = converseStringToLowerCase(str);
//display the string (could use another function for that: easier to debug and locate problems and in bigger projects)
out.println("Your new string is: " + str);
//prompt user for respond to continue or not
ans = promptForContinue();
handleResponse(ans);
} while (!ans.equals("n"));
}//END MAIN
//prompts user for an input string
public static String promptForString() {
out.println("Please enter string to be converted to lowercase: ");
String str = new String(s.nextLine());
return str;
}
//converts any given string to lower case
public static String converseStringToLowerCase(String str) {
return str.toLowerCase();
}
//is used to prompt user for reply
public static String promptForContinue() {
out.println("Would you like to convert another string? (Y/N)");
String str = new String(s.nextLine());
//is good to make if...else statements easier - it will always be lower case (or upper if you prefer)
return str.toLowerCase();
}
//easier to locate other response scenarios
public static void handleResponse(String response) {
if (response.equals("n")) {
out.println("Thank you for using this program!");
//it's not a very good practice to innaturally break loops. Use input for that in while(..) statement
// break;
} else if (!response.equals("y")) {
out.println("Invalid entry!");
out.println("Would you like to convert another string?\n(Please type 'Y' for yes, or 'N' for no.)");
}
}
I am working on a program that allows me to move a pen, making a mark on a canvas. At the moment, I have a method called convertToInteger in class "MyInput" (which in the class with my methods I've referred to as "reader"), which converts a string into an integer.
public int convertToInteger(String word)
{
return Integer.parseInt(word);
}
I've then tied this into my method, converting a string input into an integer.
case "move":
int distance = reader.convertToInteger(command.get(1));
brush.move(distance);
break;
Thus, in my program I can type "move 100" and the brush move 100 pixels. The code, in its current state, crashes with an exception error if I tried typing a non-integer; e.g. "move here".
In "MyInput" class, I created a boolean method that checks to see if it's a integer or not using 'try' and 'catch':
public boolean isAnInteger(String word)
{
boolean ok;
try {
Integer.parseInt(word);
ok = true;
}
catch(NumberFormatException ex) {
// Non-integer string.
ok = false;
}
return ok;
}
Then tried implementing it in my code:
case "move":
int distance = reader.convertToInteger(command.get(1));
if (reader.isAnInteger(command.get(1)) == true){
brush.move(distance);
}
else {
printError();
}
break;
When I run the code and type something like "move here" in the terminal, it throws an exception so clearly its bypassing my code - but typing "move 100" or any other valid integer works.
Any suggestions? Thanks in advance.
Your instructions are in the wrong order. Your are attempting to parse, then checking if it can be parsed. You should really check first, then try to parse.
I'm trying to make a "choice" menu, where I am using a switch/case function to make the user choose. The problem in my code is that I want it to keep asking for input until the user types in "sair" which means "exit" in portuguese. When they type "ajuda" which means "help" they get a list of available commands to execute, but if the user types "ajuda" then the "sout" is executed and build is finished, the program ends there...
My goal is to make it run until we choose to stop, I think there was a ways using readln or similar.
Anyways, here's the chunk of code regarding to the choice:
public static String escolha() {
Scanner userInput = new Scanner(System.in);
String strEscolha = userInput.next();
boolean sair = false;
do {
switch (strEscolha) {
case "ajuda":
System.out.println("Comandos disponiveis:");
System.out.println("Ajuda; Fogo; Jogo; Resposta; Estado; Acaso; Reset; Sair;");
break;
case "Ajuda":
System.out.println("Comandos disponiveis:");
System.out.println("Ajuda; Fogo; Jogo; Resposta; Estado; Acaso; Reset; Sair;");
break;
case "sair":
System.out.println("Obrigado por jogar!");
sair = true;
break;
default:
System.out.println("Comando Invalido!");
continue;
}
} while (sair == false);
return null;
}
If anyone has a simple way to make it keep asking for commands, please let me know :(
Thanks in advance!!
PS: I just started, plese don't judge, my knowledge on java is neglectable :\
The main problem of your code is that you do not request user input in the 'ajuda' case.
Here is the code with some minor changes and some comments and recommendations:
// if your method isn't supposed to return anything, simply make it void
public static void escolha() {
Scanner userInput = new Scanner(System.in);
// print some useful information when the application starts, so that the user knows
// what to do
System.out.println("Comandos disponiveis:");
System.out
.println("Ajuda; Fogo; Jogo; Resposta; Estado; Acaso; Reset; Sair;");
String strEscolha = userInput.next();
boolean sair = false;
do {
// remove duplicate case by converting the input to lower letters
switch (strEscolha.toLowerCase()) {
case "ajuda":
System.out.println("Comandos disponiveis:");
System.out
.println("Ajuda; Fogo; Jogo; Resposta; Estado; Acaso; Reset; Sair;");
// read the user input
strEscolha = userInput.next();
System.out.println(strEscolha);
break;
case "sair":
System.out.println("Obrigado por jogar!");
sair = true;
break;
default:
System.out.println("Comando Invalido!");
}
} while (sair == false);
// do not forget to close the scanner, it might cause a memory leak
userInput.close();
}
Firstly, remove the System.exit, or you will shut down the entire JVM without executing the subsequent code (your IDE may have given you a dead code warning about this).
Secondly, you need to use sair == false (or, better, !sair) instead of sair = false. The former is a comparison; the latter is an assignment, making sair false.
do { ... } while (false) will execute the loop body once, but will not repeat.
Thirdly, the return strEscolha; immediately before while will cause the method to return before it attempts to loop, so it should be removed.
I am making a Text-Based Adventure game. In one room, I want to ask the player what to do, and if he goes through the door he/she moves to the next room. If he/she picks up the flashlight, the "what do you want to do?" question is repeated so they can go through the door after that. Here is my code:
case 1:
System.out.println("What do you want to do? Type 'door' to go through the door or 'flashlight' to pick up the flashlight.");
String roomOneAction = input.nextLine();
switch(roomOneAction) {
case "flashlight":
System.out.println("Picked up flashlight.");
//repeat what do you want to do? question
break;
case "door":
System.out.println("You open the door.");
//continue plot, don't repeat question
break;
default:
System.out.println("Error");
// repeat what do you want to do? question
break;
}
break;
With this code right now, it repeats the question for anything you type. I do not want this to happen if "door" is typed.
Also, how can I make it so that once the flashlight is picked up and the question is repeated, the flashlight can't be picked up a second time?
This might be close to what you want:
import java.util.Scanner;
public class Game {
private static boolean flashlightPicked = false;
private static boolean doorEntered = false;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
while (true) {
int x = 1;
switch (x) {
case 1:
System.out
.println("What do you want to do? Type 'door' to go through the door or 'flashlight' to pick up the flashlight.");
String roomOneAction = input.nextLine();
switch (roomOneAction) {
case "flashlight" :
if(!flashlightPicked){
System.out.println("Picked up flashlight.");
flashlightPicked = true;
} else {
System.out.println("Already picked up flashlight!");
}
// repeat what do you want to do? question
break;
case "door":
if(!doorEntered){
System.out.println("You open the door.");
doorEntered = true;
}else{
System.out.println("Already opened the door!");
}
// continue plot, don't repeat question
break;
default:
System.out.println("Error");
// repeat what do you want to do? question
break;
}
}
}
}
In this case you should probably store the information if you want to ask again or not:
boolean askAgain = true;
//...
case "door":
//...
askAgain = false;
//...
if (askAgain) {
System.out.println("...");
}
I would recommend using a while loop here. Can the player do anything else in the room or leave the room in a different way? If they can only leave the room using the 'door' command, set up the while loop to have the terminating factor being the 'door' command.
I don't like the idea of cascading multiple switches as you did. You should use state pattern and command pattern, but I assume you're a programming beginner, so I'll just try to answer your question.
Wrap the roomOneAction switch statement in a while loop, like
boolean foundFlashlight = false;
boolean askAgain = true;
while (askAgain)
{
// question + switch statement and so on
}
if the player picks the flashflight, set foundFlashlight to true.
In the next run, the player gets asked again. If he picks flashlight,
you have to evaluate the foundFlashlight variable, if the value is true,
tell the player he already has the flashlight and he should answer again.
In the door case, simply set askAgain to false. The loop while terminate then.
But again, this is not a nice, clean and easy to maintain approach. You should take a look at some design patterns. Especially the above mentioned state pattern.