diff --git a/2048 game.py b/2048 game.py new file mode 100644 index 0000000..b337461 --- /dev/null +++ b/2048 game.py @@ -0,0 +1,327 @@ +import copy +import random +import tkinter +import tkinter.messagebox +from PIL import ImageTk, Image + + +class Matrix2048(): + def __init__(self, column: int = 4): + self.column = column + self.matrix = [[0 for i in range(column)] for li in range(column)] + self.history = [] + self.score = 0 + self.init() + + def generate_number(self): + matrix = self.matrix + column = self.column + zero = [(x, y) for x in range(column) + for y in range(column) if matrix[x][y] == 0] + if zero != []: + x, y = random.choice(zero) + matrix[x][y] = random.choice([2, 2]) + + def gameover(self) -> bool: + matrix = self.matrix + column = self.column + + if 0 in [i for li in matrix for i in li]: + return False + + + for row in range(column): + for col in range(column-1): + if matrix[row][col] == matrix[row][col+1]: + return False + + + for row in range(column-1): + for col in range(column): + if matrix[row][col] == matrix[row+1][col]: + return False + return True + + + def init(self): + self.matrix = [[0 for x in range(self.column)] + for y in range(self.column)] + self.generate_number() + self.generate_number() + + self.history = [] + self.score = 0 + + + def matrix_move(self, direction): + if direction in ['L', 'R', 'D', 'U']: + + + prev_step = { + 'score': copy.deepcopy(self.score), + 'matrix': copy.deepcopy(self.matrix) + } + self.history.append(prev_step) + + if len(self.history) > 10: + self.history = self.history[-10:] + if direction == 'U': + self.move_up() + if direction == 'D': + self.move_down() + if direction == 'L': + self.move_left() + if direction == 'R': + self.move_right() + + + def move_left(self): + column = self.column + matrix = self.matrix + + + def move_left_(matrix): + for row in range(column): + while 0 in matrix[row]: + matrix[row].remove(0) + while len(matrix[row]) != column: + matrix[row].append(0) + return matrix + + + def merge_left(matrix): + for row in range(column): + for col in range(column-1): + if matrix[row][col] == matrix[row][col+1] and matrix[row][col] != 0: + matrix[row][col] = 2 * matrix[row][col] + matrix[row][col+1] = 0 + self.score = self.score + matrix[row][col] + return matrix + + matrix = move_left_(matrix) + matrix = merge_left(matrix) + self.matrix = move_left_(matrix) + + + def move_right(self): + self.matrix = [li[::-1] for li in self.matrix] + self.move_left() + self.matrix = [li[::-1] for li in self.matrix] + + def move_up(self): + column = self.column + + self.matrix = [[self.matrix[x][y] + for x in range(column)] for y in range(column)] + self.move_left() + self.matrix = [[self.matrix[x][y] + for x in range(column)] for y in range(column)] + + def move_down(self): + self.matrix = self.matrix[::-1] + self.move_up() + self.matrix = self.matrix[::-1] + + def prev_step(self): + if self.history: + prev_data = self.history[-1] + self.score = prev_data['score'] + self.matrix = prev_data['matrix'] + self.history = self.history[0:-1] + + def show(self): + r = '+-----' * self.column + '+\n' + for li in self.matrix: + for i in li: + s = '|' + ' '*5 if i == 0 else '|' + str(i).center(5, ' ') + r = r + s + r = r + '|\n' + '+-----' * self.column + '+\n' + print(r) + + +class Window2048(): + + def __init__(self, column: int = 4): + self.init_setting(column) + self.data = Matrix2048(column) + self.root = self.init_root() + self.t = 0 # 判断游戏结束时用 + self.main() + + def init_setting(self, column): + + self.column = column + + self.space_size = 12 + + self.cell_size = 80 + + self.emts = [] # 存储lable对象 + + self.style = { + 'page': {'bg': '#d6dee0', }, + 0: {'bg': '#EEEEEE', 'fg': '#EEEEEE', 'fz': 30}, + 2**1: {'bg': '#E5E5E5', 'fg': '#707070', 'fz': 30}, + 2**2: {'bg': '#D4D4D4', 'fg': '#707070', 'fz': 30}, + 2**3: {'bg': '#FFCC80', 'fg': '#FAFAFA', 'fz': 30}, + 2**4: {'bg': '#FFB74D', 'fg': '#FAFAFA', 'fz': 30}, + 2**5: {'bg': '#FF7043', 'fg': '#FAFAFA', 'fz': 30}, + 2**6: {'bg': '#FF5722', 'fg': '#FAFAFA', 'fz': 30}, + 2**7: {'bg': '#FFEE58', 'fg': '#FAFAFA', 'fz': 30}, + 2**8: {'bg': '#FFEB3B', 'fg': '#FAFAFA', 'fz': 30}, + 2**9: {'bg': '#FDD835', 'fg': '#FAFAFA', 'fz': 30}, + 2**10: {'bg': '#FF9800', 'fg': '#FAFAFA', 'fz': 30}, + 2**11: {'bg': '#FB8C00', 'fg': '#FAFAFA', 'fz': 28}, + 2**12: {'bg': '#fb3030', 'fg': '#FAFAFA', 'fz': 28}, + 2**13: {'bg': '#e92e2e', 'fg': '#FAFAFA', 'fz': 28}, + 2**14: {'bg': '#da1e1e', 'fg': '#FAFAFA', 'fz': 24}, + 2**15: {'bg': '#3a3a3a', 'fg': '#E0E0E0', 'fz': 22}, + 2**16: {'bg': '#3a3a3a', 'fg': '#E0E0E0', 'fz': 20}, + 2**17: {'bg': '#3a3a3a', 'fg': '#E0E0E0', 'fz': 20}, + 2**18: {'bg': '#3a3a3a', 'fg': '#E0E0E0', 'fz': 20}, + 2**19: {'bg': '#3a3a3a', 'fg': '#E0E0E0', 'fz': 18}, + 2**20: {'bg': '#3a3a3a', 'fg': '#E0E0E0', 'fz': 17}, + 2**21: {'bg': '#3a3a3a', 'fg': '#E0E0E0', 'fz': 16}, + 2**22: {'bg': '#3a3a3a', 'fg': '#E0E0E0', 'fz': 15}, + 2**23: {'bg': '#3a3a3a', 'fg': '#E0E0E0', 'fz': 14}, + 2**24: {'bg': '#3a3a3a', 'fg': '#E0E0E0', 'fz': 13}, + 2**25: {'bg': '#3a3a3a', 'fg': '#E0E0E0', 'fz': 12}, + } + + def init_root(self): + column = self.column + space_size = self.space_size + cell_size = self.cell_size + + root = tkinter.Tk() + root.title('2048') + + window_w = column * (space_size + cell_size) + space_size + window_h = window_w + cell_size + 2 * space_size + root.geometry(f'{window_w}x{window_h}') + + header_h = cell_size + space_size * 2 + header = tkinter.Frame(root, height=header_h, width=window_w) + self.init_header(header) + + table = tkinter.Frame(root, height=window_w, width=window_w) + self.init_table(table) + + return root + + def init_header(self, master): + master['bg'] = self.style['page']['bg'] + + emt_score = tkinter.Label(master, bd=0) + emt_score['fg'] = '#707070' + emt_score['bg'] = self.style['page']['bg'] + emt_score['font'] = ("黑体", 30, "bold") + img = Image.new('RGB', (self.cell_size, self.cell_size), + self.style['page']['bg']) + img = ImageTk.PhotoImage(img) + emt_score.configure(image=img) + emt_score['image'] = img + + emt_score['text'] = 'score:' + str(self.data.score) + emt_score['compound'] = 'center' + self.emt_score = emt_score + emt_score.place(x=15, y=15) + master.pack() + + def init_table(self, master): + column = self.column + cell_size = self.cell_size + space_size = self.space_size + + master['bg'] = self.style['page']['bg'] + + emts = [[0 for x in range(column)] for y in range(column)] + for row in range(column): + for col in range(column): + emt = tkinter.Label(master, bd=0) + emt['width'] = self.cell_size + emt['height'] = self.cell_size + emt['text'] = '' + emt['compound'] = 'center' + + y = space_size + (cell_size + space_size) * row + x = space_size + (cell_size + space_size) * col + + emt.place(x=x, y=y) + emts[row][col] = emt + self.emts = emts + master.pack() + + def update_ui(self): + def update_score(): + img = Image.new( + 'RGB', (self.cell_size, self.cell_size), self.style['page']['bg']) + img = ImageTk.PhotoImage(img) + self.emt_score.configure(image=img) + self.emt_score['image'] = img + + self.emt_score['text'] = 'score:' + str(self.data.score) + update_score() + matrix = self.data.matrix + for row in range(self.column): + for col in range(self.column): + num = matrix[row][col] + emt = self.emts[row][col] + img = Image.new( + 'RGB', (self.cell_size, self.cell_size), self.style[num]['bg']) + img = ImageTk.PhotoImage(img) + emt.configure(image=img) + emt['fg'] = self.style[num]['fg'] + emt['bg'] = self.style[num]['bg'] + emt['image'] = img + emt['font'] = ("黑体", self.style[num]['fz'], "bold") + emt['text'] = str(num) if num != 0 else '' + + def key_event(self, event): + if event.keysym in ['Up', 'w', 'Down', 's', 'Left', 'a', 'Right', 'd']: + if event.keysym in ['Up', 'w']: # 向上 + self.data.matrix_move('U') + elif event.keysym in ['Down', 's']: # 向下 + self.data.matrix_move('D') + elif event.keysym in ['Left', 'a']: # 向左 + self.data.matrix_move('L') + elif event.keysym in ['Right', 'd']: # 向右 + self.data.matrix_move('R') + self.data.generate_number() + + if event.keysym == 'z': + if self.data.history != []: + self.data.prev_step() + self.update_ui() + + def reset_game(): + self.t = 0 + self.data.init() + self.update_ui() + + if self.data.gameover() is True: + + if self.t == 0: + self.t = 1 + else: + res = tkinter.messagebox.askyesno( + title="2048", message="Game Over!\n是否重新开始!") + if res is True: + reset_game() + else: + self.root.quit() + + def reset_game(self): + self.t = 0 + self.data.init() + self.update_ui() + + def main(self): + self.update_ui() + + self.root.bind('', self.key_event) + + self.root.mainloop() + + +g = Window2048(4) \ No newline at end of file