24点游戏算法

游戏规则: 一副牌中去掉大小王,在剩下的52张牌中任意取四张。使用四则运算,使其最后结果为24.其中每张牌只能使用一次且A=1,J=11,Q=12,K=13。

     譬如 2,4,6,8  ------>  结果为 6/(4-2)*8=24;

算法思考: 首先,从宏观上说,这种问题都是遍历穷举。再看看运算符,其中+,* 都是没有顺序的。即(a*b=b*a), 但是 -、/ 是有顺序的。那么假设都有顺序的。那么就可以统一处理了(最多效率低点,先解决问题。再考虑优化)。那么遍历所有a,b,c,d 以及 三次运算 。即A(4,4) *4*4*4 就是该算法的复杂度。(事实证明我错了。后面会讲到。)

     微观上,由于中间有除法,那么不能用int类型来储存数据了。需要用double或者float.每次运算都只有两个数运算。我们可用 Function CalcValue(float x,float y , char sy)来表示。x表示第一数,y表示第二个数, sy表示四则运算符之一。

  代码如下:

ContractedBlock.gif ExpandedBlockStart.gif View Code
        public float CalcValue(float x, float y, char f)
{
float res = 0;
switch (f)
{
case '+': res = x + y;
break;
case '-': res = x - y;
break;
case '*': res = x * y;
break;
case '/': res = x / y;
break;
default:
break;
}
return res;
}

  遍历代码如下

ContractedBlock.gif ExpandedBlockStart.gif View Code
for (int i1 = 0; i1 < Nums.Count; i1++)//Nums 为4个数   
{
List<float> Nums1 = CloneValue(this.Nums);
float num1 = Nums1[i1];//第一个数
Nums1.RemoveAt(i1);//移除第一数

for (int i2 = 0; i2 < Nums1.Count; i2++)//遍历剩下的3个数
{
List<float> Nums2 = CloneValue(Nums1);
float num2 = Nums1[i2];//第二个数
Nums2.RemoveAt(i2);

for (int i3 = 0; i3 < Nums2.Count; i3++)
{
List<float> Nums3 = CloneValue(Nums2);
float num3 = Nums2[i3];//第三个数
Nums3.RemoveAt(i3);

//第四个数,因为最后一个了。不要循环了。
float num4 = Nums3.First();

//即四个数的顺序为num4,num3,num2,num1;接下来遍历符号

for (int sy1 = 0; sy1 < 4; sy1++)//遍历第一的运算符号
{
char currentSymbol1 = symbols[sy1];
float tem1 = CalcValue(num4, num3, currentSymbol1);//第一个中间值

for (int sy2 = 0; sy2 < 4; sy2++)
{
char currentSymbol2 = symbols[sy2];

float tem2 = 0;
for (int dir = 0; dir < 2; dir++)//一开始没写这个循环。只计算了下面注释的部分。其实写程序到这里我就感觉不太对了。。后来验证果然不对。
{
if (dir == 0)
{
tem2 = CalcValue(tem1, num2, currentSymbol2);
}
if (dir == 1)
{
tem2 = CalcValue(num2, tem1, currentSymbol2);
}
// float tem2 = CalcValue(tem1, num2, currentSymbol2);
for (int sy3 = 0; sy3 < 4; sy3++)
{
char currentSymbol3 = symbols[sy3];
float tem3 = 0;
for (int dir2 = 0; dir2 < 2; dir2++)//同样。这个一开始没写。后来补的。
{
if (dir2 == 0)
{
tem3 = CalcValue(tem2, num1, currentSymbol3);
}
if (dir2 == 1)
{
tem3 = CalcValue(num1, tem2, currentSymbol3);
}
// float tem3 = CalcValue(tem2, num1, currentSymbol3);

if (tem3 == 24)//发现了计算
{
//下面的都是后来补的。所以导致程序很乱。
if (dir == 0 && dir2==0)//按顺序的
{
Console.WriteLine("{0}{1}{2}, {3}{4},{5}{6}", num4, currentSymbol1, num3, currentSymbol2, num2, currentSymbol3, num1);
}
if (dir == 1 && dir2==0)//第二次计算时 num2与temp四则运算 如 6/(4-2) * 8
{
Console.WriteLine("{3}{4},{0}{1}{2},{5}{6}", num4, currentSymbol1, num3, num2, currentSymbol2, currentSymbol3, num1);
}
if (dir==0 && dir2 == 1)// 最后次计算 num4与temp四则运算 如 4/(1-5/6)
{
Console.WriteLine("{6}{5}, ({0}{1}{2},{4}{3})", num4, currentSymbol1, num3, num2, currentSymbol2, currentSymbol3, num1);
}
if (dir==1 && dir2 == 1)// 如 8/(3-8/3)
{
Console.WriteLine("{6}{5}, {4}{3},{0}{1}{2}", num4, currentSymbol1, num3, num2, currentSymbol2, currentSymbol3, num1);
}
return;
}
}//---

}

}//---
}
}
}
}



}

  从遍历代码中发现。我们少考虑的点东西。 即并不是遍历所有abcd以及 运算的组合就行了。我们遍历的只是数出现的顺序。而并没有遍历所有表达式。

举个例子: ((a+b)-c)+d 和 (c-(a+b))+d  这两个表达式 都是 ab运算, 再和c运算,最后和d运算。 运算数的顺序是一样的,都是abcd,但是表达式不同。

也就是说,遍历数所有abcd的组合还不够。还需要添加一个顺序。计算的顺序。于是在遍历的程序中 多了两个for(dir=0;dir<2;dir++) 的循环。。。

重新思考:  看到计算表达式 ((a+b)-c)+d  ,就想起大学时候的波兰表达式。 先去括号再说。ab+c-d+。很好很强大!!这个就能解决顺序的问题。不必先弄所有的数字的组合(带顺序的,A(x,x),不是C(x,x) ) 然后还要考虑 计算的顺序。。。。那么关键是有多少种符合的表达式类型呢? 穷举!!!

改天再想吧。。。

罗列下待解决的问题: 效率问题。太多的重复判断。或许波兰表达式能解决。

           去括号后相同的表达式。。 譬如 a-(b+c)+d  与 a-b-c+d  是相同的。

 




转载于:https://www.cnblogs.com/xinjian/archive/2011/10/23/2221544.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
扑克牌24点游戏算法Java的实现可以分为以下几个步骤: 1. 使用Random类生成四个范围为1~13的随机数代表四张牌。 2. 在数组中存放这四个数的所有排列组合方式。 3. 利用穷举法列出四个数和运算符号的所有组合方式。 4. 构造每种组合方式的计算函数。 5. 利用while循环和for循环的嵌套使用求出所有能算出24点的计算式。 具体实现可以参考以下代码: ```java import java.util.Random; public class TwentyFourPoints { public static void main(String[] args) { int[] nums = new int[4]; Random random = new Random(); for (int i = 0; i < 4; i++) { nums[i] = random.nextInt(13) + 1; } System.out.println("四张牌为:" + nums[0] + " " + nums[1] + " " + nums[2] + " " + nums[3]); int[][] permutes = permute(nums); for (int i = 0; i < permutes.length; i++) { int[] p = permutes[i]; if (calculate(p[0], p[1], p[2], p[3])) { System.out.println("能够得到24点的表达式为:" + p[0] + " " + p[1] + " " + p[2] + " " + p[3]); } } } public static int[][] permute(int[] nums) { int[][] result = new int[24][4]; int index = 0; for (int i = 0; i < nums.length; i++) { for (int j = 0; j < nums.length; j++) { if (j != i) { for (int k = 0; k < nums.length; k++) { if (k != i && k != j) { int l = 6 - i - j - k; result[index++] = new int[]{nums[i], nums[j], nums[k], nums[l]}; } } } } } return result; } public static boolean calculate(int a, int b, int c, int d) { return calculate(a, b, c, d, 0, 0, 0, 0) == 24; } public static int calculate(int a, int b, int c, int d, int i, int j, int k, int l) { if (i == 3 && j == 3 && k == 3 && l == 3) { return a; } int result = 0; switch (i) { case 0: result = calculate(a + b, c, d, 0, i + 1, j, k, l); break; case 1: result = calculate(a - b, c, d, 0, i + 1, j, k, l); break; case 2: result = calculate(a * b, c, d, 0, i + 1, j, k, l); break; case 3: result = calculate(a / b, c, d, 0, i + 1, j, k, l); break; } switch (j) { case 0: result = calculate(result + c, 0, 0, 0, i, j + 1, k, l); break; case 1: result = calculate(result - c, 0, 0, 0, i, j + 1, k, l); break; case 2: result = calculate(result * c, 0, 0, 0, i, j + 1, k, l); break; case 3: result = calculate(result / c, 0, 0, 0, i, j + 1, k, l); break; } switch (k) { case 0: result = calculate(result + d, 0, 0, 0, i, j, k + 1, l); break; case 1: result = calculate(result - d, 0, 0, 0, i, j, k + 1, l); break; case 2: result = calculate(result * d, 0, 0, 0, i, j, k + 1, l); break; case 3: result = calculate(result / d, 0, 0, 0, i, j, k + 1, l); break; } return result; } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值