日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
用90行Haskell代碼實現(xiàn)2048游戲

上個星期賴斯大學(xué)的MOOC 計算的規(guī)則 公開課在 Coursera 上開講啦. 從***周的材料來看,看起來它有了他們之前的課程 Python中的交互式編程介紹 所有優(yōu)良的東西: 演示文稿做的很不錯,也有大量的支持可用, 而布置的作業(yè)也很有趣. ***個作業(yè)就是編寫 2048 游戲的邏輯.

鑒于其設(shè)計中的根本性缺陷,我并不認(rèn)為2048特別的有趣. 首先,你并不能在某個地方取得游戲的勝利. 其次,最有希望的游戲策略使得其玩起來相當(dāng)?shù)姆爆崳?**的樂趣并不是自己的游戲技能而是隨機(jī)數(shù)生成器制造的幸運(yùn)連勝. 就我個人而言,更愿意選擇那種有時被稱為“理論***”的游戲, 比如,游戲的一個屬性使得玩它的人能夠取得一個確定的勝利. 而2048的游戲結(jié)果卻沒有吸引到我,不過我也明白為什么會有人喜歡讓瓷磚四處滑動起來.

為游戲的邏輯編寫代碼是相當(dāng)直接的。歸因于使用Python作為教學(xué)語言的計算原則課程, 對于在我的最初版本中的一個錯誤是由于python發(fā)生了改變,我不會感到奇怪. 我想著用Haskell寫這個東西可能會更有趣, 隨后就著手開始用這個語言編寫了2048的一個完整實現(xiàn), 包括 I/O 處理. 整個代碼可以在 我的git賬號 上找到. 最終結(jié)果證明,更加完整的Haskell方案所需要的代碼比使用Python的程序邏輯要少幾行.

作為說明,如果你到這個頁面來只是為了找尋計算規(guī)則這門課程的Python作業(yè)的解決方案,那你就是在浪費(fèi)時間. Haskell的實現(xiàn)和Python的實現(xiàn)很不同,使用的編程語言構(gòu)造也不能在Python上用. 換言之,如果你正糾結(jié)這個作業(yè),Haskell的源代碼將不會對你有所幫助.

在這篇文章中,我僅想著重強(qiáng)調(diào)游戲邏輯的核心部分,因為它很好地顯示了函數(shù)式編程的力量。首先,我定義一個數(shù)據(jù)類型,用于展示網(wǎng)格中的數(shù)字移動的方向,還有一個用于存放整數(shù)列表的列表的類型同義詞,用來提高類型特征的可讀性。從函數(shù)‘move’的命名可以明顯看出函數(shù)的作用;再下一步,將輸入作為一個網(wǎng)格的數(shù)字和移動方向,并產(chǎn)生新的網(wǎng)格。

 
 
  1. data Move = Up | Down | Left | Right  
  2. type Grid = [[Int]] 

2048這個游戲是在一個4x4的棋盤上進(jìn)行的。開始位置在我的實現(xiàn)中是固定的:

 
 
  1. start :: Grid  
  2. start = [[0, 0, 0, 0],  
  3.          [0, 0, 0, 0],  
  4.          [0, 0, 0, 2],  
  5.          [0, 0, 0, 2]]  

棋盤上可以在4個方向上對數(shù)字進(jìn)行移動,意味著所有的數(shù)字的移動都會向著一個指定的方向,如果是2個數(shù)字,移動相同的方向,以彼此相臨而告終,則他們合并到一起。舉例來說,在如下所示的起始位置,移動方向為‘Up’,結(jié)果棋盤變成了下面所示:

 
 
  1. [[0, 0, 0, 4],  
  2.  [0, 0, 0, 0],  
  3.  [0, 0, 0, 0],  
  4.  [0, 0, 0, 0]]  

如果網(wǎng)格中的起始位置移動方向為向右,則不會有任何變化。如果網(wǎng)格變化了,則一個新的數(shù)字會在任何空的格子中產(chǎn)生,這個數(shù)字可能是2或者4.

我們看這種方法,問題在于其如何更有效的建模。在網(wǎng)格中的任何行列,都可被理解為一個列表。行和列表之間的關(guān)系是簡單明了的。列將不得不提取、 修改,或雖然再,插入?;蛘咚麄儾恍枰?/p>

我寫了一個函數(shù)來合并一行或一列,表示為一個列表。首先,所有的0要被移動,然后該列表將被處理,合并相鄰元素,如果它們包含相同的數(shù)字,接著如果必要的話,為結(jié)果中填充0.

 
 
  1. merge :: [Int] -> [Int]  
  2. merge xs = merged ++ padding  
  3.     where padding          = replicate (length xs - length merged) 0 
  4.           merged           = combine $ filter (/= 0) xs  
  5.           combine (x:y:xs) | x == y    = x * 2 : combine xs  
  6.                            | otherwise = x     : combine (y:xs)   
  7.           combine x        = x  

當(dāng)棋盤中的移動方心為左時,這個合并函數(shù)可以立刻被應(yīng)用。其他方向的移動,然而,需要進(jìn)行一些考慮,如果希望代碼保持簡潔。向右移動網(wǎng)格是通過采取反轉(zhuǎn)它之前將它提交給函數(shù)merge的每一行完成的,然后再次反轉(zhuǎn)結(jié)果:

 
 
  1. move :: Grid -> Move -> Grid  
  2. move grid Left  = map merge grid  
  3. move grid Right = map (reverse . merge . reverse) grid  
  4. move grid Up    = transpose $ move (transpose grid) Left  
  5. move grid Down  = transpose $ move (transpose grid) Right  

對于網(wǎng)格向上或者向下移動,如果你想提取出一列,對其應(yīng)用合并函數(shù),然后產(chǎn)生新的網(wǎng)格進(jìn)行列的插入,這是極其痛苦的。相反,雖然一點點的線性代數(shù)知識,卻導(dǎo)致一個更優(yōu)雅的解決方案。如果你不能立即明確如何移調(diào)導(dǎo)致所期望的結(jié)果,請看看下面的插圖。

 
 
  1. input       transpose   move        transpose  
  2.  
  3. 0 0         0 2         2 0         2 2 
  4. 2 2         0 2         2 0         0 0 
  5.  
  6.  
  7. 2 2         2 0         0 2         0 0   
  8. 0 0         2 0         0 2         2 2 

我Haskell的實現(xiàn)使用終端作為輸出。它不像Gabriele Cirulli版本的JavaScript前端一樣令人印象深刻,但它是可維護(hù)的,如下兩個屏幕截圖展示:

總體來講,我對于這個原型還是很滿意的。當(dāng)然有幾個可能的改進(jìn)。一個分?jǐn)?shù)跟蹤器的添加將是微不足道的,雖然一個 GUI 將是一個更加耗時的努力。如果有立即響應(yīng)鍵盤輸入的程序,我會覺得這個很有趣。當(dāng)前,每個通過 WASD的輸入 需要點擊回車鍵進(jìn)行確認(rèn)。如果只按一個鍵將觸發(fā)程序執(zhí)行的下一步,那么游戲玩法會加快很多。在研究這一問題時,我沒有找到任何快速的解決辦法。盡管Haskell庫NCurses包含鍵盤事件。我可能會深入探究一下,如果我用ASCII 圖形進(jìn)行編程使之成為一個“獨立”游戲。

如果你覺得這篇文章有趣,請隨意看看我的 2048的 Haskell 實現(xiàn)的源代碼。

英文原文:Implementing the game 2048 in less than 90 lines of Haskell

譯文出自:http://www.oschina.net/translate/2048-in-90-lines-haskell


文章題目:用90行Haskell代碼實現(xiàn)2048游戲
鏈接地址:http://www.5511xx.com/article/dhjcjoc.html