俄罗斯方块

修改处:添加了 开始 和 设置 选项

代码

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()
原文地址:https://www.cnblogs.com/syf0105/p/14057205.html