前言: 这是我在去年记录的笔记, 那会儿在上一家公司, 以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-companyworknodejsvscodedoNewTest190305newTest> tsc .newTest.ts
PS D:new-companyworknodejsvscodedoNewTest190305newTest> 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-companyworknodejsvscodedoNewTest190305newTest> tsc .newTest.ts
PS D:new-companyworknodejsvscodedoNewTest190305newTest> 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-companyworknodejsvscodedoNewTest190305newTest>
运行次数多了, 会发现第一个和最后一个随机出来的次数总会少那么一些
还得改进
后来发现是这个rand
函数的原因, 于是重新写了个函数, 如
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-companyworknodejsvscodedoNewTest190305newTest> tsc .newTest.ts
PS D:new-companyworknodejsvscodedoNewTest190305newTest> node .newTest.js
resObj: { '1': 10021,
'2': 10010,
'3': 10071,
'4': 9943,
'5': 10026,
'6': 9970,
'7': 9919,
'8': 10078,
'9': 9963,
'10': 9999 }
文章首发来自公众号:程序员品