2017-05-31 66 views
-3

我編寫了一款遊戲。 我用開關盒來實現一個狀態機。 問題是,如果ZIEHEN_SP break語句不起作用。 當我調試它時,編譯器只是跨越break語句並轉到下一個案例ZIEHEN_BA。Java:無法在開關盒中打開一個案件 - 爲什麼?

我評論了編譯器忽略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; 
      } 
     } 
    } 

} 
+2

這與C有什麼關係? –

+1

您將狀態設置爲'State.ZIEHEN_BA',並在'switch'周圍有一個'while'循環,那麼除了進入該狀態還有什麼比您期望的更好? – Tom

+0

在其「switch」評估中更改'state's值是個不錯的主意。在你的'switch'裏面,你應該把下一個狀態賦值給一個新的變量,並在'switch'語句 –

回答

3

因你而改變state到與State.ZIEHEN_BA條件相匹配的值:

while(true){ 
    ... 
     state = State.ZIEHEN_BA; 
     break; 

    case ZIEHEN_BA: 
     banksTurn(); 
     state = State.INIT; 
     break; 
    ... 
} 

case ZIEHEN_BA在循環的下一次迭代中執行:

state = State.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 

而且看在我設置情況A的情況下進入情況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 

沒有在此編譯的代碼優化。

案件後,執行:

 36: getstatic  #31     // Field a/TestSwitch$MyEnum.B:La/TestSwitch$MyEnum; 
    39: astore_1 

下一個指令是一個跳轉到環路:

40: goto   4 

因此優化可能是在運行時由JVM或Eclipse調試器執行。

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 
+0

是的,同意...但問題是,當我運行代碼...它掛在一個循環中,什麼都不做......:/ – Johnson

+0

這是因爲,外部while循環沒有中斷。休息時間僅適用於開關盒。你需要處理外部while循環 – npradeep357

0

這是一個優化。當你將狀態設置爲ZIEHEN_BA時,編譯器知道它會作爲下一步到達那裏。沒有優化,只會有一些附加的步驟,但無論如何它會到達那裏:

設置狀態;休息一下;到了那個時候(真的),現在做開關,然後......到達ZIEHEN_BA。所以這相當於直接去那裏。

+0

是的好,同意......但問題是,當我運行代碼時......它掛在一個循環中,什麼都不做......:/ – Johnson

0

其實,編譯器不會忽略中斷。

當你在現有的情況下,語句設置state = State.ZIEHEN_BA
調用打破它會直接到​​在下一個迭代while(ture)循環 .... :)

它後可能如此看來,它的直接進入​​忽略break,但它在下面的迭代中進入。

0

你寫的主程序是一個牢不可破的循環。有一次,如果我們正確地看到代碼,那麼無論何時遇到某種情況,都會將狀態分配給其他情況。而且你永遠不會結束這個循環。 while循環不知道在哪裏停止。不完全確定你想要做什麼。

僅供參考,中斷不會被跳過,但它的工作只會打破開關循環。我想你的期望是打破while循環...

如果你想停止代碼在特定的點,請爲while循環放置一箇中斷。在交換機內部再次放置break;不起作用,因爲它會中斷交換機環路。相反,在嘗試設置Boolean variable之前,並將變量值更改爲false,以便您希望循環中斷。

相關問題