正文

我学c++Builder系列(6)2008-05-25 15:13:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/goal00001111/35438.html

分享到:

8,计算表达式结果
算法思路:此游戏的难点是如何将一个字符串形式的表达式解析成计算机能计算的算术表达式。我们的想法是按照数学四则运算法则,先去掉括号,然后按照先乘除后加减的顺序计算。
按照这种思路,我们必须解决如何寻找匹配的符号,如何寻找算术符号两边的数字,如何定位第一个算术符号的位置等问题。
    新建一个Unit文件“UnitComputer”,打开UnitComputer.h,加入如下代码:
//---------------------------------------------------------------------------

#ifndef UnitComputerH
#define UnitComputerH
#include <vcl.h>


//定位第一个算术符号的位置,如果没有算术符号,则返回0
int AnyFirstPos(String str);

//定位最后一个算术符号的位置,如果没有算术符号,则返回0
int AnyLastPos(String str);

//返回最先出现的算术符号
char AnyFirstF(String str);

//计算不带()号的四则运算,先乘除,后加减
int SubCompute(String str);

//计算带()号的四则运算表达式
int TotalCompute(String str);
//---------------------------------------------------------------------------
#endif
    然后切换到UnitComputer.cpp,实现上述自定义函数。
//---------------------------------------------------------------------------

#pragma hdrstop

#include "UnitComputer.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

//---------------------------------------------------------------------------
//定位第一个算术符号的位置,如果没有算术符号,则返回0
int AnyFirstPos(String str)
{
    const int IMPOSSIBLE = 2000;
    int pos = IMPOSSIBLE; //将pos设置成一个不可能值
    int subPos = str.Pos("-");
    int plusPos = str.Pos("+");
    int mulPos = str.Pos("*");
    int divPos = str.Pos("/");

    //返回第一个算术符号的位置
    if (subPos != 0 && pos > subPos)
        pos = subPos;
    if (plusPos != 0 && pos > plusPos)
        pos = plusPos;
    if (mulPos != 0 && pos > mulPos)
        pos = mulPos;
    if (divPos != 0 && pos > divPos)
        pos = divPos;

    if (pos == IMPOSSIBLE)  //如果没有算术符号,则返回0
        pos = 0;

    return pos;
}
//---------------------------------------------------------------------------
//定位最后一个算术符号的位置,如果没有算术符号,则返回0
int AnyLastPos(String str)
{
    int subPos = str.LastDelimiter("-");
    int plusPos = str.LastDelimiter("+");
    int mulPos = str.LastDelimiter("*");
    int divPos = str.LastDelimiter("/");
    int pos = subPos;

    if (pos < plusPos)
        pos = plusPos;
    if (pos < mulPos)
        pos = mulPos;
    if (pos < divPos)
        pos = divPos;

    return pos;
}
//---------------------------------------------------------------------------
//返回最先出现的算术符号
char AnyFirstF(String str)
{
    //定位第一个算术符号的位置
    int pos = AnyFirstPos(str);
    if (pos == 0)
        return '\0';

    return str[pos];
}
//---------------------------------------------------------------------------
//计算不带()号的四则运算,先乘除,后加减
int SubCompute(String str)
{
    const int IMPOSSIBLE = 2000;
    String midStr = ""; //中间结果
    String leftStr = "";   //左边子串
    String rightStr = "";  //右边子串
    String factor1 = "";   //参与运算的因数1
    String factor2 = "";   //参与运算的因数2

    //定位第一个"*"或"/"的位置
    int mulPos = str.Pos("*");
    int divPos = str.Pos("/");
    int first = 0;

    if (mulPos != 0 && divPos != 0)
    {
        first = (mulPos < divPos) ? mulPos : divPos;
    }
    else if (mulPos == 0 && divPos != 0)
    {
        first = divPos;
        mulPos = IMPOSSIBLE;  //用IMPOSSIBLE替代返回值0,表示没有出现该运算符
    }
    else if (mulPos != 0 && divPos == 0)
    {
        first = mulPos;
        divPos = IMPOSSIBLE;
    }

    while (first)    //循环进行乘除运算
    {
        //获取左子串
        String tempStr = str.SubString(1, first-1);
        int temp = AnyLastPos(tempStr);
        leftStr = str.SubString(1, temp);
        factor1 = str.SubString(temp+1, first-temp-1);
        //获取右子串
        tempStr = str.SubString(first+1, str.Length()-first);
        temp = AnyFirstPos(tempStr);
        if (temp == 0)//右子串中无运算符
        {
            factor2 = tempStr;
            rightStr = "";
        }
        else
        {
            factor2 = tempStr.SubString(1, temp-1);
            rightStr = tempStr.SubString(temp, tempStr.Length()-temp+1);
        }
        //进行乘除运算,得到中间结果
        if (mulPos > divPos)
            midStr = IntToStr(StrToInt(factor1) / StrToInt(factor2));
        else
            midStr = IntToStr(StrToInt(factor1) * StrToInt(factor2));
        //组合新的字符串表达式
        str = leftStr + midStr + rightStr;

        //查找乘除运算符,循环进行乘除运算
        //定位第一个"*"或"/"的位置
        mulPos = str.Pos("*");
        divPos = str.Pos("/");
        first = 0;

        if (mulPos != 0 && divPos != 0)
        {
            first = (mulPos < divPos) ? mulPos : divPos;
        }
        else if (mulPos == 0 && divPos != 0)
        {
            first = divPos;
            mulPos = IMPOSSIBLE;
        }
        else if (mulPos != 0 && divPos == 0)
        {
            first = mulPos;
            divPos = IMPOSSIBLE;
        }
    }

    //定位第一个"+"或"-"的位置
    char fuHao = AnyFirstF(str);
    first = AnyFirstPos(str);

    while (first)//循环进行加减运算
    {
        String tempStr = str.SubString(1, first-1);
        int temp = AnyLastPos(tempStr);
        leftStr = str.SubString(1, temp);
        factor1 = str.SubString(temp+1, first-temp-1);
        //获取右子串
        tempStr = str.SubString(first+1, str.Length()-first);
        temp = AnyFirstPos(tempStr);
        if (temp == 0)//右子串中无运算符
        {
            factor2 = tempStr;
            rightStr = "";
        }
        else
        {
            factor2 = tempStr.SubString(1, temp-1);
            rightStr = tempStr.SubString(temp, tempStr.Length()-temp+1);
        }
        //进行加减运算,得到中间结果
        if (fuHao == '+')
            midStr = IntToStr(StrToInt(factor1) + StrToInt(factor2));
        else
            midStr = IntToStr(StrToInt(factor1) - StrToInt(factor2));
        //组合新的字符串表达式
        str = leftStr + midStr + rightStr;

        //查找加减运算符,循环进行加减运算
        fuHao = AnyFirstF(str);
        first = AnyFirstPos(str);
    }

    return StrToInt(str);
}
//-----------------------------------------------------------------------------
//计算带()号的四则运算表达式
int TotalCompute(String str)
{
    int first = str.LastDelimiter("(");//定位最后一个"("的位置

    while (first)
    {
        String subStr = str.SubString(first+1, str.Length()-first);
        int last = subStr.Pos(")") + first;  //定位与最后一个"("对应的")"的位置
        String leftStrStr = str.SubString(1, first-1);//"("左边的子串
        String midStr = str.SubString(first+1, last-first-1);//"("与")"之间的子串
        String rightStrStr = str.SubString(last+1, str.Length()-last);//")"右边的子串

        midStr = IntToStr(SubCompute(midStr));//计算括号内的算术表达式

        str = leftStrStr + midStr + rightStrStr;
        first = str.LastDelimiter("(");//定位最后一个"("的位置
    }

    return SubCompute(str);//返回运算结果
}

9,判断输入的数据是否合法
功能:虽然我们前面已经屏蔽了用户输入的一些非法数据,但是我们仍然不能判断用户输入的数据是否有效,如第一个符号是否合法(只能以数字或"("开头),左右括号是否成对出现,运算表达式中的数字是否与牌面的数字吻合等。
代码:
bool TForm1::IsInputValide() //判断输入的数据是否合法
{
    String tempStr = Edit1->Text;

    //判断第一个符号是否合法(只能以数字或"("开头)
    if ((tempStr.c_str()[0]<'0' || tempStr.c_str()[0]>'9') && tempStr.c_str()[0]!='(')
    {
        ShowMessage("第一个符号不合法");
        return false;
    }

    //判断左右括号是否成对出现
    if (!RightBracket(tempStr))
        return false;

    //去掉括号
    int pos = tempStr.Pos("(");
    while (pos)
    {
        tempStr.Delete(pos, 1);
        pos = tempStr.Pos("(");
    }
    pos = tempStr.Pos(")");
    while (pos)
    {
        tempStr.Delete(pos, 1);
        pos = tempStr.Pos(")");
    }

    //获取输入的数字
    const int MAX = 4; //最多4张牌,结合图片的数量,可以更改MAX的值
    int inputData[MAX];
    int n = 0;

    pos = AnyFirstPos(tempStr);
    while (pos)
    {
        inputData[n++] = StrToInt(tempStr.SubString(1, pos-1));
        tempStr = tempStr.SubString(pos+1, tempStr.Length()-pos);
        pos = AnyFirstPos(tempStr);
    }
    inputData[n] = StrToInt(tempStr);
    if (n != MAX-1) //输入的数不是MAX个
    {
        String s = "输入的数不是";
        s += IntToStr(MAX);
        s += "个";
        ShowMessage(s);
        return false;
    }

    //利用循环判断当前字符是不是属于4张牌中的任何一个
    for (int i=0; i<MAX; i++)
    {
        bool flag = false;
        for (int j=0; j<MAX; j++)
        {
             if (inputData[i] == ColorData[j])
             {
                 flag = true;
                 break;
             }
        }
        if (flag == false) //不属于任何一张牌的数值
        {
            String s = "数据 ";
            s += IntToStr(inputData[i]);
            s += "不属于任何一张牌";
            ShowMessage(s);
            return false;
        }
    }

    //利用循环判断是否所有的牌都出现在运算表达式中
    for (int i=0; i<MAX; i++)
    {
        bool flag = false;
        for (int j=0; j<MAX; j++)
        {
             if (inputData[j] == ColorData[i])
             {
                 flag = true;
                 break;
             }
        }
        if (flag == false) //此张牌没有出现在运算表达式中
        {
            String s = "牌 ";
            s += IntToStr(ColorData[i]);
            s += "没有出现在运算表达式中";
            ShowMessage(s);
            return false;
        }
    }
    return true;
}
//---------------------------------------------------------------------------

bool TForm1::RightBracket(const String & str)//判断左右括号排列是否正确
{
    String tempStr = str;
    const int MAXSIZE = 100;
    char stack[MAXSIZE];
    int top = 0;
    int pos1 = tempStr.Pos("(");
    int pos2 = tempStr.Pos(")");

    while (pos2)
    {
        if (pos1 > 0 && pos1 < pos2)
        {
            stack[top++] = '(';
            tempStr = tempStr.SubString(pos1+1, tempStr.Length()-pos1);
        }
        else if (top > 0 && stack[top-1] == '(')
        {
            top--;
            tempStr = tempStr.SubString(pos2+1, tempStr.Length()-pos2);
        }
        else
        {
            ShowMessage("左右括号排列不正确");
            return false;
        }

        pos1 = tempStr.Pos("(");
        pos2 = tempStr.Pos(")");
    }
    if (top > 0 || tempStr.Pos("(") > 0)//有多余的"("或")"
    {
        ShowMessage("有多余的括号");
        return false;
    }

    return true;
}

阅读(3331) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册