Advertisement
Guest User

Untitled

a guest
May 24th, 2019
122
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 17.65 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Wed Nov 21 18:53:53 2018
  4.  
  5. @author: Eric
  6. """
  7.  
  8. import tkinter as tk
  9. import random
  10.  
  11. class Grid:
  12.     def __init__(self, n):
  13.         self.size = n
  14.         self.cells = self.generate_empty_grid()
  15.         """設定標誌,用來判斷是否壓縮、合併、移動"""
  16.         self.compressed = False
  17.         self.merged = False
  18.         self.moved = False
  19.    
  20.     """生成空的棋盤"""
  21.     def generate_empty_grid(self):
  22.         #建立一個儲存整個二維串列
  23.         emptyGrid = []
  24.         """用二維巢狀迴圈建立二維串列"""
  25.         for i in range(self.size):
  26.             #建立一個儲存"列"的串列
  27.             rowGrid = []
  28.             for j in range(self.size):
  29.                 rowGrid.append(0)
  30.                
  31.             emptyGrid.append(rowGrid)
  32.                
  33.         return emptyGrid
  34.    
  35.     """取得所有空的格子"""
  36.     def retrieve_empty_cells(self):
  37.         #建立一個儲存所有空格子的串列
  38.         empty_cells = []
  39.         """用二維朝狀迴圈掃過網格"""
  40.         for i in range(self.size):
  41.             for j in range(self.size):
  42.                 """如果該格子等於0,則在empty_cells新增"""
  43.                 if self.cells[i][j] == 0:
  44.                     empty_cells.append((i, j))
  45.                    
  46.         return empty_cells
  47.    
  48.     """隨機選一個空的棋格生成數字2"""
  49.     def random_cell(self):
  50.         cell = random.choice(self.retrieve_empty_cells())
  51.         """把取到的元祖資料分別存入i和j"""
  52.         i = cell[0]
  53.         j = cell[1]
  54.         self.cells[i][j] = 2
  55.        
  56.     """直接設定格子"""
  57.     def set_cells(self, col , row , num):
  58.         """直接設定格子的數值"""
  59.         self.cells[col][row] = num
  60.        
  61.     """清除標誌"""
  62.     def clear_flags(self):
  63.         self.compressed = False
  64.         self.merged = False
  65.         self.moved = False
  66.        
  67.     """向左壓縮"""
  68.     def left_compress(self):
  69.         self.compressed = False
  70.         """重新生成一個空的二為串列網格,儲存至new_grid"""
  71.         new_grid = self.generate_empty_grid()
  72.        
  73.         """用二維網格掃過網格"""
  74.         for i in range(self.size):
  75.             count = 0
  76.             for j in range(self.size):
  77.                 """如果該格子的值不等於0,則進行壓縮"""
  78.                 if self.cells[i][j] != 0:
  79.                     new_grid[i][count] = self.cells[i][j]
  80.                     """如果count不等於j,則表示有進行過壓縮"""
  81.                     if count != j:
  82.                         self.compressed = True
  83.                     """若成功進行壓縮,count值加一"""
  84.                     count += 1
  85.         """全部壓縮完後,將舊的網格取代成新的網格"""
  86.         self.cells = new_grid
  87.    
  88.     """向上壓縮"""
  89.     def up_compress(self):
  90.         self.compressed = False
  91.         """重新生成一個空的二為串列網格,儲存至new_grid"""
  92.         new_grid = self.generate_empty_grid()
  93.        
  94.         """用二維網格掃過網格"""
  95.         for i in range(self.size):
  96.             count = 0
  97.             for j in range(self.size):
  98.                 """如果該格子的值不等於0,則進行壓縮"""
  99.                 if self.cells[j][i] != 0:
  100.                     new_grid[count][i] = self.cells[j][i]
  101.                     """如果count不等於j,則表示有進行過壓縮"""
  102.                     if count != j:
  103.                         self.compressed = True
  104.                     """若成功進行壓縮,count值加一"""
  105.                     count += 1
  106.         """全部壓縮完後,將舊的網格取代成新的網格"""
  107.         self.cells = new_grid
  108.  
  109.     """向右壓縮"""
  110.     def right_compress(self):
  111.         self.compressed = False
  112.         """重新生成一個空的二為串列網格,儲存至new_grid"""
  113.         new_grid = self.generate_empty_grid()
  114.        
  115.         """用二維網格掃過網格"""
  116.         for i in range(self.size):
  117.             count = self.size -1
  118.             for j in range(self.size -1,-1,-1):
  119.                 """如果該格子的值不等於0,則進行壓縮"""
  120.                 if self.cells[i][j] != 0:
  121.                     new_grid[i][count] = self.cells[i][j]
  122.                     """如果count不等於j,則表示有進行過壓縮"""
  123.                     if count != j:
  124.                         self.compressed = True
  125.                     """若成功進行壓縮,count值減一"""
  126.                     count -= 1
  127.         """全部壓縮完後,將舊的網格取代成新的網格"""
  128.         self.cells = new_grid
  129.        
  130.     """向下壓縮"""
  131.     def down_compress(self):
  132.         self.compressed = False
  133.         """重新生成一個空的二為串列網格,儲存至new_grid"""
  134.         new_grid = self.generate_empty_grid()
  135.        
  136.         """用二維網格掃過網格"""
  137.         for i in range(self.size):
  138.             count = self.size -1
  139.             for j in range(self.size -1,-1,-1):
  140.                 """如果該格子的值不等於0,則進行壓縮"""
  141.                 if self.cells[j][i] != 0:
  142.                     new_grid[count][i] = self.cells[j][i]
  143.                     """如果count不等於j,則表示有進行過壓縮"""
  144.                     if count != j:
  145.                         self.compressed = True
  146.                     """若成功進行壓縮,count值減一"""
  147.                     count -= 1
  148.         """全部壓縮完後,將舊的網格取代成新的網格"""        
  149.         self.cells = new_grid
  150.  
  151.     """向左合併"""
  152.     def left_merge(self):
  153.         self.merged = False
  154.         """用二維網格掃過網格(須注意range範圍及串列索引值)"""
  155.         for i in range(self.size):
  156.             """由於cells[i][j+1]會超出索引值,因而此處range放size-1"""
  157.             for j in range(self.size - 1):
  158.                
  159.                 """如果數字相同,且不為0則合併"""
  160.                 if self.cells[i][j] == self.cells[i][j + 1] \
  161.                 and  self.cells[i][j] != 0:
  162.                     """左方數字*2,右方數值等於0"""
  163.                     self.cells[i][j] *= 2
  164.                     self.cells[i][j + 1] = 0
  165.                     self.merged = True
  166.                    
  167.    
  168.     """向上合併"""            
  169.     def up_merge(self):
  170.         self.merged = False
  171.         """用二維網格掃過網格(須注意range範圍及串列索引值)"""
  172.         for i in range(self.size):
  173.             for j in range(self.size - 1):
  174.                
  175.                 """如果數字相同,且不為0則合併"""
  176.                 if self.cells[j][i] == self.cells[j+1][i] \
  177.                 and self.cells[j][i] != 0:
  178.                     """上方數字*2,下方數值等於0"""
  179.                     self.cells[j][i] *= 2
  180.                     self.cells[j+1][i] = 0
  181.                     self.merged = True
  182.                    
  183.     """向右合併"""              
  184.     def right_merge(self):
  185.         self.merged = False
  186.         """用二維網格掃過網格(須注意range範圍及串列索引值)"""
  187.         for i in range(self.size):
  188.             for j in range(self.size -1, 0, -1):
  189.                
  190.                 """如果數字相同,且不為0則合併"""
  191.                 if self.cells[i][j] == self.cells[i][j - 1] \
  192.                 and self.cells[i][j] != 0:
  193.                     """右方數字*2,左方數值等於0"""
  194.                     self.cells[i][j] *= 2
  195.                     self.cells[i][j - 1] = 0
  196.                     self.merged = True
  197.                    
  198.     """向下合併"""            
  199.     def down_merge(self):
  200.         self.merged = False
  201.         """用二維網格掃過網格(須注意range範圍及串列索引值)"""
  202.         for i in range(self.size):
  203.             for j in range(self.size -1, 0, -1):
  204.                
  205.                 """如果數字相同,且不為0則合併"""
  206.                 if self.cells[j][i] == self.cells[j-1][i] \
  207.                 and self.cells[j][i] != 0:
  208.                     """下方數字*2,上方數值等於0"""
  209.                     self.cells[j][i] *= 2
  210.                     self.cells[j-1][i] = 0
  211.                     self.merged = True
  212.                    
  213.         """找到2048這個數字"""
  214.     def found_2048(self):
  215.         """用二維網格掃過網格"""
  216.         for i in range(self.size):
  217.             for j in range(self.size):
  218.                 if self.cells[i][j] >= 2048:
  219.                     return True
  220.         return False
  221.  
  222.     """有沒有空的格子"""
  223.     def has_empty_cells(self):
  224.         """用二維網格掃過網格,如果有任一格數值為0回傳True,否則為False"""
  225.         for i in range(self.size):
  226.             for j in range(self.size):
  227.                 if self.cells[i][j] == 0:
  228.                     return True
  229.         return False
  230.  
  231.     """是否可以合併"""
  232.     def can_merge(self):
  233.         """用二維網格掃過網格"""
  234.         for i in range(self.size):
  235.             for j in range(self.size - 1):
  236.                 """判斷水平方向是否有相鄰且相同的兩個數字,若有回傳True"""
  237.                 if self.cells[i][j] == self.cells[i][j + 1]:
  238.                     return True
  239.         """用二維網格掃過網格"""
  240.         for j in range(self.size):
  241.             for i in range(self.size - 1):
  242.                 """判斷垂直方向是否有相鄰且相同的兩個數字,若有回傳True"""
  243.                 if self.cells[i][j] == self.cells[i + 1][j]:
  244.                     return True
  245.         """如果都找不到則回傳False"""
  246.         return False
  247.    
  248.  
  249. class GamePanel():
  250.    
  251.     """整體背景顏色"""
  252.     BACKGROUND_COLOR = '#92877d'
  253.    
  254.     """空格子顏色"""
  255.     EMPTY_CELL_COLOR = '#9e948a'
  256.    
  257.     """數字背景顏色"""
  258.     CELL_BACKGROUND_COLOR_DICT = {
  259.         '2': '#eee4da',
  260.         '4': '#ede0c8',
  261.         '8': '#f2b179',
  262.         '16': '#f59563',
  263.         '32': '#f67c5f',
  264.         '64': '#f65e3b',
  265.         '128': '#edcf72',
  266.         '256': '#edcc61',
  267.         '512': '#edc850',
  268.         '1024': '#edc53f',
  269.         '2048': '#edc22e',
  270.         'default': '3c3a32'
  271.     }
  272.    
  273.     """數字字體顏色 """
  274.     CELL_COLOR_DICT = {
  275.         '2': '#776e65',
  276.         '4': '#776e65',
  277.         '8': '#f9f6f2',
  278.         '16': '#f9f6f2',
  279.         '32': '#f9f6f2',
  280.         '64': '#f9f6f2',
  281.         '128': '#f9f6f2',
  282.         '256': '#f9f6f2',
  283.         '512': '#f9f6f2',
  284.         '1024': '#f9f6f2',
  285.         '2048': '#f9f6f2',
  286.         'default': '#f9f6f2'
  287.     }
  288.    
  289.     FONT = ('Verdana', 24, 'bold')
  290.     UP_KEYS = ('w', 'W', 'Up')
  291.     LEFT_KEYS = ('a', 'A', 'Left')
  292.     DOWN_KEYS = ('s', 'S', 'Down')
  293.     RIGHT_KEYS = ('d', 'D', 'Right')
  294.  
  295.     def __init__(self , grid):
  296.         """將grid放入類別屬性內"""
  297.         self.grid = grid
  298.         self.size = grid.size
  299.         """建立一個tkinter主視窗"""
  300.         self.window = tk.Tk()
  301.         """設定視窗標題"""
  302.         self.window.title('2048')
  303.         """設定遊戲背景"""
  304.         self.background = tk.Frame(self.window, bg=self.BACKGROUND_COLOR)
  305.         """建立空串列,用來儲存格子Label"""
  306.         self.cell_labels = []
  307.        
  308.         """初始化文字"""
  309.         """用二維巢狀迴圈建立二維串列"""
  310.         for i in range(self.size):
  311.             #建立一個儲存"列"的串列
  312.             row_labels = []
  313.             for j in range(self.size):
  314.                 """背景顏色為EMPTY_CELL_COLOR"""
  315.                 """font為剛剛設置的FONT"""
  316.                 label = tk.Label(self.background, text='',
  317.                                  bg=self.EMPTY_CELL_COLOR,
  318.                                  font=self.FONT,
  319.                                  width=4, height=2)
  320.                 """設定label位置"""
  321.                 label.grid(row=i, column=j, padx=10, pady=10)
  322.                 """將新增好的Label放入row_labels內"""
  323.                 row_labels.append(label)
  324.                 """將新增好的row_labels放入cell_labels內"""
  325.             self.cell_labels.append(row_labels)
  326.         self.background.grid()
  327.  
  328.     """把格子和字上色"""
  329.     def paint(self):
  330.         """用兩個迴圈掃過網格"""
  331.         for i in range(self.size):
  332.             for j in range(self.size):
  333.                
  334.                  #如果那個格子數字是0
  335.                 if self.grid.cells[i][j] == 0:
  336.                     """設定該格子的文字為空,背景為MPTY_CELL_COLOR"""
  337.                     self.cell_labels[i][j].configure(
  338.                          text='',
  339.                          bg=GamePanel.EMPTY_CELL_COLOR)
  340.                    
  341.                 #如果不是0,則依照字典顏色上色
  342.                 #bg->background(背景)
  343.                 #fg->foreground(前景)
  344.                 else:
  345.                     """cell_text為該格子的數值,轉為字串型態"""
  346.                     cell_text = str(self.grid.cells[i][j])
  347.                     """如果數字超過2048"""
  348.                     if self.grid.cells[i][j] > 2048:
  349.                         """color等於預設值"""
  350.                         bg_color = GamePanel.CELL_BACKGROUND_COLOR_DICT.get('beyond')
  351.                         fg_color = GamePanel.CELL_COLOR_DICT.get('beyond')
  352.                         """如果數字沒超過2048"""
  353.                     else:
  354.                         """color由字典取值"""
  355.                         bg_color = GamePanel.CELL_BACKGROUND_COLOR_DICT.get(cell_text)
  356.                         fg_color = GamePanel.CELL_COLOR_DICT.get(cell_text)
  357.                        
  358.                     self.cell_labels[i][j].configure(
  359.                         text=cell_text,
  360.                         bg=bg_color, fg=fg_color)
  361.                    
  362.            
  363. """控制整個遊戲流程"""
  364. class Game:
  365.     def __init__(self, panel):
  366.         """將panel轉為Game的屬性"""
  367.         self.panel =
  368.         """將panel內的grid轉為Game的屬性"""
  369.         self.grid =
  370.         self.start_cells_num = 2#用來設定一開始隨機產生幾個數字2
  371.         self.over = False
  372.         self.won = False
  373.  
  374.     """遊戲停止(輸了或贏了)"""
  375.     def is_game_terminated(self):
  376.         """如果遊戲結束或勝利,那就回傳True,否則False"""
  377.         return self.over or self.won
  378.  
  379.     """遊戲開始,控制整個遊戲流程
  380.    1.隨機在網格中產生數字2
  381.    2.將panel畫出來
  382.    3.如果監聽到事件則進入到key_handler方法
  383.    4.主視窗開始運行"""
  384.     def start(self):
  385.         self.add_start_cells()
  386.         self
  387.         self.panel.window.bind('<Key>', self.key_handler)
  388.         self
  389.     """開始遊戲後產生的格子"""
  390.     def add_start_cells(self):
  391.         for i in range(self.start_cells_num):
  392.             """以for迴圈控制隨機產生幾次數字二
  393.            進而呼叫grid裡面產隨機產生數字2的方法"""
  394.            
  395.  
  396.     """判斷有沒有辦法移動(合併)"""
  397.     def can_move(self):
  398.         """如果網格中有空格子,或網格可以被合併則回傳True"""
  399.         return self. or self.
  400.  
  401.     """當按下鍵盤時所要做的事情"""
  402.     def key_handler(self, event):
  403.         """先判斷遊戲是否終止"""
  404.         if self:
  405.             return
  406.         """每次點擊案件先清除網格的旗標(flags)"""
  407.         self
  408.         """設定變數儲存事件抓到的按鍵"""
  409.         key_value = event.keysym
  410.        
  411.        
  412.         #判斷按下的按鍵是哪個功能
  413.         if key_value in GamePanel.UP_KEYS:
  414.             self.up()
  415.         elif key_value in GamePanel.LEFT_KEYS:
  416.             self.left()
  417.         elif key_value in GamePanel.DOWN_KEYS:
  418.             self.down()
  419.         elif key_value in GamePanel.RIGHT_KEYS:
  420.             self.right()
  421.        
  422.         """如果找到2048,呼叫you_win方法"""
  423.         if self:
  424.             self
  425.        
  426.         """如果已經移動完了,則產生一個隨機數字"""
  427.         if self:
  428.             self
  429.  
  430.         """進行完按鍵動作後將panel現況畫出來"""
  431.         self.panel.paint()
  432.        
  433.         """如果無法再移動"""
  434.         if not self.can_move():
  435.             """遊戲結束的旗標設為True,並且呼叫game_over方法"""
  436.             self.over = True
  437.             self.game_over()
  438.  
  439.     """遊戲勝利"""
  440.     def you_win(self):
  441.         self.won = True
  442.         print('You Win!')
  443.  
  444.     """遊戲失敗"""
  445.     def game_over(self):
  446.         print('Game over!')
  447.  
  448.     """往上移動的方法
  449.    1.往上壓縮
  450.    2.往上合併
  451.    3.若有成功進行壓縮或合併,則grid.moved旗標設為True
  452.    4.在次往上壓縮"""
  453.     def up(self):
  454.         self
  455.         self
  456.         self.grid.moved = self.grid.compressed or self.grid.merged
  457.         self
  458.  
  459.     """往左移動的方法
  460.    1.往左壓縮
  461.    2.往左合併
  462.    3.若有成功進行壓縮或合併,則grid.moved旗標設為True
  463.    4.在次往左壓縮"""
  464.     def left(self):
  465.         self
  466.         self
  467.         self.grid.moved = self.grid.compressed or self.grid.merged
  468.         self
  469.  
  470.     """往下移動的方法
  471.    1.往下壓縮
  472.    2.往下合併
  473.    3.若有成功進行壓縮或合併,則grid.moved旗標設為True
  474.    4.在次往下壓縮"""
  475.     def down(self):
  476.         self
  477.         self
  478.         self.grid.moved = self.grid.compressed or self.grid.merged
  479.         self
  480.  
  481.     """往右移動的方法
  482.    1.往右壓縮
  483.    2.往右合併
  484.    3.若有成功進行壓縮或合併,則grid.moved旗標設為True
  485.    4.在次往右壓縮"""
  486.     def right(self):
  487.         self
  488.         self
  489.         self.grid.moved = self.grid.compressed or self.grid.merged
  490.         self
  491.  
  492. size = 4
  493. grid = Grid(size)
  494. panel = GamePanel(grid)
  495. game2048 = Game(panel)
  496. game2048.start()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement