一.问题




  随机生成4个代表扑克牌牌面的数字或字母,由用户输入包含这4个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24就代表用户赢了此局,否则失败。


二.思路




  利用随机发牌函数产生四个1-13的数字,根据所给四个数字,输入字符串并按回车,检查输入的表达式形式是否正确。如果错误,重新输入,否则调用ExpressTransform函数将中缀表达式expMiddle换为后缀表达式expBack并且输出转换后的后缀表达式,然后调用ExpressComputer函数计算后缀表达式的值。计算结果为24时,赢得此局,否则失败。




(1)中缀表达式换为后缀表达式

  从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级不高于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。​


(2)后缀表达式求值

  从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是运算符就将栈顶的两个数字出栈,进行运算,运算结果入栈,一直到最终获得结果。这时送入栈顶的值就是结果。


注意: 1.运算符的优先级处理

         2.运算过程中的运算符和运算数的操作处理


三.测试




24点游戏_i++




四.运行结果



24点游戏_i++_02



24点游戏_后缀表达式_03




五.源代码



// twentyfour.cpp : 定义控制台应用程序的入口点。
//作者:马露露
//平台:Visual Stdio 2015
//创建时间:2017年4月3日
//要求:随机生成4个代表扑克牌牌面的数字,由用户输入包含这4个数字的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。

#include "stdafx.h"

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <time.h>
#include <ctype.h> /*字符操作函数*/

#define BUFFSIZE 32
#define COL 128
#define ROW 64


/*定义栈1*/
typedef struct node
{
int data;
struct node *next;
}STACK1;

/*定义栈2*/
typedef struct node2
{
char data;
struct node2 *next;
}STACK2;

/*入栈函数*/
STACK1 *PushStack(STACK1 *top, int x)
{
STACK1 *p;
p = (STACK1 *)malloc(sizeof(STACK1));
if (p == NULL)
{
printf("ERROR\n!");
exit(0);
}
p->data = x;
p->next = top;
top = p;
return top;
}

/*出栈函数*/
STACK1 *PopStack(STACK1 *top)
{
STACK1 *q;
q = top;
top = top->next;
free(q);
return top;
}

/*读栈顶元素*/
int GetTop(STACK1 *top)
{
if (top == NULL)
{
printf("Stack is null\n");
return 0;
}
/*返回栈顶元素*/
return top->data;
}

/*取栈顶元素,并删除栈顶元素*/
STACK1 *GetDelTop(STACK1 *top, int *x)
{
*x = GetTop(top);
top = PopStack(top);
return top;
}

int EmptyStack(STACK1 *top) /*判栈是否为空*/
{
if (top == NULL)
return 1;
return 0;
}

/*入栈函数*/
STACK2 *PushStack2(STACK2 *top, char x)
{
STACK2 *p;
p = (STACK2 *)malloc(sizeof(STACK2));
if (p == NULL)
{
printf("error\n!");
exit(0);
}
p->data = x;
p->next = top;
top = p;
return top;
}

/*出栈*/
STACK2 *PopStack2(STACK2 *top)
{
STACK2 *q;
q = top;
top = top->next;
free(q);
return top;
}

/*读栈顶元素*/
char GetTop2(STACK2 *top)
{
if (top == NULL)
{
printf("Stack is null\n");
return 0;
}
return top->data;
}

/*取栈顶元素,并删除栈顶元素*/
STACK2 *GetDelTop2(STACK2 *top, char *x)
{
*x = GetTop2(top);
top = PopStack2(top);
return top;
}

/*判栈是否为空*/
int EmptyStack2(STACK2 *top)
{
if (top == NULL)
return 1;
else
return 0;
}

/*随机发牌函数*/
void GenCard()
{
int num, i;
srand((unsigned)time(NULL));
for (i = 0; i<4; i++)
{
num = rand() % 13 + 1; /*大小随机数*/
printf("%d ", num);
}
}

/*中缀字符串e转后缀字符串a函数*/
void ExpressTransform(char *expMiddle, char *expBack)
{
STACK2 *top = NULL; /* 定义栈顶指针*/
int i = 0, j = 0;
char ch;
while (expMiddle[i] != '\0')
{
/*判断字符是数字*/
if (isdigit(expMiddle[i]))
{
do {
expBack[j] = expMiddle[i];
i++; j++;
} while (expMiddle[i] != '.');
expBack[j] = '.';
j++;
}
/*处理“(”*/
if (expMiddle[i] == '(')
top = PushStack2(top, expMiddle[i]);
/*处理“)”*/
if (expMiddle[i] == ')')
{
top = GetDelTop2(top, &ch);
while (ch != '(')
{
expBack[j] = ch;
j++;
top = GetDelTop2(top, &ch);
}
}
/*处理加或减号*/
if (expMiddle[i] == '+' || expMiddle[i] == '-')
{
if (!EmptyStack2(top))
{
ch = GetTop2(top);
while (ch != '(')
{
expBack[j] = ch;
j++;
top = PopStack2(top);
if (EmptyStack2(top))
break;
else
ch = GetTop2(top);
}
}
top = PushStack2(top, expMiddle[i]);
}
/*处理乘或除号*/
if (expMiddle[i] == '*' || expMiddle[i] == '/')
{
if (!EmptyStack2(top))
{
ch = GetTop2(top);
while (ch == '*' || ch == '/')
{
expBack[j] = ch;
j++;
top = PopStack2(top);
if (EmptyStack2(top))
break;
else
ch = GetTop2(top);
}
}
top = PushStack2(top, expMiddle[i]);
}
i++;
}
while (!EmptyStack2(top))
top = GetDelTop2(top, &expBack[j++]);
expBack[j] = '\0';
}

/*后缀表达式求值函数*/
int ExpressComputer(char *s)
{
STACK1 *top = NULL;
int i, k, num1, num2, result;
i = 0;
while (s[i] != '\0') /*当字符串没有结束时作以下处理*/
{
if (isdigit(s[i])) /*判字符是否为数字*/
{
k = 0; /*k初值为0*/
do {
k = 10 * k + s[i] - '0'; /*将字符连接为十进制数字*/
i++; /*i加1*/
} while (s[i] != '.'); /*当字符不为‘.’时重复循环*/
top = PushStack(top, k); /*将生成的数字压入堆栈*/
}
if (s[i] == '+') /*如果为'+'号*/
{
top = GetDelTop(top, &num2); /*将栈顶元素取出存入num2中*/
top = GetDelTop(top, &num1); /*将栈顶元素取出存入num1中*/
result = num2 + num1; /*将num1和num2相加存入result中*/
top = PushStack(top, result); /*将result压入堆栈*/
}
if (s[i] == '-') /*如果为'-'号*/
{
top = GetDelTop(top, &num2); /*将栈顶元素取出存入num2中*/
top = GetDelTop(top, &num1); /*将栈顶元素取出存入num1中*/
result = num1 - num2; /*将num1减去num2结果存入result中*/
top = PushStack(top, result); /*将result压入堆栈*/
}
if (s[i] == '*') /*如果为'*'号*/
{
top = GetDelTop(top, &num2); /*将栈顶元素取出存入num2中*/
top = GetDelTop(top, &num1); /*将栈顶元素取出存入num1中*/
result = num1*num2; /*将num1与num2相乘结果存入result中*/
top = PushStack(top, result); /*将result压入堆栈*/
}
if (s[i] == '/') /*如果为'/'号*/
{
top = GetDelTop(top, &num2); /*将栈顶元素取出存入num2中*/
top = GetDelTop(top, &num1); /*将栈顶元素取出存入num1中*/
result = num1 / num2; /*将num1除num2结果存入result中*/
top = PushStack(top, result); /*将result压入堆栈*/
}
i++; /*i加1*/
}
top = GetDelTop(top, &result); /*最后栈顶元素的值为计算的结果*/
return result; /*返回结果*/
}

/*检查输入的表达式是否正确*/
int CheckExpression(char *e)
{
int i = 0;
while (e[i] != '\0')
{
if (isdigit(e[i]))
{
if (isdigit(e[i + 1]))
{
i++;
continue;
}
if (e[i + 1] != '.')
{
printf("\n所输入的表达式形式错误!!\n");
return 0;
}
i++;
}
i++;
}
return 1;
}

/*主函数*/
int main()
{
char expMiddle[BUFFSIZE], expBack[BUFFSIZE], ch;
int i, result;
int d = 0;
system("cls");
printf("*******************************************\n");
printf("* 欢迎来到经典益智游戏——24点游戏! *\n");
printf("* 输入表达式形式如下: *\n");
printf("* 10.*(5.-3.)+4. *\n");
printf("*******************************************\n");
system("pause");
while (1)
{
printf("\n随机生成的四个数字是: ");
GenCard();
printf("\n");
do {
printf("请输入正确的表达式:\n");
/*输入字符串压回车键*/
scanf("%s%c", expMiddle, &ch);
/*检查输入的表达式是否正确*/
} while (!CheckExpression(expMiddle));

printf("%s\n", expMiddle);
/*调用ExpressTransform函数将中缀表达式expMiddle转换为后缀表达式expBack*/
ExpressTransform(expMiddle, expBack);
/*计算后缀表达式的值*/
result = ExpressComputer(expBack);
printf("该表达式 %s 计算结果为:%d.\n", expMiddle, result);
if (result == 24)
{
printf("恭喜,您答对了!\n");
d = d + 1;
printf("积分为:%d\n", d);
}
else
{
printf("遗憾,您答错了!\n");
d = d - 1;
printf("积分为:%d\n", d);
}
printf("您还想在玩一次吗(y/n)?\n");
scanf("%c", &ch);
if (ch == 'n' || ch == 'N')
break;
}
return 0;
}