# Javascript 第四章 流程控制與迴圈
###### tags: `JS X Codeshiba`
## 決策流程的範例_Crown & Anchor
### 背景介紹


水手可以針對不同的花色來押寶,以下是各類情形他可以獲得的金錢:
| 賭注 | 骰子 | 贏錢 |
|:-------:|:-----:|:------:|
| 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)
在這裡,我們把要做成迴圈的部份給標示出來

## 迴圈架構撰寫
要讓迴圈運轉的條件為`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判斷式)
範例

我們的對象要掏出7塊錢來下注,但他有個怪癖
只要他掏出的是幸運數字7,他就會把錢全部壓在"Heart"那一格

```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的話,咱們的對象就會把拿到的賭金隨意地放在各個方格中,而且有可能重複下注

```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迴圈

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 判斷
從多個條件去做判讀


## While迴圈
while(判斷){
若判斷的結果是正確的(true)執行大括號區塊中的程式碼。
程式碼執行完畢,回到上方while的位置,做第二次判斷。直到判斷結果是錯誤的(false),才會跳離整個迴圈結構。
}
小小Debug的寫法

也可以使用continue

還有break

```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的差別

## For迴圈
for(初始區塊;判斷;迴圈區塊){
判斷概念同while迴圈。
請在講解中,注意「初始區塊」與「迴圈區塊」的執行時機。
}

Let 也可以喔!(ES6)

倒著數也是可以的喔

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>
```
### 跳著算可不可以啊?


## Break的範例
強制跳出迴圈

```
<script>
var n=0;
var sum=0;
while(n<=100){
sum=sum+n
if (n>=3){
break;
}
n++;
}
alert(sum);
</script>
```
## Continue
強制進行下一次的迴圈

以下範例就是跳過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>
```
## 九九乘法表喔
