修改了:界面高度
背景颜色
1 # _*_ coding:utf-8 _*_
2 '''
3 Created on 2017年7月30日上午11:16:44
4
5 @author: xiaolin
6
7 relief=RAISED
8 sticky=N+E+S+W
9 '''
10 from tkinter import *
11 import random
12 import time
13 # from tkMessageBox import *
14
15 # 俄罗斯方块界面的高度
16 HEIGHT = 20
17
18 # 俄罗斯方块界面的宽度
19 WIDTH = 10
20
21 ACTIVE = 1
22 PASSIVE = 0
23 TRUE = 1
24 FALSE = 0
25
26 style = [
27 [[(0, 0), (0, 1), (1, 1), (2, 1)], [(1, 0), (1, 1), (1, 2), (0, 2)], [(0, 1), (1, 1), (2, 1), (2, 2)],
28 [(1, 0), (2, 0), (1, 1), (1, 2)]], # j
29 [[(1, 0), (1, 1), (1, 2), (2, 1)], [(1, 0), (0, 1), (1, 1), (2, 1)], [(1, 0), (1, 1), (1, 2), (0, 1)],
30 [(0, 1), (1, 1), (2, 1), (1, 2)]], # T
31 [[(0, 1), (1, 1), (2, 1), (2, 0)], [(0, 0), (1, 0), (1, 1), (1, 2)], [(0, 1), (1, 1), (2, 1), (0, 2)],
32 [(1, 0), (1, 1), (1, 2), (2, 2)]], # 反L
33 [[(0, 0), (0, 1), (1, 1), (1, 2)], [(2, 1), (1, 1), (1, 2), (0, 2)], [(0, 0), (0, 1), (1, 1), (1, 2)],
34 [(2, 1), (1, 1), (1, 2), (0, 2)]], # Z
35 [[(1, 0), (1, 1), (0, 1), (0, 2)], [(0, 1), (1, 1), (1, 2), (2, 2)], [(1, 0), (1, 1), (0, 1), (0, 2)],
36 [(0, 1), (1, 1), (1, 2), (2, 2)]], # 反Z
37 [[(0, 0), (0, 1), (1, 1), (1, 0)], [(0, 0), (0, 1), (1, 1), (1, 0)], [(0, 0), (0, 1), (1, 1), (1, 0)],
38 [(0, 0), (0, 1), (1, 1), (1, 0)]], # 田
39 [[(1, 0), (1, 1), (1, 2), (1, 3)], [(0, 1), (1, 1), (2, 1), (3, 1)], [(1, 0), (1, 1), (1, 2), (1, 3)],
40 [(0, 1), (1, 1), (2, 1), (3, 1)]] # 长条
41 ]
42
43 root = Tk();
44 root.title('俄罗斯方块')
45
46
47 class App(Frame):
48 def __init__(self, master):
49 Frame.__init__(self)
50 master.bind('<Up>', self.Up)
51 master.bind('<Left>', self.Left)
52 master.bind('<Right>', self.Right)
53 master.bind('<Down>', self.Down)
54
55 master.bind('<space>', self.Space)
56 master.bind('<Control-Shift-Key-F12>', self.Play)
57 master.bind('<Key-P>', self.Pause)
58 master.bind('<Key-S>', self.StartByS)
59
60 # rgb颜色值
61 self.backg = "#%02x%02x%02x" % (120, 150, 30) # 大背景
62 self.frontg = "#%02x%02x%02x" % (40, 120, 150) # 下一个形状颜色
63 self.nextg = "#%02x%02x%02x" % (150, 100, 100) # 小背景
64 self.flashg = "#%02x%02x%02x" % (210, 130, 100) # 炸的颜色
65
66 self.LineDisplay = Label(master, text='Lines: ', bg='black', fg='red')
67 self.Line = Label(master, text='0', bg='black', fg='red')
68 self.ScoreDisplay = Label(master, text='Score: ', bg='black', fg='red')
69 self.Score = Label(master, text='0', bg='black', fg='red')
70 self.SpendTimeDisplay = Label(master, text='Time: ', bg='black', fg='red')
71 self.SpendTime = Label(master, text='0.0', bg='black', fg='red')
72
73 self.LineDisplay.grid(row=HEIGHT - 2, column=WIDTH, columnspan=2)
74 self.Line.grid(row=HEIGHT - 2, column=WIDTH + 2, columnspan=3)
75 self.ScoreDisplay.grid(row=HEIGHT - 1, column=WIDTH, columnspan=2)
76 self.Score.grid(row=HEIGHT - 1, column=WIDTH + 2, columnspan=3)
77 self.SpendTimeDisplay.grid(row=HEIGHT - 4, column=WIDTH, columnspan=2)
78 self.SpendTime.grid(row=HEIGHT - 4, column=WIDTH + 2, columnspan=3)
79
80 self.TotalTime = 0.0
81 self.TotalLine = 0
82 self.TotalScore = 0
83
84 # 游戏结束
85 self.isgameover = FALSE
86 # 暂停
87 self.isPause = FALSE
88 # 开始
89 self.isStart = FALSE
90 self.NextList = [] # 整个小背景
91 self.NextRowList = [] # 一行小背景
92
93 self.px = 0
94 self.py = 0 # 记录方块参考点
95
96 # 渲染小背景
97 r = 0;
98 c = 0
99 for k in range(4 * 4):
100 LN = Label(master, text=' ', bg=str(self.nextg), fg='white', relief=FLAT, bd=3)
101 LN.grid(row=r, column=WIDTH + c, sticky=N + E + S + W)
102 self.NextRowList.append(LN)
103 c = c + 1
104 if c >= 4:
105 r = r + 1;
106 c = 0
107 self.NextList.append(self.NextRowList)
108 self.NextRowList = []
109
110 # 渲染大背景
111 self.BlockList = []
112 self.BlockRowList = []
113 self.LabelList = []
114 self.LabelRowList = []
115 row = 0;
116 col = 0
117 for i in range(HEIGHT * WIDTH):
118 L = Label(master, text=' ', bg=str(self.backg), fg='white', relief=FLAT, bd=4)
119 L.grid(row=row, column=col, sticky=N + E + S + W)
120 L.row = row;
121 L.col = col;
122 L.isactive = PASSIVE
123 self.BlockRowList.append(0); # 大背景每个格子初始化为0值
124 self.LabelRowList.append(L)
125 col = col + 1
126 if col >= WIDTH:
127 row = row + 1;
128 col = 0
129 self.BlockList.append(self.BlockRowList)
130 self.LabelList.append(self.LabelRowList)
131 self.BlockRowList = []
132 self.LabelRowList = []
133
134 # file
135 fw = open('text.txt', 'a')
136 fw.close()
137 hasHead = FALSE
138 f = open('text.txt', 'r')
139 if f.read(5) == 'score':
140 hasHead = TRUE
141 f.close()
142 self.file = open('text.txt', 'a')
143 if hasHead == FALSE:
144 self.file.write('score line time scorePtime linePtime scorePline date/n')
145 self.file.flush()
146
147 self.time = 1000
148 self.OnTimer()
149
150 def __del__(self):
151 # self.file.close()
152 pass
153
154 def Pause(self, event):
155 self.isPause = 1 - self.isPause
156
157 def Up(self, event):
158 BL = self.BlockList # 格子的值
159 LL = self.LabelList # 格子Label
160
161 Moveable = TRUE # 是否可旋转
162
163 # 代码编写开始
164 nowStyle = style[self.xnow][(self.ynow)]
165 newStyle = style[self.xnow][(self.ynow + 1) % 4] # 算出下一俄罗斯方块
166 self.ynow = (self.ynow + 1) % 4 # 此行代码非常重要,否则响应UP时,只能变第一次
167
168 print("nowStyle:" + str(nowStyle) + "=====>>newStyle:" + str(newStyle))
169
170 # 根据现有形状中每个label的坐标计算出旋转后目标坐标(x,y)
171 SourceList = [];
172 DestList = []
173
174 for i in range(4):
175 SourceList.append([nowStyle[i][0] + self.px, nowStyle[i][1] + self.py])
176 x = newStyle[i][0] + self.px
177 y = newStyle[i][1] + self.py
178 DestList.append([x, y])
179
180 if x < 0 or x >= HEIGHT or y < 0 or y >= WIDTH: # or BL[x][y]==1 or LL[x][y].isactive==PASSIVE
181 Moveable = FALSE
182
183 if Moveable == TRUE:
184 for i in range(len(SourceList)):
185 self.Empty(SourceList[i][0], SourceList[i][1])
186 for i in range(len(DestList)):
187 self.Fill(DestList[i][0], DestList[i][1])
188
189 def Left(self, event):
190 BL = self.BlockList;
191 LL = self.LabelList
192 Moveable = TRUE
193 for i in range(HEIGHT):
194 for j in range(WIDTH):
195 if LL[i][j].isactive == ACTIVE and j - 1 < 0: Moveable = FALSE
196 if LL[i][j].isactive == ACTIVE and j - 1 >= 0 and BL[i][j - 1] == 1 and LL[i][
197 j - 1].isactive == PASSIVE: Moveable = FALSE
198 if Moveable == TRUE:
199 self.py -= 1
200 for i in range(HEIGHT):
201 for j in range(WIDTH):
202 if j - 1 >= 0 and LL[i][j].isactive == ACTIVE and BL[i][j - 1] == 0:
203 self.Fill(i, j - 1);
204 self.Empty(i, j)
205
206 def Right(self, event):
207 BL = self.BlockList;
208 LL = self.LabelList
209 Moveable = TRUE
210 for i in range(HEIGHT):
211 for j in range(WIDTH):
212 if LL[i][j].isactive == ACTIVE and j + 1 >= WIDTH: Moveable = FALSE
213 if LL[i][j].isactive == ACTIVE and j + 1 < WIDTH and BL[i][j + 1] == 1 and LL[i][
214 j + 1].isactive == PASSIVE: Moveable = FALSE
215 if Moveable == TRUE:
216 self.py += 1
217 for i in range(HEIGHT - 1, -1, -1):
218 for j in range(WIDTH - 1, -1, -1):
219 if j + 1 < WIDTH and LL[i][j].isactive == ACTIVE and BL[i][j + 1] == 0:
220 self.Fill(i, j + 1);
221 self.Empty(i, j)
222
223 def Down(self, event):
224 BL = self.BlockList;
225 LL = self.LabelList
226 Moveable = TRUE
227 for i in range(HEIGHT):
228 for j in range(WIDTH):
229 if LL[i][j].isactive == ACTIVE and i + 1 >= HEIGHT: Moveable = FALSE
230 if LL[i][j].isactive == ACTIVE and i + 1 < HEIGHT and BL[i + 1][j] == 1 and LL[i + 1][
231 j].isactive == PASSIVE: Moveable = FALSE
232 if Moveable == TRUE and self.isStart:
233 self.px += 1
234 for i in range(HEIGHT - 1, -1, -1):
235 for j in range(WIDTH - 1, -1, -1):
236 if i + 1 < HEIGHT and LL[i][j].isactive == ACTIVE and BL[i + 1][j] == 0:
237 self.Fill(i + 1, j);
238 self.Empty(i, j);
239 if Moveable == FALSE:
240 for i in range(HEIGHT):
241 for j in range(WIDTH):
242 LL[i][j].isactive = PASSIVE
243 self.JudgeLineFill()
244 self.Start()
245 if self.isgameover == TRUE: showinfo('T_T', 'The game is over!');self.Distroy();return FALSE
246 for i in range(4):
247 for j in range(4):
248 self.NextEmpty(i, j)
249 self.Rnd()
250 return Moveable
251
252 def Space(self, event):
253 while 1:
254 if self.Down(0) == FALSE: break
255
256 def OnTimer(self):
257 if self.isStart == TRUE and self.isPause == FALSE:
258 self.TotalTime = self.TotalTime + float(self.time) / 1000
259 self.SpendTime.config(text=str(self.TotalTime))
260
261 if self.isPause == FALSE:
262 self.Down(0)
263 if self.TotalScore >= 1000: self.time = 900
264 if self.TotalScore >= 2000: self.time = 750
265 if self.TotalScore >= 3000: self.time = 600
266 if self.TotalScore >= 4000: self.time = 400
267 self.after(self.time, self.OnTimer) # 随着分数增大,俄罗斯方块下降速度加快
268
269 def JudgeLineFill(self):
270 BL = self.BlockList;
271 LL = self.LabelList
272 count = 0;
273 LineList = []
274 for i in range(WIDTH): LineList.append(1)
275 # display flash
276 for i in range(HEIGHT):
277 if BL[i] == LineList:
278 count = count + 1
279 for k in range(WIDTH):
280 LL[i][k].config(bg=str(self.flashg))
281 LL[i][k].update()
282 if count != 0: self.after(100)
283 # delete block
284 for i in range(HEIGHT):
285 if BL[i] == LineList:
286 # count=count+1
287 for j in range(i, 0, -1):
288 for k in range(WIDTH):
289 BL[j][k] = BL[j - 1][k]
290 LL[j][k]['relief'] = LL[j - 1][k].cget('relief')
291 LL[j][k]['bg'] = LL[j - 1][k].cget('bg')
292 for l in range(WIDTH):
293 BL[0][l] = 0
294 LL[0][l].config(relief=FLAT, bg=str(self.backg))
295 self.TotalLine = self.TotalLine + count
296 if count == 1: self.TotalScore = self.TotalScore + 1 * WIDTH
297 if count == 2: self.TotalScore = self.TotalScore + 3 * WIDTH
298 if count == 3: self.TotalScore = self.TotalScore + 6 * WIDTH
299 if count == 4: self.TotalScore = self.TotalScore + 10 * WIDTH
300 self.Line.config(text=str(self.TotalLine))
301 self.Score.config(text=str(self.TotalScore))
302
303 def Fill(self, i, j):
304 if j < 0: return
305 if self.BlockList[i][j] == 1: self.isgameover = TRUE
306 self.BlockList[i][j] = 1
307 self.LabelList[i][j].isactive = ACTIVE
308 self.LabelList[i][j].config(relief=RAISED, bg=str(self.frontg))
309
310 def Empty(self, i, j):
311 self.BlockList[i][j] = 0
312 self.LabelList[i][j].isactive = PASSIVE
313 self.LabelList[i][j].config(relief=FLAT, bg=str(self.backg))
314
315 def Play(self, event):
316 showinfo('Made in China', '^_^')
317
318 def NextFill(self, i, j):
319 self.NextList[i][j].config(relief=RAISED, bg=str(self.frontg))
320
321 def NextEmpty(self, i, j):
322 self.NextList[i][j].config(relief=FLAT, bg=str(self.nextg))
323
324 def Distroy(self):
325 # save
326 if self.TotalScore != 0:
327 # cehkongfu
328 savestr = '%-9u%-8u%-8.2f%-14.2f%-13.2f%-14.2f%s/n' % (
329 self.TotalScore, self.TotalLine, self.TotalTime
330 , self.TotalScore / self.TotalTime
331 , self.TotalLine / self.TotalTime
332 , float(self.TotalScore) / self.TotalLine
333 , time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
334 self.file.seek(0, 2)
335 self.file.write(savestr)
336 self.file.flush()
337
338 for i in range(HEIGHT):
339 for j in range(WIDTH):
340 self.Empty(i, j)
341 self.TotalLine = 0;
342 self.TotalScore = 0;
343 self.TotalTime = 0.0
344 self.Line.config(text=str(self.TotalLine))
345 self.Score.config(text=str(self.TotalScore))
346 self.SpendTime.config(text=str(self.TotalTime))
347 self.isgameover = FALSE
348 self.isStart = FALSE
349 self.time = 1000
350 for i in range(4):
351 for j in range(4):
352 self.NextEmpty(i, j)
353
354 # 游戏开始方块
355 def Start(self):
356 nextStyle = style[self.x][self.y] # 下一形状
357 self.xnow = self.x
358 self.ynow = self.y # 记录大背景中的方块
359 self.py = random.randint(0, 6)
360 print("给py赋任意值:" + str(self.py))
361 self.px = 0
362 for ii in range(4):
363 self.Fill(int(nextStyle[ii][0]), int(nextStyle[ii][1]) + self.py)
364 self.isStart = TRUE # 游戏开始
365
366 # 预处理方块
367 def Rnd(self):
368 self.x = random.randint(0, 6)
369 self.y = random.randint(0, 3)
370 nextStyle = style[self.x][self.y] # 下一形状
371 for ii in range(4):
372 self.NextFill(int(nextStyle[ii][0]), int(nextStyle[ii][1]))
373
374 # 游戏开始给出一次任意形状的方块
375 def RndFirst(self):
376 self.x = random.randint(0, 6) # 选择第一个方块style
377 self.y = random.randint(0, 3)
378
379 def Show(self):
380 self.file.seek(0)
381 strHeadLine = self.file.readline()
382 dictLine = {}
383 strTotalLine = ''
384 for OneLine in self.file.readlines():
385 temp = int(OneLine[:5])
386 dictLine[temp] = OneLine
387
388 list = sorted(dictLine.items(), key=lambda d: d[0])
389 ii = 0
390 for onerecord in reversed(list):
391 ii = ii + 1
392 if ii < 11:
393 strTotalLine += onerecord[1]
394 showinfo('Ranking', strHeadLine + strTotalLine)
395
396 def StartByS(self, event):
397 self.RndFirst()
398 self.Start()
399 self.Rnd()
400
401
402 def Start():
403 app.RndFirst()
404 app.Start()
405 app.Rnd()
406
407
408 def End():
409 app.Distroy()
410
411
412 def Set():
413 print("设置功能待完善...")
414
415
416 def Show():
417 app.Show()
418
419
420 # 主菜单
421 mainmenu = Menu(root)
422 root['menu'] = mainmenu
423
424 # 二级菜单:game
425 gamemenu = Menu(mainmenu)
426 mainmenu.add_cascade(label='游戏', menu=gamemenu)
427 gamemenu.add_command(label='开始', command=Start)
428 gamemenu.add_command(label='结束', command=End)
429 gamemenu.add_separator()
430 gamemenu.add_command(label='退出', command=root.quit)
431
432 # 二级菜单:set
433 setmenu = Menu(mainmenu)
434 mainmenu.add_cascade(label='设置', menu=setmenu)
435 setmenu.add_command(label='设置', command=Set)
436
437 # 二级菜单:show
438 showmenu = Menu(mainmenu)
439 mainmenu.add_cascade(label='展示', menu=showmenu)
440 showmenu.add_command(label='展示', command=Show)
441
442 # 绑定功能
443
444 app = App(root)
445 # 程序入口
446 root.mainloop()
运行结果: