Advertisement
archlinuxorg

Untitled

Jun 28th, 2016
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.06 KB | None | 0 0
  1. from PyQt5 import QtCore, QtGui, QtWidgets
  2. import sys
  3. import re
  4. import random
  5.  
  6.  
  7. class block_map:
  8.     def __init__(self, squares):
  9.         self.squares = squares
  10.         self.width = len(squares[0])
  11.         self.height = len(squares)
  12.  
  13.     def draw(self, painter, offset_x=0, offset_y=0):
  14.         for x in range(0, self.width):
  15.             for y in range(0, self.height):
  16.                 if (self.squares[y][x]):
  17.                     painter.drawRect((x + offset_x) * 10 + 1, (y + offset_y) * 10 + 1, 8, 8)
  18.  
  19.  
  20. class shape(block_map):
  21.     def __init__(self, sq):
  22.         block_map.__init__(self, sq[0])
  23.         self.full_sq_data = sq
  24.         self.angle = 0
  25.         self.x = 0
  26.         self.y = 0
  27.  
  28.     def setPos(self, pos):
  29.         self.x = pos[0]
  30.         self.y = pos[1]
  31.  
  32.     def draw(self, painter):
  33.         block_map.draw(self, painter, self.x, self.y)
  34.  
  35.     def tryMove(self, field, vec_x, vec_y):
  36.         if self.collisionDetected(field, vec_x, vec_y):
  37.             return False
  38.         self.x += vec_x
  39.         self.y += vec_y
  40.         return True
  41.  
  42.     def tryDrop(self, field):
  43.         pass
  44.         while self.tryMove(field, 0, 1):
  45.             pass
  46.         return True
  47.  
  48.     def tryRotate(self, field):
  49.         dx = (self.width) / 2 - 1
  50.         dy = (self.height) / 2 - 1
  51.         delta = dx - dy
  52.  
  53.         self.angle = self.nextAngleID()
  54.         block_map.__init__(self, self.full_sq_data[self.angle])
  55.  
  56.         if not self.collisionDetected(field, delta, -delta):
  57.             self.x = self.x + delta
  58.             self.y = self.y - delta
  59.             return True
  60.         elif not self.collisionDetected(field, delta + 1, -delta):
  61.             self.x = self.x + delta + 1
  62.             self.y = self.y - delta
  63.             return True
  64.         elif not self.collisionDetected(field, delta + 1, -delta + 1):
  65.             self.x = self.x + delta + 1
  66.             self.y = self.y - delta + 1
  67.             return True
  68.         elif not self.collisionDetected(field, delta, -delta + 1):
  69.             self.x = self.x + delta
  70.             self.y = self.y - delta + 1
  71.             return True
  72.         else:
  73.             self.angle = self.prevAngleID()
  74.             block_map.__init__(self, self.full_sq_data[self.angle])
  75.             return False
  76.  
  77.     def nextAngleID(self):
  78.         if self.angle == 3:
  79.             return 0
  80.         else:
  81.             return self.angle + 1
  82.  
  83.     def prevAngleID(self):
  84.         if self.angle == 0:
  85.             return 3
  86.         else:
  87.             return self.angle - 1
  88.  
  89.     def mergeToField(self, field):
  90.         for block_x in range(0, self.width):
  91.             for block_y in range(0, self.height):
  92.                 if self.squares[block_y][block_x]:
  93.                     field.squares[block_y + self.y][block_x + self.x] = True
  94.  
  95.     def collisionDetected(self, field, offset_x = 0, offset_y = 0):
  96.         if field.blockOutsideBorders(self.x + offset_x,
  97.                                      self.y + offset_y):
  98.             return True
  99.         if field.blockOutsideBorders(self.x + self.width + offset_x - 1,
  100.                                      self.y + self.height + offset_y - 1):
  101.             return True
  102.  
  103.         for block_x in range(0, self.width):
  104.             for block_y in range (0, self.height):
  105.                 if self.squares[block_y][block_x]:
  106.                     if field.squares[self.y + block_y + offset_y]\
  107.                                     [self.x + block_x + offset_x]:
  108.                         return True
  109.         return False
  110.  
  111.  
  112. class field(block_map):
  113.     def __init__(self, w=10, h=20):
  114.         block_map.__init__(self, [[False for x in range(0, w)] for y in range(0, h)])
  115.  
  116.     def draw(self, painter):
  117.         block_map.draw(self, painter)
  118.         painter.drawRect(0, 0, self.width * 10, self.height * 10)
  119.  
  120.     def blockOutsideBorders(self, pos_x, pos_y):
  121.         x_outside = pos_x < 0 or pos_x >= self.width
  122.         y_outside = pos_y < 0 or pos_y >= self.height
  123.         return x_outside or y_outside
  124.  
  125.     def defaultRespawnPos(self, shape):
  126.         return (self.width / 2 - shape.width / 2, 0)
  127.  
  128.     def updateRows(self):
  129.         for current_index in reversed(range(0, self.height)):
  130.             while self.fullRow(current_index):
  131.                 self.burnRow(current_index)
  132.  
  133.     def fullRow(self, row_index):
  134.         for block in self.squares[row_index]:
  135.             if not block:
  136.                 return False
  137.         return True
  138.  
  139.     def burnRow(self, row_index):
  140.         for current_index in reversed(range(1, row_index + 1)):
  141.             self.squares[current_index] = self.squares[current_index - 1]
  142.         self.squares[0] = [False for x in range(0, self.width)]
  143.  
  144.  
  145. class TetrisFieldWidget(QtWidgets.QWidget):
  146.     def __init__(self, parent=None):
  147.         QtWidgets.QWidget.__init__(self, parent)
  148.         self.shape_data = self.parseShapesFile("shapes")
  149.         self.field = field()
  150.         self.genNextShape()
  151.         self.trySpawnShape()
  152.         self.genNextShape()
  153.         self.running = True
  154.  
  155.     def parseShapesFile(self, file):
  156.         data = re.sub('\s*', '', open(file, "r").read())
  157.         data = re.findall('shape\{(?:(?:[01]*;)+)\}', data)
  158.         data = [re.findall('([01]+);', sh) for sh in data]
  159.         data = [self.genShapePrototypes([[int(digit) for digit in row] for row in sh]) for sh in data]
  160.         return data
  161.  
  162.     def genShapePrototypes(self, raw_shape):
  163.         width = len(raw_shape[0])
  164.         result = []
  165.         result.append(raw_shape)
  166.         result.append([[row[i] for row in reversed(raw_shape)] for i in range(0, width)])
  167.         result.append([[item for item in reversed(row)] for row in reversed(result[0])])
  168.         result.append([[item for item in reversed(row)] for row in reversed(result[1])])
  169.         return result
  170.  
  171.     def randomShapeId(self):
  172.         return random.randint(0, len(self.shape_data) - 1)
  173.  
  174.     def paintEvent(self, QPaintEvent):
  175.         painter = QtGui.QPainter()
  176.         painter.begin(self)
  177.         self.field.draw(painter)
  178.         self.shape.draw(painter)
  179.         self.nextShapeSample.draw(painter, self.field.width + 5, 8)
  180.         painter.end()
  181.  
  182.     def keyPressEvent(self, event):
  183.         if not self.running:
  184.             return
  185.         if type(event) == QtGui.QKeyEvent and event.key() == QtCore.Qt.Key_Left:
  186.             self.shape.tryMove(self.field, -1, 0)
  187.             self.update()
  188.         if type(event) == QtGui.QKeyEvent and event.key() == QtCore.Qt.Key_Right:
  189.             self.shape.tryMove(self.field, 1, 0)
  190.             self.update()
  191.         if type(event) == QtGui.QKeyEvent and event.key() == QtCore.Qt.Key_Down:
  192.             self.shape.tryMove(self.field, 0, 1)
  193.             self.update()
  194.         if type(event) == QtGui.QKeyEvent and event.key() == QtCore.Qt.Key_End:
  195.             self.shape.tryDrop(self.field)
  196.             self.onShapeLanding()
  197.             self.update()
  198.         if type(event) == QtGui.QKeyEvent and event.key() == QtCore.Qt.Key_Space:
  199.             self.shape.tryRotate(self.field)
  200.             self.update()
  201.  
  202.     def onShapeLanding(self):
  203.         self.shape.mergeToField(self.field)
  204.         self.field.updateRows()
  205.         if not self.trySpawnShape():
  206.             self.gameOver()
  207.         else:
  208.             self.genNextShape()
  209.  
  210.     def trySpawnShape(self):
  211.         self.shape = shape(self.shape_data[self.nextShapeID])
  212.         self.shape.setPos(self.field.defaultRespawnPos(self.shape))
  213.         if self.shape.collisionDetected(self.field):
  214.             return False
  215.         return True
  216.  
  217.     def genNextShape(self):
  218.         self.nextShapeID = self.randomShapeId()
  219.         self.nextShapeSample = block_map(self.shape_data[self.nextShapeID][0])
  220.  
  221.     def updateGame(self):
  222.         if not self.running:
  223.             return
  224.         if not self.shape.tryMove(self.field, 0, 1):
  225.             self.onShapeLanding()
  226.         self.update()
  227.  
  228.     def gameOver(self):
  229.         print ("Game Over")
  230.         self.running = False
  231.  
  232.  
  233. app = QtWidgets.QApplication(sys.argv)
  234.  
  235. window = TetrisFieldWidget()
  236. window.show()
  237.  
  238. timer = QtCore.QTimer()
  239. timer.timeout.connect(window.updateGame)
  240. timer.start(1000)
  241.  
  242. sys.exit(app.exec_())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement