现在的位置: 首页 > 综合 > 正文

24点游戏7节课–第3节-格式化结果表达式

2013年08月19日 ⁄ 综合 ⁄ 共 3215字 ⁄ 字号 评论关闭

 这是前两节课:

 
 
-----------------------------------------------------------
 
 格式化?是printf吗?
 
不是啦,上一节已经能够计算出给定的4个数,如何计算出24点,只是在答案输出上,有点不爽,比如:5,10,2 ,6四个数,上节课我们输出的答案是:5+10*2-6。 仔细 一算,这答案5+20-6,就是19嘛。这一节课的任务很简单,就是让它能够正确地输出为:(5+10)*2-6.
 
问题关键显然是在加括号上,怎么实现?从运算符号下手,上例中,第一个运算符是+号,第二个则是*,后面的运算符优先级大于前面的,而按照上一节提到“连贯式”的意义,我们要的是前面的运算先处理,所以必须给前面的计算加括号。
 
 
新加exp_getter.h 和 exp_getter.cpp 到项目中。
 
exp_getter.h 
Code:
  1. #ifndef EXP_GETTER_H_INCLUDED    
  2. #define EXP_GETTER_H_INCLUDED    
  3.     
  4. #include <string>    
  5.     
  6. #include "common_def.h"    
  7.     
  8. //组装连续运算形式的表达式:    
  9. std::string get_consecutive_exp(int opds[4], operator_index oprs[3]);    
  10.     
  11. //组装分割运算形式的表达式:    
  12. std::string get_separate_exp(int opds[4], operator_index oprs[3]);    
  13.     
  14. #endif // EXP_GETTER_H_INCLUDED    
 
 
代码文件没有什么好废话的。头文件中就是声明了两个函数,一个函数用来为“连贯式”计算的结果格式化,一个为“分割式”计算的结果格式化——等等,我们还没有讲为“分割式”结果格式化的思路呢?这个太简单了,留给大家先自行看代码再说吧。
 
 
exp_getter.cpp,片段一
Code:
  1. #include <sstream> //for stringstream    
  2.     
  3. #include "exp_getter.h"    
  4.     
  5. using namespace std;    
  6.     
  7. void add_parenthesis(stringstream& ss)    
  8. {    
  9.     ss.str("(" + ss.str() + ")");    
  10.     ss.seekp(0, ios_base::end);        
  11. }  
 
这是给一个字符串加上一对括号的。为了其它一些地方的操作方便,我用的是 stringstream流。如果你不熟悉,那是时候熟悉这家伙了,它是C++ 标准库中一个最常用的家伙。
 
一定要注意哦,这个流将被我们“又读又写”,此时就是“写”,为了保证后续还有的写操作写入位置正确,我们在改变它的内容(这是写入操作)之后,将写的位置,强置到流最后面。
 
 
 
exp_getter.cpp,片段二
继续前面的代码,这是实现格式“连贯式”计算的函数。
 
Code:
  1. string get_consecutive_exp(int n[4], operator_index o[3])    
  2. {    
  3.     stringstream ss;    
  4.         
  5.     //12*2-12*2 ==> (12 * 2 - 12) * 2    
  6.     //2+1*4*2 ==> (2+1)*4*2    
  7.     //2*2+8*2 ==> (2*2+8)*2    
  8.         
  9.     ss << n[0] << operator_char_def[o[0]] << n[1];     
  10.         
  11.     if(o[0] < 2 && o[1] >= 2)     
  12.         add_parenthesis(ss);    
  13.     
  14.     ss << operator_char_def[o[1]] << n[2];    
  15.         
  16.     if (o[1] < 2 && o[2] >= 2)    
  17.         add_parenthesis(ss);    
  18.         
  19.     ss << operator_char_def[o[2]] << n[3];    
  20.         
  21.     return ss.str();    
  22. }    
 
 
n[4]是4张牌的牌面值(再自我检讨一下,入参中的4,不过是用来好看的,根本不起作用,而函数中的代码也没有检查任何数组戴的问题)。 operator_index[3] 则是结果表达式中的那三个操作符(再再自我检讨一下,入参中的3……)。
 
由于我们是用 0,1,2,3,分别表示“+”,"-","*","/"。所以下面的这个if语句:
 
 if (o[1] < 2 && o[2] >= 2)  
 
它在判断什么呢? 其实就是:如果 第1个运算符是加或减,并且第二个运算符是乘或除,则需要进行加括号处理,比如答案是:
 
1 + 3  * 5 +  4  ,则——
 
上述代码第14行,通过流操作,得到:1+3。
 
然后第17行,得到 (1+3)
 
再往后的判断逻辑一样。本例中由于*比+优先级高,所以后面判断结果不需要再添加括号,最终结果就是(1+3)*5+4。
 
会不会忘记 operator_char_def 数组是什么东西?直接说下,免得非要查前面的课程: operator_index 存的是0,1,2,3,用来表示加减乘除,而operator_char_def 才是真正存着 “+,-,*,/”四个字符。
 
 
exp_getter.cpp,片段三
继续前面代码,这是实现“分割式”计算结果的格式化函数:
 
Code:
  1. string get_separate_exp(int n[4], operator_index o[3])    
  2. {    
  3.     stringstream ss;    
  4.             
  5.     //3*4+4*3 ==> (3*4) + (4*3)    
  6.         
  7.     ss << '(' << n[0] << operator_char_def[o[0]] << n[1] << ')'    
  8.         << operator_char_def[o[1]]     
  9.         << '(' << n[2] << operator_char_def[o[2]] << n[3] << ')';    
  10.             
  11.     return ss.str();    
  12. }    
 
 
它简单多了,因为我们是强制加括号,正如代码那行注释,理论是不需要括号的,但我们为了简化处理,就强制添加了。
 
 
有了以上两个函数,回到 calc_24.cpp文件,开始处增加一行:
 
#include "exp_getter.h"
 
然后在 bool calc_24(int num[4])  函数,找到合适的位置,替换原来输出的那两个处代码,编译通过就完成了。现在,我们的输出漂亮极了。下面是实例:
 
 
输入: 12  9  9 3, 输出:(12-9)*9-3。
 
输入:4 5 6 7 ,输出: (5+7-6)*4。
 
-------------------------------------------------------------------------------
 
如果您想与我交流,请点击如下链接成为我的好友:
 
 

抱歉!评论已关闭.