#!/usr/bin/env python
# -*- coding: utf-8 -*-
import curses
import locale
import random
import time
import copy
width, height, offx, offy = 20, 24, 18, 0
colors = ('CYAN', 'BLUE', 'WHITE', # foreground, background, wall
'RED', 'GREEN', 'RED', 'GREEN', 'MAGENTA', 'YELLOW', 'CYAN') # tetris
blocklist = (
((1, 1), ('** ', ' **')), ((1, 1), (' **', '** ')),
((1, 2), (' *', '***')), ((0, 2), ('***', ' *')),
((0, 2), ('****')), ((1, 1), (' * ', '***')), ((1, 1), ('**', '**')))
blocks = []
scrmap = [[0 for i in xrange(width)] for j in xrange(height)]
def makecoords(bl):
r = []
for k, (o, b) in enumerate(bl):
if not isinstance(b, tuple): b = (b, )
p = []
for j, s in enumerate(b):
for i, c in enumerate(s):
if c == '*': p.append([j - o[0], i - o[1]])
r.append(p)
return r
def showblock(y, x, b, n):
for p in b: scrmap[y + p[0]][x + p[1]] = 2 + n
def hideblock(y, x, b):
showblock(y, x, b, -2)
def checkspace(y, x, b):
for p in b:
ny, nx = y + p[0], x + p[1]
if ny < 0 or ny >= height - 1 or nx <= 0 or nx >= width - 1: return False
if scrmap[ny][nx]: return False
return True
def rotateblock(y, x, b, n, r):
if n == len(blocks) - 1: return
hideblock(y, x, b)
for i in xrange(len(b)): b[i] = [r * b[i][1], -r * b[i][0]]
if not checkspace(y, x, b):
for i in xrange(len(b)): b[i] = [-r * b[i][1], r * b[i][0]]
showblock(y, x, b, n)
def moveblock(y, x, b, n, dy, dx):
hideblock(y, x, b)
ny, nx = y + dy, x + dx
if not checkspace(ny, nx, b):
showblock(y, x, b, n)
return y, x
showblock(ny, nx, b, n)
return ny, nx
def display(v):
for j in xrange(height):
for i in xrange(width):
v.addstr(j, i * 2, ' ', curses.color_pair(scrmap[j][i] + 1))
t = time.time()
v.addstr(0, 8,
'%s.%03d' % (time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(t)),
int(t * 1000) % 1000),
curses.color_pair(1))
v.refresh(0, 0, offy, offx, offy + height, offx + width * 2)
def main(stdscr):
locale.setlocale(locale.LC_ALL, '')
enc = locale.getpreferredencoding()
w = curses.initscr()
curses.curs_set(0)
curses.noecho()
w.keypad(1)
curses.cbreak()
curses.start_color()
for i, c in enumerate(colors):
if i: curses.init_pair(i, getattr(curses, 'COLOR_%s' % colors[0]) + 8,
getattr(curses, 'COLOR_%s' % c) + (0 if i == 1 else 8))
v = curses.newpad(height + 1, (width + 1) * 2) # double buffering
v.keypad(1)
global blocks, scrmap
blocks = makecoords(blocklist)
for j in xrange(height):
if j < height - 1:
scrmap[j][0] = scrmap[j][width - 1] = 1
else:
for i in xrange(width): scrmap[j][i] = 1
random.seed()
speed, tp, stat, y, x, n, b = 0.5, 0, 0, 3, 10, -1, []
while True:
curses.flushinp() # clear key buffer
if stat == 0:
stat += 1
y, x = 3, 10
n = random.randint(0, len(blocks) - 1)
b = copy.deepcopy(blocks[n])
showblock(y, x, b, n)
tp = time.time()
elif stat == 1:
if time.time() - tp >= speed:
ny, nx = moveblock(y, x, b, n, 1, 0)
if ny != y: y, x = ny, nx
else: stat = 2
tp = time.time()
elif stat == 2:
if time.time() - tp >= speed:
stat = 0
tp = time.time()
display(v)
v.timeout(50)
c = v.getch()
if c == -1: pass
elif c == ord('q'): break
elif c == ord('z'): rotateblock(y, x, b, n, -1) # counter clockwise
elif c == ord('x'): rotateblock(y, x, b, n, 1) # clockwise
elif c == curses.KEY_UP: rotateblock(y, x, b, n, 1) # clockwise
elif c == curses.KEY_LEFT: y, x = moveblock(y, x, b, n, 0, -1)
elif c == curses.KEY_RIGHT: y, x = moveblock(y, x, b, n, 0, 1)
elif c == curses.KEY_DOWN: y, x = moveblock(y, x, b, n, 1, 0)
elif c == ord(' '): y, x = moveblock(y, x, b, n, 3, 0)
else: pass
v.keypad(0)
curses.nocbreak()
w.keypad(0)
curses.echo()
curses.curs_set(1)
curses.endwin()
if __name__ == '__main__':
curses.wrapper(main)
IyEvdXNyL2Jpbi9lbnYgcHl0aG9uCiMgLSotIGNvZGluZzogdXRmLTggLSotCgppbXBvcnQgY3Vyc2VzCmltcG9ydCBsb2NhbGUKaW1wb3J0IHJhbmRvbQppbXBvcnQgdGltZQppbXBvcnQgY29weQoKd2lkdGgsIGhlaWdodCwgb2ZmeCwgb2ZmeSA9IDIwLCAyNCwgMTgsIDAKY29sb3JzID0gKCdDWUFOJywgJ0JMVUUnLCAnV0hJVEUnLCAjIGZvcmVncm91bmQsIGJhY2tncm91bmQsIHdhbGwKICAnUkVEJywgJ0dSRUVOJywgJ1JFRCcsICdHUkVFTicsICdNQUdFTlRBJywgJ1lFTExPVycsICdDWUFOJykgIyB0ZXRyaXMKYmxvY2tsaXN0ID0gKAogICgoMSwgMSksICgnKiogJywgJyAqKicpKSwgKCgxLCAxKSwgKCcgKionLCAnKiogJykpLAogICgoMSwgMiksICgnICAqJywgJyoqKicpKSwgKCgwLCAyKSwgKCcqKionLCAnICAqJykpLAogICgoMCwgMiksICgnKioqKicpKSwgKCgxLCAxKSwgKCcgKiAnLCAnKioqJykpLCAoKDEsIDEpLCAoJyoqJywgJyoqJykpKQpibG9ja3MgPSBbXQpzY3JtYXAgPSBbWzAgZm9yIGkgaW4geHJhbmdlKHdpZHRoKV0gZm9yIGogaW4geHJhbmdlKGhlaWdodCldCgpkZWYgbWFrZWNvb3JkcyhibCk6CiAgciA9IFtdCiAgZm9yIGssIChvLCBiKSBpbiBlbnVtZXJhdGUoYmwpOgogICAgaWYgbm90IGlzaW5zdGFuY2UoYiwgdHVwbGUpOiBiID0gKGIsICkKICAgIHAgPSBbXQogICAgZm9yIGosIHMgaW4gZW51bWVyYXRlKGIpOgogICAgICBmb3IgaSwgYyBpbiBlbnVtZXJhdGUocyk6CiAgICAgICAgaWYgYyA9PSAnKic6IHAuYXBwZW5kKFtqIC0gb1swXSwgaSAtIG9bMV1dKQogICAgci5hcHBlbmQocCkKICByZXR1cm4gcgoKZGVmIHNob3dibG9jayh5LCB4LCBiLCBuKToKICBmb3IgcCBpbiBiOiBzY3JtYXBbeSArIHBbMF1dW3ggKyBwWzFdXSA9IDIgKyBuCgpkZWYgaGlkZWJsb2NrKHksIHgsIGIpOgogIHNob3dibG9jayh5LCB4LCBiLCAtMikKCmRlZiBjaGVja3NwYWNlKHksIHgsIGIpOgogIGZvciBwIGluIGI6CiAgICBueSwgbnggPSB5ICsgcFswXSwgeCArIHBbMV0KICAgIGlmIG55IDwgMCBvciBueSA+PSBoZWlnaHQgLSAxIG9yIG54IDw9IDAgb3IgbnggPj0gd2lkdGggLSAxOiByZXR1cm4gRmFsc2UKICAgIGlmIHNjcm1hcFtueV1bbnhdOiByZXR1cm4gRmFsc2UKICByZXR1cm4gVHJ1ZQoKZGVmIHJvdGF0ZWJsb2NrKHksIHgsIGIsIG4sIHIpOgogIGlmIG4gPT0gbGVuKGJsb2NrcykgLSAxOiByZXR1cm4KICBoaWRlYmxvY2soeSwgeCwgYikKICBmb3IgaSBpbiB4cmFuZ2UobGVuKGIpKTogYltpXSA9IFtyICogYltpXVsxXSwgLXIgKiBiW2ldWzBdXQogIGlmIG5vdCBjaGVja3NwYWNlKHksIHgsIGIpOgogICAgZm9yIGkgaW4geHJhbmdlKGxlbihiKSk6IGJbaV0gPSBbLXIgKiBiW2ldWzFdLCByICogYltpXVswXV0KICBzaG93YmxvY2soeSwgeCwgYiwgbikKCmRlZiBtb3ZlYmxvY2soeSwgeCwgYiwgbiwgZHksIGR4KToKICBoaWRlYmxvY2soeSwgeCwgYikKICBueSwgbnggPSB5ICsgZHksIHggKyBkeAogIGlmIG5vdCBjaGVja3NwYWNlKG55LCBueCwgYik6CiAgICBzaG93YmxvY2soeSwgeCwgYiwgbikKICAgIHJldHVybiB5LCB4CiAgc2hvd2Jsb2NrKG55LCBueCwgYiwgbikKICByZXR1cm4gbnksIG54CgpkZWYgZGlzcGxheSh2KToKICBmb3IgaiBpbiB4cmFuZ2UoaGVpZ2h0KToKICAgIGZvciBpIGluIHhyYW5nZSh3aWR0aCk6CiAgICAgIHYuYWRkc3RyKGosIGkgKiAyLCAnICAnLCBjdXJzZXMuY29sb3JfcGFpcihzY3JtYXBbal1baV0gKyAxKSkKICB0ID0gdGltZS50aW1lKCkKICB2LmFkZHN0cigwLCA4LAogICAgJyVzLiUwM2QnICUgKHRpbWUuc3RyZnRpbWUoJyVZLSVtLSVkICVIOiVNOiVTJywgdGltZS5sb2NhbHRpbWUodCkpLAogICAgICBpbnQodCAqIDEwMDApICUgMTAwMCksCiAgICBjdXJzZXMuY29sb3JfcGFpcigxKSkKICB2LnJlZnJlc2goMCwgMCwgb2ZmeSwgb2ZmeCwgb2ZmeSArIGhlaWdodCwgb2ZmeCArIHdpZHRoICogMikKCmRlZiBtYWluKHN0ZHNjcik6CiAgbG9jYWxlLnNldGxvY2FsZShsb2NhbGUuTENfQUxMLCAnJykKICBlbmMgPSBsb2NhbGUuZ2V0cHJlZmVycmVkZW5jb2RpbmcoKQogIHcgPSBjdXJzZXMuaW5pdHNjcigpCiAgY3Vyc2VzLmN1cnNfc2V0KDApCiAgY3Vyc2VzLm5vZWNobygpCiAgdy5rZXlwYWQoMSkKICBjdXJzZXMuY2JyZWFrKCkKICBjdXJzZXMuc3RhcnRfY29sb3IoKQogIGZvciBpLCBjIGluIGVudW1lcmF0ZShjb2xvcnMpOgogICAgaWYgaTogY3Vyc2VzLmluaXRfcGFpcihpLCBnZXRhdHRyKGN1cnNlcywgJ0NPTE9SXyVzJyAlIGNvbG9yc1swXSkgKyA4LAogICAgICBnZXRhdHRyKGN1cnNlcywgJ0NPTE9SXyVzJyAlIGMpICsgKDAgaWYgaSA9PSAxIGVsc2UgOCkpCiAgdiA9IGN1cnNlcy5uZXdwYWQoaGVpZ2h0ICsgMSwgKHdpZHRoICsgMSkgKiAyKSAjIGRvdWJsZSBidWZmZXJpbmcKICB2LmtleXBhZCgxKQogIGdsb2JhbCBibG9ja3MsIHNjcm1hcAogIGJsb2NrcyA9IG1ha2Vjb29yZHMoYmxvY2tsaXN0KQogIGZvciBqIGluIHhyYW5nZShoZWlnaHQpOgogICAgaWYgaiA8IGhlaWdodCAtIDE6CiAgICAgIHNjcm1hcFtqXVswXSA9IHNjcm1hcFtqXVt3aWR0aCAtIDFdID0gMQogICAgZWxzZToKICAgICAgZm9yIGkgaW4geHJhbmdlKHdpZHRoKTogc2NybWFwW2pdW2ldID0gMQogIHJhbmRvbS5zZWVkKCkKICBzcGVlZCwgdHAsIHN0YXQsIHksIHgsIG4sIGIgPSAwLjUsIDAsIDAsIDMsIDEwLCAtMSwgW10KICB3aGlsZSBUcnVlOgogICAgY3Vyc2VzLmZsdXNoaW5wKCkgIyBjbGVhciBrZXkgYnVmZmVyCiAgICBpZiBzdGF0ID09IDA6CiAgICAgIHN0YXQgKz0gMQogICAgICB5LCB4ID0gMywgMTAKICAgICAgbiA9IHJhbmRvbS5yYW5kaW50KDAsIGxlbihibG9ja3MpIC0gMSkKICAgICAgYiA9IGNvcHkuZGVlcGNvcHkoYmxvY2tzW25dKQogICAgICBzaG93YmxvY2soeSwgeCwgYiwgbikKICAgICAgdHAgPSB0aW1lLnRpbWUoKQogICAgZWxpZiBzdGF0ID09IDE6CiAgICAgIGlmIHRpbWUudGltZSgpIC0gdHAgPj0gc3BlZWQ6CiAgICAgICAgbnksIG54ID0gbW92ZWJsb2NrKHksIHgsIGIsIG4sIDEsIDApCiAgICAgICAgaWYgbnkgIT0geTogeSwgeCA9IG55LCBueAogICAgICAgIGVsc2U6IHN0YXQgPSAyCiAgICAgICAgdHAgPSB0aW1lLnRpbWUoKQogICAgZWxpZiBzdGF0ID09IDI6CiAgICAgIGlmIHRpbWUudGltZSgpIC0gdHAgPj0gc3BlZWQ6CiAgICAgICAgc3RhdCA9IDAKICAgICAgICB0cCA9IHRpbWUudGltZSgpCiAgICBkaXNwbGF5KHYpCiAgICB2LnRpbWVvdXQoNTApCiAgICBjID0gdi5nZXRjaCgpCiAgICBpZiBjID09IC0xOiBwYXNzCiAgICBlbGlmIGMgPT0gb3JkKCdxJyk6IGJyZWFrCiAgICBlbGlmIGMgPT0gb3JkKCd6Jyk6IHJvdGF0ZWJsb2NrKHksIHgsIGIsIG4sIC0xKSAjIGNvdW50ZXIgY2xvY2t3aXNlCiAgICBlbGlmIGMgPT0gb3JkKCd4Jyk6IHJvdGF0ZWJsb2NrKHksIHgsIGIsIG4sIDEpICMgY2xvY2t3aXNlCiAgICBlbGlmIGMgPT0gY3Vyc2VzLktFWV9VUDogcm90YXRlYmxvY2soeSwgeCwgYiwgbiwgMSkgIyBjbG9ja3dpc2UKICAgIGVsaWYgYyA9PSBjdXJzZXMuS0VZX0xFRlQ6IHksIHggPSBtb3ZlYmxvY2soeSwgeCwgYiwgbiwgMCwgLTEpCiAgICBlbGlmIGMgPT0gY3Vyc2VzLktFWV9SSUdIVDogeSwgeCA9IG1vdmVibG9jayh5LCB4LCBiLCBuLCAwLCAxKQogICAgZWxpZiBjID09IGN1cnNlcy5LRVlfRE9XTjogeSwgeCA9IG1vdmVibG9jayh5LCB4LCBiLCBuLCAxLCAwKQogICAgZWxpZiBjID09IG9yZCgnICcpOiB5LCB4ID0gbW92ZWJsb2NrKHksIHgsIGIsIG4sIDMsIDApCiAgICBlbHNlOiBwYXNzCiAgdi5rZXlwYWQoMCkKICBjdXJzZXMubm9jYnJlYWsoKQogIHcua2V5cGFkKDApCiAgY3Vyc2VzLmVjaG8oKQogIGN1cnNlcy5jdXJzX3NldCgxKQogIGN1cnNlcy5lbmR3aW4oKQoKaWYgX19uYW1lX18gPT0gJ19fbWFpbl9fJzoKICBjdXJzZXMud3JhcHBlcihtYWluKQ==