关于DNF金刚Go游戏的决策实践

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



原文地址:https://www.cnblogs.com/actanble/p/6713461.html