1. 程式人生 > >洗牌演算法 -javascript實現

洗牌演算法 -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])