/*
编写人@wonder
版本:v0.1
因为对这个游戏感兴趣,想到用编程求解法,
固编写了本程序。
本程序用来求游戏《计算器-游戏》的解法。
输入:
开始数字start,最大步数step,目标数字target,
为三个数字,
(如123 3 321)
与可用的计算按钮
为若干字符串,用空格隔开,输入e结束。
(如r13 *-15 r < e)。
输出:
所有可行的按键顺序,可能有多个输出。
目前集成的运算有:
+n
-n
*n
/n
<_______<<去掉最后一位
n_______在最后加上数字n
n=》m___将所有数字n换为数字m
^n______幂运算
!_______+/-
r_______reverse
s_______sum
{_______<shift
}_______>shift
m_______mirror
共14种运算
可以求出131关以内的解
基本算法:
1.输入数据
2.用递归找出所有可能的操作,生成一操作顺序码
3.对每个操作码计算,如果可行就输出
以后应优化一下算法,每次递归进行一次运算
继续增加运算,求出所有关卡。
*/
#include<stdio.h>
#include<stdlib.h>
#define R 10
int start,step,target;
int OPNumber=0;
char operate[6][R];
int debug = 0;//将值设为1开启debug模式
void inputDate()
{
char OPstring[R];
int i,j;
printf("input start,step,target=");
scanf("%d%d%d",&start,&step,&target);
printf("input operate:\n");
for(i=0;i<6;i++){
scanf("%s",&OPstring);
if(OPstring[0] == 'e')break;
for(j=0;j<R;j++){
operate[i][j] = OPstring[j];
}
OPNumber++;
}
system("cls");//输入结束,清屏
printf("start=%d,step=%d,target=%d\n",start,step,target);
printf("all operate are:\n");
for(i=0;i<OPNumber;i++){
printf(operate[i]);
printf("\n");
}
printf("\n");
printf("\n");
}//输入数据
void outDate(int n){
int i=1;
printf("result:\n");
while(n!=0){
printf("step %d : %s\n",i,operate[n%10-1]);
n /= 10;
i++;
}
printf("\n");
printf("\n");
}//对符合要求的结果输出
//比较复杂的运算放在单独的方法里
void OPadd(int *result,int number){
int lv=10;
for(number;number>lv-1;lv*=10);
if(*result<0)number = -number;
*result = *result * lv + number;
}
void OPchange(int *result,int n){
int number1=0,number2=0;
int number0 = *result;
int i;
int lv0=1,lv1=1,lv2=1;
*result = 0;
for(i=1;'0'<=operate[n%10-1][i]&&operate[n%10-1][i]<='9';i++){
number1 = number1*10+operate[n%10-1][i]-'0';
lv1 *= 10;
}
i++;
for(i;'0'<=operate[n%10-1][i]&&operate[n%10-1][i]<='9';i++){
number2 = number2*10+operate[n%10-1][i]-'0';
lv2 *= 10;
}
for(number0;number0!=0;){
if(number0%lv1==number1){
number0 /= lv1;
*result = *result + number2*lv0;
lv0 *= lv2;
}
else{
*result = *result + number0%10*lv0;
lv0 *= 10;
number0 /= 10;
}
}
//printf("number1=%d,number2=%d,lv1=%d,lv2=%d\n",number1,number2,lv1,lv2);
//printf("result=%d\n",result);
//printf("number1=%s,number2=%s",number1,number2);
}//目前最复杂的运算,替换数字
void OPreverse(int *result){
int some;
some = *result;
*result = 0;
for(some;some!=0;some /=10)
*result = *result * 10 + some%10;
}//反转数字
void OPsum(int *result){
int sum=0;
for(*result;*result!=0;*result/=10)
sum += *result % 10;
*result = sum;
}//对所有数字求和
void OPpow(int *result,int number){
int end=1;
int i;
for(i=0;i<number;i++)
end *= *result;
*result = end;
}//幂运算
void OPshift(int *result,int p){//p为标识位,0表示{,1表示}
int lv=10;
int end;
for(*result;*result>lv-1;lv*=10);
lv /= 10;
if(p)
end = *result / 10 + *result % 10 * lv;//}
else
end = *result % lv * 10 + *result / lv;//{
*result = end;
}//将数字左移或右移
void OPmirror(int *result){
int lv=1,x;
for(lv;lv<*result+1;lv*=100){
x = *result % (lv*10) / lv;
*result = *result * 10 + x;
}
}//镜像复制,将各数字反过来接在原数后面
void calculate(int code){
char OP;
int number;
int n = code;
int result = start;
int i;
while(n!=0){
OP = operate[n%10-1][0];
number = 0;
i=1;
if(operate[n%10-1][1]=='-')i++;//解析出正负
for(i;'0'<=operate[n%10-1][i]&&operate[n%10-1][i]<='9';i++){
number = number*10+operate[n%10-1][i]-'0';
}//解析出操作中数字
if(operate[n%10-1][1]=='-')
number = -number;//解析出正负
if(OP == '+')//分支判断出改进行什么操作
result += number;
else if(OP == '-')
result -= number;
else if(OP == '*')
result *= number;
else if(OP == '/'){
if(result % number == 0)
result /= number;
else
break;
}//当除法结果为小数时,判为失败
else if(OP == '<')
result /= 10;
else if(OP == 'a')
OPadd(&result,number);
else if(OP == '>')
OPchange(&result,n);
else if(OP == '^')
OPpow(&result,number);
else if(OP == '!')
result = -result;
else if(OP == 'r')
OPreverse(&result);
else if(OP == 's')
OPsum(&result);
else if(OP == '{')
OPshift(&result,0);
else if(OP == '}')
OPshift(&result,1);
else if(OP == 'm')
OPmirror(&result);
n /= 10;
if(debug)printf("result=%d\n",result);//测试用
if(result >9999999)break;//当结果超限时判为异常
if(result == target)
outDate(code); //结果正确输出
}
}//根据操作码计算,关键函数
void allCode(int n,int s)
{
if(n==0){
if(debug)printf("\ncode=%d\n",s);//测试用,显示操作码
calculate(s);
}
else
for(int i=1;i<=OPNumber;i++)
allCode(n-1,s*10+i);
}//利用递归,找出所有可能的操作顺序,算出操作码,交给calculate函数计算
//注意操作是从最后一位向前操作
void renew(){
OPNumber = 0;
}
int main()
{
while(true){
renew();
inputDate();
allCode(step,0);
}
return 0;
}//主函数