应用二维数组实现抽奖功能(九宫格)

一.需求简介:使用二维数组划分物品的分区,物品出现的顺序为分区的顺序,分区内物品为权重随机. 例如:分区内有’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
已经全部打开!

五.总结

上面给出的仅仅是限定条件(九宫格)的分块顺序随机的方法,由此可以扩展到任何翻牌抽奖的功能.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值