lehrkraefte:blc:informatik:glf20:oxotetris

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
lehrkraefte:blc:informatik:glf20:oxotetris [2020/12/17 12:27] – [Highscores auf dem Web] Ivo Blöchligerlehrkraefte:blc:informatik:glf20:oxotetris [2020/12/17 13:02] (current) – [Highscores auf dem Web] Ivo Blöchliger
Line 1: Line 1:
 +====== Tetris auf der OxoCard ======
  
 +Erläuterungen zum Code gibt es als Videos:
 +  * [[https://fginfo.ksbg.ch/~ivo/videos/informatik/python/oxocard-tetris-uebersicht.mp4|Übersicht über den Tetris-Code]] (und für Datenspender auf [[https://web.microsoftstream.com/video/53283307-05fb-4568-b6ae-9c0af3a51e18|Stream]])
 +  * [[https://fginfo.ksbg.ch/~ivo/videos/informatik/python/oxocard-tetris-variable-feld.mp4|Erklärungen zur Variable]] ''tetris['feld']'' (und für Datenspender auf [[https://web.microsoftstream.com/video/de88ae07-5296-46ad-adec-eb8bbce41706|Stream]])
 +  * [[https://fginfo.ksbg.ch/~ivo/videos/informatik/python/oxocard-tetris-stein-manipulation.mp4|Erklärungen zur Datenstruktur und Manipulation der Steine]] (und für Datenspender auf [[https://web.microsoftstream.com/video/d5095d75-191c-4f27-95e2-b7b1a4d538a6|Stream]])
 +
 +
 +<code python oxotetris.py>
 +from oxocard import *
 +from ivobuttons import *
 +from random import randrange  # Funktion randrange importieren
 +
 +ivobuttons.delay=300            # Tasten nach 300ms repetieren repetieren beginnen
 +ivobuttons.repeat_delay=100     # Tasten danach 10x pro Sekunde repetieren
 +
 +# Gamestate als Dictionary, d.h. wie eine Liste aber mit Namen als Indizes
 +tetris = {
 +    "feld": [[False for y in range(8)] for x in range(8)],   # Pixel belegt oder nicht (wenn belegt, dann Farbe)
 +    "steine": list(map(lambda x:list(map(lambda y: [y%4,y//4],x)), [(0,1,2,3),(0,1,2,5), (0,1,4,5), (0,1,5,6), (4,5,1,2), (0,1,2,6), (4,0,1,2)])),
 +    "farben": [(255,0,0), (0,255,0), (0,0,255), (255,255,0), (255,0,255), (0,255,255),(255,255,255)],
 +    "stein": None,  # Positionen der Steinpixel
 +    "farbe": None,
 +    "empty" : (10,10,10),  # Hintergrundfarbe, damit das Spielfeld sichtbar ist.
 +    "x": None,     # Untere linke Ecke der Boundingbox des Steins
 +    "y": None,     # Untere linke Ecke der Boundingbox des Steins
 +    "last": 0,     # Zeit bis der Stein weiter fällt.
 +    "score": 0,
 +}
 +
 +
 +# Ergibt True, wenn der Stein platziert werden kann,
 +# False sonst.
 +def platzierbar(stein,x,y):
 +    global tetris
 +    return all((pt[0]+x>=0 and pt[0]+x<=7 and pt[1]+y<=7 and 
 +             (pt[1]+y<0 or tetris['feld'][pt[0]+x][pt[1]+y]==False)) for pt in stein)
 +
 +
 +# Generiert einen neuen Stein und gibt
 +# True zurück, wenn das möglich ist, und sonst
 +# False, wenn der Stein nicht mehr platziert werden kann.
 +def neuerStein():
 +    global tetris
 +    # Zufälligen Stein kopieren
 +    stein = randrange(len(tetris["steine"]))
 +    tetris["stein"] = [[pt[0], pt[1]] for pt in tetris["steine"][stein]]
 +    tetris["farbe"] = tetris["farben"][stein]
 +    
 +    tetris["x"]=3  # Koordinaten vom Stein
 +    tetris["y"]=-max(pt[1] for pt in tetris["stein"])
 +
 +    tetris["last"] = getms()  # Zeit der Letzten Aktion, damit der Stein selber fällt
 +    tetris['score']+=1
 +    print("Score %d" % tetris['score'])
 +    return platzierbar(tetris["stein"], tetris["x"], tetris["y"])
 +
 +# Generiert ein neues Array mit Koordinaten des gedrehten Steins
 +# Die richtung ist +1 oder -1
 +def drehen(richtung):
 +    global tetris
 +    # Gedrehte Koordinaten
 +    res = [[pt[1]*richtung,-pt[0]*richtung] for pt in tetris["stein"]]
 +    # Untere linke Ecke
 +    mins = [min([pt[0] for pt in res]), max([pt[1] for pt in res])]
 +    for pt in res:
 +        for i in range(2):
 +            pt[i]-=mins[i]
 +    return res
 +
 +# Aktuellen Stein zeichnen (evtl. mit Farbe)
 +def steinZeichnen(farbe=None):
 +    global tetris
 +    if farbe==None:
 +        farbe = tetris['farbe']
 +    for pt in tetris['stein']:
 +        if (pt[1]+tetris['y'] >=0):
 +            if farbe==BLACK:
 +                black(pt[0]+tetris['x'], pt[1]+tetris['y'])
 +            else:
 +                fastDot(pt[0]+tetris['x'], pt[1]+tetris['y'], farbe)
 +    fastRepaint()
 +
 +# y ist ein Array mit True/False, welche Linien zu blinken sind
 +def blinkLines(y):
 +    for i in range(5):
 +        for farbe in (WHITE, BLACK):
 +            for yy in range(8):
 +                if y[yy]:
 +                    for xx in range(8):
 +                        fastDot(xx,yy, farbe)
 +            fastRepaint()
 +            sleep(0.1)
 +
 +# Lässt Linien verschwinden, wobei y ein Array mit True/False für jede Linie ist.
 +def removeLines(y):
 +    global tetris
 +    count = 0
 +    for yy in range(8):
 +        if y[yy]:
 +            count+=1
 +            for yyy in range(yy,-1,-1):
 +                for x in range(8):
 +                    f = BLACK
 +                    if yyy>0:
 +                        tetris['feld'][x][yyy] = tetris['feld'][x][yyy-1]
 +                    else:
 +                        tetris['feld'][x][yyy] = False
 +                    if tetris['feld'][x][yyy]:
 +                        fastDot(x,yyy,tetris['feld'][x][yyy])
 +                    else:   
 +                        black(x,yyy);
 +                fastRepaint()
 +            sleep(0.1)
 +    tetris['score']+= [0,5,20,100,500][count]
 +    print("Score %d" % tetris['score'])
 +    
 +# Überprüft, ob volle Zeilen da sind und löscht diese    
 +def checkLines():
 +    global tetris
 +    # Array mit True, False, für volle Zeilen True
 +    y = [all(tetris['feld'][x][y] for x in range(8)) for y in range(8)]
 +    # Volle Zeilen?
 +    if any(y):
 +        blinkLines(y)
 +        removeLines(y)
 +        
 +
 +# Stein runter, evtl. Linien löschen, neuer Stein generieren
 +# Liefert False, wenn das Spiel weiter geht
 +# True, wenn GameOver ist.    
 +def steinDown():
 +    global tetris
 +    tetris['last'] = zeit
 +    if platzierbar(tetris['stein'], tetris['x'], tetris['y']+1):
 +        steinZeichnen(BLACK)
 +        tetris['y']+=1
 +        steinZeichnen()
 +        return False
 +    else:
 +        # Stein definitiv platzieren:
 +        for pt in tetris['stein']:
 +            if (pt[1]+tetris['y']>=0):
 +                tetris['feld'][pt[0]+tetris['x']][pt[1]+tetris['y']] = tetris['farbe']
 +        checkLines()
 +        return not neuerStein()
 +
 +
 +# Richtung ist +1 oder -1
 +def steinMove(richtung):
 +    global tetris
 +    if platzierbar(tetris['stein'], tetris['x']+richtung, tetris['y']):
 +        steinZeichnen(BLACK)
 +        tetris['x']+=richtung
 +        steinZeichnen()
 +        
 +# Richtung ist +1 oder -1        
 +def steinRotate(richtung):
 +    global tetris
 +    gedreht = drehen(richtung)
 +    if platzierbar(gedreht, tetris['x'], tetris['y']):
 +        steinZeichnen(BLACK)
 +        tetris['stein']=gedreht
 +        steinZeichnen()
 +
 +def black(x,y):
 +    fastDot(x,y, (4,4,4));
 +
 +def init():
 +    for x in range(8):
 +        for y in range(8):
 +            black(x,y)
 +    neuerStein();    
 +    steinZeichnen();
 +                       
 +bigTextScroll(" Oxo Tetris ", (10,40,200), BLACK)
 +init()
 +
 +#############
 +# Game Loop #
 +#############
 +gameOver = False
 +
 +while not gameOver:
 +    zeit = getms()
 +    s = ivobuttons.states()
 +    if zeit-tetris['last']>800 or s & IVO_R3:
 +        gameOver = steinDown();
 +    if s & IVO_L2:
 +        steinMove(-1)
 +    if s & IVO_R2:
 +        steinMove(1)
 +    if s & IVO_R1:
 +        steinRotate(1)
 +    if s & IVO_L1:
 +        steinRotate(-1)
 +        
 +
 +# Game Over
 +
 +print("Game over")
 +while True:    
 +    bigTextScroll((" %d " % tetris['score']), (100,0,0), BLACK)
 +</code>
 +
 +
 +===== Highscores auf dem Web =====
 +Was folgt sind Notizen, um von der OxoCard die Highscores auf dem Web zu publizieren.
 +<code python>
 +from tcpcom import *
 +# See dcoumentation directly in the code of the OxoCard modules files
 +Wlan.connect("stopbuepf", "stopbuepf")
 +client = HTTPClient()  # Pass True for debugging...
 +client._isSSL=True
 +if client.connect("tech-lab.ch", 443):  # Host is used in HTTP-Query
 +    response = client.sendPostRequest("/scores/index.php", "name="+HTTPClient.toUrl("Hase")+"&score=123")
 +    print(response)
 +    client.closeConnection()
 +
 +</code>