Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from PyQt5 import QtCore, QtGui, QtWidgets
- import sys
- import re
- import random
- class block_map:
- def __init__(self, squares):
- self.squares = squares
- self.width = len(squares[0])
- self.height = len(squares)
- def draw(self, painter, offset_x=0, offset_y=0):
- for x in range(0, self.width):
- for y in range(0, self.height):
- if (self.squares[y][x]):
- painter.drawRect((x + offset_x) * 10 + 1, (y + offset_y) * 10 + 1, 8, 8)
- class shape(block_map):
- def __init__(self, sq):
- block_map.__init__(self, sq[0])
- self.full_sq_data = sq
- self.angle = 0
- self.x = 0
- self.y = 0
- def setPos(self, pos):
- self.x = pos[0]
- self.y = pos[1]
- def draw(self, painter):
- block_map.draw(self, painter, self.x, self.y)
- def tryMove(self, field, vec_x, vec_y):
- if self.collisionDetected(field, vec_x, vec_y):
- return False
- self.x += vec_x
- self.y += vec_y
- return True
- def tryDrop(self, field):
- pass
- while self.tryMove(field, 0, 1):
- pass
- return True
- def tryRotate(self, field):
- dx = (self.width) / 2 - 1
- dy = (self.height) / 2 - 1
- delta = dx - dy
- self.angle = self.nextAngleID()
- block_map.__init__(self, self.full_sq_data[self.angle])
- if not self.collisionDetected(field, delta, -delta):
- self.x = self.x + delta
- self.y = self.y - delta
- return True
- elif not self.collisionDetected(field, delta + 1, -delta):
- self.x = self.x + delta + 1
- self.y = self.y - delta
- return True
- elif not self.collisionDetected(field, delta + 1, -delta + 1):
- self.x = self.x + delta + 1
- self.y = self.y - delta + 1
- return True
- elif not self.collisionDetected(field, delta, -delta + 1):
- self.x = self.x + delta
- self.y = self.y - delta + 1
- return True
- else:
- self.angle = self.prevAngleID()
- block_map.__init__(self, self.full_sq_data[self.angle])
- return False
- def nextAngleID(self):
- if self.angle == 3:
- return 0
- else:
- return self.angle + 1
- def prevAngleID(self):
- if self.angle == 0:
- return 3
- else:
- return self.angle - 1
- def mergeToField(self, field):
- for block_x in range(0, self.width):
- for block_y in range(0, self.height):
- if self.squares[block_y][block_x]:
- field.squares[block_y + self.y][block_x + self.x] = True
- def collisionDetected(self, field, offset_x = 0, offset_y = 0):
- if field.blockOutsideBorders(self.x + offset_x,
- self.y + offset_y):
- return True
- if field.blockOutsideBorders(self.x + self.width + offset_x - 1,
- self.y + self.height + offset_y - 1):
- return True
- for block_x in range(0, self.width):
- for block_y in range (0, self.height):
- if self.squares[block_y][block_x]:
- if field.squares[self.y + block_y + offset_y]\
- [self.x + block_x + offset_x]:
- return True
- return False
- class field(block_map):
- def __init__(self, w=10, h=20):
- block_map.__init__(self, [[False for x in range(0, w)] for y in range(0, h)])
- def draw(self, painter):
- block_map.draw(self, painter)
- painter.drawRect(0, 0, self.width * 10, self.height * 10)
- def blockOutsideBorders(self, pos_x, pos_y):
- x_outside = pos_x < 0 or pos_x >= self.width
- y_outside = pos_y < 0 or pos_y >= self.height
- return x_outside or y_outside
- def defaultRespawnPos(self, shape):
- return (self.width / 2 - shape.width / 2, 0)
- def updateRows(self):
- for current_index in reversed(range(0, self.height)):
- while self.fullRow(current_index):
- self.burnRow(current_index)
- def fullRow(self, row_index):
- for block in self.squares[row_index]:
- if not block:
- return False
- return True
- def burnRow(self, row_index):
- for current_index in reversed(range(1, row_index + 1)):
- self.squares[current_index] = self.squares[current_index - 1]
- self.squares[0] = [False for x in range(0, self.width)]
- class TetrisFieldWidget(QtWidgets.QWidget):
- def __init__(self, parent=None):
- QtWidgets.QWidget.__init__(self, parent)
- self.shape_data = self.parseShapesFile("shapes")
- self.field = field()
- self.genNextShape()
- self.trySpawnShape()
- self.genNextShape()
- self.running = True
- def parseShapesFile(self, file):
- data = re.sub('\s*', '', open(file, "r").read())
- data = re.findall('shape\{(?:(?:[01]*;)+)\}', data)
- data = [re.findall('([01]+);', sh) for sh in data]
- data = [self.genShapePrototypes([[int(digit) for digit in row] for row in sh]) for sh in data]
- return data
- def genShapePrototypes(self, raw_shape):
- width = len(raw_shape[0])
- result = []
- result.append(raw_shape)
- result.append([[row[i] for row in reversed(raw_shape)] for i in range(0, width)])
- result.append([[item for item in reversed(row)] for row in reversed(result[0])])
- result.append([[item for item in reversed(row)] for row in reversed(result[1])])
- return result
- def randomShapeId(self):
- return random.randint(0, len(self.shape_data) - 1)
- def paintEvent(self, QPaintEvent):
- painter = QtGui.QPainter()
- painter.begin(self)
- self.field.draw(painter)
- self.shape.draw(painter)
- self.nextShapeSample.draw(painter, self.field.width + 5, 8)
- painter.end()
- def keyPressEvent(self, event):
- if not self.running:
- return
- if type(event) == QtGui.QKeyEvent and event.key() == QtCore.Qt.Key_Left:
- self.shape.tryMove(self.field, -1, 0)
- self.update()
- if type(event) == QtGui.QKeyEvent and event.key() == QtCore.Qt.Key_Right:
- self.shape.tryMove(self.field, 1, 0)
- self.update()
- if type(event) == QtGui.QKeyEvent and event.key() == QtCore.Qt.Key_Down:
- self.shape.tryMove(self.field, 0, 1)
- self.update()
- if type(event) == QtGui.QKeyEvent and event.key() == QtCore.Qt.Key_End:
- self.shape.tryDrop(self.field)
- self.onShapeLanding()
- self.update()
- if type(event) == QtGui.QKeyEvent and event.key() == QtCore.Qt.Key_Space:
- self.shape.tryRotate(self.field)
- self.update()
- def onShapeLanding(self):
- self.shape.mergeToField(self.field)
- self.field.updateRows()
- if not self.trySpawnShape():
- self.gameOver()
- else:
- self.genNextShape()
- def trySpawnShape(self):
- self.shape = shape(self.shape_data[self.nextShapeID])
- self.shape.setPos(self.field.defaultRespawnPos(self.shape))
- if self.shape.collisionDetected(self.field):
- return False
- return True
- def genNextShape(self):
- self.nextShapeID = self.randomShapeId()
- self.nextShapeSample = block_map(self.shape_data[self.nextShapeID][0])
- def updateGame(self):
- if not self.running:
- return
- if not self.shape.tryMove(self.field, 0, 1):
- self.onShapeLanding()
- self.update()
- def gameOver(self):
- print ("Game Over")
- self.running = False
- app = QtWidgets.QApplication(sys.argv)
- window = TetrisFieldWidget()
- window.show()
- timer = QtCore.QTimer()
- timer.timeout.connect(window.updateGame)
- timer.start(1000)
- sys.exit(app.exec_())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement