最近闲来登上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
恭喜您猜中了