考拉 发表于 2004-4-27 17:53:00

有没有人想过怎么用计算机来实现24点

就是扑克里的24点游戏,4个数,+-*/得24……

偶还在想……

游侠无极限 发表于 2004-4-29 17:01:00

电脑爱好者上曾经有这个编程的例子

yzhlinux 发表于 2004-5-1 09:53:00

穷举法吧

考拉 发表于 2004-5-1 21:43:00

以下是引用yzhlinux在2004-5-1 9:53:31的发言:
穷举法吧

那你的代码要写P4,4=4*4*4*4=256行代码??

游侠无极限 发表于 2004-5-2 08:14:00

256行代码,什么意思,就算是这样,256行算多吗??

yzhlinux 发表于 2004-5-2 09:31:00

当然不是的,穷举是用程序去穷举,而不是在程序里先举好,并且不是p4,元素显然不止4个,至少是七个如:A+B+C+D 就又7个字符了,而穷举就是吧A,B,C,D,+,_,*,\,(,) 这个十个元素来排列组合,组合成一个四则运算表达试,然后传递给一个计算函数得出结果,如果是24 则表达试就是我们要求的了。比如:
function GetMach(A,B,C,D) as String       '得到一个字符串组合如:(A+B*D)-C
function GetValue(MachString) as Float    '得到字符串的计算值 ,可能是小数
那么程序就好写了:
GetNumber(&A,&B,&C,&D) ;    '得到ABCD则四个数字,赋给A,B,C,D四个变量
do{
MachString = GetMach(A,B,C,D); '得到一个表达试的字符传
if(GetValue(MachString)==24) break;
}
print XXXXXX;

游侠无极限 发表于 2004-5-2 11:57:00

我现在试着在写,就是不知道有什么好办法解决重复的算式问题,比如
(5-2)*8*1

(5-2)*1*8
8*(5-2)*1
等等

yzhlinux 发表于 2004-5-2 13:17:00



花了一个上午,终于完成了
你参考参考吧,哈哈


[此贴子已经被作者于2004-5-2 13:43:13编辑过]

yzhlinux 发表于 2004-5-2 13:42:00

上面的发现有一点bug,
这个改过了
一个计算 24 点的小游戏
VB 编写


[此贴子已经被作者于2004-5-2 15:17:46编辑过]

游侠无极限 发表于 2004-5-2 14:41:00

#include <stdio.h>
#include <stdlib.h>

int EnumFormula(int min,int max,int num,int sum);
void ShowFormula(int *Num,int *Sym,int count,int sum);
double GetFormulaVal(int *Num,int *Sym,int count);
int EnumArray(int *Num,int min,int max,int count);
void InitArray(int *Num,int min,int max,int count);
const char cSym = {0,'+','-','*','/'};

int main(int argc, char *argv[])
{
printf("总计%d个式子\n",EnumFormula(1,10,4,24));
system("PAUSE");   
return 0;
}

int EnumFormula(int min,int max,int num,int sum)
{
    int *FormulaNum = (int*)calloc(num,sizeof(int));    //储存操作数
    //储存操作符号
    //最后一位用于穷举结束标记
    // 1 - 4 代表 '+' '-' '*' '/'
    int *FormulaSym = (int*)calloc(num,sizeof(int));
                                                      
    int result = 0;
    // 初始化操作数和操作符号数组
   
    int i;

    for(i=0;i<num;i++) FormulaNum = min;
    for(i=0;i<num;i++) FormulaSym = 1;
    FormulaNum--;

    InitArray(FormulaNum,min,max,num);
    FormulaNum++;
    // 穷举操作数和操作符号组合
    while(FormulaSym == 1)
    {
      double t = GetFormulaVal(FormulaNum,FormulaSym,num) - sum;
          if(t>-0.01 && t<0.01)
      {
            //printf("%d %d %d %d | %d %d %d",FormulaNum,FormulaNum,
            //FormulaNum,FormulaNum,
            //                              FormulaSym,FormulaSym,
            //                              FormulaSym,FormulaSym);
               ShowFormula(FormulaNum,FormulaSym,num,sum);
            result++;
      }
      
      // 依次穷举操作数
      
      //允许数字重复的穷举
          //FormulaNum++;
      //for(i=0;FormulaNum > max && i<num-1;i++)
      //{
      //    FormulaNum = min;
      //    FormulaNum++;
      //}
      // 操作数穷举与操作符号穷举联接
      //if(FormulaNum > max)
      //{
      //    FormulaNum = min;
      //    FormulaSym++;
      //}

      // 不允许数字重复的穷举
      // 数字必须从小到大的排列,防止重复
      if((max - min)< num) exit(0);    // 出错

      if(EnumArray(FormulaNum,min,max,num))
      {
            FormulaSym++;
            InitArray(FormulaNum,min,max,num);
            FormulaNum++;
      }
      
      // 操作符号穷举
      for(i=0;FormulaSym > 4 && i<num-1;i++)
      {
            FormulaSym = 1;
            FormulaSym++;
      }

    }
    //释放空间
    free(FormulaNum);
    free(FormulaSym);
    return result;
}
// 计算算式结果
double GetFormulaVal(int *Num,int *Sym,int count)
{
    int i,j;
    double preresult;
    preresult = Num;
    i=1;j=0;
    while(i<count)
    {
      switch(Sym)
      {
            case 1:
                preresult += Num;
                break;
            case 2:
                preresult -= Num;
                break;
            case 3:
                preresult *= Num;
                break;
            case 4:
                   if(Num == 0) return -1000;
                preresult /= Num;
                break;
      }
      i++;j++;
    }
    return preresult; //进行修正
}
// 打印算式
void ShowFormula(int *Num,int *Sym,int count,int sum)
{

   int i,j,len;
    char *Formula = (char*)calloc(count*4,sizeof(char));
    char temp;
    itoa(Num,Formula,10);
    i=1;j=0;
    while(i<count)
    {
      itoa(Num,temp,10);
      len = strlen(Formula);
          switch(Sym)
      {
            case 1:
            case 2:
                Formula = cSym];
                strcat(Formula,temp);
                break;
            case 3:
            case 4:
               
                // 如果上一个操作符号优先级低于当前的,应加上括号
                if(j==0 || Sym > 2)
                {
                  Formula = cSym];
                  strcat(Formula,temp);
                }
                else
                {
                  int n;
                  char *FormulaTemp = (char*)calloc(len+1,sizeof(char));
                  for(n=0;n<len+1;n++)
                     {
                         FormulaTemp = Formula;
                         Formula = 0;
                  }
                  Formula = '(';
                  strcat(Formula,FormulaTemp);
                  free(FormulaTemp);
                  Formula =')';
                  Formula = cSym];
                  strcat(Formula,temp);
                }
                break;
      }
      i++;j++;
    }
    printf("%s",Formula);
    printf("=%d\n",sum);
    free(Formula);
}

// 以当前数组为基础得到一个从小到大排列的数组
// 返回非0表示穷举结束
int EnumArray(int *Num,int min,int max,int count)
{
    int i,top;
    top = count-1;
   Num++;
    while(Num>max-count+top+1 && top>=0)
    {
      top--;
      Num++;
    }
    for(i=top+1;i<count;i++)
    {
      Num = Num+1;
    }
    if(Num > max) return 1;
    else return 0;
}

// 不允许重复的初始化数组
void InitArray(int *Num,int min,int max,int count)
{
    int i;
    for(i=0;i<count;i++) Num=min+i;
    Num--;
}




[此贴子已经被作者于2004-5-2 14:50:47编辑过]

游侠无极限 发表于 2004-5-2 14:54:00

本法穷举出所有用min - max之间的num个数组成算式,结果为sum的情况

如要具体的话,可以不穷举操作数,直接输入操作数,进行操作符号穷举

yzhlinux 发表于 2004-5-2 15:17:00

以下是引用游侠无极限在2004-5-2 14:41:26的发言:
#include <stdio.h>
#include <stdlib.h>

int EnumFormula(int min,int max,int num,int sum);
void ShowFormula(int *Num,int *Sym,int count,int sum);
double GetFormulaVal(int *Num,int *Sym,int count);
int EnumArray(int *Num,int min,int max,int count);
void InitArray(int *Num,int min,int max,int count);
const char cSym = {0,&#39;+&#39;,&#39;-&#39;,&#39;*&#39;,&#39;/&#39;};

int main(int argc, char *argv[])
{
   printf(&quot;总计%d个式子\n&quot;,EnumFormula(1,10,4,24));
   system(&quot;PAUSE&quot;);   
   return 0;
}

int EnumFormula(int min,int max,int num,int sum)
{
   int *FormulaNum = (int*)calloc(num,sizeof(int));    //储存操作数
   //储存操作符号
   //最后一位用于穷举结束标记
   // 1 - 4 代表 &#39;+&#39; &#39;-&#39; &#39;*&#39; &#39;/&#39;
   int *FormulaSym = (int*)calloc(num,sizeof(int));
                                                         
   int result = 0;
   // 初始化操作数和操作符号数组
      
   int i;

   for(i=0;i<num;i++) FormulaNum = min;
   for(i=0;i<num;i++) FormulaSym = 1;
   FormulaNum--;

   InitArray(FormulaNum,min,max,num);
   FormulaNum++;
   // 穷举操作数和操作符号组合
   while(FormulaSym == 1)
   {
         double t = GetFormulaVal(FormulaNum,FormulaSym,num) - sum;
         if(t>-0.01 && t<0.01)
         {
             //printf(&quot;%d %d %d %d | %d %d %d&quot;,FormulaNum,FormulaNum,
             //FormulaNum,FormulaNum,
             //                              FormulaSym,FormulaSym,
             //                              FormulaSym,FormulaSym);
                ShowFormula(FormulaNum,FormulaSym,num,sum);
             result++;
         }
         
         // 依次穷举操作数
         
         //允许数字重复的穷举
         //FormulaNum++;
         //for(i=0;FormulaNum > max && i<num-1;i++)
         //{
         //    FormulaNum = min;
         //    FormulaNum++;
         //}
         // 操作数穷举与操作符号穷举联接
         //if(FormulaNum > max)
         //{
         //    FormulaNum = min;
         //    FormulaSym++;
         //}

         // 不允许数字重复的穷举
         // 数字必须从小到大的排列,防止重复
         if((max - min)< num) exit(0);    // 出错

         if(EnumArray(FormulaNum,min,max,num))
         {
               FormulaSym++;
               InitArray(FormulaNum,min,max,num);
               FormulaNum++;
         }
         
         // 操作符号穷举
         for(i=0;FormulaSym > 4 && i<num-1;i++)
         {
             FormulaSym = 1;
             FormulaSym++;
         }

   }
   //释放空间
   free(FormulaNum);
   free(FormulaSym);
   return result;
}
// 计算算式结果
double GetFormulaVal(int *Num,int *Sym,int count)
{
   int i,j;
   double preresult;
   preresult = Num;
   i=1;j=0;
   while(i<count)
   {
         switch(Sym)
         {
             case 1:
               preresult += Num;
               break;
             case 2:
               preresult -= Num;
               break;
             case 3:
               preresult *= Num;
               break;
             case 4:
                  if(Num == 0) return -1000;
               preresult /= Num;
               break;
         }
         i++;j++;
   }
   return preresult; //进行修正
}
// 打印算式
void ShowFormula(int *Num,int *Sym,int count,int sum)
{

      int i,j,len;
   char *Formula = (char*)calloc(count*4,sizeof(char));
   char temp;
   itoa(Num,Formula,10);
   i=1;j=0;
   while(i<count)
   {
         itoa(Num,temp,10);
         len = strlen(Formula);
         switch(Sym)
         {
             case 1:
             case 2:
               Formula = cSym];
               strcat(Formula,temp);
               break;
             case 3:
             case 4:
               
               // 如果上一个操作符号优先级低于当前的,应加上括号
               if(j==0 || Sym > 2)
               {
                     Formula = cSym];
                     strcat(Formula,temp);
               }
               else
               {
                     int n;
                     char *FormulaTemp = (char*)calloc(len+1,sizeof(char));
                     for(n=0;n<len+1;n++)
                      {
                        FormulaTemp = Formula;
                        Formula = 0;
                     }
                     Formula = &#39;(&#39;;
                     strcat(Formula,FormulaTemp);
                     free(FormulaTemp);
                     Formula =&#39;)&#39;;
                     Formula = cSym];
                     strcat(Formula,temp);
               }
               break;
         }
         i++;j++;
   }
   printf(&quot;%s&quot;,Formula);
   printf(&quot;=%d\n&quot;,sum);
   free(Formula);
}

// 以当前数组为基础得到一个从小到大排列的数组
// 返回非0表示穷举结束
int EnumArray(int *Num,int min,int max,int count)
{
   int i,top;
   top = count-1;
      Num++;
   while(Num>max-count+top+1 && top>=0)
   {
         top--;
         Num++;
   }
   for(i=top+1;i<count;i++)
   {
         Num = Num+1;
   }
   if(Num > max) return 1;
   else return 0;
}

// 不允许重复的初始化数组
void InitArray(int *Num,int min,int max,int count)
{
   int i;
   for(i=0;i<count;i++) Num=min+i;
   Num--;
}




[此贴子已经被作者于2004-5-2 14:50:47编辑过]


printf("总计%d个式子\n",EnumFormula(1,10,4,24)); 的运行结果是:
1+4+9+10=24
1+5+8+10=24
1+6+7+10=24
1+6+8+9=24
2+3+9+10=24
2+4+8+10=24
2+5+7+10=24
2+5+8+9=24
2+6+7+9=24
3+4+7+10=24
3+4+8+9=24
3+5+6+10=24
3+5+7+9=24
3+6+7+8=24
4+5+6+9=24
4+5+7+8=24
这是什么意思?似乎是找出了 1 至 10 之间的和是24 的数据,这和完成计算24点,差很多吧?
比如用户输入 2 ,5,7,8 程序应该能得到计算这四个数据得到24的表达式才行啊,这样就可以写一个游戏了。
如: 1,5,7,8 有如下方法可以算出 24
((1+7)-5)*8 = 24
((7+1)-5)*8 = 24
(1+7)*(8-5) = 24
(7+1)*(8-5) = 24
((1-5)+7)*8 = 24
((7-5)+1)*8 = 24
(8-5)*(1+7) = 24
(8-5)*(7+1) = 24
8*(1+7-5) = 24
8*((1+7)-5) = 24
8*(1+(7-5)) = 24
8*(7+1-5) = 24
8*((7+1)-5) = 24
8*(7+(1-5)) = 24
8*(1-5+7) = 24
8*((1-5)+7) = 24
8*(7-5+1) = 24
8*((7-5)+1) = 24

游侠无极限 发表于 2004-5-2 15:21:00

结果是这样的:
1+4+9+10=24
1+5+8+10=24
1+6+7+10=24
1+6+8+9=24
2+3+9+10=24
2+4+8+10=24
2+5+7+10=24
2+5+8+9=24
2+6+7+9=24
3+4+7+10=24
3+4+8+9=24
3+5+6+10=24
3+5+7+9=24
3+6+7+8=24
4+5+6+9=24
4+5+7+8=24
1*5+9+10=24
1*6+8+10=24
1*7+8+9=24
2*3+8+10=24
2*4+6+10=24
2*4+7+9=24
2*5+6+8=24
3*4+5+7=24
4*5-6+10=24
(1+2)*5+9=24
(1+3)*4+8=24
1*2*7+10=24
1*3*5+9=24
6*7-8-10=24
(2+4)*5-6=24
2*3*5-6=24
(1+2+3)*4=24
(1-2+4)*8=24
(1-2+5)*6=24
(1-3+5)*8=24
(1-4+6)*8=24
(1-5+7)*8=24
(2-3+4)*8=24
(2-3+5)*6=24
(2-4+5)*8=24
(2-5+6)*8=24
(2-6+7)*8=24
(3-4+5)*6=24
(4+5-6)*8=24
(4+6-7)*8=24
(2*4-5)*8=24
(2*5-7)*8=24
1*2*3*4=24
1/2*6*8=24
1/3*8*9=24
2/3*4*9=24
2/4*6*8=24
2/5*6*10=24
2/6*8*9=24
3*4/5*10=24
5*6*8/10=24
总计57个式子

游侠无极限 发表于 2004-5-2 15:22:00

当然不会只考虑加法的情况,大概你复制的时候出现问题了,你可以下载这页最上面的那个程序

yzhlinux 发表于 2004-5-2 15:23:00

to游侠无极限
你的方法思路比较特别,不过似乎更浪费资源啊,如果范围是1,100,那么你的循环将更多,而目前只是 sum 的,如果加上有 -,*,/ 和括号的话,那么就更多了,并且,如果游戏中规定可以使用三角函数,那么你这样就无法穷举出来了。
参考我的代码中,由于是组合成合法的表达算式后在进行计算得到结果,判断是否24,所以对于符号的增加和三角函数的支持都很简单的实现了。都变成了字符串的组合而已

yzhlinux 发表于 2004-5-2 15:28:00

(2-1)*3*8 这个算式你就没有啊,这4个数字的组合都没有出现






[此贴子已经被作者于2004-5-2 15:32:12编辑过]

yzhlinux 发表于 2004-5-2 15:28:00

似乎少了很多算式

yzhlinux 发表于 2004-5-2 15:29:00

另外,玩游戏的时候应该是可以重复出现的,不规定4张牌都必须不一样吧。

游侠无极限 发表于 2004-5-2 15:35:00



用这个好了,只不过输入的时候要按从小到大

好象有BUG,我暂时不太清楚

游侠无极限 发表于 2004-5-2 15:38:00

以下是引用yzhlinux在2004-5-2 15:28:15的发言:
(2-1)*3*8 这个算式你就没有啊,这4个数字的组合都没有出现


本来为了防止诸如
1*2*3*4
1*3*4*2
2*3*4*1
等的重复,只使用了从小到大的数组,不过这样好象也丢了不少可行的式子

另外你的程序就是有这些重复的

PS:VB的程序感觉就是慢好多啊
[此贴子已经被作者于2004-5-2 15:42:01编辑过]
页: [1] 2 3
查看完整版本: 有没有人想过怎么用计算机来实现24点