Created
September 2, 2012 08:50
-
-
Save ccc-larc/3596027 to your computer and use it in GitHub Desktop.
tetris-visual.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding=utf8 -*- | |
''' | |
* 參考 weijr 老師的 tetris in tkinter -- ``http://weijr-note.blogspot.tw/2007/04/tetris-program-in-lines.html`` | |
* full documents of Vpython -- ``http://vpython.org/contents/docs/visual/index.html`` | |
''' | |
# update: 2012.07.29 完成大部分功能 | |
# update: 2012.09.01 加入暫停與 hjkl 方向鍵控制 (Vim 操作練習?!) | |
from __future__ import division | |
from random import choice | |
import time | |
from visual import * | |
any = __builtins__.any | |
#=============================================================================== | |
# 設定值 | |
#=============================================================================== | |
BOARD_WIDTH = 10 | |
BOARD_HEIGHT = 20 | |
score, R, N, T = 0, 0.9, 100, 0.5 | |
scene.center = ((BOARD_WIDTH - 1) / 2, (BOARD_HEIGHT - 1) / 2) | |
scene.width = BOARD_WIDTH * 35 | |
scene.height = BOARD_HEIGHT * 35 | |
scene.forward = (0, 0, +1) | |
scene.up = 0, -1, 0 | |
scene.lights = \ | |
[distant_light(direction=(0.22, 0.44, -0.88), color=color.gray(0.8)), | |
distant_light(direction=(-0.88, -0.22, +0.44), color=color.gray(0.3))] | |
scene.autoscale = False | |
#scene.show_rendertime = 1 | |
scene.pause = False | |
blk = { 0x0f:(0, 0, 1), 0x2e:(0, 1, 1), 0x27:(0, 1, 0), 0x47:(1, 0, 1), 0xC6:(1, 0, 0), 0x6C:(1, 1, 0), 0x66:(1, 0.6, 0) } | |
new_piece = lambda pc: ([((z >> 2) + 1, z & 3) for z in xrange(16) if (pc >> z) & 1], 3, -2, pc) | |
new_focus = lambda piece, pc: [box(pos=p, color=blk[pc], size=(R, R, R)) for p in piece] | |
points(pos=[(x, y) for x in xrange(BOARD_WIDTH) for y in xrange(BOARD_HEIGHT)]) | |
#=============================================================================== | |
# score | |
#=============================================================================== | |
def reset_score(): | |
global score | |
score = 0 | |
def get_score(): | |
return score | |
def incr_score(value): | |
global score | |
assert isinstance(value, int), value | |
score += value | |
#=============================================================================== | |
# collide | |
#=============================================================================== | |
""" | |
collide = lambda piece, px, py: [1 for (i, j) in piece if board[j + py][i + px]] #是否碰撞 | |
""" | |
def collide(piece, px, py): | |
assert isinstance(px, int), px | |
assert isinstance(py, int), py | |
for (i, j) in piece: | |
x = px + i | |
y = py + j | |
if not (0 <= x < BOARD_WIDTH): | |
return True | |
if y >= BOARD_HEIGHT: | |
return True | |
if y < 0: | |
continue | |
if board[y][x]: | |
return True | |
return False | |
#=============================================================================== | |
# board | |
#=============================================================================== | |
def new_board_lines(num): | |
assert isinstance(num, int), num | |
return [[0] * BOARD_WIDTH for j in range(num)] | |
board = new_board_lines(BOARD_HEIGHT) | |
def place_piece(piece, px, py, pc): | |
""" | |
for i, j in piece: | |
board[j + py][i + px] = pc | |
""" | |
for i, j in piece: | |
x = px + i | |
y = py + j | |
if not (0 <= x < BOARD_WIDTH): | |
continue | |
if not (0 <= y < BOARD_HEIGHT): | |
continue | |
board[y][x] = pc | |
def clear_complete_lines(): | |
global board | |
nb = [] | |
fn = [] | |
for j, line in enumerate(board): | |
if 0 in line: | |
nb.append(line) | |
else: | |
fn.append(j) | |
if fn: | |
board = new_board_lines(len(fn)) + nb | |
# 消去 | |
d_line = [obj for obj in scene.objects if type(obj) is box and obj.y in fn] | |
for _ in xrange(10): | |
rate(20) | |
for obj in d_line: | |
obj.opacity -= 1 / 10 | |
for obj in d_line: | |
obj.visible = 0 | |
# 下降 | |
for n in fn: | |
for obj in (obj for obj in scene.objects if type(obj) is box and obj.y < n): | |
obj.y += 1 | |
return fn | |
#=============================================================================== | |
# | |
#=============================================================================== | |
def switch_pause(): | |
scene.pause = (not scene.pause) | |
def game_over(): | |
exit("GAME OVER: score %i" % get_score()) # game over 的狀況 | |
#=============================================================================== | |
# tick | |
#=============================================================================== | |
def tick(t_stamp=[time.time(), 0]): | |
global piece, px, py, pc, focus | |
# 自動處理 | |
t_stamp[1] = time.time() | |
if t_stamp[1] - t_stamp[0] > T and not scene.pause: | |
if not collide(piece, px, py + 1): #自動落下 | |
py += 1 | |
elif py < 0: #Game over | |
game_over() | |
return | |
else: #到底 | |
place_piece(piece, px, py, pc) | |
# 檢查消去 | |
fn = clear_complete_lines() | |
if fn: | |
incr_score(2 ** len(fn)) | |
piece, px, py, pc = new_piece(choice(blk.keys())) | |
focus = new_focus(piece, pc) | |
t_stamp[0] = t_stamp[1] | |
# 鍵盤控制 | |
if scene.kb.keys: | |
key = scene.kb.getkey() | |
if key in ('down', 'j'): | |
py = (j for j in xrange(py, BOARD_HEIGHT) if collide(piece, px, j + 1)).next()# 找出第一個會碰撞的 | |
elif key in ('up', 'k'): | |
npiece = [(j, 3 - i) for (i, j) in piece] | |
if not collide(npiece, px, py): piece = npiece | |
elif key in ('left', 'right', 'h', 'H', 'l', 'L'): | |
npx = px + (-1 if key in ('left', 'h', 'H') else 1) | |
if not collide(piece, npx, py): px = npx | |
elif key == 'p': | |
scene.pause = switch_pause() | |
# 方塊位置變更 | |
for i in xrange(4): focus[i].pos = vector(px, py) + piece[i] | |
# mainloop | |
piece, px, py, pc = new_piece(choice(blk.keys())) | |
focus = new_focus(piece, pc) | |
while 1: | |
rate(N) | |
tick() | |
#### Debug 用的工具 | |
#print [py+y for x,y in piece if 0 not in board[py+y]] | |
#fill_line = {py+y for x,y in piece if 0 not in board[py+y]} | |
#for line in board: print line, 0 not in line | |
#from arrow import draw_arrow ;draw_arrow(AL=BH) | |
#for y in xrange(BH): print '%2d:'%y+''.join('%5d'%board[y][x] for x in xrange(BW)) #for debug |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment