======Tetris in Minecraft======
====Projekt von Maxim Pürzer und Andrin Reber====
Die Idee Tetris in Minecraft zu erstellen kam ziemlich spontan. Nachdem wir den Auftrag bekommen hatten, ein Projekt in Minecraft zu realisieren, war unsere erste Idee, innerhalb vom Spiel einen sehr simplen Computer zu programmieren, auf dem man ein sehr simples Spiel spielen kann. Da Tetris ein einfaches Konzept hat, und mit der Zeit zu einem Klassiker geworden ist, dachten wir, dass Tetris des perfekte Spiel dafür ist. Um das Projekt etwas einfacher zu machen, liessen wir das mit dem Computer bleiben und erstellten nur das Spiel selber.
Das Prinzip von Tetris ist ganz einfach. Vom oberen Rand des Bildschirms fallen vorbestimmte Formen, sogenannte Tetrominos, welche liegen bleiben, sobald sie Kontakt mit etwas unter ihnen haben. Das Spielbrett ist 2-dimensional und in beiden Dimensionen räumlich begrenzt. Wenn eine horizontale Reihe vollständig ausgefüllt ist, verschwindet diese, und alle Blöcke darüber senken sich um eine Ebene, um die entstandene Lücke aufzufüllen. Sobald eine vertikale Reihe vollständig ausgefüllt ist, ist das Spiel vorbei, und man hat verloren. Das Ziel ist es, so lange wie möglich im Spiel zu bleiben. Um das zu erreichen, kann man die Formen, welche von oben fallen, horizontal bewegen und drehen, immer jeweils um 90°.
Beim normalen Tetris ist die Kontrolle der Blöcke auf Tasten belegt. Da dies innerhalb von einem anderen Spiel jedoch sehr schwierig umzusetzen war, haben wir die Kontrolle der Blöcke mit den Bewegungen des Spielers verbunden. So bewegen sich die Blöcke nach rechts, wenn der Spieler nach rechts geht und nach links wenn der Spieler nach links geht. Bewegt sich der Spieler nach vorne, dreht sich die Form gegen den Uhrzeigersinn, bewegt man sich nach hinten, mit dem Uhrzeigersinn. Damit sich der Spieler nicht vom Spielbrett entfernt, wird dieser in einem Zaun eingeschlossen, und nach jeder Bewegung zurück zum Startpunkt teleportiert.
{{ef:minecraft:projekt:maximandrin:tetristhumbnail.png?|}}
===== Vor dem Starten =====
[[archiv:ef:ef2020_2022:minecraft:projekt:maximandrin:start:sourcecode| Kompletter Quellcode zum Kopieren]]
Dieser Quellcode muss in den Code-Editor kopiert und gestartet werden. Das Spiel beginnt nicht sofort, es besteht also kein Grund zur Eile. Falls ein Fehler wie "unexpected indent" oder "inconsistent indentation" angezeigt wird, haben wir [[archiv:ef:ef2020_2022:minecraft:projekt:maximandrin:start:sourcecode-unformatted| hier]] den Quellcode ohne Formatierung. Um ihn zu Kopieren kann man in der Seitenleiste auf "Seite bearbeiten" clicken, dann auf den Text clicken und dann mit "control" + "A" und + "C" auf Windows oder "command" + "A" und + "C" auf Mac alles auswählen und kopieren. Um danach hierher zurückzugelangen, kann man in der auf "Links hierher" klicken.
Um das optimale Spielerlenis zu geniessen, empfehlen wir den Autojump abzuschalten. Dieser befindet sich in den Einstellungen (Escape Taste) unter "Einstellungen", "Tastatur und Maus", "Automatisches Springen". Ebenfalls empfiehlt es sich das HUD auszublenden, unter "Einstellungen", "Grafik", "HUD Ausblenden", damit der Chat nicht stört. Man kann auch das Blickfeld vergrössern, unter "Einstellungen", "Grafik", "Sichtfeld".
Die Steuerung für unser Spiel lautet wie folgt:
^Tastaturbefehl ^Funktion^
| W | Gegen den Uhrzeigersinn drehen |
| A | Nach links schieben |
| S | Im Uhrzeigersinn drehen |
| D | Nach rechts schieben |
| Shift | Plazieren (ganz nach unten) |
| "Start" im Chat | Spiel starten |
| "Stop" im Chat | Spiel anhalten |
===== Allgemeine Spielmechanik & Deklaration =====
Das momentane Spielfeld wird in der 2-Dimensionalen Liste ''Board'' gespeichert. 1 steht jeweils für einen Block und 0 für keinen. So wird auch das momentane Tetromino in der Liste ''piece'' gespeichert. Wenn nun das Tetromino bewegt werden soll, wird zuerst ''piece'' bewegt, dann wird überprüft, ob es Überschneidungen gibt, und danach werden erst die Blöcke auf dem Bildschirm verändert. Es werden auch jeweils nur diejenigen Blöcke verändert, bei denen es notwendig ist. Wir haben uns für diese Vorgehensweise entschieden, damit möglichst Wenig Kommunikation zwischen dem Code und der Minecraft Welt stattfinden muss. Diese ist sehr langsam und zu viel davon würde das Spiel unspielbar machen.
Wir haben uns entschieden diese Variablen als globale Variablen zu speichern. So können sie in jeder Funktion verwendet werden, solange man sie an deren Anfang so deklariert. Dafür verwendet man die Kennzeichnung ''global'' und danach den Variabelnamen. Ganz zu Beginn des Quellendes werden alle Globalen Variablen ausserhalb einer Funktion deklariert:
#Globale Variabeln initiieren
#Nach Präferenz ändern:
w = 0
h = 0
playerY = 3
playerZ = 20
buildGlass = True
#Nicht ändern:
board = [[0]]
piece = [[0]]
pieceX = 0
pieceY = 0
color = DIAMOND_BLOCK
isRunning = False
origin = player.position()
score = 0
unusedPieces = range(7)
===== User Interface =====
{{ef:minecraft:projekt:maximandrin:tetrisohneglas.png?400|}}
{{ef:minecraft:projekt:maximandrin:tetrisplattform.png?400|}}
Um die Spielkonsole zu bauen, wird beim Starten des Spieles die Funktion ''makeBoard()'' abgerufen. Sie baut die Plattform, auf der der Spieler steht, und die einzelnen Elemente der Spielkonsole. Weil das Glas nicht komplett durchsichtig ist, kann man das Bauen dieses ausschalten, in dem man am Anfang des Codes ''buildGlass'' auf False stellt. Der Boden der Plattform besteht aus dem Block "Scaffolding", weil darin der Spieler einsinkt, sobald er Schleicht, wodurch wir Schleichen auch für die Steuerung verwenden konnten.
def makeBoard(w, h):
global playerY
global playerZ
global buildGlass
#Plattform bauen
blocks.fill(GLASS, pos(-1, -2, -1), pos(1, -2, 1))
blocks.fill(blocks.block_by_name("scaffolding"), pos(-1, -1, -1), pos(1, -1, 1))
blocks.fill(GLASS_PANE, pos(-1, 0, -1), pos(1, 0, -1))
blocks.fill(GLASS_PANE, pos(-1, 0, 1), pos(1, 0, 1))
blocks.place(GLASS_PANE, pos(-1, 0, 0))
blocks.place(GLASS_PANE, pos(1, 0, 0))
#Bildschirm bauen
n = Math.round(w / 2)
o = Math.round(w/2%1)
blocks.fill(BLACK_CONCRETE, pos(-n, -playerY, playerZ+1), pos(n+o, h-playerY, playerZ+1))
blocks.fill(POLISHED_ANDESITE, pos(-n-1, -1-playerY, playerZ+1), pos(-n-1, h+1-playerY, playerZ-1))
blocks.fill(POLISHED_ANDESITE, pos(n+o+1, -1-playerY, playerZ+1), pos(n+o+1, h+1-playerY, playerZ-1))
blocks.fill(POLISHED_ANDESITE, pos(-n-1, -1-playerY, playerZ+1), pos(n+o+1, -1-playerY, playerZ-1))
blocks.fill(POLISHED_ANDESITE, pos(-n-1, h+1-playerY, playerZ+1), pos(n+o+1, h+1-playerY, playerZ-1))
blocks.fill(AIR, pos(-n, -playerY, playerZ-1), pos(n+o, h-playerY, playerZ))
if buildGlass:
blocks.fill(GLASS, pos(-n, -playerY, playerZ-1), pos(n+o, h-playerY, playerZ-1))
===== GameLoop =====
Die Funktion ''gameloop()'' läuft während des Spiels kontinuierlich. Sie führt jedes Mal die Funktion ''playerMoved()'' aus, die überprüft, ob sich der Spieler bewegt hat. Wenn dies der Fall ist, leitet sie die Bewegung an die Funktion ''movePiece()'' weiter, die dann entscheidet, wie das ''piece'' bewegt werden muss. Danach teleportiert sie den Spieler zurück zum Startpunkt ''origin''. Jedes 20. Mal führt sie zusätzlich die Funktion ''moveDown()'' aus, die das ''piece'' um einen Block nach unten bewegt. So funktioniert sie als Timer für das ganze Spiel.
def gameloop():
global isRunning
frame = 0
#Wiederholen bis Spieler "stop" schreibt
while isRunning:
#Bei Bewegung den Tetromino bewegen
movedDirection = playerMoved()
if movedDirection[0] != "":
movePiece(movedDirection[0], movedDirection[1])
player.teleport(origin)
#Alle 20 Durchläufe den Tetromino nach unten bewegen
if frame % 20 == 0:
moveDown()
frame += 1
===== Bewegung detektieren =====
==== playerMoved() ====
Die Funktion ''playerMoved()'' wird bei jedem Durchlauf von ''gameloop'' abgerufen. Sie vergleicht die momentane Position des Spielers mit der Startposition, die in der Variable ''origin'' abgespeichert ist. Um die zwei Positionen zu vergleichen, werden sie zuerst in ein String umgewandelt. Damit werden sie automatisch auf den vollen Block gerundet. Wenn sie nicht übereinstimmen, wird die Bewegung des Spielers als Liste zurückgeschickt. Das erste Element beschreibt die Richtung (x, y oder z), und das zweite Element zeigt an, ob sich der Spieler in die positive oder die negative Richtung bewegt.
def playerMoved():
#neue und alte Position vergleichen
cPos = player.position()
if origin.to_string() == cPos.to_string():
return ["", ""]
else:
#Richtung bestimmen
x = origin.get_value(Axis.X) - cPos.get_value(Axis.X)
y = origin.get_value(Axis.Y) - cPos.get_value(Axis.Y)
z = origin.get_value(Axis.Z) - cPos.get_value(Axis.Z)
if x < 0:
return ["x", "+"]
elif x > 0:
return ["x", "-"]
elif y != 0:
return ["y", "+"]
elif z < 0:
return ["z", "+"]
else:
return ["z", "-"]
==== movePiece() ====
Die Funktion ''movePiece()'' wird con ''gameloop'' ausgeführt, und erhält dabei auch den Inhalt der Liste, die von ''playerMoved()'' zurückgeschickt wurde. Sie entziffert diesen und führt die entsprechende Funktion aus, die dann das ''piece'' bewegt.
def movePiece(direction, sign):
global piece
#Je nach Richtung richtige Bewegung ausführen
if direction == "x" and sign == "-":
move(-1)
elif direction == "x" and sign == "+":
move(1)
elif direction == "y":
moveToBottom()
elif direction == "z" and sign == "-":
rotateLeft()
else:
rotateRight()
==== Nach links oder rechts ====
Zum bewegen des ''piece'' in der Horizontalen, wird zuerst die X-Position ''pieceX'' verändert, und danach das ''piece'' mit der neuen Position an ''checkCollisions()'' weitergeleitet.
def move(n):
global piece
global pieceX
global pieceY
#X Wert des Tetrominos ändern
newX = pieceX + n
if not checkCollisions(piece, newX, pieceY, False):
checkCollisions(piece, newX, pieceY, True)
def moveDown():
global piece
global pieceX
global pieceY
#Y Wert des Tetrominos ändern
newY = pieceY - 1
checkCollisions(piece, pieceX, newY, True)
==== Platzieren (Ganz nach unten) ====
Zum direkten Plazieren des ''piece'', wird es Block für Block nach unten bewegt, und jeweils mit der Funktion ''checkCollisions()'' überprüft, ob es Überlagerungen gibt. Wenn es diese gibt, wird das ''piece'' mit der Funktion ''placePiece()'' am letzten überlagerungsfreien Ort plaziert. Damit die vorherigen Blöcke nicht auf dem Bildschirm zurückbleiben, werden diese zuvor noch mit dem Befehl ''player.execute("fill ~" + str(-w/2-1) + " ~" + str(-playerY) + " ~" + str(playerZ) + " ~" + str(w/2+1) + " ~" + str(h-playerY) + " ~" + str(playerZ) + " air 0 replace wool " + id(color))'' entfernt. Hier haben wir den Befehl ''player.execute()'' anstatt ''blocks.fill()'' verwenden, weil man bei diesem auch einstellen kann, dass es nur Blöcke eines bestimmten Types löschen soll.
def moveToBottom():
global piece
global pieceX
global pieceY
global board
global playerY
global playerZ
#Y Wert des Tetrominos senken bis Kollision stattfindet
newY = pieceY
while not checkCollisions(piece, pieceX, newY, False):
newY = newY - 1
player.execute("fill ~" + str(-w/2-1) + " ~" + str(-playerY) + " ~" + str(playerZ) + " ~" + str(w/2+1) + " ~" + str(h-playerY) + " ~" + str(playerZ) + " air 0 replace wool " + id(color))
pieceY = newY + 1
placePiece()
==== Drehen ====
Zum drehen des ''piece'' wird dessen Liste an der X-Achse und an der Diagonale gespiegelt. Zuerst wird ''piece'' Element für Element gespiegelt in die temporäre Liste ''tempPiece'' gespeichert, danach dasselbe aber an der Diagonalen gespiegelt und in die Liste ''newPiece'' gespeichert. Hier ist wahrscheinlich irgendwo ein kleiner Fehler verborgen, weil beim anschliessenden Bewegen des ''piece'' auf dem Bildschirm unlogische weitere Fehler auftraten. Dieser hat jedoch keine grosse Auswirkung auf das Spiel, weil wir grösstenteils behoben haben, in dem wir den nicht richtig ausgeführten Code, ''player.execute("fill ~" + str(-w/2) + " ~" + str(-playerY) + " ~" + str(playerZ) + " ~" + str(w/2) + " ~" + str(h-playerY) + " ~" + str(playerZ+1) + " air 0 replace wool " + id(color))'', einfach ein zweites Mal ausführten.
def rotateLeft():
global piece
global pieceX
global pieceY
tempPiece = []
newPiece = []
for i in range(piece.length):
tr = range(piece.length)
tempPiece[i] = tr
newPiece[i] = tr
for j in range(piece.length):
tempPiece[i][j] = 0
newPiece[i][j] = 0
newPiece = piece
tPiece = piece
#Gedrehtes Tetromino in neue Liste speichern
for i in range(piece.length):
for j in range(piece.length):
tempPiece[i][j] = tPiece[i][piece.length-1-j]
for i in range(piece.length):
for j in range(piece.length):
newPiece[j][i] = tempPiece[i][j]
player.execute("fill ~" + str(-w/2) + " ~" + str(-playerY) + " ~" + str(playerZ) + " ~" + str(w/2) + " ~" + str(h-playerY) + " ~" + str(playerZ+1) + " air 0 replace wool " + id(color))
checkCollisions(newPiece, pieceX, pieceY, True)
def rotateRight():
global piece
global pieceX
global pieceY
tempPiece = []
newPiece = []
for i in range(piece.length):
tr = range(piece.length)
tempPiece[i] = tr
newPiece[i] = tr
for j in range(piece.length):
tempPiece[i][j] = 0
newPiece[i][j] = 0
newPiece = piece
#Gedrehtes Tetromino in neue Liste speichern
for i in range(piece.length):
for j in range(piece.length):
tempPiece[j][i] = piece[i][j]
for i in range(tempPiece.length):
for j in range(tempPiece.length):
newPiece[i][tempPiece.length-1-j] = tempPiece[i][j]
player.execute("fill ~" + str(-w/2) + " ~" + str(-playerY) + " ~" + str(playerZ) + " ~" + str(w/2) + " ~" + str(h-playerY) + " ~" + str(playerZ-1) + " air 0 replace wool " + id(color))
checkCollisions(newPiece, pieceX, pieceY, True)
===== Tetromino bewegen =====
===== Überlagerungen verhindern =====
Zum Verhindern von Überlagerungen wird von den Funktionen zum Bewegen jeweils die Funktion ''checkCollisions'', mit dem neuen Tetromino ''newPiece'' und dessen Position abgerufen. Diese überprüft dann, ob das ''newPiece'' mit Blocken im ''Board'', mit den Wänden oder mit dem Boden kollidiert. Wenn es mit dem Boden oder dem ''Board'' kollidiert, wird das ursprüngliche ''piece'' mit der Funktion ''placePiece()'' am vorherigen Ort plaziert. Wenn ''newPiece'' mit den Wänden kollidiert, wird die Bewegung ignoriert, es passiert also nichts, und wenn es nirgends kollidiert, wird die Bewegung mit der Funktion ''updatePiece'' ausgeführt, und der Bildschirm aktualisiert. Falls nur überprüft werden soll, ob es Überlagerungen gibt, aber danach nicht schon alles aktualisiert werden soll, kann man als Input ''proceed'' "False" schicken. Dann wird, falls eine Kollision stattfindet, "True" und sonst "False" zurückgeschickt.
def checkCollisions(newPiece, newX, newY, proceed):
global board
#Kollisionen finden und testen ob Tetromino zuunterst ist
#Ohne tempPiece entsteht Error, weil type von newPiece nicht bekannt ist
tempPiece = [[0]]
tempPiece = newPiece
collided = False
bottom = False
walls = False
for i in range(newPiece.length):
for j in range(newPiece.length):
if newPiece[i][j] == 1:
if i + newX >= board.length or i + newX < 0:
walls = True
elif board[i + newX][j + newY] == 1:
collided = True
elif j + newY < 0:
bottom = True
if proceed and not walls :
if bottom:
placePiece()
elif not collided:
updatePiece(newPiece, newX, newY)
else:
placePiece()
elif bottom or collided or walls:
return(True)
return(False)
===== Bewegung auf Bildschirm anzeigen =====
==== Tetromino bewegen ====
Um das ''piece'' zu bewegen, wird die Funktion ''updatePiece()'' eingesetzt. Sie löscht das momentane ''piece'', baut das ''newPiece'' Block für Block auf dem Bildschirm auf, und speichert dann ''newPiece'' in die Variable ''piece'', um die Bewegung abzuschliessen.
def updatePiece(newPiece, newX, newY):
global board
global piece
global pieceX
global pieceY
global h
global playerY
global playerZ
global color
player.execute("fill ~" + str(-w/2-1) + " ~" + str(-playerY) + " ~" + str(playerZ) + " ~" + str(w/2+1) + " ~" + str(h-playerY) + " ~" + str(playerZ) + " air 0 replace wool " + id(color))
for i in range(newPiece.length):
for j in range(newPiece.length):
if newPiece[i][j] == 1:
if newY + j < h:
blocks.place(color, positions.add(origin, pos(-w/2+newX+i, newY+j-playerY, playerZ)))
piece = newPiece
pieceX = newX
pieceY = newY
==== Tetromino platzieren ====
Die Funktion ''placePiece()'' funktioniert grundsätzlich gleich, wie ''updatePiece()'', aber hat noch einige Additionen. Es wird nähmlich zusätzlich überprüft, ob das ''piece'' zu weit oben platziert wurde, also ob das Spiel verloren ist, und wenn nicht führt sie ''removeRow()'' aus und generiert dann ein neuer Tetromino mit der Funktion ''getPiece()''.
def placePiece():
global board
global piece
global pieceX
global pieceY
global score
global isRunning
#Tetromino zur "board" Liste hinzufügen
for i in range(piece.length):
for j in range(piece.length):
if piece[i][j] == 1:
board[i + pieceX][j + pieceY] = 1
if pieceY + j < h:
blocks.place(placeColor(color), positions.add(origin, pos(-w/2+pieceX+i, pieceY+j-playerY, playerZ)))
if pieceY + j >= h:
isRunning = False
if isRunning:
#Komplette Reihen entfernen
removeRow(i)
#Neues Tetromino generieren
score = score + 1
pieceX = Math.round(w/2) - 2
pieceY = h - 1
getPiece()
else:
player.say("Zu langsam ☹")
player.say("score: " + str(score))
==== Volle Zeilen entfernen ====
Um die vollen Zeilen zu entfernen, wird zuerst von unten nach oben für jede Zeile überprüft, ob sie vollständig ist. Wenn dies der Fall ist, wird sie gelöscht, und jede darüberstehende Zeile wird nach unten kopiert. Auf dem Bildschirm geschieht dies mit dem Befehl ''blocks.clone(...)''. Die oberste Zeile wird jeweils mit Luft gefüllt, damit dort nicht die vorherige Zeile zurückbleibt.
def removeRow(j):
global board
global w
global h
y = 0
for _ in range(h):
complete = 1
for i in range(w):
complete = complete * board[i][y]
if complete == 1:
#alles über der Reihe nach unten schieben
for k in range(w):
for l in range(y, h):
board[k][l] = board[k][l+1]
for l in range(y, h-1):
blocks.clone(positions.add(origin, pos(-w/2, l+1-playerY, playerZ)), positions.add(origin, pos(w/2, l+1-playerY, playerZ)), positions.add(origin, pos(-w/2, l-playerY, playerZ)), CloneMask.REPLACE, CloneMode.NORMAL)
for k in range(w-2):
board[k][h-1]=0
blocks.fill(AIR, positions.add(origin, pos(-w/2,h-1-playerY, playerZ)), positions.add(origin, pos(w/2-1, h-1-playerY, playerZ)))
else:
y = y + 1
===== Diverses =====
==== startTetris() ====
Hier werden alle Werte des Spieles zurückgesetzt, damit es anschliessend neu gestartet werden kann.
def startTetris():
global w
global h
global playerZ
global board
global piece
global pieceX
global pieceY
global isRunning
global origin
global score
global unusedPieces
#erstellen einer zweidimensionalen Liste zum Speichern der Spielfläche
# (0/1) (1/1)
# (0/0) (1/0)
board = []
for i in range(w):
temparr = range(h)
board[i] = temparr
for j in range(h):
board[i][j] = 0
#erstellen des ersten Tetrominos
unusedPieces = range(7)
pieceX = Math.round(w/2) - 2
pieceY = h - 1
getPiece()
#Spieler zentrieren und Agenten wegteleportieren
agent.teleport_to_player()
player.teleport(agent.get_position())
origin = player.position()
player.execute("tp ~ ~ ~ facing ~ ~ ~1")
agent.teleport(pos(0, -10, 0), SOUTH)
#"Spielkonsole" bauen
makeBoard(w - 1, h - 1)
#Spiel starten
isRunning = True
score = 0
gameloop()
player.on_chat("start", startTetris)
==== stopTetris() ====
In dieser Funktion wird nur ''isRunning'' auf "False" gesetzt. Wenn diese Variabel das nächste Mal überprüft wird, wird das Spiel gestoppt.
def stopTetris():
global isRunning
#Aus gameloop() ausbrechen
isRunning = False
player.on_chat("stop", stopTetris)
==== getPiece() ====
Die Funktion ''getPiece()'' wählt eines der sieben möglichen Tetrominos aus. Damit nicht zu oft nacheinander die gleichen Tetrominos ausgewählt werden, werden in der Liste ''unusedPieces'' alle noch unbenutzten abgespeichert. Wenn eines davon ausgewählt wird, wird dieses mir dem Befehl ''unusedPieces.remove(n)'' aus der Liste entfernt. Dieser Befehl scheint nicht immer zu funktionieren, was zu wiederholungen des selben Tetrominos führt. Eine lösung dafür haben wir noch nicht gefunden. Auch ''unusedPieces.pop()'' hat Fehler generiert. Wenn eines ausgewählt wurde, wird es in die Liste ''piece'' gespeichert.
def getPiece():
global piece
global color
global pieceX
global unusedPieces
#Eines der Tetrominos wählen
random = Math.round(Math.random()*unusedPieces.length)
n = unusedPieces[random]
if unusedPieces.length < 1:
unusedPieces = range(7)
else:
unusedPieces.remove(n)
if n < 1:
#I
piece = [[0,1,0,0],[0,1,0,0],[0,1,0,0],[0,1,0,0]]
color = LIGHT_BLUE_WOOL
elif n < 2:
#O
piece = [[1,1],[1,1]]
color = YELLOW_WOOL
pieceX = pieceX + 1
elif n < 3:
#T
piece = [[0,1,0],[1,1,0],[0,1,0]]
color = PURPLE_WOOL
elif n < 4:
#S
piece = [[1,0,0],[1,1,0],[0,1,0]]
color = RED_WOOL
elif n < 5:
#2
piece = [[0,1,0],[1,1,0],[1,0,0]]
color = LIME_WOOL
elif n < 6:
#L
piece = [[1,1,0],[0,1,0],[0,1,0]]
color = ORANGE_WOOL
elif n < 7:
#J
piece = [[0,1,0],[0,1,0],[1,1,0]]
color = BLUE_WOOL
==== Blöcke und Farben ====
Die Funktion ''placeColor()'' wandelt die Bezeichnung für Wolle in die Bezeichnung für Beton (Concrete auf enlisch) um. Dabei bleibt die Farbe immer die selbe.
def placeColor(color):
if color == LIGHT_BLUE_WOOL:
return(LIGHT_BLUE_CONCRETE)
elif color == YELLOW_WOOL:
return(YELLOW_CONCRETE)
elif color == PURPLE_WOOL:
return(PURPLE_CONCRETE)
elif color == LIME_WOOL:
return(LIME_CONCRETE)
elif color == RED_WOOL:
return(RED_CONCRETE)
elif color == ORANGE_WOOL:
return(ORANGE_CONCRETE)
else:
return(BLUE_CONCRETE)
Weil im Code-Editor und in Befehlen im Chat nicht die selben Bezeichnungen für die Blöcke verwendet werden, haben wir ebenfalls eine Funktion geschrieben, die die Bezeichnung aus dem Code-Editor in die der Befehle umwandelt.
def id(color):
if color == LIGHT_BLUE_WOOL:
return 3
elif color == YELLOW_WOOL:
return 4
elif color == PURPLE_WOOL:
return 10
elif color == LIME_WOOL:
return 5
elif color == RED_WOOL:
return 14
elif color == ORANGE_WOOL:
return 1
else:
return 11