报数游戏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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值