国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

蛋疼之作:99行代碼的2048

2019-11-14 17:29:41
字體:
來源:轉載
供稿:網友

基于Python和numpy,自帶基于Tk最簡仿原生2048配色的圖形界面。文件代碼行數(Physical LOC)一共99,沒有統計過邏輯行數,因為是Python。

本來是想寫個最簡單的內核然后用機器學習算策略的,可是寫了幾行又不想寫了,索性加了個GUI做個最簡版的2048,所以完全沒有效率和Pythonic可言。不過只是作為2048模塊的話10ms和1ms能有什么區別呢。總之這就是一個蛋疼的作品,寫它最主要的原因是無聊。

對2048游戲規則的理解:

1) 方塊合并時從滑動所指方向開始合并,合并不遞歸,比如:

|-|2|2|2|向右滑動后,最右兩塊合并,變為|-|-|2|4|

|2|2|2|2|向右滑動后,最右和最左兩塊分別合并,變為|-|-|4|4|

2) 每次滑動后如果方塊發生了變化則生成新方塊,新方塊的取值集為{2, 4},4出現的概率是0.1,初始化游戲產生兩個新方塊。

3) 游戲的分數是累加每次合并得到的新方塊的值。

代碼分為兩個模塊:

1) 核心模塊,用一個4x4矩陣表示游戲中方塊的數值,沒有方塊的位置值為nan。基本思想是用concatenate函數實現方塊的移動,用將矩陣擴展成5x4并錯開一行和原矩陣相減得到列方向相鄰相同的方塊位置。

按照滑動方向先將矩陣中的非空元素全部排列到每行的最右,用numpy的concatenate函數和isnan函數實現

將得到的已經移動過的矩陣旋轉,然后分別在第一行和行尾插入新的空行,得到兩個5x4的矩陣

這兩個矩陣相減之后相鄰并等值的位置就會得到0,這里我們定義空值和任何值得減法仍然得到空值,在numpy中對應的是nan和任何float的加法

注意執行完上面的合并操作后,如果是一排4個方塊等值,則新合成的兩個方塊不相鄰,所以還需要再將矩陣轉回去執行一遍移動操作才能確保一排4個值都相等的情況下正確的移動并合并方塊。

模塊代碼如下:

 1 from numpy import random, array, zeros, append, sum, concatenate, copy, ndenumerate, isnan, rot90, nan, int, float 2 DOWN, RIGHT, UP, LEFT = range(4) 3  4 class Game2048: 5     def __init__(self): 6         self._grid, self._score = zeros(16) + nan, 0 7         self._grid[random.choice(16, 2, replace=False)] = random.choice([2]*9+[4], 2, replace=False) # init with 2 tiles 8         self._grid = self._grid.reshape((4, 4))  # create 4x4 grid 9 10     @staticmethod11     def _merge_down(grid):12         merge = concatenate((grid, [zeros(4) + nan])) - concatenate(([zeros(4) + nan], grid))  # find the mergable tiles13         merge[2][merge[3]==0], merge[1][merge[2]==0] = nan, nan     # remove redundant 0 by 3 same tiles14         score = sum(grid[merge[:4] == 0])15         grid[merge[:4] == 0], grid[merge[1:] == 0] = grid[merge[:4] == 0] * 2, nan # fill the merged  with new number16         return score17 18     def _create_tiles(self):19         avail = isnan(self._grid)20         if avail[avail==True].size > 0:21             new_tiles = append(random.choice([20]*9+[40]), zeros(avail[avail==True].size - 1) + nan)22             random.shuffle(new_tiles)23             self._grid[avail] = new_tiles24 25     def step(self, direction):26         self._grid[self._grid%10==0] /= 1027         merge_v, merge_h, grid_copy = copy(self._grid), copy(rot90(self._grid)), copy(self._grid)28         map(Game2048._merge_down, [merge_v, merge_h])       # try to merge tiles along two directions29         if merge_v[isnan(merge_v)].size is 0 and merge_h[isnan(merge_h)].size is 0:         # Check if game is over30             return False31         self._grid = rot90(self._grid, RIGHT - direction)32         self._grid = array([concatenate((x[isnan(x)], x[~isnan(x)])) for x in self._grid])  # move tiles33         self._grid = rot90(self._grid, -1)34         self._score += Game2048._merge_down(self._grid)                                     # merge tiles35         self._grid = rot90(self._grid, 1)36         self._grid = array([concatenate((x[isnan(x)], x[~isnan(x)])) for x in self._grid])  # move tiles37         self._grid = rot90(self._grid, direction - RIGHT)38         if not ((self._grid == grid_copy) | (isnan(self._grid) & isnan(grid_copy))).all():39             self._create_tiles()40         return True41 42     def get_grid(self):43         grid = copy(self._grid)44         grid[grid%10==0] /= 1045         return grid46 47     def get_new_tiles(self):48         grid = zeros((4, 4), int)49         grid[self._grid%10==0] = 150         return grid51 52     def get_score(self):53         return self._score

2) GUI模塊,直接捕捉鍵盤的上下左右4個按鍵移動方塊,窗體標題欄顯示游戲相關信息,無動畫,新出現的方塊用橙色表示,使用大多數Python版本中內置的GUI庫Tk實現,代碼如下:

 1 from Tkinter import Tk, Label, Frame, BOTH 2 from tkFont import Font 3 from game2048 import Game2048, UP, DOWN, LEFT, RIGHT, ndenumerate, copy, isnan 4  5 key_map = {'Up': UP, 'Down': DOWN, 'Left': LEFT, 'Right': RIGHT} 6 color_map = {2: ('#776e65', '#eee4da'), 4: ('#776e65', '#ede0c8'), 8: ('#f9f6f2', '#f2b179'), 16: ('#f9f6f2', '#f2b179'), 7              32: ('#f9f6f2', '#f67c5f'), 64: ('#f9f6f2', '#f65e3b'), 128:('#f9f6f2', '#edcf72'), 256: ('#f9f6f2', '#edcc61'), 8              512: ('#f9f6f2', '#edc850'), 1024: ('#f9f6f2', '#edc53f'), 2048: ('#f9f6f2', '#edc22e'), 'base': '#ccc0b3'} 9 color_map.update(dict.fromkeys([2**x for x in range(12, 18)], ('#f9f6f2', '#3c3a32')))10 11 def input_listener(event=None, game=None, tk_root=None, labels=None):12     key = '{}'.format(event.keysym)13     if key in key_map and game and labels and tk_root:14         if game.step(key_map[key]):15             grid, new_tiles, score = game.get_grid(), game.get_new_tiles(), int(game.get_score())16             max_tile = int(grid[~isnan(grid)].max())17             tk_root.title('Move tiles to get {}! Score: {}'.format(2048 if max_tile < 2048 else max_tile * 2, score))18             for (i, j), value in ndenumerate(grid):19                 text = '{}'.format('' if isnan(grid[i][j]) else int(grid[i][j]))20                 font_color = color_map[32][1] if new_tiles[i][j] else color_map['base'] if isnan(value) else color_map[value][0]21                 labels[4*i+j].config(text=text, fg=font_color, bg=color_map['base'] if isnan(value) else color_map[value][1])22         else:23             grid, new_tiles, score = game.get_grid(), game.get_new_tiles(), int(game.get_score())24             max_tile = int(grid[~isnan(grid)].max())25             [labels[i].config(text='' if i < 4 or i > 11 else 'GAMEOVER'[i-4], bg=color_map['base']) for i in xrange(16)]26             tk_root.title('Game Over! Tile acheived: {}, Score: {}'.format(max_tile, score))27 28 if __name__ == '__main__':29     game, root, window_size = Game2048(), Tk(), 36030     root.title('Move tiles to get 2048! Score: 0')31     root.geometry('{0}x{0}+111+111'.format(window_size))32     root.config(background='#bbada0')33 34     grid, labels = game.get_grid(), []35     for (i, j), value in ndenumerate(grid):36         frame = Frame(root, width=window_size/4-2, height=window_size/4-2)37         font = Font(family='Helvetica', weight='bold', size=window_size/15)38         frame.pack_PRopagate(0)39         frame.place(x=j*window_size/4+1, y=i*window_size/4+1)40         (text, color) = ('', color_map['base']) if isnan(value) else ('{}'.format(int(value)), color_map[value][0])41         label = Label(frame, text=text, font=font, fg=color, bg=color_map['base'] if isnan(value) else color_map[value][1])42         label.pack(fill=BOTH, expand=True)43         labels.append(label)44 45     root.bind_all('<Key>', lambda event: input_listener(event, game=game, tk_root=root, labels=labels))46     root.mainloop()

發布在github上了,還沒有完全測試過,歡迎fork。

GitHub: https://github.com/frombeijingwithlove/mini2048


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 大理市| 柳州市| 珲春市| 朝阳市| 青浦区| 乳山市| 灯塔市| 渝中区| 晋宁县| 陕西省| 临泽县| 陇西县| 乌兰浩特市| 临猗县| 永吉县| 深水埗区| 时尚| 资源县| 伽师县| 永安市| 台南县| 阿拉善左旗| 炉霍县| 敦煌市| 定南县| 文登市| 阜阳市| 成武县| 绵阳市| 宁都县| 秀山| 犍为县| 定南县| 阳高县| 德庆县| 五台县| 永修县| 五指山市| 比如县| 新营市| 朔州市|