一位赌狗前端的自我修养
栏目: JavaScript · 发布时间: 7年前
内容简介:这段时间工作巨多,直到今天才有时间写点东西。可是要输出点什么比较好呢?这时候看到了隔壁桌面上放着一张机打的写着一组一组数字的纸,有了!那要不抽个奖吧!抽奖,讲究一个随机,只要把随机摇号解决了不就不管什么规则都能抽了?所以我们需要一个可以产生随机数的函数。不仅要随机数,我们还需要的是一个闭区间随机取整数的函数。所以没吃过猪肉还见过猪跑,号码肯定是抽一个少一个,所以根本不存在随机数能相同的情况!所以这个方法是不能用的。那么,拿来抽的方法肯定得满足三个条件:
这段时间工作巨多,直到今天才有时间写点东西。可是要输出点什么比较好呢?这时候看到了隔壁桌面上放着一张机打的写着一组一组数字的纸,有了!那要不抽个奖吧!
问题分析
抽奖,讲究一个随机,只要把随机摇号解决了不就不管什么规则都能抽了?所以我们需要一个可以产生随机数的函数。不仅要随机数,我们还需要的是一个闭区间随机取整数的函数。所以
const random = (m, n) => m + Math.floor(Math.random() * (n - m)) 复制代码
没吃过猪肉还见过猪跑,号码肯定是抽一个少一个,所以根本不存在随机数能相同的情况!所以这个方法是不能用的。那么,拿来抽的方法肯定得满足三个条件:
- 有范围,是闭区间
- 起始值肯定大于1
- 随机数不能有重复
问题解决
关于随机不重复我最先想到的是利用 sort 对数组随机打散的方法。这个时候可能会有其他声音:
要不要这么水? sort 用来 排序 的不懂?
水不水不知道,看一下MDN。
arr.sort([compareFunction])
- 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
- 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。备注: ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本);
- 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。
- compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。
so
// arr 数组,num 取个数 const random = (arr:number[], num: number) => arr.sort(() => Math.random() - 0.5).splice(0, num) 复制代码
具体问题具体解决
首先,我们需要通过百度查一下业界知名抽奖活动典型的游戏规则:
某抽奖游戏分为红色区和蓝色区,红色区由1-33共三十三个号码组成,蓝色区由1-16共十六个号码组成。需要在红色区选择6个号码和在蓝色区选择1个号码合成一次有效号码组。
作为赌狗前端,提取这段话几个关键点:
- 红色区 1 ~ 33
- 蓝色区 1 ~ 16
- 取红 6 个,取蓝 1 个
别说了我脑子里又有函数了
// ...random
const dualColor = () => {
const reds = [1, 2, ..33]
const blues = [1, 2, ..16]
const red = random(reds, 6)
const blue = random(blues, 1)
return [red, blue]
}
复制代码
这个时候我们看一眼方法,你这方法不对啊!以红色为例子,我们的函数表达结果是:直接把号码打散后流出前 6 个,而游戏规则指出号码不仅一个一个放出,而且放的过程中并没有停止打散。所以这个随机函数显然不合理。那还能怎么办,改啊!
// 打散后流出第一个和剩下的号码组
function random(arr) {
const newarr = arr.sort(() => Math.random() - 0.5)
const val = newarr.shift()
return [val, newarr]
}
function dualColor() {
let redballs = [1, 2, ..33]
let blueballs = [1, 2, ..16]
let red = [], blue = []
for (let i = 0; i < 6; i++) {
const balls = random(redballs)
red.push(balls[0])
redballs = balls[1]
}
blue.push(random(blueballs)[0])
return [red, blue]
}
复制代码
做法优化
说实话这么写程序可憋死我了…
不会真的有人这么写数组吧
如果按照正常随机数方法那么做的话,我确实提供一个最大值一个最小值就结束了,关键这是个数组,又没有什么 range 之类的可以用,不会真的有人手写 1 ~ 33 吧。不过我们可以曲线捞一下
// 0 ~ 9 const arr = [...Array(10).keys()] 复制代码
所以第一点改造两个球数组
let reds: number[] = [...Array(33).keys()].map(i => i+1) let blues: number[] = [...Array(16).keys()].map(i => i+1) 复制代码
为什么 +1 呢?号码也没从 0 开始的啊!
也许我们应该让随机函数更纯更通用?
我们需要让抽奖更灵活一些,毕竟只要是抽的,我全都要。我想让随机函数能接受一个数组和我想要的个数,再返回结果。
同样的会出现需要循环取值的情况,为什么我们不用神奇的尾递归呢?
function randomVal(
arr: number[],
total: number,
temp: number[] = [],
): number[] {
const [head, ...body] = arr
.sort(() => Math.random() - 0.5)
return !total
? temp
: randomVal(body, total - 1, temp.concat(head));
}
复制代码
俺寻思这两个号组写起来可太累了
改!都可以改!我们可以改成存放起始值和终止值的元组
function dualColor() {
const reds: [number, number] = [1, 33]
const blues: [number, number] = [1, 16]
return [randomVal(reds, 6), randomVal(blues, 1)]
}
复制代码
相应的随机函数也做点小改动
function randomVal(
fromto: number[],
total: number,
temp: number[] = [],
): number[] {
const [head, ...body] = (temp.length
? fromto
: [...Array(fromto[1]).keys()]
.map(item => item + 1)
.splice(fromto[0] - 1)
).sort(() => Math.random() - 0.5);
return !total
? temp
: randomVal(body, total - 1, temp.concat(head))
}
复制代码
我好像看漏了规则
除此之外还有三种: (一)从红色区中选择7--20个,从蓝色区中选择1个。 (二)从红色区中选择6个,从蓝色区中选择2--16个。 (三)从红色区中选择7--20个,从蓝色区中选择2--16个。
虽然我看不懂,但是这么改就没问题了吧
// 我管你几个,全给你安排上!
function dualColor(red: number = 6, blue: number = 1) {
const reds: [number, number] = [1, 33]
const blues: [number, number] = [1, 16]
return [randomVal(reds, red), randomVal(blues, blue)]
}
复制代码
所以最后解决方案是
function dualColor(red: number = 6, blue: number = 1) {
const reds: [number, number] = [1, 33]
const blues: [number, number] = [1, 16]
return [randomBall(reds, red), randomBall(blues, blue)]
}
function randomBall(
fromto: number[],
total: number,
temp: number[] = [],
): number[] {
const [head, ...body] = (temp.length
? fromto
: [...Array(fromto[1]).keys()]
.splice(fromto[0] - 1)
.map(item => item + 1)
).sort(() => Math.random() - 0.5);
return !total
? temp
: randomBall(body, total - 1, temp.concat(head))
}
复制代码
赏心悦目?
以上所述就是小编给大家介绍的《一位赌狗前端的自我修养》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Designing Data-Intensive Applications
Martin Kleppmann / O'Reilly Media / 2017-4-2 / USD 44.99
Data is at the center of many challenges in system design today. Difficult issues need to be figured out, such as scalability, consistency, reliability, efficiency, and maintainability. In addition, w......一起来看看 《Designing Data-Intensive Applications》 这本书的介绍吧!