Seite 1 von 1

Tetris Programm erklären

Verfasst: Montag 3. Februar 2014, 21:40
von darktrym
Kann mir erklären wie das Programm funktioniert. Ich blick' irgendwie nicht durch.

Code: Alles auswählen

#!/usr/bin/env python
import curses
from random import randrange 
curses.initscr()
curses.curs_set(0)
win = curses.newwin(18,18,0,0)
win.keypad(1) 
win.nodelay(1)
f = [ [0x315,0x4cd,0x13f,0xc47],[0x31d,0x4cf,0x137,0xc45],[0x374,0x374,0x374,0x374],[0x741,0x51c,0xdc3,0xf34],[0xfc1,0x73c,0x543,0xd14],[0x311,0x4cc,0x133,0xc44],[0xc34,0x341,0x41c,0x1c3]]

def chkFig(crds, s): 
    chk = all([win.inch(c[1],c[0]) & 255 == 32 for c in crds])
    for c in crds: 
        win.addch(c[1],c[0],'X' if s == 1 else 32) if ((chk and s == 1) or s == 0) else None
    return True if s == 0 else chk

def putFig(FP, s): 
    c = lambda el,n: -1 if (n >> el & 3) == 3 else 1 if (n >> el & 3) == 1 else 0; pos = [ c(i ,f[ FP[3] ][ FP[2] ] ) for i in range(0,15,2)[::-1]]
    return chkFig([map(lambda x,y: x+y, FP[0:2]*4,pos)[i-2:i] for i in range(2,9,2)],s)

def MoveFig(FP, key, d): 
    '''figure moving function'''
    FP[0] = FP[0] - d if key == curses.KEY_LEFT else FP[0] + d if key == curses.KEY_RIGHT else FP[0]; FP[1] = FP[1] + d if key in [curses.KEY_DOWN, -1] else FP[1]  
    if key == curses.KEY_UP: 
        FP[2] = 0 if FP[2] + d > 3 else 3 if FP[2] + d < 0 else FP[2] + d 

def chkBoard(score): 
    '''kill full lines and increase score'''
    for i in range(17):
        if all([chr(win.inch(i,x)) == 'X' for x in range(1, 17)]):
            win.deleteln()
            win.move(1,1)
            win.insertln() 
            score += 1
            if score % 10 == 0: 
                win.timeout(300 - (score * 2))
    return score

FigPos = [8,3,0,randrange(0,6,1)]
score = putFig(FigPos,1) ^ 1
win.timeout(300) 

while True:
    win.border('|','|','-','-','+','+','+','+')
    win.addstr(0,2,' Score: %d ' % score)
    key = win.getch()
    if key == 27: 
        break
    putFig(FigPos,0)
    MoveFig(FigPos,key,1)
    if not putFig(FigPos,1):
        MoveFig(FigPos,key, -1)
        putFig(FigPos,1)
        if FigPos[1]==3: 
            break
        if key in [curses.KEY_DOWN, -1]:
            score = chkBoard(score)
            FigPos = [8,3,0,randrange(0,6,1)]
            putFig(FigPos,1)
curses.endwin() 

Re: Tetris Programm erklären

Verfasst: Montag 3. Februar 2014, 21:55
von BlackJack
@darktrym: Ich glaube Lesbarkeit und Verständlichkeit waren nicht die Topprioritäten bei diesem Quelltext. ;-)

Ich würde anfangen das lesbarer umzuschreiben um es zu verstehen.

Re: Tetris Programm erklären

Verfasst: Montag 3. Februar 2014, 22:01
von /me
BlackJack hat geschrieben:@darktrym: Ich glaube Lesbarkeit und Verständlichkeit waren nicht die Topprioritäten bei diesem Quelltext. ;-)
Für einen "Obfuscated Python Contest" reicht es noch nicht, aber es ist auf dem guten Weg ein Kandidat dafür zu werden.

Re: Tetris Programm erklären

Verfasst: Montag 3. Februar 2014, 22:08
von darktrym
Eigentlich wurde der schon von mir ein wenig bearbeitet.
Die ursprüngliche Fassung hatte lediglich 28 Zeilen.

Ich hätte ja angenommen, f steht für die 4 Positionen des Steins.
Die dann jeweils binär in einem 4x4 Block von oben nach unter kodiert sind.
Passt aber irgendwie nicht ganz.

Re: Tetris Programm erklären

Verfasst: Samstag 8. Februar 2014, 10:17
von BlackJack
@darktrym: Da ist ein Fehler drin der verhindert dass das ”T”-Stück jemals ausgewählt wird. `f` hat sieben Elemente, ``randrange(0, 6)`` wählt aber immer nur aus den ersten 6 aus weil die 6 selbst, also das siebte Element nicht zur Ergebnismenge von dem Aufruf gehört. Hast Du den Fehler „eingebaut” oder war der schon im Original?

@/me: Ich denke dafür reicht es schon, beziehungsweise vermute ich mal darktrym hat das schon ein wenig ”ent-obfuscated”.

Edit: Noch ein Programmfehler: Wenn man ein neues Teil sofort an den linken oder rechten Rand verschiebt in dem man die entsprechende Taste so schnell wiederholt drückt, dass das Teil keine Chance hat zwischendruch nach unten bewegt zu werden, dann bricht das Programm ab wenn das Teil den Rand erreicht hat, weil die Spiellogik in diesem Fall nicht berücksichtigt, dass das nicht gleichbedeutend damit ist, dass sich das Teil nicht nach unten bewegen *kann*.

Re: Tetris Programm erklären

Verfasst: Samstag 8. Februar 2014, 12:08
von Sirius3
Da sind weitere Fehler drin: das "I"-Stück ist nur 3 Elemente lang.
Wenn das Ziel war, Tetris in möglichst wenig Python-Zeilen unterzubringen, sind 28 recht viel:

Code: Alles auswählen

import curses;from random import choice;curses.initscr();curses.curs_set(0);win = curses.newwin(18,18,0,0);win.keypad(1);win.nodelay(1);trafo = [lambda (x,y): (x,y), lambda (x,y): (-y, x), lambda (x,y): (-x, -y), lambda (x,y): (y, -x)];f = [[(0, 0), (0, -1), (0, 1), (1, 1)],[(0, 0), (0, -1), (0, 1), (-1, 1)],[(0, 0), (0, -1), (1, -1), (1, 0)],[(0, 0), (1, -1), (1, 0), (0, 1)],[(0, 0), (-1, -1), (-1, 0), (0, 1)],[(0, 0), (0, -1), (0, 1), (0, 2)],[(0, 0), (-1, 0), (0, -1), (1, 0)]];chkFig=lambda pos,s: (s==0 or all(win.inch(c[1],c[0]) & 255 == 32 for c in pos)) and [win.addch(c[1],c[0],'X' if s == 1 else 32) for c in pos];putFig=lambda FP, s: chkFig(map(lambda(x,y):(x+FP[0],y+FP[1]),map(trafo[FP[2]],FP[3])),s);MoveFig=lambda FP, key, d: (FP[0] + {curses.KEY_LEFT: -d, curses.KEY_RIGHT: d}.get(key,0), FP[1] + {curses.KEY_DOWN: d, -1:d}.get(key,0), (FP[2] + {curses.KEY_UP: d}.get(key,0)) % 4, FP[3]);chkBoard=lambda: sum(win.deleteln() or win.move(1,1) or win.insertln() or 1 for i in range(17) if all(chr(win.inch(i,x)) == 'X' for x in range(1, 17)));FigPos = [8,3,0,choice(f)];score = 0;putFig(FigPos,1);win.timeout(300);key=0
while key!=27 or curses.endwin():
    win.border('|','|','-','-','+','+','+','+');win.addstr(0,2,' Score: %d ' % score);key = win.getch();putFig(FigPos,0);FigPos=MoveFig(FigPos,key,1)
    if key!=27 and not putFig(FigPos,1): FigPos=MoveFig(FigPos,key, -1);putFig(FigPos,1);key=27 if FigPos[1]==3 else -2 if key in [curses.KEY_DOWN, -1] else 0
    if key==-2:score += chkBoard();win.timeout(300 - (score//10 * 20));FigPos = [8,3,0,choice(f)];putFig(FigPos,1)
Ich hab man »f« dekodiert und die Drehungen in eine eigene Liste gepackt.

Re: Tetris Programm erklären

Verfasst: Samstag 8. Februar 2014, 13:50
von darktrym
An der Codelogik selbst hab ich keine Änderungen vorgenommen, d.h. die Fehler sind im Original ebenfalls enthalten.
Ich werd' den Code mal auseinander nehmen, mal schauen ob's lesbarer/fehlerfreier geht.

Re: Tetris Programm erklären

Verfasst: Samstag 8. Februar 2014, 16:45
von Sirius3
Ich bin mit meiner Einzeilenversion nicht zufrieden. Irgendwann wird die Rekursionstiefe überschritten:

Code: Alles auswählen

import curses;from random import choice;trafo = [lambda (x,y): (x,y), lambda (x,y): (-y, x), lambda (x,y): (-x, -y), lambda (x,y): (y, -x)];f = [[(0, 0), (0, -1), (0, 1), (1, 1)],[(0, 0), (0, -1), (0, 1), (-1, 1)],[(0, 0), (0, -1), (1, -1), (1, 0)],[(0, 0), (1, -1), (1, 0), (0, 1)],[(0, 0), (-1, -1), (-1, 0), (0, 1)],[(0, 0), (0, -1), (0, 1), (0, 2)],[(0, 0), (-1, 0), (0, -1), (1, 0)]];chkFig=lambda pos,s: (s==0 or all(win.inch(c[1],c[0]) & 255 == 32 for c in pos)) and [win.addch(c[1],c[0],'X' if s == 1 else 32) for c in pos];putFig=lambda FP, s: chkFig(map(lambda(x,y):(x+FP[0],y+FP[1]),map(trafo[FP[2]],FP[3])),s);MoveFig=lambda FP, key, d: (FP[0] + {curses.KEY_LEFT: -d, curses.KEY_RIGHT: d}.get(key,0), FP[1] + {curses.KEY_DOWN: d, -1:d}.get(key,0), (FP[2] + {curses.KEY_UP: d}.get(key,0)) % 4, FP[3]);chkBoard=lambda: sum(win.deleteln() or win.move(1,1) or win.insertln() or 1 for i in range(17) if all(chr(win.inch(i,x)) == 'X' for x in range(1, 17)));move=lambda FigPos, key: (putFig(FigPos,0), MoveFig(FigPos,key,1), key)[1:];new_tile=lambda score, FigPos: (win.timeout(300 - (score//10 * 20)) or score, (putFig(FigPos,1) or 1) and FigPos);rollback=lambda score, FigPos, key: (putFig(FigPos,1), (score, None) if FigPos[1]==3 else new_tile(score+chkBoard(),[8,3,0,choice(f)]) if key in [curses.KEY_DOWN, -1] else (score,FigPos))[1];step=lambda score,FigPos,key: (score,None) if key==27 else (score,FigPos) if putFig(FigPos,1) else rollback(score,MoveFig(FigPos,key, -1), key);play=lambda score,FigPos:reduce(lambda r,x:r and r[1] and step(r[0],*move(r[1], win.border('|','|','-','-','+','+','+','+') or win.addstr(0,2,' Score: %d ' % score) or win.getch())),xrange(10000),(score,FigPos));repeat=lambda x: x and repeat(play(*x));curses.initscr();curses.curs_set(0);win = curses.newwin(18,18,0,0);win.keypad(1);win.nodelay(1);FigPos = [8,3,0,choice(f)];putFig(FigPos,1);win.timeout(300);repeat((0,FigPos));curses.endwin()

Re: Tetris Programm erklären

Verfasst: Sonntag 9. Februar 2014, 09:33
von bwbg
Es wird Zeit, dass Python TCO unterstützt ... ;)

Wobei Semikolon zu verwenden ist ja eigentlich Cheating.