前言
培训遗留作业,计划放在国庆空闲时间做,所以这算是走计划节奏。另外,真的是不喜欢做这些题,虽然实现以后发现很简单。但是没实现之前,多少还是觉得有些困难,可能是自己做题太少(不知道别人做题时候啥感觉)。。另外,做这些题我是感觉完全搭不上算法的边,可能是我自己没专门学过的原因吧,基本上纯粹是按照题的说明需求,然后自己思考,整理思路,然后实现...过程就是这样。
保龄球计分
(题目摘自网络,反正都一个规则)
打保龄球是用一个滚球去撞击10个站立的瓶,将瓶击倒。一局分10轮,每轮可滚球1 次或多次,以击到的瓶数为依据计分,一局得分为10轮得分之和,而每轮的得分不仅与本轮的滚球情况有关,还可能与后一轮或两轮的滚球情况有关,即:某轮某次滚球击倒的瓶数不仅要计入本轮得分,还可能会计入前一轮或两轮得分。
计分规则具体如下:
① 若某一轮的第一次滚球就击倒全部10个瓶,则本轮不再滚球(若是第10轮还需加2次滚球),该轮得分为本次击倒瓶数10与以后2次滚球所击倒瓶数之和。
② 若某一轮的第一次滚球未击倒全部10个球,则对剩下未击倒的瓶再滚球一次,如果这2次滚球击倒全部10个瓶,则本轮不再滚球(若是第10轮还需加1次滚球),该轮得分为这2次击倒瓶数10与以后1次滚球所击倒瓶数之和。
③ 若某一轮2次滚球未击倒全部10个瓶,则本轮不在滚球,该轮得分为这2次滚球所击倒瓶数之和。
编写一个程序,统计各轮得分和累积总分。
Input:
输入数据是文本格式,共1行(字符串),有最多22个[0,10]之间的整数,表示每轮滚球第一次或第二次记到的秋熟,输入数据保证合法,两个整数间仅有一个空格。
Output:
自定义。对外接口为 Calcscore(const char *s);
实现思路
计算每轮单独得分,十轮累加得总分。每轮单独得分,按规则可以大致总结出,如果议论中首次全中或者两次补中,则相当于第一次滚球后连续加后面两次;否则,只加后面一次。直接看代码吧,按照TDD方式,先写测例,再快速实现,最后的抽象实在不知道怎么抽象,估计是仅仅实现了功能,代码质量还相当欠缺,后续看下别人实现,再来做修改。
<span style="font-size:18px;">/* test.cpp */ #include <assert.h> extern int Calcscore(const char *s); void main() { assert(Calcscore("10 10 10 10 10 10 10 10 10 10 10 10") == 300); assert(Calcscore("10 10 10 7 2 9 1 8 1 8 2 10 9 1 10 8 2") == 192); assert(Calcscore("1 4 4 5 6 4 5 5 10 0 1 7 3 6 4 10 2 8 6") == 133); }</span>
<span style="font-size:18px;">/* bowling.cpp */ #include <stdio.h> #include <stdlib.h> typedef struct _context { const char *s; int pos; }Context; int Record[10]; bool Is_STRIKE(int score) { return score == 10; } int Parsescore(Context &ctx,int offset) { int temp_score = 0; if (ctx.s[ctx.pos] == ' ') { ctx.pos++; } return atoi(ctx.s + ctx.pos + offset); } int CalcscorePerRound(Context &ctx) { int offset = 0; int curr_score = 0; int next_score = 0; int round_score = 0; curr_score = Parsescore(ctx,0); // 0表示解析分数的起始偏移 if (Is_STRIKE(curr_score)) { offset = 2; next_score = Parsescore(ctx,offset); ctx.pos += 2; // 本轮STRIKE,下一轮击球开始解析的位置 } else { offset = 0; ctx.pos++; next_score = Parsescore(ctx,offset); ctx.pos++; // 本轮SPARE,下一轮击球开始解析的位置 } // 本轮计分 if (10 > (curr_score + next_score)) // 本轮两次击球未全中 { round_score = curr_score + next_score; } else // 本轮STRIKE或两次补中 { int third_score = Parsescore(ctx,offset); round_score = curr_score + next_score + third_score; } return round_score; } int Calcscore(const char *s) { Context ctx = {s,0}; int total_score = 0; printf("每轮得分:\n"); for (int i = 0; i < 10; i++) { Record[i] = CalcscorePerRound(ctx); printf("%-2d ",Record[i]); total_score += Record[i]; } printf("\n累计总分:%d",total_score); printf("\n+++++++++++++++++++++++++++++++++\n"); return total_score; }</span>
总结
领域规则抽象,思考了N久,真心就是(臣妾做不到啊...)。如果仅仅就为实现功能而写的代码,再进行重构抽象,现在感觉好难。只能是多看高质量代码,多积累,多练习了!