====== 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]])
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)
===== Highscores auf dem Web =====
Was folgt sind Notizen, um von der OxoCard die Highscores auf dem Web zu publizieren.
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()