洗牌算法 -javascript实现

比如我们有52张牌,现在的需求就是洗牌(俗名打乱顺序 - -!)

先构造一个数组:

const nums = ['A', 1,2,3,4,5,6,7,8,9,'J','Q','K']
const signs = ['♥️', '♦️', '♣️', '♠️']
const cards = []

signs.forEach(sign=>{
nums.forEach(num=>{
cards.push({
kind: sign,
num: num
})
})
})

这样cards 就构造完成了,但是JS这样写很low,但是我觉得很快就想出来了,我们换一种其他优雅一点的方法(下面这段代码的作者是 月影):


function * getCards() {
const nums = ['A', 1,2,3,4,5,6,7,8,9,'J','Q','K']
yield * nums.map(num=>({key: '♥️', num: num }))
yield * nums.map(num=>({key: '♠️', num: num }))
yield * nums.map(num=>({key: '♦️', num: num }))
yield * nums.map(num=>({key: '♣️', num: num }))
}
const cards = [...getCards()]


上面生成器的Key Point有两点:


  // Key Point -01

...扩展运算符 内部调用的是数据结构的Iterator接口,生成器返回的就是一个Iterator对象,即遍历器对象
对这个遍历器对象执行扩展运算符 ... 就会将内部遍历到的值转为一个数组

// Key Point -02

任何数据结构只要有Iterator接口,就可以用yield * 来遍历
let readStr = (function* (){ yield* 'hello from other side' }())
readStr.next().value 这一句会输出 字符'h'
如果你写一个执行器把这个生成器执行完毕,你会发现会依次将这个字符串的单个字符给输出


好到现在为止,准备工作做完了,cards数组我们已经有了,现在我们来洗牌


// 洗牌
function shuffle(cards) {
for(let i = cards.length-1; i >= 0; i--) {
var randomIndex = Math.floor(i * Math.random())
// 从 index 为 51 开始, 51 * Math.random() 的范围是 (0, 51)
// Math.floor 之后的整数范围是 [0, 50]
// 我们将 cards[51] 和 前面的随机索引位置的值交换
// 然后到 50个的时候,和 前面 [0, 49] 中索引取一个随机的 然后交换值
// 这样下去,交换位置之后 索引为51 和 50 的值就不会变动了
const temp = cards[randomIndex]
cards[randomIndex] = cards[i]
cards[i] = temp
}
return cards
}


其实感觉在遍历数组的时候改变数组不太好,可以返回一个新的数组更好一点,当然也看实际的需求。


// 强制复习一下
const params = (function * (){
yield 1;
yield 2;
yield * (function *(){ yield 3; yield 4; })()
yield * [5,6,7]
yield * 'abc'
// yield * { length: 9, name: 'Ariza' }
})()
console.log([...params])



posted on 2018-06-22 12:08  狂奔的冬瓜  阅读(1394)  评论(1编辑  收藏  举报