#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)

#Generelle Funktionen

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)

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))

def stopTetris():

  global isRunning
  
  #Aus gameloop() ausbrechen
  isRunning = False

player.on_chat(„stop“, stopTetris)

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

#Durchgehend wiederholende Funktion die Spiel „steuert“

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

#Bewegen der Tetrominos

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", "-"]

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()

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)

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()

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)

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)

#Funktionen zum Ändern des Bildschirms der „Konsole“

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

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))

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

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)

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