最近闲来登上DNF玩了下游戏,发现更新了个玩具,就是金刚Go;
线面将这个游戏的概念抽象出来。
游戏规则:
* 实现猜数字的游戏,每次必须填入两位数字,在数字卡片各个数值都固定的情况下。实现最终将数值都猜完的游戏。
* 每次猜完数值后,拿出来的两张卡片会消失。没猜正确的话,需要继续猜。
Java实现。
为了实现这个需求,我写了个小程序,有三处有待改善,我也实现了,但是传过来一个次品供大家观赏和优化。优化可以用贝叶斯决策。
1,键盘互动,猜大了,猜小了,用键盘互动实现flag = 1/0让程序自动进行选择,依次填写相应的结果。
2,在算法上有些细节有些冗余,代码不够简洁,在传入A,B数值上可以看出。
3,实现A,B待留数组的保留上可以用决策的思想优化,我这里全部是min/10-max/10来处理十位数的保留。
实际上当个位min%10 = 9 就可以忽视该值min/10,同理max%10 = 0可以忽视 max/10了,那么 = 8/2又该以什么样的权值或者是什么样的集合环境去替换,这就是个值得研究的问题,可以有很大程度的优化了。
初步基本思想:
1,实现两位数的填入,首先将最多的卡片先利用,若最多的卡片有多个就实行贴近mid的那张,大多数情况下十位数的试探方法。
2,接着实现个位数的填补,一定使用那些不会再出现在十位数上的卡片例如,第一手猜了56后,猜大了那么01234中最多的就可以一直当做个位卡片试探。
3,梯形试探,当进入十位和个位相同的时候,采用梯形试探法,同上,只是结合了广义二分查找。
主程序
import java.util.ArrayList; public class Test2 { static boolean flag = true; static int[] countVal = Data.valueArray; static int[] countValue = Data.valueArray; static int[] indexArray = Data.indexArray; public static void main(String[] args) { int c = (int ) (100*Math.random()); int max = 100; int min = 0; while(max != min && flag){ int ab = sureAB(min, max); System.out.println("你猜的值为:"+ ab); if(ab > c){ System.out.println("猜大了"); max = ab; }else if(ab < c){ System.out.println("猜小了"); min = ab; }else{ min = max; System.out.println("恭喜您猜中了"); } } } public static int sureAB(int min, int max) { System.out.println("执行 sureAB()"); int mid = (max + min)/2; int A = 0; int B = 0; int x = min/10;//十位 int y = max/10; if(y==10) y=9; if(x==10) x=9; if(x == y){ return lastLineSetAB(min, max, x); }else{ //h为0或者1对应到A有没有包含到A_max int[] array1_Value = new int[y-x+1]; int[] array1_Index = new int[y-x+1]; int k1 = 0; for (int i = x ; i <= y; i++) { array1_Index[k1] = i; array1_Value[k1] = countVal[i]; k1++; } A = selectA(mid, array1_Value, array1_Index); //确定了A再确定B try { countVal[A] = countVal[A] -1; } catch (Exception e) { System.out.println("游戏结束,您没通关;"); }finally{ //传递进去备选数组B的两个视图 B = selectB(mid, A, array1_Value, array1_Index); countVal[B] = countVal[B] -1; } } return 10*A + B; } public static int lastLineSetAB(int min, int max, int x) { System.out.println("-梯度方法执行中-"); int A = x; //只确定B的范围 int mid = (max+min)/2; int b_min = min/10; int b_max = max/10; int b_mid = (b_max + b_min)/2; int By = 10;//差值越小越好 int in = 0; int f = 0; for(int ii = 0; ii<countVal.length;ii++){ if(countVal[ii]>0){ if(Math.abs(ii - b_mid)< By){ By = Math.abs(indexArray[ii] - mid); in = ii; } f++; } } if(f == 0){ flag = false; System.out.println("没找到匹配的B值"); } int B = in; countVal[A] = countVal[A] -1; countVal[B] = countVal[B] -1; return 10*A + B; } public static int selectB(int mid, int A, int[] array1_Value, int[] array1_Index) { int B; int[] array2_Index; int[] array2_Value; if(array1_Value.length == 10){ array2_Index = array1_Index; array2_Value = array1_Value; }else{ array2_Index = new int[10 - (array1_Value.length)]; array2_Value = new int[array2_Index.length]; int j=0; for (int i = 0; i < 10; i++) { if (!arraycontainElements(array1_Index,i)) { array2_Index[j] = i; array2_Value[j] = countVal[i]; j++; } } } Data.arraySort(array2_Value, array2_Index, 0); printArr(array2_Value); printArr(array2_Index); if(array2_Value[0] == 0){ System.out.println("没有B可抽,来抽A当B"); B = selectA(mid, array1_Value, array1_Index); }else{ ArrayList<Integer> maxMat2 = Data.maxMat(array2_Value, array2_Index); if(maxMat2.size() == 1){ B = array2_Index[0]; }else{ int[] jl = new int[maxMat2.size()]; int index = 0; int min_jl = 100; for (int i = 0; i < maxMat2.size(); i++) { jl[i] = Math.abs(10*A+maxMat2.get(i) - mid); if(jl[i] < min_jl){ min_jl = jl[i]; index = maxMat2.get(i); } } B = index; } } System.out.println("执行selectB(),打印出B: "+B); return B; } public static int selectA(int mid, int[] array1_Value, int[] array1_Index) { int A = 5; int A_ = mid/10;//期望的十位 Data.arraySort(array1_Value, array1_Index, 0); printArr(array1_Value); printArr(array1_Index); ArrayList<Integer> maxMat = Data.maxMat(array1_Value, array1_Index); if(array1_Value[0] == 0){ System.out.println("没有A可抽"); flag = false; return 100; } if(maxMat.size() == 1){ A = array1_Index[0]; }else{ int[] jl = new int[maxMat.size()]; int index = 0; int min_jl = 10; for (int i = 0; i < maxMat.size(); i++) { jl[i] = Math.abs(maxMat.get(i) - A_); if(jl[i] < min_jl){ min_jl = jl[i]; index = maxMat.get(i); } } A = index; } System.out.println("执行 selectA(),打印 A:"+ A); return A; } public static boolean arraycontainElements(int[] arr, int k){ for (int i = 0; i < arr.length; i++) { if(k == arr[i]){ return true; } } return false; } public static void printArr(int[] arr){ System.out.print("["); for (int i = 0; i < arr.length; i++) { if (i== arr.length - 1) { System.out.println(arr[i] + "]"); }else{ System.out.print(arr[i]+","); } } } }工具类:
package com.byk.demo; import java.util.ArrayList; public class Data { static int[] valueArray = {6,4,3,5,3,5,5,2,5,7}; static int[] indexArray = {0,1,2,3,4,5,6,7,8,9}; /* * 从索引from 根据arr1数组排序,arr2随着arr1对应而定 */ public static void arraySort(int[] arr1,int[] arr2,int from){ for (int i = 0; i < arr2.length; i++) { for (int j = 0; j < arr2.length; j++) { if(arr1[i]>arr1[j]){ swap(arr1,i,j); swap(arr2,i,j); } } } } public static void swap(int[] arr,int i,int j){ int temp = 0; temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } public static boolean isMaxUnique(int[] arr){ /* int i=0; while(i<arr.length){ if(arr[0] != arr[i]){ return false; } i++; } return true;*/ int[] arr2 = Data.indexArray; ArrayList<Integer> al = maxMat(arr, arr2); if(al.size() == 1){ return true; }else{ return false; } } //返回最大值索引的集合。arr1为count,arr2为降序最大索引序列 public static ArrayList<Integer> maxMat(int[] arr1,int[] arr2){ ArrayList<Integer> ali = new ArrayList<Integer>(); a:for (int i=0; i < arr1.length;i++) { if(arr1[i] == arr1[0]){ ali.add(arr2[i]); }else{ break a; } } return ali; } }
给出一个执行结果:
执行 sureAB()
[7,6,5,5,5,5,4,3,3,2]
[9,0,5,6,8,3,1,4,2,7]
执行 selectA(),打印 A:9
[7,6,5,5,5,5,4,3,3,2]
[9,0,6,8,3,5,1,2,4,7]
执行selectB(),打印出B: 9
你猜的值为:99
猜大了
执行 sureAB()
[6,5,5,5,5,5,4,3,3,2]
[0,3,5,6,8,9,1,4,2,7]
执行 selectA(),打印 A:0
[6,5,5,5,5,5,4,3,3,2]
[0,5,6,8,9,3,1,2,4,7]
执行selectB(),打印出B: 0
你猜的值为:0
猜小了
执行 sureAB()
[5,5,5,5,5,4,4,3,3,2]
[3,5,6,8,9,0,1,4,2,7]
执行 selectA(),打印 A:3
[5,5,5,5,5,4,4,3,3,2]
[5,6,8,9,3,1,0,2,4,7]
执行selectB(),打印出B: 9
你猜的值为:39
恭喜您猜中了
//再执行一次
执行 sureAB()
[7,6,5,5,5,5,4,3,3,2]
[9,0,5,6,8,3,1,4,2,7]
执行 selectA(),打印 A:9
[7,6,5,5,5,5,4,3,3,2]
[9,0,6,8,3,5,1,2,4,7]
执行selectB(),打印出B: 9
你猜的值为:99
猜大了
执行 sureAB()
[6,5,5,5,5,5,4,3,3,2]
[0,3,5,6,8,9,1,4,2,7]
执行 selectA(),打印 A:0
[6,5,5,5,5,5,4,3,3,2]
[0,5,6,8,9,3,1,2,4,7]
执行selectB(),打印出B: 0
你猜的值为:0
猜小了
执行 sureAB()
[5,5,5,5,5,4,4,3,3,2]
[3,5,6,8,9,0,1,4,2,7]
执行 selectA(),打印 A:3
[5,5,5,5,5,4,4,3,3,2]
[5,6,8,9,3,1,0,2,4,7]
执行selectB(),打印出B: 9
你猜的值为:39
猜小了
执行 sureAB()
[5,5,5,4,4,3,2]
[5,6,8,3,9,4,7]
执行 selectA(),打印 A:6
[4,4,3]
[1,0,2]
执行selectB(),打印出B: 1
你猜的值为:61
猜大了
执行 sureAB()
[5,4,4,3]
[5,3,6,4]
执行 selectA(),打印 A:5
[5,4,4,3,3,2]
[8,0,9,2,1,7]
执行selectB(),打印出B: 8
你猜的值为:58
猜小了
执行 sureAB()
[4,4]
[5,6]
执行 selectA(),打印 A:5
[4,4,4,4,3,3,3,2]
[0,3,8,9,1,2,4,7]
执行selectB(),打印出B: 9
你猜的值为:59
恭喜您猜中了