# Javascript 第四章 流程控制與迴圈 ###### tags: `JS X Codeshiba` ## 決策流程的範例_Crown & Anchor ### 背景介紹 ![](https://i.imgur.com/H9DZvhi.png) ![](https://i.imgur.com/Y2yHRym.png) 水手可以針對不同的花色來押寶,以下是各類情形他可以獲得的金錢: | 賭注 | 骰子 | 贏錢 | |:-------:|:-----:|:------:| | Crown 5塊錢 | Crown Crown Crown | 15元 | | Crown 5塊錢 | Crown Crown Anchor | 10元 | | Crown 5塊錢 | Crown Heart Spade | 5元 | | Crown 5塊錢 | Anchor Heart Spade | 0元 | | Crown 3塊錢 Spade 2塊錢 | Crown Crown Crown | 9元 | | Crown 3塊錢 Spade 2塊錢 | Crown Heart Spade | 5元 | | 每個格子都1塊錢 | Anything | 3元 | 假設有個人它的決策模式為,每次上岸都拿50元來玩,**只要贏到本錢的兩倍**,他就不玩了,只要他沒有達成目標,他就會**玩到沒錢為止** 此時我們可以把這個決策畫成流程圖 ```flow st=>start: 開始 cond1=>condition: 沒錢或贏到100? op=>operation: 結束 op2=>operation: 下注 op3=>operation: 擲骰子 op4=>operation: 拿到錢(回到決策點) st->cond1->op2->op3->op4-> cond1(yes)->op cond1(no)->op2 ``` ### 解構 此時的決策圖還是有些模糊,我們需要限制流程圖的動作: 1. 變數賦值: funds=50, bets={}, hand = [], 2. 介於m跟n的隨機整數,包含首尾值: rand(1,6) 3. 隨機骰面字串("heart", "crown"等等):randFace() 4. 物件特性賦值:bets["heart"]=5、bets[randFace()]=5 5. 將元素加入陣列: hand.push(randFace()) 6. 基本算術: funds - totalBet、funds + winnings 7. 遞增: roll++(代表把變數roll + 1) 在這裡,我們把要做成迴圈的部份給標示出來 ![](https://i.imgur.com/0GwUmOi.png) ## 迴圈架構撰寫 要讓迴圈運轉的條件為`funds > 1 && funds < 100` ```javascript= let funds = 50; //起始條件 while(funds > 1 && funds < 100) { //下注 //擲骰子 //拿贏得的錢 } ``` ### 區塊陳述式(複合陳述式) 區塊陳述式是以大括號包起來的一系列陳述式,被視為一個單位來處理,雖然迴圈不用區塊陳述式也可以執行,例如: ```javascript= // 沒有換行 while(funds > 1 && funds < 100) funds = funds + 2; //沒有換行,裡面只有一個陳述式的區塊 while(funds > 1 && funds < 100){funds = funds + 2; } ``` 為了避免縮排造成的問題,建議還是用區塊陳述式來進行撰寫 ### 協助函式 在這個案例會需要兩個協助函式 ```javascript= //隨機回傳範圍[m,n](包括頭尾)之間的整數 function rand(m,n) { return m + Math.floor((n - m + 1)*Math.random()); } ``` ```javascript= //隨機回傳一個代表 //六個Crown and Anchor 圖案的字串 function randFace() { return ["crown", "anchor", "heart", "spade", "club", "diamond"] [rand(0,5)]; } ``` ### 第一部分(下注): 情境一(if-else if -else判斷式) 範例 ![](https://i.imgur.com/sLqiVVu.png) 我們的對象要掏出7塊錢來下注,但他有個怪癖 只要他掏出的是幸運數字7,他就會把錢全部壓在"Heart"那一格 ![](https://i.imgur.com/VBHd29N.png) ```javascript= const bets = {crown: 0, anchor: 0, heart: 0, spade:0, club:0, diamond: 0}; //先把賭注的類別列出來 let totalBet = rand(1, funds); //賭注的金額從1到剩餘的本金數j目隨機取數 if(totalBet === 7) { //把七塊錢作為賭本,壓在heart上面 totalBet = funds; bets.heart = totalBet; } else { // 分發所有賭注 } funds = funds - totalBet; ``` ### 第一部分(下注): 情境二(do...while迴圈) 如果不是拿到7的話,咱們的對象就會把拿到的賭金隨意地放在各個方格中,而且有可能重複下注 ![](https://i.imgur.com/7LVvy2i.png) ```javascript= let remaining = totalBet; do { let bet = rand(1, remaining); //隨機拿取剩餘的賭金 let face = randFace(); //隨機選擇下注花色 bets[face] = bets[face] + bet; //針對隨機選擇的花色來下注 remaining = remaining - bet; //扣掉已經下注的賭金 } while(remaining > 0); //當還有剩餘賭金時持續的下注 ``` ### 第二部分(擲骰子):For迴圈 ![](https://i.imgur.com/MhGWKIg.png) for迴圈最適合需要作與固定次數的事情來使用,所以適合用來投擲固定次數的骰子,這次需要丟擲三次骰子(因為有三顆)。因為習慣用0作起始,所以我們的參數從0開始,在2結束。 此時的for迴圈包含三個部分: 1. 初始設定式 2. 條件 3. 最終運算式 ```javascript= const hand = []; for(let roll = 0; roll < 3; roll++) { hand.push(randFace()); } ``` ### 第三部分(拿回彩金):if陳述式 ```javascript= let winnings = 0; for(let die=0; die < hand.length; die++) { let face = hand[die]; if(bets[face] > 0) winnings = winnings + bets[face]; } funds = funds + winnings; ``` ### 整合 ```javascript= // returns a random integer in the range [m, n] (inclusive) function rand(m, n) { return m + Math.floor((n - m + 1)*Math.random()); } // randomly returns a string representing one of the six // Crown and Anchor faces function randFace() { return ["crown", "anchor", "heart", "spade", "club", "diamond"] [rand(0, 5)]; } let funds = 50; // starting conditions 起始條件 let round = 0; while(funds > 0 && funds < 100) { round++; console.log(`round ${round}:`); console.log(`\tstarting funds: ${funds}p`); // place bets 下注 let bets = { crown: 0, anchor: 0, heart: 0, spade: 0, club: 0, diamond: 0 }; let totalBet = rand(1, funds); if(totalBet === 7) { totalBet = funds; bets.heart = totalBet; } else { // distribute total bet let remaining = totalBet; do { let bet = rand(1, remaining); let face = randFace(); bets[face] = bets[face] + bet; remaining = remaining - bet; } while(remaining > 0) } funds = funds - totalBet; console.log('\tbets: ' + Object.keys(bets).map(face => `${face}: ${bets[face]} pence`).join(', ') + ` (total: ${totalBet} pence)`); // roll dice const hand = []; for(let roll = 0; roll < 3; roll++) { hand.push(randFace()); } console.log(`\thand: ${hand.join(', ')}`); // collect winnings let winnings = 0; for(let die=0; die < hand.length; die++) { let face = hand[die]; if(bets[face] > 0) winnings = winnings + bets[face]; } funds = funds + winnings; console.log(`\twinnings: ${winnings}`); } console.log(`\tending funds: ${funds}`); ``` ## Switch 判斷 從多個條件去做判讀 ![](https://i.imgur.com/0CimgvL.png) ![](https://i.imgur.com/bAqKaxh.png) ## While迴圈 while(判斷){ 若判斷的結果是正確的(true)執行大括號區塊中的程式碼。 程式碼執行完畢,回到上方while的位置,做第二次判斷。直到判斷結果是錯誤的(false),才會跳離整個迴圈結構。 } 小小Debug的寫法 ![](https://i.imgur.com/rNu7OPm.png) 也可以使用continue ![](https://i.imgur.com/wxpsxSz.png) 還有break ![](https://i.imgur.com/OSNPZeZ.png) ```Example <script> var n=0; while(n<50){ n++; } alert(n); </script> ``` ```Example <script> //如何1加到100? var n=0; var sum=0; while(n<=100){ sum=sum+n; n=n+1; } alert(sum); </script> ``` ## While和Do While的差別 ![](https://i.imgur.com/BPjYR00.png) ## For迴圈 for(初始區塊;判斷;迴圈區塊){ 判斷概念同while迴圈。 請在講解中,注意「初始區塊」與「迴圈區塊」的執行時機。 } ![](https://i.imgur.com/Zy1i1JU.png) Let 也可以喔!(ES6) ![](https://i.imgur.com/0Yko9dB.png) 倒著數也是可以的喔 ![](https://i.imgur.com/2vOiFMo.png) For、While迴圈可以**相互替代** ``` <script> //如何1加到100? var n=0; var sum=0; for(;n<=100;){ sum=sum+n; n=n+1; } alert(sum); </script> ``` 該如何使用for迴圈呢? ``` <script> //如何1加到100? var sum=0; for(var i=1;i<=100;i++){ sum=sum+i; } alert(sum); </script> ``` ### 跳著算可不可以啊? ![](https://i.imgur.com/jtQ2dRc.png) ![](https://i.imgur.com/69iNpC6.png) ## Break的範例 強制跳出迴圈 ![](https://i.imgur.com/VD84Ypz.png) ``` <script> var n=0; var sum=0; while(n<=100){ sum=sum+n if (n>=3){ break; } n++; } alert(sum); </script> ``` ## Continue 強制進行下一次的迴圈 ![](https://i.imgur.com/0szd3eR.png) 以下範例就是跳過4的整數,所以只有顯示75 ```Example <script> //今天我要示範continue var times=0; for(var i=0;i<=100;i=i+1){ if(i%4==0){ continue; } times=times+1 } alert(times); </script> ``` ## 程式碼比較 判斷式位置不一樣,造成的結果也不一樣 結果5151 ``` <script> //今天我要示範while var sum=0; var i=0; while(i<=100){ i=i+1; sum=sum+i; } alert(sum); </script> ``` 結果是5050 ``` <script> var sum=0; var i=0; while(i<=100){ sum=sum+i; i=i+1; } alert(sum); </script> ``` ## 九九乘法表喔 ![](https://i.imgur.com/2dGvCEe.png)