前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >typescript根据权重进行随机

typescript根据权重进行随机

原创
作者头像
cg错过
修改2020-11-24 18:07:10
1.2K0
修改2020-11-24 18:07:10
举报
文章被收录于专栏:程序笔记

前言: 这是我在去年记录的笔记, 那会儿在上一家公司, 以nodejs为环境来开发小游戏, 使用ts来编写. 那会儿写笔记只顾着记录, 并没着重去组织语言, 我现在也是搬运过来, 并未更改正文, 望见谅.

正文

代码如下

代码语言:javascript
复制
/**
 * describe: 根据权重来随机
 * 从一个数组中进行随机选择元素, 需要其元素为一个obj类型, 包含名为weight的key
 * 返回下标
 * @param array 
 */
function randByWeight(array: Array<Object>): number {
    let self = this;
    let totalWeight: number = 0;
    let randIndex: number;
    array.forEach(element => {
        totalWeight += element["weight"];
    });

    if (totalWeight <= 0) {
        randIndex = undefined;
        return randIndex
    } else {
        let randVal: number = rand(1, totalWeight);
        for (let index = 0; index < array.length; index++) {
            const element = array[index];
            if (randVal <= element["weight"]) {
                randIndex = index;
                break;
            } else {
                randVal -= element["weight"];
            }
        }
    }
    return randIndex;
}

function rand(min: number, max: number): number {
    let n: number = max - min;
    return min + Math.round(Math.random() * n);
}

测试传入参数如下

代码语言:javascript
复制
let weightObjArr: Array<any> = [{"weight": 50, "name": 'attack'}, {"weight": 50, "name": 'defense'}, {"weight": 50, "name": 'balanced'}];

update-1

代码如下

代码语言:javascript
复制
interface WeightMsg{
    id: number,
    weight: number
}

/**
 * describe: 根据权重来随机
 * 从一个数组中进行随机选择元素, 需要其元素为一个obj类型, 包含名为weight的key
 * 返回下标
 * @param array 
 */
function randByWeight(arr: Array<WeightMsg>): number {
    let totalWeight: number = 0;
    let randIndex: number;
    for(let itemWeightMsg of arr){
        totalWeight += itemWeightMsg.weight;
    }

    if (totalWeight <= 0) {
        return randIndex
    } else {
        let randVal: number = rand(1, totalWeight);
        for (let index = 0; index < arr.length; index++) {
            if (randVal <= arr[index].weight) {
                randIndex = index;
                break;
            } else {
                randVal -= arr[index].weight;
            }
        }
    }
    return randIndex;
}

function rand(min: number, max: number): number {
    let n: number = max - min;
    return min + Math.round(Math.random() * n);
}

/**
 * describe: 将数组结构的权重数据转成带weightd的key的obj元素类型的数组
 * 如arr: [[1, 10]], 1为id, 10表示权重
 * @param arr: 双重数组, 且元素长度为2, 元素个数不限, 子元素为number
 */
function arrChangeWeightObjArr(arr: Array<Array<number>>): Array<WeightMsg> {
    let arrWeight: Array<WeightMsg> = [];
    for (let arrItem of arr) {
        let itemObj: WeightMsg = {
            id: arrItem[0],
            weight: arrItem[1]
        }
        arrWeight.push(itemObj);
    }
    return arrWeight;
}

/**
 * describe: 权重抽取id
 * @param arr 
 */
function getIdByWeght(arr: Array<Array<number>>): number{
    let weightArr: Array<WeightMsg> = arrChangeWeightObjArr(arr);
    let resIndex: number = randByWeight(weightArr);
    return weightArr[resIndex].id;
}

/**
 * describe: 记录次数, 将添加值为value的个数信息计入到containerObj中
 * @param containerObj : 存放数据的obj
 * @param value : 记录的值
 * @param num 
 */
function statisticalNum(containerObj: Object, value: number, num: number = 1): Object{
    let oldNum: number = containerObj[value] || 0;
    let newNum: number = oldNum + num;
    containerObj[value] = newNum;
    return containerObj;
}

let testTypeArr: Array<Array<number>> = [[1, 10], [2, 10]];
let resObj: Object = {}

for(let intIndex = 0; intIndex < 10; intIndex ++){
    let typeNum: number = getIdByWeght(testTypeArr);
    resObj = statisticalNum(resObj, typeNum)
}

console.log('resObj: ', resObj);

如上面的输出如下

代码语言:javascript
复制
PS D:\new-company\work\nodejs\vscode\doNewTest\190305\newTest> tsc .\newTest.ts
PS D:\new-company\work\nodejs\vscode\doNewTest\190305\newTest> node .\newTest.js
resObj:  { '1': 7, '2': 3 }

感觉有点差距

如果我把参数代码改成如下

代码语言:javascript
复制
let testTypeArr: Array<Array<number>> = [[1, 10], [2, 10], [3, 10], [4, 10], [5, 10], [6, 10], [7, 10], [8, 10], [9, 10], [10, 10]];
let resObj: Object = {}

for(let intIndex = 0; intIndex < 100000; intIndex ++){
    let typeNum: number = getIdByWeght(testTypeArr);
    resObj = statisticalNum(resObj, typeNum)
}

console.log('resObj: ', resObj);

其输出如

代码语言:javascript
复制
PS D:\new-company\work\nodejs\vscode\doNewTest\190305\newTest> tsc .\newTest.ts
PS D:\new-company\work\nodejs\vscode\doNewTest\190305\newTest> node .\newTest.js
resObj:  { '1': 9659,
  '2': 10241,
  '3': 10086,
  '4': 9928,
  '5': 9985,
  '6': 10077,
  '7': 10263,
  '8': 10064,
  '9': 10127,
  '10': 9570 }
PS D:\new-company\work\nodejs\vscode\doNewTest\190305\newTest>

运行次数多了, 会发现第一个和最后一个随机出来的次数总会少那么一些

还得改进

后来发现是这个rand函数的原因, 于是重新写了个函数, 如

代码语言:javascript
复制
function getRandomIntInclusive(min: number, max: number): number {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive 
}

整理后, 代码如下

代码语言:javascript
复制
interface WeightMsg{
    id?: number,
    weight: number
}

/**
 * describe: 根据权重来随机
 * 从一个数组中进行随机选择元素, 需要其元素为一个obj类型, 包含名为weight的key
 * 返回下标
 * @param arr 
 */
function randByWeight(arr: Array<WeightMsg>): number {
    let totalWeight: number = 0;
    let randIndex: number;
    for(let itemWeightMsg of arr){
        totalWeight += itemWeightMsg.weight;
    }

    if (totalWeight <= 0) {
        return randIndex
    } else {
        let randVal: number = getRandomIntInclusive(1, totalWeight);
        for (let index = 0; index < arr.length; index++) {
            if (randVal <= arr[index].weight) {
                randIndex = index;
                break;
            } else {
                randVal -= arr[index].weight;
            }
        }
    }
    return randIndex;
}

/**
 * describe: 在范围内获取随机整数值 [min, max]
 * @param min : 最小值
 * @param max : 最大值
 */
function getRandomIntInclusive(min: number, max: number): number {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive 
}

/**
 * describe: 将数组结构的权重数据转成带weightd的key的obj元素类型的数组
 * 如arr: [[1, 10]], 1为id, 10表示权重
 * @param arr: 双重数组, 且元素长度为2, 元素个数不限, 子元素为number
 */
function arrChangeWeightObjArr(arr: Array<Array<number>>): Array<WeightMsg> {
    let arrWeight: Array<WeightMsg> = [];
    for (let arrItem of arr) {
        let itemObj: WeightMsg = {
            id: arrItem[0],
            weight: arrItem[1]
        }
        arrWeight.push(itemObj);
    }
    return arrWeight;
}

/**
 * describe: 权重抽取id
 * @param arr 
 */
function getIdByWeght(arr: Array<Array<number>>): number{
    let weightArr: Array<WeightMsg> = arrChangeWeightObjArr(arr);
    let resIndex: number = randByWeight(weightArr);
    return weightArr[resIndex].id;
}

/**
 * describe: 记录次数, 将添加值为value的个数信息计入到containerObj中
 * @param containerObj : 存放数据的obj
 * @param value : 记录的值
 * @param num 
 */
function statisticalNum(containerObj: Object, value: number, num: number = 1): Object{
    let oldNum: number = containerObj[value] || 0;
    let newNum: number = oldNum + num;
    containerObj[value] = newNum;
    return containerObj;
}

let testTypeArr: Array<Array<number>> = [[1, 10], [2, 10], [3, 10], [4, 10], [5, 10], [6, 10], [7, 10], [8, 10], [9, 10], [10, 10]];
let resObj: Object = {}

for(let intIndex = 0; intIndex < 100000; intIndex ++){
    let typeNum: number = getIdByWeght(testTypeArr);
    resObj = statisticalNum(resObj, typeNum)
}

console.log('resObj: ', resObj);

运行输出如下

代码语言:javascript
复制
PS D:\new-company\work\nodejs\vscode\doNewTest\190305\newTest> tsc .\newTest.ts
PS D:\new-company\work\nodejs\vscode\doNewTest\190305\newTest> node .\newTest.js
resObj:  { '1': 10021,
  '2': 10010,
  '3': 10071,
  '4': 9943,
  '5': 10026,
  '6': 9970,
  '7': 9919,
  '8': 10078,
  '9': 9963,
  '10': 9999 }


文章首发来自公众号:程序员品

欢迎关注
欢迎关注

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档