You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

327 lines
11 KiB

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('<Key>', self.key_event)
self.root.mainloop()
g = Window2048(4)