我编写了一个游戏。 我使用switch case来实现状态机。 问题是,在ZIEHEN_SP的情况下,break语句不起作用。 当我调试它时,编译器只是跳过break语句并转到下一个案例ZIEHEN_BA。
我评论了编译器忽略break语句的部分。
为什么?
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;
}
}
}
}
答案 0 :(得分:3)
因为您将state
更改为与State.ZIEHEN_BA
条件匹配的值:
state = State.ZIEHEN_BA;
所以这里:
while(true){
...
state = State.ZIEHEN_BA;
break;
case ZIEHEN_BA:
banksTurn();
state = State.INIT;
break;
...
}
case ZIEHEN_BA
在循环的下一次迭代中执行。
Eclipse显示的可能是在运行时或编译器执行的JVM的优化。您可以反汇编课程以获取更多信息。
编辑
我已完成测试,我认为这不是编译器优化。
看看这个最小的例子,我没有在这种情况下设置状态:
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;
}
}
}
}
这是main()方法的反汇编代码:
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
然后查看我在案例B中设置状态的版本以便输入案例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;
}
}
}
}
这是main()方法的反汇编代码:
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
此编译代码中没有优化。
案例A执行后:
36: getstatic #31 // Field a/TestSwitch$MyEnum.B:La/TestSwitch$MyEnum;
39: astore_1
下一条指令是转到循环:
40: goto 4
因此,优化可能是由JVM或Eclipse调试器在运行时执行的。
答案 1 :(得分:1)
编译器优化了您的代码: - )
当你将开关变量设置为State.ZIEHEN_BA
时,在(while (true)
和重新进入开关之间)没有任何东西可以执行,而这正是下一行要执行的。
我不确定它是否应该以这种方式运行(在开关内部更改变量会导致检查以下情况)但在您的情况下我完全同意编译器。
正如您在此示例中所看到的,此行为并非总是如此:
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);
}
结果
3:
I = 5
答案 2 :(得分:0)
这是一项优化。当您将状态设置为ZIEHEN_BA时,编译器知道它将作为下一步到达那里。如果没有优化,就会有一些附加的步骤,但无论如何它都会实现:
设置状态;做休息;转到while(true),现在进行切换......它到达ZIEHEN_BA。所以这相当于直接去那里。
答案 3 :(得分:0)
实际上,编译器并没有忽略中断。
在现有案例陈述中设置ZIEHEN_BA
时
因此,在调用break之后,它会在while(ture)
循环的下一次迭代中直接进入ZIEHEN_BA
.... :)
它似乎可以通过忽略break
直接转到declare @table table (starttime datetime)
insert into @table values
('2017-05-31 13:00:00'),
('2017-05-31 13:15:00'),
('2017-05-31 13:30:00'),
('2017-05-31 13:45:00'),
('2017-05-31 14:00:00'),
('2017-05-31 14:15:00'),
('2017-05-31 14:30:00'),
('2017-05-31 14:45:00'),
('2017-05-31 15:00:00'),
('2017-05-31 15:15:00')
Select dateadd(hour,datepart(hour,starttime), cast(cast(starttime as date)as datetime)) aggrHour
from @table
group by dateadd(hour,datepart(hour,starttime), cast(cast(starttime as date)as datetime))
having count(starttime) = 4
,但它会在接下来的迭代中进入//Custom Controller
app.controller('custom_controller', function($http, $scope, $compile) {
$scope.change = function() {
switch ($scope.data['model']) {
case 'Telecom':
$scope.controller = 'Telecom_Controller';
break;
case 'Netflix':
$scope.controller = 'Netflix_Controller';
break;
case 'Bank':
$scope.controller = 'Bank_Controller';
break;
case 'Beauty':
$scope.controller = 'Beauty_Controller';
break;
case 'Mutual Funds':
$scope.controller = 'MF_Controller';
break;
case 'Motor Insurance':
$scope.controller = 'MI_Controller';
break;
case 'Job Hunt':
$scope.controller = 'Job_Controller';
break;
default:
alert("None Selected");
break;
}
};
});
。
答案 4 :(得分:0)
你写的主程序是一个牢不可破的循环。如果我们正确地看到代码,那么只要遇到某个案例,就会将状态分配给另一个案例。而且你永远不会结束循环。 while循环不知道在哪里停止。不完全确定你想做什么。
仅供参考,不会跳过中断,但只会破坏交换机循环。我猜你期望打破while循环......
如果您希望代码在特定点停止,请为while循环设置一个中断。再次将break;
放在开关内部不起作用,因为它会破坏开关循环。相反,尝试在while之前设置Boolean variable
,并将变量值更改为false
,而不想让循环中断。