import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
public class PointGame {
/**编程之美 24点游戏
* 1.穷举。计算所有的可能,若能得到24,输出
* 2.分治。引入集合,去重。另外,利用x=5=(0101)来表示(a0,a1,a2,a3)的子集(a1,a3)是非常巧妙的
*/
private static final double DIFF=1E-6F;
private static final int CardsNumber = 4;
private static final int CardMax = 13; //扑克。最大值是13
private static final int ResultValue = 24;
public static void main(String[] args) throws Exception {
int k=0;
while(k<100){ //测试100次
int[] source=new int[CardsNumber];
double[] number=new double[CardsNumber];
String[] result=new String[CardsNumber]; //记录number[i]是通过什么运算表达式得到的
Random random=new Random();
for(int i=0;i<CardsNumber;i++){ //随机生成4个数字
int x=random.nextInt(CardMax)+1;
source[i]=x;
number[i]=x;
result[i]=""+x;
}
//打印参与运算的数字
System.out.println(Arrays.toString(source));
//方法1
boolean ok=PointGame.compute(number,result,CardsNumber);
if(ok){
System.out.println("1. "+result[0]);
}
//方法2
boolean ok2=PointGame.compute(source);
if(ok!=ok2){ //两种方法得到结果(能否生成24)应该是一致的
throw new Exception("something wrong");
}
System.out.println("===================================");
k++;
}
}
//方法1
public static boolean compute(double[] number,String[] result,int n){
if(n==1){
return (Math.abs(number[0]-ResultValue)<DIFF); //number[0]==ResultValue or not
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
double a=number[i];
double b=number[j];
String expa=result[i];
String expb=result[j];
//每计算一次,参与运算的数字就少一个。将最后一个数字复制到位置j,可达到缩小(缩短)数组的效果
number[j]=number[n-1];
result[j]=result[n-1];
//加法操作 a+b
number[i] = a+b;
result[i] = '(' + expa + '+' + expb + ')';
if(compute(number,result,n-1)){
return true;
}
//减法操作 a-b
number[i] = a - b;
result[i] = '(' + expa + '-' + expb + ')';
if(compute(number,result,n-1)){
return true;
}
//减法操作 b-a
number[i] = b - a;
result[i] = '(' + expb + '-' + expa + ')';
if(compute(number,result,n-1)){
return true;
}
//乘法操作 a*b
number[i] = a * b;
result[i] = '(' + expa + '*' + expb + ')';
if(compute(number,result,n-1)){
return true;
}
//除法操作 a/b, 如果除数不为0
if(b != 0){
number[i] = a / b;
result[i] = '(' + expa + '/' + expb + ')';
if(compute(number,result,n-1))
{
return true;
}
}
//除法操作 b/a , 如果除数不为0
if(a != 0){
number[i] = b / a;
result[i] = '(' + expb + '/' + expa + ')';
if(compute(number,result,n-1)){
return true;
}
}
number[i] = a;
number[j] = b;
result[i] = expa;
result[j] = expb;
}
}
return false;
}
//方法2
private static final int n=CardsNumber;
private static final int m=(1<<n)-1; //(10000)-1=(1111)=15
private static List<Node>[] S;
public static boolean compute(int[] number){
S=new ArrayList[m+1];
//(a0,a1,a2,a3)的子集(a0),(a1),(a2),(a3)只有一个元素,不用运算直接返回即可
for(int j=0;j<n;j++){
int v=number[j];
Node node=new Node((0.0+v),(""+v));
List<Node> Si=new ArrayList<Node>();
Si.add(node);
int i=1<<j;
S[i]=Si;
}
for(int i=1;i<=m;i++){
List<Node> Si=fun(i);
S[i]=Si;
}
List<Node> Sm=S[m];
for(Node v:Sm){
if(Math.abs(v.value-ResultValue)<DIFF){
System.out.println("2. "+v.exp);
return true;
}
}
return false;
}
//递归求S[i]
public static List<Node> fun(int i){
List<Node> si=S[i];
if(si!=null&&!si.isEmpty()){
return si;
}
si=new ArrayList<Node>();
for(int x=1;x<i;x++){
if((x&i)==x){ //确保x是i的子集
List<Node> sx=fun(x);
List<Node> s_x=fun(i-x);
si.addAll(fork(sx,s_x));
}
}
return si;
}
//集合里元素两两运算并去重
public static List<Node> fork(List<Node> sx,List<Node> s_x){
Set<Node> set=new HashSet<Node>();
for(int i=0,m=sx.size();i<m;i++){
for(int j=0,n=s_x.size();j<n;j++){
Node a=sx.get(i);
Node b=s_x.get(j);
set.add(new Node(a.value+b.value,"("+a.exp+"+"+b.exp+")"));
set.add(new Node(a.value-b.value,"("+a.exp+"-"+b.exp+")"));
set.add(new Node(b.value-a.value,"("+b.exp+"-"+a.exp+")"));
set.add(new Node(a.value*b.value,"("+a.exp+"*"+b.exp+")"));
if(b.value!=0){
set.add(new Node(a.value/b.value,"("+a.exp+"/"+b.exp+")"));
}
if(a.value!=0){
set.add(new Node(b.value/a.value,"("+b.exp+"/"+a.exp+")"));
}
}
}
List<Node> si=new ArrayList<Node>(set);
return si;
}
static class Node{
double value; //表达式的值
String exp; //表达式
Node(double value,String exp){
this.value=value;
this.exp=exp;
}
public boolean equals(Object o) {
if (!(o instanceof Node))
return false;
Node node = (Node) o;
return Double.doubleToLongBits(this.value)==
Double.doubleToLongBits(node.value);
//&&this.exp.equals(node.exp); //只关心值是否相等,不关心表达式
}
public int hashCode() {
int result = 17;
long tolong = Double.doubleToLongBits(value);
result = 37 * result + (int) (tolong ^ (tolong >>> 32));
//result = 37 * result + exp.hashCode();
return result;
}
}
}
分享到:
相关推荐
《商业编程:深入解析俄罗斯方块游戏源代码》 俄罗斯方块是一款经典的电子游戏,自1984年诞生以来,其简洁而富有挑战性的玩法深受全球玩家喜爱。本资源包含了一款精美的俄罗斯方块游戏的源代码,是学习商业编程、...
【Python少儿编程】课程资料包含了从基础到进阶的24个主题,旨在培养孩子们对计算机编程的兴趣和技能。这些课程适用于多种级别的编程竞赛,如蓝桥杯一级、NOC一二级,旨在帮助孩子们在实战中提升编程能力。课程资料...
《少儿Scratch编程项目:赛车小游戏1204》 Scratch是一款由麻省理工学院(MIT)媒体实验室“终身幼儿园”团队开发的图形化编程工具,专为儿童设计,旨在激发他们对计算机科学的兴趣。这个名为“赛车小游戏1204”的...
这门技术涉及了从基础的编程概念到高级的游戏引擎架构,为有志于成为游戏编程者的学员提供了全面的学习资源。"游戏编程者必看"这一标签表明,无论你是初学者还是经验丰富的开发者,这个资料都能提供宝贵的见解和实践...
在这个"Scratch少儿编程项目作品图片素材-益智游戏素材包.zip"中,包含了丰富的资源,适合用于制作各种益智游戏,帮助孩子们在娱乐中学习编程。 首先,我们要理解少儿趣味编程的概念。趣味编程是通过寓教于乐的方式...
【标题】"03几何之美-少儿编程scratch项目源代码文件案例素材.zip"是一个针对儿童设计的编程学习资源,旨在通过几何图形的创作与互动,让孩子们在玩乐中掌握编程基础。Scratch是一款由麻省理工学院(MIT)媒体实验室...
《少儿编程奇幻之旅-整装待发》项目为孩子们准备了一个名叫“整装待发”的起始点,这里的“整装待发”不仅仅是游戏或故事的开始,更是孩子们编程之旅的开端。在这个阶段,孩子们将学会如何创建属于自己的角色、设计...
《游戏编程入门》是Michael Morrison撰写的一本专为初学者设计的游戏编程教程。该书旨在引导读者进入游戏开发的世界,通过一系列章节逐步介绍游戏编程的基础概念和技术。在压缩包文件中,我们可以看到多个章节的代码...
OpenGL编程基础是计算机图形学领域中的重要组成部分,它是一种用于渲染2D和3D图形的应用程序编程接口(API)。...这不仅有助于提升你的编程技能,也有助于你理解和开发游戏、虚拟现实、科学可视化等领域的应用程序。
经典著作《游戏编程精粹》系列。我这里收集了1-7卷合集。因为只能上传60M以内的,所以只能分卷上传。
而《飞机吃彩虹编程大作战》正是迎合这一趋势的少儿编程项目,它以游戏的形式,让孩子们在轻松愉悦的环境中学习编程,实现了知识与乐趣的完美结合。 ### 游戏化学习:激发编程兴趣 《飞机吃彩虹编程大作战》是一款...
在计算机游戏的发展史上,Windows游戏编程大师技巧的演变是一个关键部分。60年代,随着第一台大型主机的出现,游戏的雏形开始形成。Core Wars是Unix系统上最早的游戏之一,它为后来的游戏开发奠定了基础。70年代,...
《少儿编程奇幻之旅-石风力发电》是一个专为儿童设计的编程学习项目,通过使用Scratch编程语言,孩子们可以在游戏中了解风力发电的工作原理,同时锻炼编程思维和逻辑能力。这个项目源代码文件案例素材.zip包含了一个...
《游戏编程模式》是Robert Nystrom所著的一本关于游戏开发的专业书籍,它深入探讨了在游戏开发中广泛使用的各种设计模式和技术。这本书旨在帮助游戏开发者提高代码的可读性、可维护性和复用性,使游戏项目更加高效、...
### 二、21点棋牌游戏的开发 #### 1. 游戏概述 21点棋牌游戏是一种非常流行的纸牌游戏,在许多国家和地区都有广泛的受众。其规则简单,但策略性较强,玩家的目标是让手中的牌的点数尽可能接近21点,但不能超过21点...
03 几何之美.zipscratch2.0 3.0编程项目源文件源码经典游戏案例素材源代码03 几何之美.zipscratch2.0 3.0编程项目源文件源码经典游戏案例素材源代码03 几何之美.zipscratch2.0 3.0编程项目源文件源码经典游戏案例...
《少儿编程奇幻之旅-侦测目标》是一套专为儿童设计的编程学习资源,主要使用了Scratch这一可视化编程...因此,这个项目非常适合童程童美这样的少儿编程教育机构,旨在为孩子们的编程之旅提供一个充满想象和探索的空间。
C++游戏编程入门教程 (美)道森(Dawson,M.) 著,徐刚,薛雷,于健 译 人民邮电出版社 本书从C++语言和游戏编程最基础的内容开始,讲述如何用C++语言进行游戏编程。全书共分10章,内容由浅入深,全面覆盖了C++语言的...
【少儿编程Scratch课程——冒险之旅】是一门旨在教授儿童编程知识的课程,主要使用Scratch编程语言。Scratch是麻省理工学院(MIT)的“终身幼儿园团队”开发的一款面向儿童的图形化编程工具,它通过拖拽积木式的编程语...