Download presentation
Presentation is loading. Please wait.
1
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
程式規劃與函式導向程式設計 鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
2
綱要 作文與程式設計 範例:決勝21點 版本規劃 測試規劃 一些良好的程式設計習慣 測試驅動之程式開發及函式導向二十一點模擬程式0.0.0版
3
綱要 逐步細分法開發程式及函式導向二十一點模擬程式0.0.1版 函式導向二十一點模擬程式0.0.2版 函式導向二十一點模擬程式0.1版
4
綱要 作文與程式設計 範例:決勝21點 版本規劃 測試規劃 一些良好的程式設計習慣 測試驅動之程式開發及函式導向二十一點模擬程式0.0.0版
5
計算機程式設計與作文 以程式語言指示計算機工作 說明文敘述事物內容 同樣以簡潔明確為目標
6
作文技巧與程式設計 構思立意( 解法構想 ) 布局謀篇( 模組規畫 ) 度句裁章( 流程設計 ) 用字遣詞( 變數運算 )
7
兒童作文缺失 (1/2) 低年級小朋友. . . 尚無法完整表達意念、掌握形式結構,內容常跳躍,不能聯貫主題。
低年級階段的寫作以「我手寫我口」為主要訓練方式. . . 剛升上中年級的小朋友,在遣詞造句上易流於口語化,甚至常重複出現相同的語詞、句型. . . *蘇國書、林瑋,國語日報兒童園地版兒童寫作觀察報告(九十七年一月到六月) 三之二, 國語日報, 中華民國97年9月18日
8
兒童作文缺失 (2/2) 大部份的小朋友都是想到什麼就寫什麼,往往把主要內容全寫進某一個段落。這樣一來,不僅段落雜亂,整篇文章也缺乏分段的概念。 高年級學生. . .需要加強的,則是大多慣用條列式思考,缺少在每一條列下衍生細膩描述的能力 *蘇國書、林瑋,國語日報兒童園地版兒童寫作觀察報告(九十七年一月到六月) 三之二, 國語日報, 中華民國97年9月18日
9
虛擬程式設計 程式設計 就解決問題而言,高階程式語言仍是過細 必須先想好問題解法,才能轉成程式
二進位碼 組合語言 程式語言 就解決問題而言,高階程式語言仍是過細 必須先想好問題解法,才能轉成程式 問題解法先區分模組,寫成演算法,才容易寫成程式 模組區分與演算法構思:虛擬程式設計
10
綱要 作文與程式設計 範例:決勝21點 版本規劃 測試規劃 一些良好的程式設計習慣 測試驅動之程式開發及函式導向二十一點模擬程式0.0.0版
11
範例:二十一點 維基百科
12
流程 下注 向各家派發一張明牌 向各家派發一張暗牌 莊家明牌是10 或 A , 詢問閒家是否購買保險 莊家打開暗牌 閒家加註、分牌等動作
莊家逐位詢問閒家是否加牌, 直至閒家不加牌或報到, 才詢問下一位閒家, 輪流詢問閒家直至最後一位閒家加牌完成 莊家如不足 17點便需加牌直至超過或等於 17點 對未有爆煲或報到的玩家, 比點數大小, 大者勝, 可得賠金; 如莊家爆煲, 未有爆煲或報到的閒家便可得賠金 回收已使用的牌及打賞 注: 回收已使用的牌必須順序回收。如分開大牌和小牌個別回收等不正常收牌行為,便有出千的可能,並且可能會被請提出異議而被迫離開。 維基百科 &variant=zh-tw#.E5.9F.BA.E6.9C.AC.E7.8E.A9.E6.B3.95
13
點數計算與發牌 A作一點或十一點,2-10作該牌之點數,J、Q、K作十點。
首先由一位玩家作莊家負責發牌,其餘玩家為閒家。閒家會向莊家投下一定注碼,莊家會以順時鐘方向向眾閒家派發一張暗牌(即不掀開的牌),然後向自己派發一張暗,接著莊家會以順時鐘方向向眾閒家派發一張明牌(即掀開的牌),之後又向自己派發一張明牌。 當眾人手上各擁一張暗牌和一張明牌,莊家就以順時鐘方向逐位閒家詢問是否再要牌(以明牌方式派發),玩家此時要計算是否要牌,因為排牌局的最終目的,是要玩家手上擁有的牌總點數達到21點(或最接近又小於21點),然後和莊家比大小。當一位閒家決定不再要牌後,莊家才向下一位閒家詢問是否再要牌。 (按: 在一般賭場的賭局,莊家並不一定是發牌者。) 維基百科 &variant=zh-tw#.E5.9F.BA.E6.9C.AC.E7.8E.A9.E6.B3.95
14
爆煲(超過21點) 若果閒家要牌後,其手上擁有的牌的總點數超過21點,便要揭開手上所擁有的牌,俗稱爆煲,該閒家的注碼會歸莊家。
反之若其手上擁有的牌的總點數不超過21點,該閒家可決定是否繼續要牌。 當最後一位閒家決定不再要牌後,莊家就必須揭開自己所有手上的牌,若總點數少於17點,就必須繼續要牌;如果莊家爆煲的話,便向原來沒有爆煲的閒家,賠出該閒家所投住的同等的注碼。 維基百科 &variant=zh-tw#.E5.9F.BA.E6.9C.AC.E7.8E.A9.E6.B3.95
15
點數決勝與例牌報到 如果莊家最終沒有爆煲的話,原來沒有爆煲的眾閒家便要揭開手上所有的牌,比較點數決定誰勝誰負,點數較大的取勝。(例牌例外,詳見下文閒家例牌先報到和特別規例) 若某閒家例牌,必須向立即莊家揭開手上所有的牌(即俗稱報到),莊家亦必須向該擁有例牌的閒家賠上一定注碼。 維基百科 &variant=zh-tw#.E5.9F.BA.E6.9C.AC.E7.8E.A9.E6.B3.95
16
保險、加註、分牌 當莊家面牌是10或A,閒家可以外加註碼的一半買保險,以賭莊家的二張牌總和是不是21點,如莊家不是21點便沒收保險金,如是21點便以注碼的一倍半賠償。 如閒家首兩張牌點數之和為11點,可以選擇加倍投注,但加註後僅獲發1張牌。有些賭局容許閒家在首兩張牌總和為10點(甚至任何點數)時加註。 如閒家首兩張牌點數相同,可以選擇分牌,並須加註。分出每門的下注金額須與原注相同。若閒家打兩張A分開,則每張A只獲發1張牌,不可再要牌。有些分牌後後不可再分牌。 維基百科 &variant=zh-tw#.E5.9F.BA.E6.9C.AC.E7.8E.A9.E6.B3.95
17
二十一點、同花順、五龍 如果閒家手中的一張暗牌和一張明牌分別是一張A牌(可作11點)和一張十點牌(K、Q、J、10),這副牌叫做二十一點(Black Jack)(屬例牌),該閒家可向莊家報到,莊家須向該閒家賠上1倍注碼。 有些賭場會加設這一賠彩規例,即玩家的牌面是同花的「6、7、8」便可即收3倍的彩金。 如果閒家要牌直至手上有5張牌而又沒有爆煲,這副牌叫做五龍(屬例牌),該閒家可向莊家報到,莊家須向該閒家賠上2倍注碼。 維基百科 &variant=zh-tw#.E5.9F.BA.E6.9C.AC.E7.8E.A9.E6.B3.95
18
莊家食夾棍 若莊家和眾閒家要以點數決勝(各方都沒有出現爆煲的情況),若該閒家和莊家手上所擁有的牌的總點數一樣的話,算莊家取勝,即俗稱莊家食夾棍,該閒家的注碼會歸莊家。 賭場規則,廿一點是沒有食夾棍這規例,如閒家和莊家手上牌總點數一樣的話,是「打和」,閒家可以拿回原先的注碼。 注意:莊家是五龍而閒家的點數比莊家大的話,仍算莊家取勝,不過莊家食夾棍的權利不適用於閒家例牌(Black Jack和五龍)的情況,因為閒家Black Jack和五龍屬於例牌先賠。 維基百科 &variant=zh-tw#.E5.9F.BA.E6.9C.AC.E7.8E.A9.E6.B3.95
19
綱要 作文與程式設計 範例:決勝21點 版本規劃 測試規劃 一些良好的程式設計習慣 測試驅動之程式開發及函式導向二十一點模擬程式0.0.0版
20
兩則做事方法的名言 物有本末,事有始终,知所先後,則近道矣。 《大學》開宗明義 學而不思則罔,思而不學則殆 《荀子》勸學篇 20
21
80-20定律、要事第一、工程方法 80-20定律 要事第一 (First things first)
工程方法 (Engineering approach) 辨識問題核心 (Core) 訂定優先順序 (Priority) 快速原型製作 (Fast prototyping) 逐步演化 (Evolution) 定時定量研究法
22
釐清問題 核心關鍵 Nice to have 優先順序 問題簡化 從實例簡化開始嘗試 做中學
23
工程方法 v 0.1 v 0.2 v 0.3 v 0.2
24
工程方法 配合實作逐漸熟悉問題,而非開始即要求全面了解 避免過度分析(analysis paralysis) ,及早獲得可用程式
隨版本演進,有系統地完成程式 隨時有產出,增進信心 越重要的部份較早完成,經歷越多測試,較確實可靠穩定;避免後期發現錯誤,須全面改寫程式 越重要的部份越早完成,可依照環境時程的改變,修改後續版本需求,富有彈性
25
程式目的 使玩家可以與電腦玩二十一點遊戲
26
二十一點遊戲模擬v0.1流程 產生牌疊 電腦(莊家)向玩家(一人)及本身派發一張明牌 電腦向玩家及本身派發一張明牌
莊家詢問玩家是否加牌, 直至玩家不加牌或報到 莊家如不足 17點便需加牌直至超過或等於 17點 對未有爆煲或報到的玩家, 比點數大小, 大者勝, 如莊家爆煲, 玩家勝
27
後續版本規劃 v0.2: 區分明牌暗牌 v0.3: 允許下注 v0.4: 處理同花順與五龍 v0.5: 處理保險、加註、分牌
28
綱要 作文與程式設計 範例:決勝21點 版本規劃 測試規劃 一些良好的程式設計習慣 測試驅動之程式開發及函式導向二十一點模擬程式0.0.0版
29
測試規劃 規劃程式須能處理的場景實例 增進對問題的確實了解 有助對程式架構與流程的思考 做為各版本程式紙筆測試、偵錯、驗證的依據
場景實例規畫由簡到繁 輸入錯誤資料等例外狀況可延後規劃 程式的功能與強健(robustness)程度,隨版本演進與通過的測試場景增加而成長
30
二十一點遊戲模擬原型之測試規劃: 場景1 玩家 莊家 ♠A ♥J ♦10 勝
31
二十一點遊戲模擬原型之測試規劃: 場景2 玩家 莊家 ♣3 ♥J ♠10 ♦ A勝
32
二十一點遊戲模擬原型之測試規劃: 場景3 玩家 莊家 ♠8 ♥J ♦7 ♠2 ♣6勝
33
二十一點遊戲模擬原型之測試規劃: 場景4 玩家 莊家 ♠8 ♥5 ♦8 ♠9 ♣6爆
34
二十一點遊戲模擬原型之測試規劃: 場景5 玩家 莊家 ♠8 ♥5 ♦8停 ♠9 ♣6勝
35
二十一點遊戲模擬原型之測試規劃: 場景6 玩家 莊家 ♠8 ♥5 ♦8停 ♠9 ♣8爆
36
綱要 作文與程式設計 範例:決勝21點 版本規劃 測試規劃 一些良好的程式設計習慣 測試驅動之程式開發及函式導向二十一點模擬程式0.0.0版
37
一些良好的程式設計習慣 使用研發日誌 夥伴合作程式設計 漸增式與回合式發展 可持續之發展步調 維護原始碼、註解、重要程式文件
依發展階段提昇程式的強健度 可持續之發展步調 維護原始碼、註解、重要程式文件
38
綱要 作文與程式設計 範例:決勝21點 版本規劃 測試規劃 一些良好的程式設計習慣 測試驅動之程式開發及函式導向二十一點模擬程式0.0.0版
39
測試 軟體錯誤代價可能極為高昂 測試可以發現並改正程式錯誤 通過的測試越多, 程式越可靠
40
測試時機與風險
41
極端化程式設計 (Extreme Programming)
撰寫一個簡單的測試程式 編譯執行程式,看它失敗 增添恰能通過測試之程式碼並編譯偵錯 重整及消除冗餘程式碼並編譯偵錯 反覆進行上述步驟
42
測試驅動開發方式 (Test-Driven Development -TDD)
寫測試主程式, 呼叫測試函式, 建置, 看它失敗 寫測試類別, 加上測試函式, 重新建置, 看它失敗 撰寫欲測試的類別, 加上株段(stub)函式, 使通過建置, 但不通過測試 改寫株段函式, 通過建置與測試 以相同方式, 增加新測試
43
BlackJack_0_0_0.Program using System; using System.Diagnostics;
namespace BlackJack_0_0_0 { class Program { static void Main(string[] args) { Debug.Assert(TestScenario_1_OK()); } static bool TestScenario_1_OK() { return true;
44
株段(Stub)函式 沒有實質內容 只是傳回true的值,使測試可以通過 可以驗證函式的呼叫與宣告是否一致,並建立程式的初步架構
45
綱要 逐步細分法開發程式及函式導向二十一點模擬程式0.0.1版 函式導向二十一點模擬程式0.0.2版 函式導向二十一點模擬程式0.1版
46
Stepwise Refinement 演算法設計
Magic number 7 加減 2 10個或更少的主要步驟或虛擬碼 逐層分解工作 各項工作依繁簡、重複性、可替代性決定是否寫為函式 以函式模組為組成單位 函式導向程式設計
47
虛擬碼TestScenario_1_OK()
設莊家手牌第一張為♥J 設玩家手牌第二張為♦10 傳回判斷玩家手牌總點數為21點之真偽
48
虛擬碼IsBlackJack(玩家手牌兩張)
合計手牌總點數(A為1點,2為2點,…,10及J、Q、K為10點) isBlackJack = 總點數為21之真偽 if !isBlackJack且第一張牌為A, 第一張牌點數改為11 isBlackJack = 總點數為21之真偽 if !isBlackJack且第二張牌為A, 第二張牌點數改為11 isBlackJack = 總點數為21之真偽 return isBlackJack
49
虛擬碼Points(牌點rank) points = rank; if (rank > 10) points = 10
return points
50
程式結構圖(Structure Chart)
TestScenario_1_OK() IsBlackJack() Points()
51
由上而下與由下而上 由上而下 由下而上 上下夾擊 假設底層類別已經存在 較易決定下層類別規格 主要之呼叫介面測試較多
先實作並測試底層類別(單元測試Unit Test) 較易測試類別實體 上下夾擊 開始時已有一批類別可用 51
52
BlackJack_0_0_1.Suit enum Suit { CLUB = 0, DIAMOND = 1, HEART = 2,
SPADE = 3 }
53
BlackJack_0_0_1.Program. TestScenario_1_OK
Suit[] humanPlayerHandSuit = new Suit[2]; int[] humanPlayerHandRank = new int[2]; Suit[] computerPlayerHandSuit = new Suit[1]; int[] computerPlayerHandRank = new int[1]; humanPlayerHandSuit[0] = Suit.SPADE; humanPlayerHandRank[0] = 1; computerPlayerHandSuit[0] = Suit.HEART; computerPlayerHandRank[0] = 11; humanPlayerHandSuit[1] = Suit.DIAMOND; humanPlayerHandRank[1] = 10; return IsBlackJack(humanPlayerHandRank);
54
BlackJack_0_0_1.Program. IsBlackJack
int point0 = Points(handRank[0]); int point1 = Points(handRank[1]); bool isBlackJack =(point0 + point1 == 21); if (!isBlackJack && point0 == 1) { point0 = 11; isBlackJack = (point0 + point1 == 21); } if (!isBlackJack && point1 == 1) { point1 = 11; return isBlackJack;
55
BlackJack_0_0_1.Program.Points
static int Points(int rank) { int points = rank; if (rank > 10) points = 10; return points; }
56
程式擴充與彈性的考慮 目的只是要完成場景1的測試 不考慮太多程式的擴充與彈性 符合TDD 每一個版本,都做一些修改,提昇程式功能與彈性
一段時日之後,所完成的程式功能就很可觀 穩紮穩打 比一開始就考慮全部功能的程式設計方法可靠
57
綱要 逐步細分法開發程式及函式導向二十一點模擬程式0.0.1版 函式導向二十一點模擬程式0.0.2版 函式導向二十一點模擬程式0.1版
58
程式BlackJack_0_0_2目標及假設 目標:掌握所有六個測試場景 假設每個場景 都有一付牌疊 (deck)
藉由發牌(deal a card)建立玩家與莊家的手牌(hand) 玩家與莊家最後的狀態(21點(BlackJack)、爆煲(Burst)、或二者皆不是(Pass)) 要分別檢驗決定
59
虛擬碼TestScenario_1_OK()
建立牌疊(♠A、♥J、♦10) 發一張牌給玩家 發一張牌給莊家 取得玩家狀態 取得莊家狀態 return 玩家狀態為BlackJack且莊家狀態為Pass之真偽
60
虛擬碼 GetStatus(手牌, out sum)
sum =手牌總點數(A為1點) status=由總點數判斷出的狀態(BlackJack、Burst、Pass) if (status != Pass) return status if(手牌中有A) total=sum+10 if(總點數==21) status = BlackJack if(total <= 21) sum = total return status
61
程式結構圖(Structure Chart)
TestScenario_1_OK PrepareDeck_1 DealACard GetStatus Point JudgeStatus
62
BlackJack_0_0_2.Program. Status
enum Status { PASS = 0, BLACK_JACK = 1, BURST = 2 }
63
BlackJack_0_0_2.Program. Main片段
Debug.Assert(TestScenario_1_OK(), "Scenario 1 test failed"); Debug.Assert(TestScenario_2_OK(), "Scenario 2 test failed"); Debug.Assert(TestScenario_3_OK(), "Scenario 3 test failed"); Debug.Assert(TestScenario_4_OK(), "Scenario 4 test failed"); Debug.Assert(TestScenario_5_OK(), "Scenario 5 test failed"); Debug.Assert(TestScenario_6_OK(), "Scenario 6 test failed");
64
BlackJack_0_0_2.Program. TestScenario_1_OK片段 (1/2)
Suit[] deckSuit = new Suit[3]; int[] deckRank = new int[3]; PrepareDeck_1(deckSuit, deckRank, out top); Suit[] humanPlayerHandSuit = new Suit[2]; int[] humanPlayerHandRank = new int[2]; int nHumanPlayerHandCards = 0; Suit[] computerPlayerHandSuit = new Suit[1]; int[] computerPlayerHandRank = new int[1]; int nComputerPlayerHandCards = 0; DealACard(deckSuit, deckRank, ref top, humanPlayerHandSuit, humanPlayerHandRank, ref nHumanPlayerHandCards);
65
BlackJack_0_0_2.Program. TestScenario_1_OK片段 (2/2)
Status humanPlayerStatus = GetStatus(humanPlayerHandRank, nHumanPlayerHandCards, out humanPlayerTotalPoints); Status computerPlayerStatus = GetStatus(computerPlayerHandRank, nComputerPlayerHandCards, out computerPlayerTotalPoints); return (humanPlayerStatus == Status.BLACK_JACK && computerPlayerStatus == Status.PASS);
66
BlackJack_0_0_2.Program. PrepareDeck_1
static void PrepareDeck_1(Suit[] deckSuit, int[] deckRank, out int top) { deckSuit[0] = Suit.SPADE; deckRank[0] = 1; deckSuit[1] = Suit.HEART; deckRank[1] = 11; deckSuit[2] = Suit.DIAMOND; deckRank[2] = 10; top = 0; }
67
BlackJack_0_0_2.Program. DealACard
static void DealACard(Suit[] deckSuit, int[] deckRank, ref int top, Suit[] suit, int[] rank, ref int nCards) { suit[nCards] = deckSuit[top]; rank[nCards] = deckRank[top]; ++top; ++nCards; }
68
BlackJack_0_0_2.Program. GetStatus片段 (1/3)
int[] point = new int[nCards]; int sum = 0; for (i = 0; i < nCards; ++i) { point[i] = Point(handRank[i]); sum += point[i]; } Status status = JudgeStatus(sum); totalPoints = sum; if (status != Status.PASS) return status; bool isWithAce = false;
69
BlackJack_0_0_2.Program. GetStatus片段 (2/3)
for (i = 0; i < nCards; ++i) { if (point[i] == 1) { isWithAce = true; break; } if (isWithAce) { sum += 10; if (sum == 21) { status = Status.BLACK_JACK;
70
BlackJack_0_0_2.Program. GetStatus片段 (3/3)
if (sum <= 21) { totalPoints = sum; } // keep original totalPoints if sum > 21 return status;
71
BlackJack_0_0_2.Program. JudgeStatus
static Status JudgeStatus(int sum) { Status status; if (sum == 21) { status = Status.BLACK_JACK; } else if (sum > 21) { status = Status.BURST; } else { status = Status.PASS; } return status;
72
綱要 逐步細分法開發程式及函式導向二十一點模擬程式0.0.1版 函式導向二十一點模擬程式0.0.2版 函式導向二十一點模擬程式0.1版
73
二十一點遊戲模擬v0.1流程 產生牌疊 電腦(莊家)向玩家(一人)及本身派發一張明牌 電腦向玩家及本身派發一張明牌
莊家詢問玩家是否加牌, 直至玩家不加牌或報到 莊家如不足 17點便需加牌直至超過或等於 17點 對未有爆煲或報到的玩家, 比點數大小, 大者勝, 如莊家爆煲, 玩家勝 73
74
二十一點遊戲模擬v0.1流程虛擬碼 虛擬碼RunGame() 1 建立牌疊 2 向玩家及電腦各發一張牌 3 向玩家及電腦各發一張牌
1 建立牌疊 2 向玩家及電腦各發一張牌 3 向玩家及電腦各發一張牌 4 取得玩家及電腦手牌狀態,並作處理 5 while(玩家要牌且牌疊仍有牌) 5.1 發一張牌給玩家 取得玩家手牌狀態,並作處理 6 while(電腦要牌且牌疊仍有牌) 發一張牌給電腦 取得電腦手牌狀態,並作處理 7 計點分勝負
75
撲克牌與數字的對應 1 2 3 4 5 6 7 8 9 10 11 12 ♣A ♣2 ♣3 ♣4 ♣5 ♣6 ♣7 ♣8 ♣9 ♣10 ♣J
1 2 3 4 5 6 7 8 9 10 11 12 ♣A ♣2 ♣3 ♣4 ♣5 ♣6 ♣7 ♣8 ♣9 ♣10 ♣J ♣Q ♣K 13 14 15 16 17 18 19 20 21 22 23 24 25 ♦A ♦2 ♦3 ♦4 ♦5 ♦6 ♦7 ♦8 ♦9 ♦10 ♦J ♦Q ♦K 26 27 28 29 30 31 32 33 34 35 36 37 38 ♥A ♥2 ♥3 ♥4 ♥5 ♥6 ♥7 ♥8 ♥9 ♥10 ♥J ♥Q ♥K 39 40 41 42 43 44 45 46 47 48 49 50 51 ♠A ♠2 ♠3 ♠4 ♠5 ♠6 ♠7 ♠8 ♠9 ♠10 ♠J ♠Q ♠K
76
準備牌疊虛擬碼 虛擬碼PrepareDeck(牌疊) 1 陣列used[0~51] (標記某張牌是否已被用過)均設為偽
2 for(i=0; i<52; ++i) 2.1 隨機產生一個0~51的整數,令為pos 2.2 while(used[pos]為真) pos pos 設為 pos 除以 52的餘數 (以免pos超出範圍) 2.3 牌疊第i張牌之花色由pos除以4的商決定 2.4 牌疊第i張牌之牌點由pos除以4的餘數加1決定 2.5 設used[pos]為真
77
程式結構圖 RunGame DealACard GetStatus DumpHand JudgeStatus Point
PrepareDeck DealACard GetStatus DumpHand IsBlackJackOrBurst ComputerPlayerWants OneMoreCard HumanPlayerWants OneMoreCard JudgeStatus Point
78
BlackJack_0_1.Program. Main
static void Main(string[] args) { Debug.Assert(TestDeck_OK(), "Deck test failed"); Console.WriteLine(); Console.WriteLine("21點遊戲開始"); RunGame(); }
79
BlackJack_0_1.Program. TestDeck片段 (1/4)
Suit[] deckSuit = new Suit[52]; int[] deckRank = new int[52]; PrepareDeck(deckSuit, deckRank, out top); Suit[] cardsSuit = new Suit[52]; int[] cardsRank = new int[52]; int nCards = 0; for (i = 0; i < 52; ++i) { DealACard(deckSuit, deckRank, ref top, cardsSuit, cardsRank, ref nCards); }
80
BlackJack_0_1.Program. TestDeck片段 (2/4)
int[] nSuit = new int[4]; for (s = 0; s < 4; ++s) { nSuit[s] = 0; } int[] nRank = new int[13]; for (r = 0; r < 13; ++r) { nRank[r] = 0;
81
BlackJack_0_1.Program. TestDeck片段 (3/4)
for (i = 0; i < 52; ++i) { switch (cardsSuit[i]) { case Suit.CLUB: nSuit[0]++; break; case Suit.DIAMOND: nSuit[1]++; break; case Suit.HEART: nSuit[2]++; break; case Suit.SPADE: nSuit[3]++; break; default: break; } nRank[cardsRank[i] - 1]++;
82
BlackJack_0_1.Program. TestDeck片段 (4/4)
bool suit_OK = true; for (s = 0; s < 4; s++) { if (nSuit[s] != 13) { suit_OK = false; break; } bool rank_OK = true; for (r = 0; r < 13; r++) { if (nRank[r] != 4) { rank_OK = false; break; return suit_OK && rank_OK;
83
BlackJack_0_1.Program. RunGame片段
Suit[] deckSuit = new Suit[52]; int[] deckRank = new int[52]; PrepareDeck(deckSuit, deckRank, out top); // a player can have at most 11 cards // {A, A, A, A, 2, 2, 2, 2, 3, 3, 3} // for not burst or BlackJack Suit[] humanPlayerHandSuit = new Suit[11]; int[] humanPlayerHandRank = new int[11]; int nHumanPlayerHandCards = 0; Suit[] computerPlayerHandSuit = new Suit[11]; int[] computerPlayerHandRank = new int[11]; int nComputerPlayerHandCards = 0;
84
BlackJack_0_1.Program. RunGame片段 (1/4)
DealACard(deckSuit, deckRank, ref top, humanPlayerHandSuit, humanPlayerHandRank, ref nHumanPlayerHandCards); Status humanPlayerStatus = GetStatus(humanPlayerHandRank, nHumanPlayerHandCards, out humanPlayerTotalPoints); DumpHand("玩家", humanPlayerHandSuit, humanPlayerHandRank, nHumanPlayerHandCards, humanPlayerTotalPoints); if (IsBlackJackOrBurst(humanPlayerStatus)) return;
85
BlackJack_0_1.Program. RunGame片段 (2/4)
DealACard(deckSuit, deckRank, ref top, computerPlayerHandSuit, computerPlayerHandRank, ref nComputerPlayerHandCards); Status computerPlayerStatus = GetStatus(computerPlayerHandRank, nComputerPlayerHandCards, out computerPlayerTotalPoints); DumpHand("電腦", computerPlayerHandSuit, computerPlayerHandRank, nComputerPlayerHandCards, computerPlayerTotalPoints); if(IsBlackJackOrBurst(computerPlayerStatus)) return;
86
BlackJack_0_1.Program. RunGame片段 (3/4)
while (humanPlayerStatus == Status.PASS && HumanPlayerWantsOneMoreCard() && top < 51){ DealACard(deckSuit, deckRank, ref top, humanPlayerHandSuit, humanPlayerHandRank, ref nHumanPlayerHandCards); humanPlayerStatus = GetStatus(humanPlayerHandRank, nHumanPlayerHandCards, out humanPlayerTotalPoints); DumpHand("玩家", humanPlayerHandSuit, humanPlayerHandRank, nHumanPlayerHandCards, humanPlayerTotalPoints); if (IsBlackJackOrBurst(humanPlayerStatus)) return; }
87
BlackJack_0_1.Program. RunGame片段 (4/4)
if (computerPlayerTotalPoints >= humanPlayerTotalPoints) { Console.WriteLine("電腦勝"); } else { Console.WriteLine("玩家勝"); }
88
BlackJack_0_1.Program. PrepareDeck片段 (1/2)
Random rand = new Random(); bool[] used = new bool[52]; for (i = 0; i < 52; ++i) { used[i] = false; } pos = rand.Next() % 52; while (used[pos]) { ++pos; pos = pos % 52; s = pos / 13;
89
BlackJack_0_1.Program. PrepareDeck片段 (2/2)
switch (s) { case 0: deckSuit[i] = Suit.CLUB; break; case 1: deckSuit[i] = Suit.DIAMOND; break; case 2: deckSuit[i] = Suit.HEART; break; case 3: deckSuit[i] = Suit.SPADE; break; default: break; } deckRank[i] = pos % ; used[pos] = true; top = 0;
90
BlackJack_0_1.Program. HumanPlayerWantsOneMoreCard
static bool HumanPlayerWantsOneMoreCard() { Console.Write("要再一張牌嗎? (y/n) "); string answer = Console.ReadLine(); return (answer == "Y" || answer == "y"); }
91
BlackJack_0_1.Program. ComputerPlayerWantsOneMoreCard
static bool ComputerPlayerWantsOneMoreCard(int totalPoints) { return (totalPoints < 17); }
92
BlackJack_0_1.Program.DumpCard片段
string[] ranks = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" }; switch (suit) { case Suit.CLUB: Console.Write("c" + ranks[rank - 1]); break; case Suit.DIAMOND: Console.Write("d" + ranks[rank - 1]); case Suit.HEART: Console.Write("h" + ranks[rank - 1]); }
Similar presentations