日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

报数游戏c语言,报数游戏-实战简单设计

發布時間:2023/12/18 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 报数游戏c语言,报数游戏-实战简单设计 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

注:手機推薦橫屏觀看:-)

幼兒園老師在給一群小朋友玩報數游戲,游戲規則如下:

老師給定任意三個特殊個位數:3,5,7

總共120位小朋友排成一排順序報數

需求1:

a. 所報數字是第一個特殊數的倍數(本例為3),不能說該數字,說“石頭”;

b. 所報數字是第二個特殊數的倍數(本例為5),不能說該數字,說“剪刀”;

c. 所報數字是第三個特殊數的倍數(本例為7),不能說該數字,說“布”;

d. 如果所報數字同時是兩個特殊數的倍數情況下,也要特殊處理,比如是3和5的倍數,那么不能說該數字,而是要說“石頭剪刀”, 以此類推。

e. 如果同時是三個特殊數的倍數,那么要說“石頭剪刀布”

Sprint 1

快速瀏覽題目,從中識別出關鍵字“報數游戲”,“特殊數:3,5,7”,“120,順序報數”。采用TDD方式,先驅動出接口。

第一個測試用例:

#include "gtest/gtest.h"

#include "CountOffGame.h"

struct GameTest : testing::Test

{

protected:

CountOffGame game;

};

TEST_F(GameTest, should_count_off_given_special_num_3_5_7)

{

ASSERT_EQ("1", game.shout(1));

}

從解決編譯問題開始,快速通過測試:

//CountOffGame.h

#include

struct CountOffGame

{

std::string shout(int n) const;

};

//CountOffGame.cpp

#include "CountOffGame.h"

std::string CountOffGame::shout(int n) const

{

return "1";

}

至此,我們已經驅動出用戶接口,通過第一個用例。

接下來,繼續增加第二個用例:

注:簡單起見,本例不對測試用例進行拆分,請大家按照 F.I.R.S.T. 原則及 given-when-then方式自行編寫測試用例 :-)

TEST_F(GameTest, should_count_off_given_special_num_3_5_7)

{

ASSERT_EQ("1", game.shout(1));

ASSERT_EQ("2", game.shout(2));

}

修改實現,老老實實把數字轉換為字符串,通過第二個用例。

//CountOffGame.cpp

#include "CountOffGame.h"

std::string CountOffGame::shout(int n) const

{

return std::to_string(n);

}

接下來我們該處理需求1-a了:

所報數字是第一個特殊數的倍數(本例為3),不能說該數字,說“石頭”

TEST_F(GameTest, should_count_off_given_special_num_3_5_7)

{

ASSERT_EQ("1", game.shout(1));

ASSERT_EQ("2", game.shout(2));

ASSERT_EQ("石頭", game.shout(3));

}

運行測試,校驗失敗,繼續完成需求1-a。這個難不倒我們,求某個數的倍數,用%即可。

std::string CountOffGame::shout(int n) const

{

if(n % 3 == 0) return "石頭";

return std::to_string(n);

}

繼續完成需求1-b:

TEST_F(GameTest, should_count_off_given_special_num_3_5_7)

{

ASSERT_EQ("1", game.shout(1));

ASSERT_EQ("2", game.shout(2));

ASSERT_EQ("石頭", game.shout(3));

ASSERT_EQ("剪刀", game.shout(5));

}

std::string CountOffGame::shout(int n) const

{

if(n % 3 == 0) return "石頭";

if(n % 5 == 0) return "剪刀";

return std::to_string(n);

}

至此,我們已經完成了需求1-a,需求1-b,但敏銳的你一定發現了不少壞味道:

業務代碼中需求1-a,需求1-b的實現存在明顯重復

測試用例中,game.shout(...)存在明顯重復

用戶APIshout()命名也不太合理

我們先忍忍,繼續完成需求1-c,因為它并不會帶來新的變化方向

TEST_F(GameTest, should_count_off_given_special_num_3_5_7)

{

ASSERT_EQ("1", game.shout(1));

ASSERT_EQ("2", game.shout(2));

ASSERT_EQ("石頭", game.shout(3));

ASSERT_EQ("剪刀", game.shout(5));

ASSERT_EQ("布", game.shout(7));

}

std::string CountOffGame::shout(int n) const

{

if(n % 3 == 0) return "石頭";

if(n % 5 == 0) return "剪刀";

if(n % 7 == 0) return "布";

return std::to_string(n);

}

至此,我們已經完成需求1-a,b,c,接下來要開啟Refactor模式了

重命名shout(int n)接口

//CountOffGame.h

struct CountOffGame

{

std::string countOff(int n) const;

};

//CountOffGame.cpp

std::string CountOffGame::countOff(int n) const

{

...

}

消除測試用例接口重復

struct GameTest : testing::Test

{

void ASSERT_COUNTOFF_GAME(int n, const std::string& words)

{

ASSERT_EQ(words, game.countOff(n));

}

protected:

CountOffGame game;

};

TEST_F(GameTest, should_count_off_given_special_num_3_5_7)

{

ASSERT_COUNTOFF_GAME(1, "1");

ASSERT_COUNTOFF_GAME(2, "2");

ASSERT_COUNTOFF_GAME(3, "石頭");

ASSERT_COUNTOFF_GAME(5, "剪刀");

ASSERT_COUNTOFF_GAME(7, "布");

}

消除業務代碼中重復,提煉出倍數概念

namespace

{

bool times(int n, int times)

{

return n % times == 0;

}

}

std::string CountOffGame::countOff(int n) const

{

if(times(n, 3)) return "石頭";

if(times(n, 5)) return "剪刀";

if(times(n, 7)) return "布";

return std::to_string(n);

}

消除報數“石頭,剪刀,布”硬編碼

namespace

{

...

std::string shout(int n, const std::string& words = "")

{

if(!words.empty()) return words;

return std::to_string(n);

}

}

std::string CountOffGame::countOff(int n) const

{

if(times(n, 3)) return shout(n, "石頭");

if(times(n, 5)) return shout(n, "剪刀");

if(times(n, 7)) return shout(n, "布");

return shout(n);

}

至此,我們已經消除了明顯的重復,但是依然存在結構性重復。即每個語句都是報數時遵循的一個規則,并且都是if(謂詞) return 動作結構。

我們對其進行抽象,進一步分析發現滿足如下形式化定義:

Rule: (int) -> string

Predicate: (int) -> bool

Action: (int) -> string

我們從武器庫中快速搜尋著各種解決方案,比較著他們的利弊。

抽象出Predicate與Action接口類,分別提供bool isMatch(int n) const與std::string do(int n) const虛方法;抽象出Rule類,注入Predicate與Action接口

定義類模板Rule,綁定謂詞與動作,要求謂詞滿足isMatch(int n),動作滿足do(int n)約束

定義兩個函數指針,用于抽象約束關系,使用函數模板rule將其綁定

綜合考慮后,發現方案3在簡單性和擴展性方面是最合適的

//CountOffGame.cpp

namespace

{

...

typedef bool (*Predicate)(int, int);

typedef std::string (*Action)(int, const std::string& );

template

std::string rule(int n, int times, const std::string& words)

{

if(isMatch(n, times))

{

return do(n, words);

}

return std::string("");

}

}

std::string CountOffGame::countOff(int n) const

{

const std::string& r1_1 = rule(n, 3, "石頭");

if( ! r1_1.empty()) return r1_1;

const std::string& r1_2 = rule(n, 5, "剪刀");

if( ! r1_2.empty()) return r1_2;

const std::string& r1_3 = rule(n, 7, "布");

if( ! r1_3.empty()) return r1_3;

return shout(n);

}

舊仇剛報,又添新恨,此時又出現了新的結構性重復,抽象一下就是:報數規則有一個滿足,就執行該規則并返回,否則繼續執行下一個規則,語義為為anyof(...)。我們暫且忍受一下,讓子彈飛一會,繼續完成下面需求。

增加需求1-d,需求1-e測試用例:

TEST_F(GameTest, should_count_off_given_special_num_3_5_7)

{

ASSERT_COUNTOFF_GAME(1, "1");

ASSERT_COUNTOFF_GAME(2, "2");

ASSERT_COUNTOFF_GAME(3, "石頭");

ASSERT_COUNTOFF_GAME(5, "剪刀");

ASSERT_COUNTOFF_GAME(7, "布");

ASSERT_COUNTOFF_GAME(15, "石頭剪刀");

ASSERT_COUNTOFF_GAME(21, "石頭布");

ASSERT_COUNTOFF_GAME(35, "剪刀布");

ASSERT_COUNTOFF_GAME(105, "石頭剪刀布");

}

我們仔細分析發現需求1-d,需求1-e是對上面需求的組合,即如果規則滿足則執行該規則,完成后繼續執行下一個規則,若不滿足則直接執行下一個規則。語義為allof(...)。本例中表現為把所有規則結果串起來。

std::string CountOffGame::countOff(int n) const

{

const std::string& r1 = rule(n, 3, "石頭") ;

+ rule(n, 5, "剪刀");

+ rule(n, 7, "布");

if( ! r1.empty()) return r1;

return shout(n);

}

至此,我們全部完成了需求1所有規則,由于需求1-d,e比需求1-a,b,c優先級高,allof()隱式滿足了anyof()需求,所以結構性重復暫時不存在了。

Sprint 2

需求 2:

a. 如果所報數字中包含了第一個特殊數,那么也不能說該數字,而是要說相應的詞,比如本例中第一個特殊數是3,那么要報13的同學應該說“石頭”。

b. 如果所報數字中包含了第一個特殊數,那么忽略規則1,比如要報35的同學只報“石頭”,不報“剪刀布”

增加需求2測試用例:

TEST_F(GameTest, should_count_off_given_special_num_3_5_7)

{

...

ASSERT_COUNTOFF_GAME(13, "石頭");

ASSERT_COUNTOFF_GAME(35, "石頭");

}

有了需求1的抽象,需求2就比較簡單了,僅需要增加一個謂詞即可

namespace

{

...

bool contains(int n, int contained)

{

int units = 0;

while(n > 0)

{

units = n % 10;

n = n /10;

if(units == contained) return true;

}

return false;

}

...

}

std::string CountOffGame::countOff(int n) const

{

const std::string& r2 = rule(n, 3, "石頭");

if(!r2.empty()) return r2;

const std::string& r1 = rule(n, 3, "石頭");

+ rule(n, 5, "剪刀");

+ rule(n, 7, "布");

if( ! r1.empty()) return r1;

return shout(n);

}

return shout(n);是什么鬼,我們進一步分析,將它抽象成一個規則

namespace

{

...

bool always_true(int,int)

{

return true;

}

std::string shout(int, const std::string& words)

{

return words;

}

std::string nop(int n, const std::string&)

{

return std::to_string(n);

}

...

}

std::string CountOffGame::countOff(int n) const

{

const std::string& r2 = rule(n, 3, "石頭");

if(!r2.empty()) return r2;

const std::string& r1 = rule(n, 3, "石頭");

+ rule(n, 5, "剪刀");

+ rule(n, 7, "布");

if( ! r1.empty()) return r1;

return rule(n, 0, "");

}

但是我們討厭的結構性重復又來了,這不就是前面抽象的anyof(...)么,看來不得不收拾他們了。

解決這個問題之前,我們先把物理耦合處理下,CountOffGame.cpp文件的職責已經太多了

//Predicate.h

bool times(int n, int times);

bool contains(int n, int contained);

bool always_true(int,int);

//Predicate.cpp

#include "Predicate.h"

bool times(int n, int times)

{

return n % times == 0;

}

bool contains(int n, int contained)

{

int units = 0;

while(n > 0)

{

units = n % 10;

n = n /10;

if(units == contained) return true;

}

return false;

}

bool always_true(int,int)

{

return true;

}

//Action.h

#include

std::string shout(int n, const std::string& words);

std::string nop(int n, const std::string&);

//Action.cpp

#include "Action.h"

std::string shout(int, const std::string& words)

{

return words;

}

std::string nop(int n, const std::string&)

{

return std::to_string(n);

}

//Rule.h

#include

typedef bool (*Predicate)(int, int);

typedef std::string (*Action)(int, const std::string& );

template

std::string rule(int n, int times, const std::string& words)

{

if(isMatch(n, times))

{

return do(n, words);

}

return std::string("");

}

CountOffGame.cpp文件中僅剩下組合游戲規則,完成游戲了

std::string CountOffGame::countOff(int n) const

{

const std::string& r2 = rule(n, 3, "石頭");

if(!r2.empty()) return r2;

const std::string& r1 = rule(n, 3, "石頭");

+ rule(n, 5, "剪刀");

+ rule(n, 7, "布");

if( ! r1.empty()) return r1;

return shout(n);

}

注:有同學不知道CountOffGame類與Rule的區別,這里解釋一下,規則僅完成每個規則自己的形式化與定義,游戲中對規則進行組合,完成游戲

完成文件物理解耦后,世界一下子清靜多了,需要特別指出的是,在使用c語言進行編程時,由于沒有類的模塊化手段,在解耦方面,文件是留給我們的唯一利器了。

我們回過頭來,再看看前面抽象的anyof(...),allof(...)概念,形式化一下可以表示為:

Rule: (int) -> string

allof: rule1 && rule2 ...

anyof: rule1 || rule2 ...

這顯然是規則的組合關系管理,我們又陷入了深深的思索,使用什么方法解決這個問題呢?

繼續搜索武器庫:

使用面向對象方法,抽象出rule對應接口,使用組合模式解決該問題

使用類模板,將不同rule通過模板參數注入,需要使用變參模板

使用函數模板,將不同rule通過模板參數注入,需要使用變參函數模板

使用函數式編程,可以使用std::function定義每個rule

綜合比較以上方案,

面向對象設計,組合模式中集合類要求每個成員rule不可以異構,并且僅能存放指向rule的指針,即要求每個rule都是一個對象。我們就需要管理每個對象的生命周期,需要使用shared_ptr,或者使用c++11 std::move語義,延長臨時對象生命周期。越想越復雜,打住!

模板元編程,需要使用c++11變參模板,或者使用repeate宏了(參看boost庫),

函數模板,需要使用c++11變參函數模板,使用尾遞歸完成組合,直接注入規則即可

函數式編程,形式化表示規則,天生具有優勢,又加之函數的無狀態,組合起來很方便,可以結合右值引用及std::move完成,考慮熟悉同學較少,暫不考慮

綜合分析后,我們選方案3

//Rule.h

...

template

Head allof(Head head)

{

return head;

}

template

Head allof(Head head, Tail... tail)

{

return head + allof

(tail...);

}

template

Head anyof(Head head)

{

if(!head.empty()) return head;

return std::string("");

}

template

Head anyof(Head head, Tail... tail)

{

if(!head.empty()) return head;

return anyof

(tail...);

}

//CountOffGame.cpp

#include "CountOffGame.h"

#include "Rule.h"

#include "Predicate.h"

#include "Action.h"

std::string CountOffGame::countOff(int n) const

{

auto r1_1 = rule(n, 3, "石頭");

auto r1_2 = rule(n, 5, "剪刀");

auto r1_3 = rule(n, 7, "布");

auto r1 = allof(r1_1, r1_2, r1_3);

auto r2 = rule(n, 3, "石頭");

auto rd = rule(n, 0, "");

return anyof(r2, r1, rd);

}

現在我們徹底解決了規則管理問題,你可以任意調整優先級了,也可以任意忽略規則了。在整個設計過程中,我們發現重復總是我們識別壞味道最好的引子。當變化方向來的時候,也就是我們被第二顆子彈擊中的時候(好吧,有時候是第三顆子彈),我們需要把該方向的所有問題解決,而不是僅解決該問題。

注: 坦白講,這里的CountOffGame類使用的完全沒有必要,你完全可以使用一個簡單的 const char* count_off(int n)函數代替,再把std::string使用char*取代,這樣就完全是一份c的代碼了:-)

Sprint 3

需求 3:

a. 第二天,幼兒園換了新老師,新老師對游戲進行了修改

三個特殊的個位數變更為5,7,9。規則1,規則2依然有效,例如:

遇到 5 的倍數說“石頭”,7的倍數說“剪刀”,9的倍數說“布”;

遇到 63 說“剪刀布”

遇到 53 說“石頭”,遇到35說“石頭”

b. 需求1,2 測試用例斷言不允許修改,僅允許修改前置條件

需求3已經說的很明顯了,三個特殊數可以發生變化,并且需要通過游戲注入,而不需要修改游戲規則

簡單重構測試用例斷言,增加需求3用例

#include "gtest/gtest.h"

#include "CountOffGame.h"

struct GameTest : testing::Test

{

GameTest() : game_sprint_1_2(3, 5, 7)

, game_sprint_3(5, 7, 9)

{

}

void ASSERT_COUNTOFF_3_5_7(int n, const std::string& words)

{

ASSERT_EQ(words, game_sprint_1_2.countOff(n));

}

void ASSERT_COUNTOFF_5_7_9(int n, const std::string& words)

{

ASSERT_EQ(words, game_sprint_3.countOff(n));

}

protected:

CountOffGame game_sprint_1_2;

CountOffGame game_sprint_3;

};

TEST_F(GameTest, should_count_off_given_special_num_3_5_7)

{

ASSERT_COUNTOFF_3_5_7(1, "1");

ASSERT_COUNTOFF_3_5_7(2, "2");

ASSERT_COUNTOFF_3_5_7(3, "石頭");

ASSERT_COUNTOFF_3_5_7(5, "剪刀");

ASSERT_COUNTOFF_3_5_7(7, "布");

ASSERT_COUNTOFF_3_5_7(15, "石頭剪刀");

ASSERT_COUNTOFF_3_5_7(21, "石頭布");

ASSERT_COUNTOFF_3_5_7(105, "石頭剪刀布");

ASSERT_COUNTOFF_3_5_7(13, "石頭");

ASSERT_COUNTOFF_3_5_7(35, "石頭");

}

TEST_F(GameTest, should_count_off_given_special_num_5_7_9)

{

ASSERT_COUNTOFF_5_7_9(1, "1");

ASSERT_COUNTOFF_5_7_9(2, "2");

ASSERT_COUNTOFF_5_7_9(5, "石頭");

ASSERT_COUNTOFF_5_7_9(7, "剪刀");

ASSERT_COUNTOFF_5_7_9(9, "布");

ASSERT_COUNTOFF_5_7_9(63, "剪刀布");

ASSERT_COUNTOFF_5_7_9(15, "石頭");

ASSERT_COUNTOFF_5_7_9(35, "石頭");

}

快速完成需求3,僅是規則中Predicate匹配內容發生了變化,修改CountOffGame即可

//CountOffGame.h

#include

struct CountOffGame

{

CountOffGame(int n1, int n2, int n3);

std::string countOff(int n) const;

private:

int n1;

int n2;

int n3;

};

//CountOffGame.cpp

CountOffGame::CountOffGame(int n1, int n2, int n3) : n1(n1), n2(n2), n3(n3)

{

}

std::string CountOffGame::countOff(int n) const

{

auto r1_1 = rule(n, n1, "石頭");

auto r1_2 = rule(n, n2, "剪刀");

auto r1_3 = rule(n, n3, "布");

auto r1 = allof(r1_1, r1_2, r1_3);

auto r2 = rule(n, n1, "石頭");

auto rd = rule(n, 0, "");

return anyof(r2, r1, rd);

}

繼續...

Sprint 4

需求 4:

第三天,原來老師又回來了,對游戲又做了如下修改

a. 老師又把三個特殊的個位數變回為3,5,7

b. 規則1與規則2中“石頭、剪刀、布”變更為 “老虎,棒子,雞”。

c. 打印120位小朋友報數的結果到文件(count_off.txt),并提交到 document 文件夾下。可以不處理IO,打印出來拷貝到 count_off.txt

這壓根沒引入什么新的變化方向,僅是規則中Action的內容發生了變化,修改CountOffGame即可,我們愛死這個老師了!

增加需求4測試用例:

struct GameTest : testing::Test

{

GameTest() : game_sprint_1_2(3, 5, 7, "石頭", "剪刀", "布")

, game_sprint_3(5, 7, 9, "石頭", "剪刀", "布")

, game_sprint_4(3, 5, 7, "老虎", "棒子", "雞")

{

}

void ASSERT_COUNTOFF_3_5_7(int n, const std::string& words)

{

ASSERT_COUNTOFF(game_sprint_1_2, n, words);

}

void ASSERT_COUNTOFF_5_7_9(int n, const std::string& words)

{

ASSERT_COUNTOFF(game_sprint_3, n, words);

}

void ASSERT_COUNTOFF_3_5_7_EX(int n, const std::string& words)

{

ASSERT_COUNTOFF(game_sprint_4, n, words);

}

private:

void ASSERT_COUNTOFF(const CountOffGame& game, int n, const std::string& words)

{

ASSERT_EQ(words, game.countOff(n));

}

protected:

CountOffGame game_sprint_1_2;

CountOffGame game_sprint_3;

CountOffGame game_sprint_4;

};

TEST_F(GameTest, should_count_off_given_special_num_3_5_7)

{

ASSERT_COUNTOFF_3_5_7(1, "1");

ASSERT_COUNTOFF_3_5_7(2, "2");

ASSERT_COUNTOFF_3_5_7(3, "石頭");

ASSERT_COUNTOFF_3_5_7(5, "剪刀");

ASSERT_COUNTOFF_3_5_7(7, "布");

ASSERT_COUNTOFF_3_5_7(15, "石頭剪刀");

ASSERT_COUNTOFF_3_5_7(21, "石頭布");

ASSERT_COUNTOFF_3_5_7(105, "石頭剪刀布");

ASSERT_COUNTOFF_3_5_7(13, "石頭");

ASSERT_COUNTOFF_3_5_7(35, "石頭");

}

TEST_F(GameTest, should_count_off_given_special_num_5_7_9)

{

ASSERT_COUNTOFF_5_7_9(1, "1");

ASSERT_COUNTOFF_5_7_9(2, "2");

ASSERT_COUNTOFF_5_7_9(5, "石頭");

ASSERT_COUNTOFF_5_7_9(7, "剪刀");

ASSERT_COUNTOFF_5_7_9(9, "布");

ASSERT_COUNTOFF_5_7_9(63, "剪刀布");

ASSERT_COUNTOFF_5_7_9(15, "石頭");

ASSERT_COUNTOFF_5_7_9(35, "石頭");

}

TEST_F(GameTest, should_count_off_given_special_num_3_5_7_countof_other)

{

ASSERT_COUNTOFF_3_5_7_EX(1, "1");

ASSERT_COUNTOFF_3_5_7_EX(2, "2");

ASSERT_COUNTOFF_3_5_7_EX(3, "老虎");

ASSERT_COUNTOFF_3_5_7_EX(5, "棒子");

ASSERT_COUNTOFF_3_5_7_EX(7, "雞");

ASSERT_COUNTOFF_3_5_7_EX(15, "老虎棒子");

ASSERT_COUNTOFF_3_5_7_EX(21, "老虎雞");

ASSERT_COUNTOFF_3_5_7_EX(105, "老虎棒子雞");

ASSERT_COUNTOFF_3_5_7_EX(13, "老虎");

ASSERT_COUNTOFF_3_5_7_EX(35, "老虎");

}

快速實現需求

//CountOffGame.h

#include

struct CountOffGame

{

CountOffGame(int n1, int n2, int n3, const std::string&, const std::string&, const std::string&);

std::string countOff(int n) const;

private:

int n1;

int n2;

int n3;

const std::string w1;

const std::string w2;

const std::string w3;

};

//CountOffGame.cpp

CountOffGame::CountOffGame(int n1, int n2, int n3, const std::string& w1, const std::string& w2, const std::string& w3)

: n1(n1), n2(n2), n3(n3), w1(w1), w2(w2), w3(w3)

{

}

std::string CountOffGame::countOff(int n) const

{

auto r1_1 = rule(n, n1, w1);

auto r1_2 = rule(n, n2, w2);

auto r1_3 = rule(n, n3, w3);

auto r1 = allof(r1_1, r1_2, r1_3);

auto r2 = rule(n, n1, w1);

auto rd = rule(n, 0, "");

return anyof(r2, r1, rd);

}

雖然實現了需求,但這一長串初始化參數,搞的人都快吐了,

仔細分析一下,報數游戲中規則條件及動作結果是一個一一映射關系,我們可以定義一個RuleMap進行化簡

//CountOffGame.h

#include

#include

#include

struct RuleMap

{

int n;

std::string words;

};

struct CountOffGame

{

CountOffGame(const std::initializer_list&);

std::string countOff(int n) const;

private:

std::vector rules;

};

//CountOffGame.cpp

#include "CountOffGame.h"

#include "Rule.h"

#include "Predicate.h"

#include "Action.h"

CountOffGame::CountOffGame(const std::initializer_list& rules) : rules(rules)

{

}

std::string CountOffGame::countOff(int n) const

{

auto r1_1 = rule(n, rules[0].n, rules[0].words);

auto r1_2 = rule(n, rules[1].n, rules[1].words);

auto r1_3 = rule(n, rules[2].n, rules[2].words);

auto r1 = allof(r1_1, r1_2, r1_3);

auto r2 = rule(n, rules[0].n, rules[0].words);

auto rd = rule(n, 0, "");

return anyof(r2, r1, rd);

}

每個規則中rules[...]又出現了重復,繼續消除

//rule.h

#include

struct RuleMap

{

int n;

std::string words;

};

typedef bool (*Predicate)(int, int);

typedef std::string (*Action)(int, const std::string& );

template

std::string rule(int n, const RuleMap& map = {})

{

if(isMatch(n, map.n))

{

return do(n, map.words);

}

return std::string("");

}

...

//CountOffGame.cpp

...

std::string CountOffGame::countOff(int n) const

{

auto r1_1 = rule(n, rules[0]);

auto r1_2 = rule(n, rules[1]);

auto r1_3 = rule(n, rules[2]);

auto r1 = allof(r1_1, r1_2, r1_3);

auto r2 = rule(n, rules[0]);

auto rd = rule(n);

return anyof(r2, r1, rd);

}

yongshunli@163.com @ November 26, 2017 11:31 PM

總結

以上是生活随笔為你收集整理的报数游戏c语言,报数游戏-实战简单设计的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。