一.需求简介:使用二维数组划分物品的分区,物品出现的顺序为分区的顺序,分区内物品为权重随机. 例如:分区内有’item1:10,item2:20’表示item1出现的概率为10/30
二.九宫格类(代码)
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
/**
* 九宫格类
*
* @author insping
*
*/
public class SudokuBody {
String[][] sudokuItems = new String[9][9]; // 九宫格的内容
List<SudokuInfo> sudokuInfos = new ArrayList<>(); // 九宫格已经翻起的内容
public SudokuBody() {
}
public String[][] getSudokuItems() {
return sudokuItems;
}
public void setSudokuItems(String[][] sudokuItems) {
this.sudokuItems = sudokuItems;
}
public List<SudokuInfo> getSudokuInfos() {
return sudokuInfos;
}
public void setSudokuInfos(List<SudokuInfo> sudokuInfos) {
this.sudokuInfos = sudokuInfos;
}
/**
* 判断翻过的ItemID是已经翻过
*
* @param totle
* @param string
* @return
*/
private boolean SudokuInfoIsExist(int start, String string) {
if (start >= sudokuInfos.size()) {
return false;
}
for (int index = start; index < sudokuInfos.size(); index++) {
SudokuInfo sudokuInfo = sudokuInfos.get(index);
if (sudokuInfo == null) {
continue;
}
if (sudokuInfo.getItemId().equals(string)) {
return true;
}
}
return false;
}
/**
* 从九宫格中随机出一个Id
*
* @return
*/
public String randomItemFromSudokuItems() {
String result = "";
int size = sudokuInfos.size();
String[] vaList = null;
int totle = 0;
// 寻找这次在那个分组中随机
for (int index = 0; index < sudokuItems.length; index++) {
if (size < sudokuItems[index].length + totle) {
vaList = sudokuItems[index];
break;
}
totle += sudokuItems[index].length;
}
String[] values = new String[vaList.length];
int[] rates = new int[vaList.length];
for (int i = 0; i < vaList.length; i++) {
String[] string = vaList[i].split(":");
if (string.length < 1) {
continue;
}
values[i] = string[0];
if (SudokuInfoIsExist(totle, string[0])) {
rates[i] = 0;
} else {
rates[i] = Integer.parseInt(string[1]);
}
}
result = getRandomObj(values, rates);// 根据values对应的权重列表rates,从values中随机出一个
return result;
}
/*************************下面是上面用的随机方法*************************/
@SuppressWarnings("unchecked")
public <T> T getRandomObj(T[] objs, int[] rates) {
int total = 0;
List<RateComparator> datas = new ArrayList<RateComparator>();
for (int i = 0; i < rates.length; i++) {
total += rates[i];
RateComparator data = new RateComparator(objs[i], rates[i]);
datas.add(data);
}
Collections.sort(datas);
int random = random(total) + 1;
int r = 0;
for (RateComparator data : datas) {
r += data.rate;
if (random <= r) {
return (T) data.value;
}
}
return null;
}
private final Random RND = new Random(System.currentTimeMillis());
static class RateComparator implements Comparable<RateComparator> {
public Object value;
public int rate;
public RateComparator(Object value, int rate) {
this.value = value;
this.rate = rate;
}
@Override
public int compareTo(RateComparator o) {
return rate - o.rate;
}
};
public int random(int size) {
return RND.nextInt(size);
}
}
三.测试
// 初始化并设置九宫格的内容
SudokuBody sudokuBody = new SudokuBody();
String[][] sudokuData = { { "item1:10", "item11:20", "item111:300" }, { "item2:10" },
{ "item3:10", "item33:20" }, { "item4:10" }, { "item5:10", "item55:10" } };
sudokuBody.setSudokuItems(sudokuData);
// 模拟打开的位置 ,其实并没有任何的作用
int[] poses = { 5, 6, 7, 8, 9, 1, 2, 3, 4 ,3};//可以为任意顺序
for (int i = 0; i < poses.length; i++) {
String id = sudokuBody.randomItemFromSudokuItems();
// 加入已经打开的list
SudokuInfo info = new SudokuInfo(poses[i], id);
sudokuBody.getSudokuInfos().add(info);
// 处理该物品
System.out.println("第" + (i + 1) + "次翻牌:" + id);
// 全部翻开重置
if (sudokuBody.getSudokuInfos().size() >= 9) {
System.out.println("已经全部打开!");
break;
}
}
其中一种结果:
第1次翻牌:item111
第2次翻牌:item11
第3次翻牌:item1
第4次翻牌:item1
第5次翻牌:item3
第6次翻牌:item33
第7次翻牌:item4
第8次翻牌:item55
第9次翻牌:item5
已经全部打开!
四.重大修订(如果测试过,会发现一个bug,当不同分区的itemId是相同的时候,在SudokuInfoIsExist()的时候会出错.)
方法:在每个itemId的前面加上标示(不如就取数组下标),保证itemId为唯一的就可以了.上面的例子也提供大家,根据上面的给出更好解决方法.
SudokuBody sudokuBody = new SudokuBody();
String[][] sudokuData = { { "00item1:10", "01item11:20", "02item111:300" }, { "10item1:10" },
{ "20item3:10", "21item33:20" }, { "30item4:10" }, { "40item5:10", "41item55:10" } };
sudokuBody.setSudokuItems(sudokuData);
// 模拟打开的位置 ,其实并没有任何的作用
int[] poses = { 5, 6, 7, 8, 9, 1, 2, 3, 4 ,3};
for (int i = 0; i < poses.length; i++) {
String id = sudokuBody.randomItemFromSudokuItems();
// 加入已经打开的list
SudokuInfo info = new SudokuInfo(poses[i], id);
sudokuBody.getSudokuInfos().add(info);
// 处理该物品
System.out.println("第" + (i + 1) + "次翻牌:" + id.substring(2, id.length()));
// 全部翻开重置
if (sudokuBody.getSudokuInfos().size() >= 9) {
System.out.println("已经全部打开!");
break;
}
}
其中一种结果:
第1次翻牌:item111
第2次翻牌:item11
第3次翻牌:item1
第4次翻牌:item1
第5次翻牌:item33
第6次翻牌:item3
第7次翻牌:item4
第8次翻牌:item5
第9次翻牌:item55
已经全部打开!
五.总结
上面给出的仅仅是限定条件(九宫格)的分块顺序随机的方法,由此可以扩展到任何翻牌抽奖的功能.