一位赌狗前端的自我修养
栏目: JavaScript · 发布时间: 5年前
内容简介:这段时间工作巨多,直到今天才有时间写点东西。可是要输出点什么比较好呢?这时候看到了隔壁桌面上放着一张机打的写着一组一组数字的纸,有了!那要不抽个奖吧!抽奖,讲究一个随机,只要把随机摇号解决了不就不管什么规则都能抽了?所以我们需要一个可以产生随机数的函数。不仅要随机数,我们还需要的是一个闭区间随机取整数的函数。所以没吃过猪肉还见过猪跑,号码肯定是抽一个少一个,所以根本不存在随机数能相同的情况!所以这个方法是不能用的。那么,拿来抽的方法肯定得满足三个条件:
这段时间工作巨多,直到今天才有时间写点东西。可是要输出点什么比较好呢?这时候看到了隔壁桌面上放着一张机打的写着一组一组数字的纸,有了!那要不抽个奖吧!
问题分析
抽奖,讲究一个随机,只要把随机摇号解决了不就不管什么规则都能抽了?所以我们需要一个可以产生随机数的函数。不仅要随机数,我们还需要的是一个闭区间随机取整数的函数。所以
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)) } 复制代码
赏心悦目?
以上所述就是小编给大家介绍的《一位赌狗前端的自我修养》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
程序员面试金典(第5版)
[美] Gayle Laakmann McDowell / 李琳骁、漆 犇 / 人民邮电出版社 / 2013-11 / 59.00
本书是原谷歌资深面试官的经验之作,层层紧扣程序员面试的每一个环节,全面而详尽地介绍了程序员应当如何应对面试,才能在面试中脱颖而出。第1~7 章主要涉及面试流程解析、面试官的幕后决策及可能提出的问题、面试前的准备工作、对面试结果的处理等内容;第8~9 章从数据结构、概念与算法、知识类问题和附加面试题4 个方面,为读者呈现了出自微软、苹果、谷歌等多家知名公司的150 道编程面试题,并针对每一道面试题目......一起来看看 《程序员面试金典(第5版)》 这本书的介绍吧!