Python小遊戲2048

qq_45434253發表於2020-12-05

python game2048
效果圖:
在這裡插入圖片描述

原始碼:

import random
import math

__mataclass__ = type  # 使用新式類

# 此類為地圖模組封裝的類
class map2048():
    # 重新設定遊戲資料
    def reset(self):
        self.__row = 4  # 行數
        self.__col = 4  # 列數
        self.data = [
            [0 for x in range(self.__col)]
            for y in range(self.__row)
        ]
        # self.data = [[x + 4 * y for x in range(self.__col)]
        #              for y in range(self.__row)]
        # self.data = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
        self.fill2()
        self.fill2()

    def __init__(self):
        self.reset()

    # 獲取沒有數字的位置的個數
    def get_space_count(self):
        #獲取沒有數字的方格的數量
        count = 0
        for r in self.data:
            count += r.count(0)
        return count

    # 獲取遊戲的得數。
    def get_score(self):
        s = 0
        for r in self.data:
            for c in r:
                s += 0 if c < 4 else c * int((math.log(c, 2) - 1.0))
        return s

    # 填充2到空位置,如果填度成功返回True,如果已滿,則返回False,
    def fill2(self):
        blank_count = self.get_space_count()
        if 0 == blank_count:
            return False
        # 生成隨機位置
        pos = random.randrange(0, blank_count)
        offset = 0
        for r in self.data:
            for ci in range(self.__col):
                if 0 == r[ci]:
                    if offset == pos:
                        r[ci] = 2
                        return True
                    offset += 1

    # 判斷遊戲是否結束
    def is_gameover(self):
        for r in self.data:
            # 如果水平方向還有0,則遊戲沒有結束
            if r.count(0):
                return False
            # 水平方向如果有兩個相鄰的元素相同,則沒有遊戲結束
            for i in range(self.__col - 1):
                if r[i] == r[i + 1]:
                    return False
        for c in range(self.__col - 1):
            # 豎直方向如果有兩個相鄰的元素相同,則沒有遊戲結束
            for r in range(self.__row - 1):
                if self.data[r][c] == self.data[r + 1][c]:
                    return False
        # 以上都沒有,則遊戲結束
        return True

    # 2048遊戲的左移動
    def left(self):
        # moveflag 是否成功移動數字標誌位,如果有移動則為真值,原地圖不變則為假值
        moveflag = False
        # 將所有數字向左移動來填補左側空格
        for times in range(self.__col - 1):
            for r in self.data:
                for c in range(self.__col - 1):
                    if 0 == r[c]:
                        moveflag = True
                        r[c] = r[c + 1]
                        r[c + 1] = 0
        # 判斷是否發生碰幢,如果有碰撞則合併,合併結果靠左,右則填充空格
        for r in self.data:
            for c in range(self.__col - 1):
                if r[c] == r[c + 1]:
                    moveflag = True
                    r[c] *= 2
                    r[c + 1] = 0
        # 再將所有數字向左移動來填補左側空格
        for times in range(self.__col - 1):
            for r in self.data:
                for c in range(self.__col - 1):
                    if 0 == r[c]:
                        moveflag = True
                        r[c] = r[c + 1]
                        r[c + 1] = 0
        return moveflag

    # 遊戲右移操作
    def right(self):
        for r in self.data:
            r.reverse()
        moveflag = self.left()
        for r in self.data:
            r.reverse()
        return moveflag

    # 遊戲上移操作
    def up(self):
        # moveflag 是否成功移動數字標誌位,如果有移動則為真值,原地圖不變則為假值
        moveflag = False
        # 將所有數字向上移動來填補上面空格
        for times in range(self.__row - 1):
            for c in range(self.__col):
                for r in range(self.__row - 1):
                    if 0 == self.data[r][c]:
                        moveflag = True
                        self.data[r][c] = self.data[r + 1][c]
                        self.data[r + 1][c] = 0
        # 判斷是否發生碰幢,如果有碰撞則合併,合併結果靠上,下面填充空格
        for c in range(self.__col):
            for r in range(self.__row - 1):
                if self.data[r][c] == self.data[r + 1][c]:
                    moveflag = True
                    self.data[r][c] *= 2
                    self.data[r + 1][c] = 0
        # 再將所有數字向上移動來填補上面空格
        for times in range(self.__row - 1):
            for c in range(self.__col):
                for r in range(self.__row - 1):
                    if 0 == self.data[r][c]:
                        moveflag = True
                        self.data[r][c] = self.data[r + 1][c]
                        self.data[r + 1][c] = 0
        return moveflag

    # 遊戲下移操作
    def down(self):
        self.data.reverse()
        moveflag = self.up()
        self.data.reverse()
        return moveflag


import sys

if (sys.version_info > (3, 0)):
    from tkinter import *
    from tkinter import messagebox
else:
    from Tkinter import *

game = map2048()

keymap = {
    'a': game.left,
    'd': game.right,
    'w': game.up,
    's': game.down,
    'Left': game.left,
    'Right': game.right,
    'Up': game.up,
    'Down': game.down,
    'q': exit,
}

game_bg_color = "#bbada0"
mapcolor = {
    0: ("#bbada0", "#0E050A"),
    2: ("#DAF5FF", "#0E050A"),
    4: ("#A5E2FF", "#0E050A"),
    8: ("#5ABBFF", "#0E050A"),
    16: ("#1F39FF", "#0E050A"),
    32: ("#0012C6", "#0E050A"),
    64: ("#3B0080", "#0E050A"),
    128: ("#570075", "#0E050A"),
    256: ("#40004A", "#0E050A"),
    512: ("#750046", "#0E050A"),
    1024: ("#690039", "#0E050A"),
    2048: ("#5A0000", "#0E050A"),
    4096: ("#004000", "#0E050A"),
    8192: ("#008000", "#0E050A"),
}

# 遊戲各方塊的lable資料
map_labels = []

# 滑鼠按下處理函式
def on_mouse_down(event):
    print("clicked at", event.x, event.y)


# 鍵盤按下處理函式
def on_key_down(event):
    keysym = event.keysym
    if keysym in keymap:
        if keymap[keysym]():
            game.fill2()
    update_ui()
    if game.is_gameover():
        mb = messagebox.askyesno(title="gameover", message="遊戲結束!\n是否退出遊戲!")
        if mb:
            exit()
        else:
            game.reset()
            update_ui()

# 重新整理介面函式
def update_ui():
    # 更改各個Label的設定
    for r in range(len(game.data)):
        for c in range(len(game.data[0])):
            number = game.data[r][c]
            label = map_labels[r][c]
            label['text'] = str(number) if number else ''
            label['bg'] = mapcolor[number][0]
            label['foreground'] = mapcolor[number][1]
    label_score['text'] = str(game.get_score())

# 2048的介面
root = Tk()
root.title('2048')
# root.iconbitmap('./favicon.ico')  # 48x48 ico bitmap

frame = Frame(root, width=300, height=300, bg=game_bg_color)
frame.grid(sticky=N + E + W + S)
# 按鍵事件見:http://blog.csdn.net/qq_25600055/article/details/46942035
# 設定焦點能接收按鍵事件
frame.focus_set()
frame.bind("<Key>", on_key_down)
# 以下繫結滑鼠按下事件
# frame.bind("<Button-1>", on_mouse_down)
# 以下繫結滑鼠移動事件
# frame.bind("<Motion>", on_mouse_down)
# 以下繫結滑鼠抬起事件
frame.bind("<ButtonRelease-1>", on_mouse_down)
# 見 :http://blog.csdn.net/wjciayf/article/details/50550947


# 初始化圖形介面
for r in range(len(game.data)):
    row = []
    for c in range(len(game.data[0])):
        value = game.data[r][c]
        text = '' if 0 == value else str(value)
        label = Label(frame, text=text, width=4, height=2,
                      font=("黑體", 30, "bold"))
        label.grid(row=r, column=c, padx=5, pady=5, sticky=N + E + W + S)
        row.append(label)
    map_labels.append(row)
bottom_row = len(game.data)
print("button", str(bottom_row))
label = Label(frame, text='分數', font=("楷體", 30, "bold"),
              bg="#bbada0", fg="#eee4da")
label.grid(row=bottom_row, column=0, padx=5, pady=5)
label_score = Label(frame, text='0', font=("楷體", 30, "bold"),
                    bg="#bbada0", fg="#ffffff")
label_score.grid(row=bottom_row, columnspan=2, column=1, padx=5, pady=5)


def reset_game():
    game.reset()
    update_ui()


# restart_button = Button(frame, text='重新開始', command=reset_game)
restart_button = Button(frame, text='重來', font=("楷體", 20, "bold"),
                        # width=4, height=2,
                        bg="#8f7a66", fg="#f9f6f2", command=reset_game)
restart_button.grid(row=bottom_row, column=3, padx=5, pady=5)

update_ui()

root.mainloop()

相關文章