Java: Cant break after a case in a switch-case - Why? - java

I programmed a game.
I used switch case to implement a state machine.
The problem is that in case ZIEHEN_SP the break statement doesn't work.
When I debug it, the compiler just step over the break statement and goes to the next case ZIEHEN_BA.
I commented the part where the compiler ignores the break statement.
Why?
import java.util.*;
import java.util.Scanner;
import java.io.*;
class BlackJack2 {
static int chips = 100;
static int einsatz = 0;
enum State { INIT, EINSATZ,ZIEHEN_SP, ZIEHEN_BA}
static State state = State.INIT;
static ArrayList<Integer> bankKarten = new ArrayList<Integer>();
static ArrayList<Integer> spielerKarten = new ArrayList<Integer>();
static Scanner scanner = new Scanner(System.in);
static String s = "";
static int eingabe = 0;
static void init(){
System.out.println("\nEin neues Spiel beginnt: ");
bankKarten.clear();
spielerKarten.clear();
bankKarten.add(giveCard());
spielerKarten.add(giveCard());
}
static void chipsSetzen(){
einsatz = 0;
if(chips == 0){
System.out.print("\nSie haben " + chips + " Chips!");
System.exit(1);
}
do{
System.out.print("\nSie haben " + chips + " Chips");
System.out.print("\nWie viel moechten Sie setzen? ");
try{
einsatz = Integer.parseInt(scanner.next());
} catch(Exception e){
}
} while(einsatz <= 0 || einsatz > chips);
chips -= einsatz;
}
static int sumSpielerKarten(){
int sum=0;
for(int i=0; i<spielerKarten.size(); i++){
sum +=spielerKarten.get(i);
}
return sum;
}
static int sumBankKarten(){
int sum=0;
for(int i=0; i<bankKarten.size(); i++){
sum +=bankKarten.get(i);
}
return sum;
}
static int giveCard(){
return (int)(Math.random()*11+1);
}
static boolean oneMoreCard(){
int ss = sumSpielerKarten();
if(ss >= 21){
return false;
} else {
do{
System.out.print("\nMoechten sie eine witere Karte ziehen? (y/n): ");
s = scanner.next();
if(s.equals("y")){
return true;
} else if(s.equals("n")){
return false;
}
} while(!s.equals("y") || !s.equals("n"));
}
return false;
}
static String evaluateWinner(int s, int b){
String ret = "";
if(b > 21 || (s > b && s<=21) || s == 21 && b != 21){
ret = "Player";
} else if(s > 21 || b > s || b == 21 && s != 21){
ret = "Bank";
} else if(b == s){
ret = "Both";
}
return ret;
}
static int updateMoney(int s, int b){
String winner = evaluateWinner(s, b);
int newChips = 0;
if(winner == "Player"){
newChips = einsatz*2 + chips;
} else if(winner == "Both"){
newChips = einsatz + chips;
} else if(winner == "Bank"){
newChips = chips;
}
System.out.println("Winner: "+ winner);
return newChips;
}
static void showCards(){
System.out.print("\nBank:\t");
for(int i=0; i<bankKarten.size(); i++){
System.out.print( "[" + bankKarten.get(i) + "]");
}
System.out.println("\t= " + sumBankKarten());
System.out.print("Player:\t");
for(int i=0; i<spielerKarten.size(); i++){
System.out.print( "[" + spielerKarten.get(i) + "]");
}
System.out.println("\t= " + sumSpielerKarten());
}
static void banksTurn(){
int sb = sumBankKarten();
int ss = sumSpielerKarten();
if(sb != 21 && ss != 21 && ss < 21){
while(sb < 17 || (ss > sb && sb < 17)){
bankKarten.add(giveCard());
}
}
updateMoney(ss, sb);
}
public static void main(String args[]){
while(true){
switch(state){
case INIT:
init();
state = State.EINSATZ;
break;
case EINSATZ:
chipsSetzen();
state = State.ZIEHEN_SP;
break;
case ZIEHEN_SP:
showCards();
while(oneMoreCard()){
spielerKarten.add(giveCard());
showCards();
}
state = State.ZIEHEN_BA;
break; // << Compiler ignores this statement and goes directly to case ZIEHEN_BA
case ZIEHEN_BA:
banksTurn();
state = State.INIT;
break;
}
}
}
}

Because you change state to a value that matches with State.ZIEHEN_BA condition :
state = State.ZIEHEN_BA;
So here :
while(true){
...
state = State.ZIEHEN_BA;
break;
case ZIEHEN_BA:
banksTurn();
state = State.INIT;
break;
...
}
the case ZIEHEN_BA is executed at the next iteration of the loop.
What Eclipse shows may be an optimization of the JVM performed at runtime or by the compiler. You could disassemble the class to have more information.
EDIT
I have done the test and i don't think it is a compiler optimization.
Look at this minimal example where I don't set the state in the case :
public class TestSwitch {
public enum MyEnum {
A, B
};
public static void main(String[] args) {
MyEnum state = MyEnum.A;
while (true) {
switch (state) {
case A:
break;
case B:
break;
}
}
}
}
Here is the disassembled code of the main() method :
public static void main(java.lang.String[]);
Code:
0: getstatic #18 // Field a/TestSwitch$MyEnum.A:La/TestSwitch$MyEnum;
3: astore_1
4: invokestatic #24 // Method $SWITCH_TABLE$a$TestSwitch$MyEnum:()[I
7: aload_1
8: invokevirtual #27 // Method a/TestSwitch$MyEnum.ordinal:()I
11: iaload
12: tableswitch { // 1 to 2
1: 36
2: 39
default: 39
}
36: goto 4
39: goto 4
And look at the version where I set the state in case A to enter in case B :
public class TestSwitch {
public enum MyEnum {
A, B
};
public static void main(String[] args) {
MyEnum state = MyEnum.A;
while (true) {
switch (state) {
case A:
state = MyEnum.B;
break;
case B:
break;
}
}
}
}
Here is the disassembled code of the main() method :
public static void main(java.lang.String[]);
Code:
0: getstatic #18 // Field a/TestSwitch$MyEnum.A:La/TestSwitch$MyEnum;
3: astore_1
4: invokestatic #24 // Method $SWITCH_TABLE$a$TestSwitch$MyEnum:()[I
7: aload_1
8: invokevirtual #27 // Method a/TestSwitch$MyEnum.ordinal:()I
11: iaload
12: tableswitch { // 1 to 2
1: 36
2: 43
default: 43
}
36: getstatic #31 // Field a/TestSwitch$MyEnum.B:La/TestSwitch$MyEnum;
39: astore_1
40: goto 4
43: goto 4
There is not optimization in this compiled code.
After case A execution :
36: getstatic #31 // Field a/TestSwitch$MyEnum.B:La/TestSwitch$MyEnum;
39: astore_1
the next instruction is a goto to the loop :
40: goto 4
So the optimization is probably performed at runtime by the JVM or the Eclipse debugger.

The compiler optimized your code :-)
As you set the switch variable to State.ZIEHEN_BA and there's nothing to be executed in between (while (true) and reentering the switch) that's exactly the next lines to be executed.
I'm not sure if it's supposed to behave that way (changing variable switched on inside switch will cause following cases to be checked) but in your case I totally agree with the compiler.
As you can see in this example, this behaviour is not always the case:
public static void main(String[] args) {
int i = 3;
switch(i) {
case 1:
System.out.println("1:");
break;
case 2:
System.out.println("2:");
break;
case 3:
System.out.println("3:");
i = 5;
break;
case 4:
System.out.println("4:");
break;
case 5:
System.out.println("5:");
i = 5;
break;
case 6:
System.out.println("6:");
break;
case 7:
System.out.println("7:");
break;
default:
break;
}
System.out.println("I = " + i);
}
Results in
3:
I = 5

This is an optimization. When you set the state to ZIEHEN_BA, the compiler knows it will get there as a next step. Without optimization, there would just be some aditional steps, but it will get there anyway:
Set the state; do the break; goto the while(true), now do the switch and...it gets to ZIEHEN_BA. So that is equivalent to going there directly.

Actually , compiler is not ignoring the break.
As you set state = State.ZIEHEN_BA in the existing case statement
So after invoking break it's going straight to ZIEHEN_BA in the next iteration of while(ture) loop .... :)
It may seems that it's directly going to ZIEHEN_BA by ignoring break but it's entering there in the following iteration.

The main program which you wrote is an unbreakable loop. Once if we see the code properly, you were assigning the state to the other case whenever some case was hit. And moreover you never ended the loop. The while loop doesn't know where to stop. Not exactly sure what you want to do.
FYI, the break is not skipped but it worked only break the switch loop. And I guess you expectation is to break the while loop...
If you want the code stop at a particular point, place a break for while loop. Again placing break; inside switch doesn't work as it breaks the switch loop. Instead try to set a Boolean variable before while and change the variable value to false where ever you want the loop to break.

Related

How i can use the string in switch case as an action?

I'm trying to code a Calculator on Java but in the switch statement, it takes the operation as a String, how can I transform it into an action?
switch(op) {
case 1: operation = "res= a + b";
break;
case 2: operation = "res = a - b";
break;
case 3: operation = "res = a * b";
break;
case 4: operation = "res = a / b";
break;
}
System.out.println(operation);
If I remove the quotes it says that I haven't initialized the variables. They are asked after choosing the operation.
EDIT:
I was applying the wrong logic to the program.
Don't perform the operation until you have the arguments:
import static java.lang.Integer.*;
import java.util.*;
class t1 {
static void calc(Scanner in) {
System.out.print("Operation: ");
int op = in.nextInt();
System.out.print("a: ");
int a = in.nextInt();
System.out.print("b: ");
int b = in.nextInt();
int res = 0;
switch(op) {
case 1:
res = a + b;
break;
case 2:
res = a - b;
break;
case 3:
res = a * b;
break;
case 4:
res = a / b;
break;
default:
System.out.println("Invalid operation");
System.exit(-1);
}
System.out.println(res);
}
public static void main(String args[]) {
Scanner in = new Scanner(System.in);
while (true) {
calc(in);
}
}
}
You could verify the operation before asking for the operands, with an additional switch statement.
There are ways to set the operation before obtaining the operands, but it's best to learn to walk before you run.

Why is the if statement not evaluated every loop

Ok I am making a simple text based game and I am unsure why and infinite loop is being created. Its not really infinite but I am unsure why the if statement is not evaluated every loop. Here is the whole program. The if Statement I need fixed is in the roomEight method which is at the end of the code.
//********************************
// A simple game that moves the
// player though the map
//********************************
import java.util.*;
import java.text.*;
public class mazegame
{
private static Scanner scan = new Scanner (System.in); // starts scanner for the program
public static Scanner scanS;
// ScanS is a scanner for strings.
// To call this variable type mazegame.scanP;
public static int lifeCount = 15;
public static int damage = 1;
// imp stats
public static int impAmount = 0;
public static int impDamage = 1;
public static int impLife = 1;
// Low level monster stats
// m followed by a number stands for monster then the level of monster
public static int m1health = 5;
public static int m1damage = 2;
// High level monster
public static int m2health = 10;
public static int m2damage = 2;
// Boss stats
public static int bosshealth = 30;
public static int bossdamage = 10;
// Placement of player
public static int placement = 3;
public static String movement;
public static int scanVal; // holder a scanner value generic.
public static void main(String[] args)
{
System.out.println("You wake up on a cold hard floor");
time();
System.out.println("you are unsure how you got there.");
time();
System.out.println("There is an opening a head");
time();
System.out.println("you walk forward into the opening the ground begins to tremble");
time();
System.out.println("the wall behind you closes you are trapped.");
time();
time();
clear(); // clears screen for user.
roomThree();
}
public static void timeHalfSec()
{
try
{
Thread.sleep(500); //1000 milliseconds is one second.
}catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}
public static void time()
{
try
{
Thread.sleep(1500); //1000 milliseconds is one second.
}catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}
public static void clear()
{
final String ANSI_CLS = "\u001b[2J";
final String ANSI_HOME = "\u001b[H";
System.out.print(ANSI_CLS + ANSI_HOME);
System.out.flush();
}
public static void position(int placement)
{
switch( placement )
{
//********************************
// For each room create a method and
// call it in this switch statement.
//********************************
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 8: roomEight();
break;
case 9:
break;
case 10:
break;
case 11:
break;
case 12:
break;
case 13:
break;
case 14:
break;
case 15:
break;
case 16:
break;
case 17:
break;
case 18:
break;
case 19:
break;
case 20:
break;
case 21:
break;
case 22:
break;
case 23:
break;
case 24:
break;
case 25:
break;
}
}
public static void askMove()
{
System.out.println("You can walk forward, left , or right. Beware the imps.");
System.out.println("Enter L for left, R for right, and F for forward.");
time();
System.out.print("Move:");
movement = scan.nextLine();
}
public static void roomThree()
{
askMove();
//--------------------------------
// This switch stament is only for this room
//--------------------------------
switch ( movement )
{
case "l":
case "L":
placement = 2;
System.out.println("Changing rooms Please wait");
time();
clear();
break;
case "r":
case "R":
placement = 4;
System.out.println("Changing rooms Please wait");
time();
clear();
break;
case "f":
case "F":
placement = 8;
System.out.println("Changing rooms Please wait");
time();
clear();
break;
}
// The switch statement changes position and position calls the next room method.
position(placement);
}
public static void roomEight()
{
System.out.print ("You have just entered a new room.");
System.out.print ("There is an imp ahead would you like to see its stats? 1 for yes and 0 ");
impAmount = 1;
scanVal = scan.nextInt();
if(scanVal == 1 )
{
impStats();
}
System.out.println("Would you like to hit the imp? 1 for yes and 0 for no.");
scanVal = scan.nextInt();
while (impAmount != 0)
{
if (scanVal == 1)
{
impAmount = 0;
damage++;
lifeCount = 15;
System.out.println("You killed an imp! You found brass knuckles your damage increased by one. Here are your stats");
playerStats();
}else{
lifeCount--;
System.out.println("The imp hit you. You took one damage");
playerStats();
timeHalfSec();
dead();
}
}
}
public static void playerStats()
{
System.out.println("*----------------*");
System.out.println("Your Hearts: " + lifeCount);
System.out.println("Your Damage: " + damage);
System.out.println("*----------------*");
}
public static void impStats()
{
System.out.println ("*----------------*");
System.out.println("Amount of Imps: " + impAmount);
System.out.println("Imp Health: 1");
System.out.println("impDamage: 1");
System.out.println("*----------------*");
}
public static void dead()
{
if(lifeCount < 1)
{
System.exit(0);
}
}
}
//********************************************************************************************************************************
// Places to look for code and things to look up.
// Lookup: .equalsIgnoreCase, global scanner.
// Places to look for code:
// http://stackoverflow.com/questions/23586732/how-to-make-a-one-static-scanner-global-variable-without-closing-scan-constantly
// https://www.youtube.com/watch?v=zijvKOjnmwY
// http://stackoverflow.com/questions/16706716/using-two-values-for-one-switch-case-statement
// http://www.csci.csusb.edu/dick/samples/java.classes.html#System
// http://stackoverflow.com/questions/22452930/terminating-a-java-program
//
//
//
//********************************************************************************************************************************
You'd probably want to move the following two lines into the loop :
System.out.println("Would you like to hit the imp? 1 for yes and 0 for no.");
scanVal = scan.nextInt();
As I can see, you scan the nextInt that a user enter, you do stuff with it and then you re-scan the nextInt. The problem with that is when you use the scanner and ask for a single int, there is still the new-line char in the scanner ('\n'). Thus, when you ask a second time for the int, this will return the new line char. My understanding of all this is not on point, but what you have to do is one of those solution :
Use nextLine instead of nextInt and parse the string value into an Int. This will clear the buffer, and you will be able to validate if the user entered a valid Int. You'd do it like this :
String scanVal = scan.nextLine();
//You can add some try catch in order to validate the int being parsed
int choice = Integer.parseInt(scanVal);
Or you can clear the buffer after you have scanned your int by calling scan.nextLine()after scan.nextInt()
Hope this helps!

Why do I get this "unreachable statement" error?

I am converting a roman numeral input to it's integer value. In my convertChar method, I keep getting an error that it is an unreachable statement whenever I add a break statement in to the code. I don't know why this is. I'm a new student and I must have done something wrong and I was hoping maybe someone can show me what I did wrong and how to fix it. It must have something to do with the way I set the methods up right? I still get confused on what variables to input so maybe I messed up there but I'm not experienced enough to know exactly what I did wrong. Here is everything I have:
public class RomanNumeralConverter {
public int romanInput() {
return convert(getUserInput());
}
public String getUserInput() {
Scanner numberInput = new Scanner (System.in);
System.out.print("Enter a roman numeral in uppercase: ");
String userInput = numberInput.next();
numberInput.close();
return userInput;
}
public int convert (String userInput) {
int result = 0;
int subtractamount = 0;
int x = userInput.length();
while(x != 0) {
char romanConvert = userInput.charAt(x);
if(x >= 1) {
if(convertChar(romanConvert) >= convertChar(userInput.charAt(x - 1))) {
subtractamount += convertChar(userInput.charAt(x - 1));
}
}
result += convertChar(romanConvert);
x--;
}
result -= subtractamount;
return result;
}
public static char convertChar(char value) {
switch (value) {
case 'I':
return 1;
break;
case 'V':
return 5;
break;
case 'X':
return 10;
break;
case 'L':
return 50;
break;
case 'C':
return 100;
break;
case 'D':
return 500;
break;
case 'M':
return 1000;
break;
default:
System.out.println("Invalid character!");
return 0;
break;
}
return value;
}
public void printValue() {
System.out.println(romanInput());
}
public static void main(String[] args) {
new RomanNumeralConverter().printValue();
}
}
Your problem lies in your switch statement. You can minimize this occurring elsewhere by attempting to have methods return only once (which i think is best practice)
public static char convertChar(char value) {
char result;
switch (value) {
case 'I':
result = 1;
break;
case 'V':
result = 5;
break;
case 'X':
result = = 10;
break;
case 'L':
result = 50;
break;
case 'C':
result = 100;
break;
case 'D':
result = 500;
break;
case 'M':
result = 1000;
break;
default:
System.out.println("Invalid character!");
result = 0;
break;
}
return result
}
In Java, it is a compile error to have statements that will never be reached while execution. In your case, the break statement will never be reached as there is a return statement above it. Also that last return statement will never be reached as you already would have returned in any case by the end of the switch block.
The problem is in your switch statement.
A default case can be thought of like the else in an if-else statement; it will always execute if no other condition in the switch is satisfied. If you are performing a return (or throw) inside of a default case, any code that follows after that will not be reachable.
You have two options:
Change the return statements to only assign a value to result instead, meaning that there's only one point of return from your code, or
Remove the return result from after your switch.

Converting int to hex string using recursion

I'm doing an assignment where I have to convert an integer number to a hexadecimal string using recursion. I have to do this using a method that returns a string value. I tried to turn the method I'm using on paper into code and it works just fine:
public class ItH {
private static String intToHex(int n) {
int temp = n % 16;
String digit = "";
if (temp < 10) digit += temp;
if (temp > 9) {
switch (temp) {
case 10: digit="A"; break;
case 11: digit="B"; break;
case 12: digit="C"; break;
case 13: digit="D"; break;
case 14: digit="E"; break;
case 15: digit="F"; break;
}
}
if (n > 0) return intToHex((n-temp)/16) + digit;
return "";
}
public static void main(String[] args) {
System.out.println(intToHex(1234));
System.out.println(intToHex(257));
System.out.println(intToHex(0));
}
}
It works just fine for the first two examples used in the main method, but I can't get it to display zero. Is there a way to get it to display zero without modifying too much? I've been going over it for some time now and I can't figure out a way to do that without adding at least one zero before every other number.
Any help would be appreciated.
How about this:
private static String intToHex(int n) {
int temp = n % 16;
String digit = "";
if (temp < 10) digit += temp;
if (temp > 9) {
switch (temp) {
case 10: digit="A"; break;
case 11: digit="B"; break;
case 12: digit="C"; break;
case 13: digit="D"; break;
case 14: digit="E"; break;
case 15: digit="F"; break;
}
}
if ( (n-temp)/16 == 0 ) return digit;
if (n > 0) return intToHex((n-temp)/16) + digit;
return "";
}
public static void main(String[] args) {
System.out.println(intToHex(1234));
System.out.println(intToHex(257));
System.out.println(intToHex(0));
}
Just add in that extra if statement,
if ( (n-temp)/16 == 0 ) return digit;

Switch statement for some reason does not like case 8. Compiler is acting real weird

Here is the code:
public static void main(String args[])
{
int i=0;
int m=0;
double scale;
boolean exit;
Shape[] s = new Shape[10];
while(exit !=true)
{
System.out.print("\nChoose an option:\n"+
"1-Add a new circle\n"+
"2-Add a new rectangle\n"+
"3-Delete all shapes\n"+
"4-Scale all shapes\n"+
"5-Display perimeter of all shapes\n"+
"6-Display the area of all shapes\n"+
"7-Enter scale factor\n"+
"8-Exit program\n");
Scanner input = new Scanner(System.in);
m=input.nextInt();
if(i<=9)
{
switch (m)
{
case 1: Circle c = new Circle(0);
s[i]=c;
i++;
break;
case 2: Rectangle r = new Rectangle(1,1);
s[i]=r;
i++;
break;
case 3: s=null;
i=0;
break;
case 4: for(i=0; i<s.length; i++)
{
s[i].scaleShape();
}
break;
case 5: for(i=0; i<s.length; i++)
{
if(s[i] != null)
{
System.out.println(s[i].getPerimeter());
}
}
break;
case 6: for(i=0; i<s.length; i++)
{
if(s[i] != null)
{
System.out.println(s[i].getArea());
}
}
break;
case 7: do
{
System.out.println("\nEnter scale factor");
scale=input.nextDouble();
}
while(scale<0);
Shape.setScaleFactor(scale);
}
break;
case 8: System.out.println("Do you want to quit?");
break; //Nothing here since loop should terminate it.
//default: System.out.println("Number must be 1-8");
// break;
}
}
}
}
Oddly the compiler is giving me an error on case 8 saying:
Type mismatch can't convert from int to boolean.
But Im not converting anything to boolean
-syntax error on token "case" assert expected
-syntax error on token :, ; expected
But all the commands there have semi-colons
expression must return a value
Why is the compiler acting so funny? Normally errors like that are easy to find. What is going on?
Your problem is in the case for 7:
case 7: do
{
System.out.println("\nEnter scale factor");
scale=input.nextDouble();
}
while(scale<0);
Shape.setScaleFactor(scale);
}
Notice the extra close brace: that's closing your switch statement, orphaning your case 8.
} // <-- Why is this here?
break;
case 8: System.out.println("Do you want to quit?");
You're ending the switch statement with an extra }. Remove it and things may work.
Every one has pointed out that you have an extra parenthesis in your code, what we've failed to point out is where it's coming from...
while(scale<0); // <-- This isn't going to work....
Shape.setScaleFactor(scale);
}
It should be...
while(scale<0) {
Shape.setScaleFactor(scale);
}
The next question is, how is scale decremented? Cause this could cause an infinite loop if you're not careful.
while(scale<0);
Shape.setScaleFactor(scale);
} // Remove this parenthesis.
break;

Categories

Resources