# 撲克牌遊戲的挑戰

## 52張牌，要如何放在記憶體中

清單，要把所有的牌都放在清單中，之後所有的操作就是利用清單的存取來進行操作。

至於如何去代表每一張牌則有許多種方式，有些人使用1到52這些數字來代表每一張牌，當要使用的時候再利用轉換的方式來算出它的值是多少，花色是什麼。也可能直接使用具備花色和值的內容來儲存在清單的資料項中。

假設我們以0為牌的背面花色，而1到52是由黑桃A排到方塊K，可以使用以下的積木一口氣把所有的牌都放到清單deck中：

![](https://1789170130-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZJEK4Zm0THA0vYxBYQ%2F-L_fcudVbAq5EqRWqecn%2F-L_feS0yA71NnDjWSkEa%2F2019-03-11_15-30-56.png?alt=media\&token=e9c58b4c-22da-4b7f-b9c5-4f2a98688fc5)

執行上述的程式積木之後，就可以得到一個長度為52的deck清單，如下所示：

![](https://1789170130-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZJEK4Zm0THA0vYxBYQ%2F-L_fcudVbAq5EqRWqecn%2F-L_ffOuCR_LSnNRPY0cX%2F2019-03-11_15-35-21.png?alt=media\&token=8134ad08-1c64-42a2-9a7f-c432aaaa02ca)

那麼，我們怎麼會知道任一個數字是哪一個花色，又是什麼編號呢？如果你手上有一幅牌的話，請直接把它們依序排成一列放在桌子上，把最左邊的第一張編上1號，第2張編上2號，依此類推，然後你就會知道如何得知每一個數字是什麼花色和它的值是多少了。

## 算出牌的花色和數值

假設我們有4個花色，從左至右是黑桃、紅心、梅花、以及方塊，那就是52張牌分成4份，如果我們拿到一個數字 N 的話，只要把它減去1，再整除13，得到的數字是0就是在第一組，也就是黑桃，如果得到的數字是1就是第二，那花色就是紅心，依此類推。所以，如果有一個數字是13的話，(13-1)//13 ==> 0，它的花色就是黑桃。

{% hint style="warning" %}
為什麼要減1，同學們可以想出它的道理嗎？
{% endhint %}

公式如下：

$$
fold = floor((n-1)/13)
$$

其中floor是無條件捨去小數點的函數，算出來的fold就是0\~3，可以代表是哪一組牌（要看你的牌放的順序）。

那要如何算出它的值呢？答案是使用取餘數計算就可以了。公式如下：

$$
value = (n-1) %13 + 1
$$

還是以13為例，(13-1)%13+1的結果是13，所以13就是黑桃13，也就是黑桃K。同理，如果是14的話，(14-1)//13==>1，花色是紅心，(14-1)%13+1==>1，結果就是紅心1，也就是紅心A。

## 洗牌的方法

洗牌的目的就是要讓前面的deck清單中的所有內容是隨機的方式放置。一般的想法是，既然有52張牌，就每一張牌要放進deck中時就使用隨機函數，每一次就從1到52的號碼中選一個就好了。但是，這樣的問題是，每一次隨機的數字，有可能會和之前選過的一樣，此種情形會在越後面越容易發生，所以如果要使用此種方式，就要在每次出現隨機數的時候就要再到清單中檢查一次，如果清單中已有這個數字的話，就要重新再找下一個隨機數，重複這些步驟直所有的數字都出現在deck清單中為止。

另外一個方式則是使用另一個方向來思考，就是一開始依序把每一張牌都放到deck清單中，再打亂它們的順序即可。

至於如何打亂順序呢？在這裡用的方法是任選deck清單中的兩位置，把它們的內容交換，只要交換的次數夠多的話，整幅牌的順序就是亂的了。先來看如何交換清單中兩個不同位置的內容，首先要建立兩個變數，在這裡我們使用x和y，接著把x和y分別使用隨機數產生1\~52之間其中一個數值，如下所示：

![](https://1789170130-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZJEK4Zm0THA0vYxBYQ%2F-L_lRTElOgq250AB1cop%2F-L_lS0KywM6hjkKGGeaT%2F%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202019-03-12%20%E4%B8%8B%E5%8D%886.30.04.png?alt=media\&token=ecbbd4da-150f-4f8b-ab0e-14b90204b3e9)

要交換清單中兩個項目的內容，其程序如下：

$$
temp = deck\[x] \newline
deck\[x]  = deck\[y] \newline
deck\[y] = temp
$$

請留意上述的說明中，temp是一個單純的變數，它只用來存放暫時性的內容，而deck則是一個清單，所以要指定清單內的值，還需要索引變數x和y的幫忙。使用Scratch積木的程式如下：

![](https://1789170130-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZJEK4Zm0THA0vYxBYQ%2F-L_lRTElOgq250AB1cop%2F-L_lTmuV4w6b610k3AVr%2F%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202019-03-12%20%E4%B8%8B%E5%8D%886.37.59.png?alt=media\&token=37d40235-c3e5-4202-82fb-f346cdeffec7)

以上的程式片段我們要讓它執行足夠的次數，所以接下來是洗牌的程式積木，也就是加上一個重複迴圈：

![](https://1789170130-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZJEK4Zm0THA0vYxBYQ%2F-L_lRTElOgq250AB1cop%2F-L_lU7mM4AE_Pudp57SY%2F%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202019-03-12%20%E4%B8%8B%E5%8D%886.39.26.png?alt=media\&token=d2a93d46-4a1d-4156-929f-314b96e58b00)

把上述這段程式碼串接上建立清單程式積木後面就可以了。以下是執行完畢之後的舞台畫面：

![](https://1789170130-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZJEK4Zm0THA0vYxBYQ%2F-L_lRTElOgq250AB1cop%2F-L_lURXusg5ryX5REYwC%2F%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202019-03-12%20%E4%B8%8B%E5%8D%886.40.35.png?alt=media\&token=4768d4b5-5c3e-423b-b319-0c9568952b6d)

## 莊家和玩家的牌，要放在哪裡

當deck中的牌是隨機擺置的情況之後，如果要發5張牌，那麼只要拿deck清單中的前面5張牌就可以了。當然為了要可以玩之後的遊戲，這5張牌最好是放在另外一個清單中，如果需比較莊家和玩家不同的牌，那麼就需要另外準備兩個清單，前10張中的單數，也就是1, 3, 5, 7, 9是給玩家，而偶數，也就是2, 4, 6, 8, 10是莊家的牌。

## 如何發牌給玩家&#x20;

在這個例子中，我們把玩家的牌放在player，而莊家則是建立一個叫做banker的清單來放置。這表示我們還需要再定義2個清單變數，分別就叫做player和banker，之後利用迴圈把deck中的資料項目複製到這兩個清單中。為了簡化說明，在這裡只複製player這個清單，複製完成之後，player中的5個項目，就是玩家所得到的5張牌。

![](https://1789170130-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZJEK4Zm0THA0vYxBYQ%2F-L_lo06aiqQ015CLNLFb%2F-L_lp0A-qkbIYdb7dwMZ%2F%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202019-03-12%20%E4%B8%8B%E5%8D%888.15.05.png?alt=media\&token=dd6d7fe9-0f38-4ce7-897d-60a0d54f17fe)

在這個例子中，我們使用角色被點擊事件來啟動發牌，也就是程式開始執行的時候是進行洗的操作，而按下貓咪之後才會發牌。發牌之後的結果，如下圖所示：

![](https://1789170130-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZJEK4Zm0THA0vYxBYQ%2F-L_lo06aiqQ015CLNLFb%2F-L_lpkvQ-TvoYcooQfxD%2F%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202019-03-12%20%E4%B8%8B%E5%8D%888.18.19.png?alt=media\&token=476266d0-96f0-4aed-8d1d-4f4e8ab40257)

從上圖中可以看出，其實player中的內容就是deck中第1到第5個資料項目的內容。再來，就是讓貓咪說明這些牌的內容，運用之前的程式碼，說出如下：

![](https://1789170130-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZJEK4Zm0THA0vYxBYQ%2F-L_p0_OPggMea9hRlyc3%2F-L_p1pWB3JPbyEN-tY8q%2F2019-03-13_11-14-06.png?alt=media\&token=032e406a-0904-472b-baa3-f6f3d7688d55)

## 使用字串組合讓貓咪一次說出牌面的花色和內容值

在前面的程式例子中，貓咪對於每一張牌都分別說出花色和內容值，如何讓牠可以把花色和內容值放在一起呢？答案就是字串組合積木。為了避免積木堆疊太長，在這裡先建立一個叫做message的變數，先組合出我們要的訊息，再由貓咪說出來。

![](https://1789170130-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZJEK4Zm0THA0vYxBYQ%2F-L_p0_OPggMea9hRlyc3%2F-L_p6sQUHVFMU36Kkb9j%2F2019-03-13_11-36-14.png?alt=media\&token=98be1e59-8b46-4629-bb63-c6b4f5da42f0)

如果還覺得太長的話，同學們別忘了，變數是個好東西，同學們想想看，如果把message分成2個獨立的變數，那要如何做呢？

## 如何補牌

發牌很簡單，就是把deck的前5張複製到player清單中，那補牌呢？首先要知道要補的是哪幾張牌，這些要有一個清單把它記錄下來，之後再補牌的時候，就利用一個迴圈去這個清單中找一通，如果有要補牌的地方，就從第6張開始，依此類推，直到所有的牌都看過一遍為止。

為了維持最新的補牌順序，需要再一個變數（例如top），一開始指向deck中的第6張牌（也就是一開始top的內容要設為6），當把牌補出去之後，再把它的內容加1，以切換到下一張牌的位置。

## 如何判斷輸贏

這個部份就要看你玩的是哪一種遊戲而有所不同，留待給同學們當作是討論的內容囉。
