#!/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', 'BLACK') # block
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
return y, x
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): return showblock(y, x, b, n)
return showblock(ny, nx, b, n)
def deleteblocks():
for j in xrange(height - 1):
for i in xrange(1, width - 1):
if not scrmap[j][i]: break
else:
for y in xrange(j, 0, -1):
for x in xrange(1, width - 1):
scrmap[y][x] = scrmap[y - 1][x]
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)
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])
if not checkspace(y, x, b):
stat = -1
for j in xrange(height - 1):
for i in xrange(1, width - 1):
if scrmap[j][i]: scrmap[j][i] = 9
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:
ny, nx = moveblock(y, x, b, n, 1, 0)
if ny != y:
stat = 1
y, x = ny, nx
else:
stat = 0
deleteblocks()
tp = time.time()
else: break
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)
IyEvdXNyL2Jpbi9lbnYgcHl0aG9uCiMgLSotIGNvZGluZzogdXRmLTggLSotCgppbXBvcnQgY3Vyc2VzCmltcG9ydCBsb2NhbGUKaW1wb3J0IHJhbmRvbQppbXBvcnQgdGltZQppbXBvcnQgY29weQoKd2lkdGgsIGhlaWdodCwgb2ZmeCwgb2ZmeSA9IDIwLCAyNCwgMTgsIDAKY29sb3JzID0gKCdDWUFOJywgJ0JMVUUnLCAnV0hJVEUnLCAjIGZvcmVncm91bmQsIGJhY2tncm91bmQsIHdhbGwKICAnUkVEJywgJ0dSRUVOJywgJ1JFRCcsICdHUkVFTicsICdNQUdFTlRBJywgJ1lFTExPVycsICdDWUFOJywgJ0JMQUNLJykgIyBibG9jawpibG9ja2xpc3QgPSAoCiAgKCgxLCAxKSwgKCcqKiAnLCAnICoqJykpLCAoKDEsIDEpLCAoJyAqKicsICcqKiAnKSksCiAgKCgxLCAyKSwgKCcgIConLCAnKioqJykpLCAoKDAsIDIpLCAoJyoqKicsICcgIConKSksCiAgKCgwLCAyKSwgKCcqKioqJykpLCAoKDEsIDEpLCAoJyAqICcsICcqKionKSksICgoMSwgMSksICgnKionLCAnKionKSkpCmJsb2NrcyA9IFtdCnNjcm1hcCA9IFtbMCBmb3IgaSBpbiB4cmFuZ2Uod2lkdGgpXSBmb3IgaiBpbiB4cmFuZ2UoaGVpZ2h0KV0KCmRlZiBtYWtlY29vcmRzKGJsKToKICByID0gW10KICBmb3IgaywgKG8sIGIpIGluIGVudW1lcmF0ZShibCk6CiAgICBpZiBub3QgaXNpbnN0YW5jZShiLCB0dXBsZSk6IGIgPSAoYiwgKQogICAgcCA9IFtdCiAgICBmb3IgaiwgcyBpbiBlbnVtZXJhdGUoYik6CiAgICAgIGZvciBpLCBjIGluIGVudW1lcmF0ZShzKToKICAgICAgICBpZiBjID09ICcqJzogcC5hcHBlbmQoW2ogLSBvWzBdLCBpIC0gb1sxXV0pCiAgICByLmFwcGVuZChwKQogIHJldHVybiByCgpkZWYgc2hvd2Jsb2NrKHksIHgsIGIsIG4pOgogIGZvciBwIGluIGI6IHNjcm1hcFt5ICsgcFswXV1beCArIHBbMV1dID0gMiArIG4KICByZXR1cm4geSwgeAoKZGVmIGhpZGVibG9jayh5LCB4LCBiKToKICBzaG93YmxvY2soeSwgeCwgYiwgLTIpCgpkZWYgY2hlY2tzcGFjZSh5LCB4LCBiKToKICBmb3IgcCBpbiBiOgogICAgbnksIG54ID0geSArIHBbMF0sIHggKyBwWzFdCiAgICBpZiBueSA8IDAgb3IgbnkgPj0gaGVpZ2h0IC0gMSBvciBueCA8PSAwIG9yIG54ID49IHdpZHRoIC0gMTogcmV0dXJuIEZhbHNlCiAgICBpZiBzY3JtYXBbbnldW254XTogcmV0dXJuIEZhbHNlCiAgcmV0dXJuIFRydWUKCmRlZiByb3RhdGVibG9jayh5LCB4LCBiLCBuLCByKToKICBpZiBuID09IGxlbihibG9ja3MpIC0gMTogcmV0dXJuCiAgaGlkZWJsb2NrKHksIHgsIGIpCiAgZm9yIGkgaW4geHJhbmdlKGxlbihiKSk6IGJbaV0gPSBbciAqIGJbaV1bMV0sIC1yICogYltpXVswXV0KICBpZiBub3QgY2hlY2tzcGFjZSh5LCB4LCBiKToKICAgIGZvciBpIGluIHhyYW5nZShsZW4oYikpOiBiW2ldID0gWy1yICogYltpXVsxXSwgciAqIGJbaV1bMF1dCiAgc2hvd2Jsb2NrKHksIHgsIGIsIG4pCgpkZWYgbW92ZWJsb2NrKHksIHgsIGIsIG4sIGR5LCBkeCk6CiAgaGlkZWJsb2NrKHksIHgsIGIpCiAgbnksIG54ID0geSArIGR5LCB4ICsgZHgKICBpZiBub3QgY2hlY2tzcGFjZShueSwgbngsIGIpOiByZXR1cm4gc2hvd2Jsb2NrKHksIHgsIGIsIG4pCiAgcmV0dXJuIHNob3dibG9jayhueSwgbngsIGIsIG4pCgpkZWYgZGVsZXRlYmxvY2tzKCk6CiAgZm9yIGogaW4geHJhbmdlKGhlaWdodCAtIDEpOgogICAgZm9yIGkgaW4geHJhbmdlKDEsIHdpZHRoIC0gMSk6CiAgICAgIGlmIG5vdCBzY3JtYXBbal1baV06IGJyZWFrCiAgICBlbHNlOgogICAgICBmb3IgeSBpbiB4cmFuZ2UoaiwgMCwgLTEpOgogICAgICAgIGZvciB4IGluIHhyYW5nZSgxLCB3aWR0aCAtIDEpOgogICAgICAgICAgc2NybWFwW3ldW3hdID0gc2NybWFwW3kgLSAxXVt4XQoKZGVmIGRpc3BsYXkodik6CiAgZm9yIGogaW4geHJhbmdlKGhlaWdodCk6CiAgICBmb3IgaSBpbiB4cmFuZ2Uod2lkdGgpOgogICAgICB2LmFkZHN0cihqLCBpICogMiwgJyAgJywgY3Vyc2VzLmNvbG9yX3BhaXIoc2NybWFwW2pdW2ldICsgMSkpCiAgdCA9IHRpbWUudGltZSgpCiAgdi5hZGRzdHIoMCwgOCwKICAgICclcy4lMDNkJyAlICh0aW1lLnN0cmZ0aW1lKCclWS0lbS0lZCAlSDolTTolUycsIHRpbWUubG9jYWx0aW1lKHQpKSwKICAgICAgaW50KHQgKiAxMDAwKSAlIDEwMDApLAogICAgY3Vyc2VzLmNvbG9yX3BhaXIoMSkpCiAgdi5yZWZyZXNoKDAsIDAsIG9mZnksIG9mZngsIG9mZnkgKyBoZWlnaHQsIG9mZnggKyB3aWR0aCAqIDIpCgpkZWYgbWFpbihzdGRzY3IpOgogIGxvY2FsZS5zZXRsb2NhbGUobG9jYWxlLkxDX0FMTCwgJycpCiAgZW5jID0gbG9jYWxlLmdldHByZWZlcnJlZGVuY29kaW5nKCkKICB3ID0gY3Vyc2VzLmluaXRzY3IoKQogIGN1cnNlcy5jdXJzX3NldCgwKQogIGN1cnNlcy5ub2VjaG8oKQogIHcua2V5cGFkKDEpCiAgY3Vyc2VzLmNicmVhaygpCiAgY3Vyc2VzLnN0YXJ0X2NvbG9yKCkKICBmb3IgaSwgYyBpbiBlbnVtZXJhdGUoY29sb3JzKToKICAgIGlmIGk6IGN1cnNlcy5pbml0X3BhaXIoaSwgZ2V0YXR0cihjdXJzZXMsICdDT0xPUl8lcycgJSBjb2xvcnNbMF0pICsgOCwKICAgICAgZ2V0YXR0cihjdXJzZXMsICdDT0xPUl8lcycgJSBjKSArICgwIGlmIGkgPT0gMSBlbHNlIDgpKQogIHYgPSBjdXJzZXMubmV3cGFkKGhlaWdodCArIDEsICh3aWR0aCArIDEpICogMikgIyBkb3VibGUgYnVmZmVyaW5nCiAgdi5rZXlwYWQoMSkKICBibG9ja3MgPSBtYWtlY29vcmRzKGJsb2NrbGlzdCkKICBmb3IgaiBpbiB4cmFuZ2UoaGVpZ2h0KToKICAgIGlmIGogPCBoZWlnaHQgLSAxOgogICAgICBzY3JtYXBbal1bMF0gPSBzY3JtYXBbal1bd2lkdGggLSAxXSA9IDEKICAgIGVsc2U6CiAgICAgIGZvciBpIGluIHhyYW5nZSh3aWR0aCk6IHNjcm1hcFtqXVtpXSA9IDEKICByYW5kb20uc2VlZCgpCiAgc3BlZWQsIHRwLCBzdGF0LCB5LCB4LCBuLCBiID0gMC41LCAwLCAwLCAzLCAxMCwgLTEsIFtdCiAgd2hpbGUgVHJ1ZToKICAgIGN1cnNlcy5mbHVzaGlucCgpICMgY2xlYXIga2V5IGJ1ZmZlcgogICAgaWYgc3RhdCA9PSAwOgogICAgICBzdGF0ID0gMQogICAgICB5LCB4ID0gMywgMTAKICAgICAgbiA9IHJhbmRvbS5yYW5kaW50KDAsIGxlbihibG9ja3MpIC0gMSkKICAgICAgYiA9IGNvcHkuZGVlcGNvcHkoYmxvY2tzW25dKQogICAgICBpZiBub3QgY2hlY2tzcGFjZSh5LCB4LCBiKToKICAgICAgICBzdGF0ID0gLTEKICAgICAgICBmb3IgaiBpbiB4cmFuZ2UoaGVpZ2h0IC0gMSk6CiAgICAgICAgICBmb3IgaSBpbiB4cmFuZ2UoMSwgd2lkdGggLSAxKToKICAgICAgICAgICAgaWYgc2NybWFwW2pdW2ldOiBzY3JtYXBbal1baV0gPSA5CiAgICAgIHNob3dibG9jayh5LCB4LCBiLCBuKQogICAgICB0cCA9IHRpbWUudGltZSgpCiAgICBlbGlmIHN0YXQgPT0gMToKICAgICAgaWYgdGltZS50aW1lKCkgLSB0cCA+PSBzcGVlZDoKICAgICAgICBueSwgbnggPSBtb3ZlYmxvY2soeSwgeCwgYiwgbiwgMSwgMCkKICAgICAgICBpZiBueSAhPSB5OiB5LCB4ID0gbnksIG54CiAgICAgICAgZWxzZTogc3RhdCA9IDIKICAgICAgICB0cCA9IHRpbWUudGltZSgpCiAgICBlbGlmIHN0YXQgPT0gMjoKICAgICAgaWYgdGltZS50aW1lKCkgLSB0cCA+PSBzcGVlZDoKICAgICAgICBueSwgbnggPSBtb3ZlYmxvY2soeSwgeCwgYiwgbiwgMSwgMCkKICAgICAgICBpZiBueSAhPSB5OgogICAgICAgICAgc3RhdCA9IDEKICAgICAgICAgIHksIHggPSBueSwgbngKICAgICAgICBlbHNlOgogICAgICAgICAgc3RhdCA9IDAKICAgICAgICAgIGRlbGV0ZWJsb2NrcygpCiAgICAgICAgdHAgPSB0aW1lLnRpbWUoKQogICAgZWxzZTogYnJlYWsKICAgIGRpc3BsYXkodikKICAgIHYudGltZW91dCg1MCkKICAgIGMgPSB2LmdldGNoKCkKICAgIGlmIGMgPT0gLTE6IHBhc3MKICAgIGVsaWYgYyA9PSBvcmQoJ3EnKTogYnJlYWsKICAgIGVsaWYgYyA9PSBvcmQoJ3onKTogcm90YXRlYmxvY2soeSwgeCwgYiwgbiwgLTEpICMgY291bnRlciBjbG9ja3dpc2UKICAgIGVsaWYgYyA9PSBvcmQoJ3gnKTogcm90YXRlYmxvY2soeSwgeCwgYiwgbiwgMSkgIyBjbG9ja3dpc2UKICAgIGVsaWYgYyA9PSBjdXJzZXMuS0VZX1VQOiByb3RhdGVibG9jayh5LCB4LCBiLCBuLCAxKSAjIGNsb2Nrd2lzZQogICAgZWxpZiBjID09IGN1cnNlcy5LRVlfTEVGVDogeSwgeCA9IG1vdmVibG9jayh5LCB4LCBiLCBuLCAwLCAtMSkKICAgIGVsaWYgYyA9PSBjdXJzZXMuS0VZX1JJR0hUOiB5LCB4ID0gbW92ZWJsb2NrKHksIHgsIGIsIG4sIDAsIDEpCiAgICBlbGlmIGMgPT0gY3Vyc2VzLktFWV9ET1dOOiB5LCB4ID0gbW92ZWJsb2NrKHksIHgsIGIsIG4sIDEsIDApCiAgICBlbGlmIGMgPT0gb3JkKCcgJyk6IHksIHggPSBtb3ZlYmxvY2soeSwgeCwgYiwgbiwgMywgMCkKICAgIGVsc2U6IHBhc3MKICB2LmtleXBhZCgwKQogIGN1cnNlcy5ub2NicmVhaygpCiAgdy5rZXlwYWQoMCkKICBjdXJzZXMuZWNobygpCiAgY3Vyc2VzLmN1cnNfc2V0KDEpCiAgY3Vyc2VzLmVuZHdpbigpCgppZiBfX25hbWVfXyA9PSAnX19tYWluX18nOgogIGN1cnNlcy53cmFwcGVyKG1haW4p