用python做俄罗斯方块,人工智能玩俄罗斯方块

  用python做俄罗斯方块,人工智能玩俄罗斯方块

  说到《俄罗斯方块》,几乎所有人都知道。以其悠久的历史和长久的可玩性,专家们轻挥一波游戏。本文将使用Python实现俄罗斯方块高级版——AI自动玩俄罗斯方块。有兴趣的可以了解一下。

  00-1010介绍文字1)tetra . py2)tetra _ model . py3)tetra _ ai . py效果显示

  

目录

  说到《俄罗斯方块》(俄罗斯方块),几乎所有人都知道。

  以其悠久的历史和长久的可玩性,专家们轻挥一波游戏。

  对于绝大多数朋友来说,《俄罗斯方块》的规则不需要多说——来填充一行不同形状的方块并消除它们。

  这个流行了30多年的《俄罗斯方块》游戏,以前也写过。可以在之前的Pygame合集里找找看!

  但是今天穆介绍了《俄罗斯方块》的新作——实现AI自动玩游戏。

  估计你三观全毁,下巴掉下来,惊呼“我玩了个假游戏!”

  

导语

  移动、放下、填充和消除!

  子木你我的童年回忆《俄罗斯方块AI版本》已正式上线!

  代码由Tetris.py、tetris_model.py和Tetis _ AI.py三部分组成,游戏的主要逻辑由Tetis控制。模型定义了方块的样式,AI顾名思义实现了主要的AI算法。

  

正文

  俄罗斯方块类(QMainWindow):

  def __init__(self):

  超级()。__init__()

  self.isStarted=False

  self.isPaused=False

  self.nextMove=None

  self.lastShape=Shape.shapeNone

  self.initUI()

  def initi(self):

  self.gridSize=22

  自我速度=10

  self.timer=QBasicTimer()

  self.setFocusPolicy(Qt。StrongFocus焦点)

  hLayout=QHBoxLayout()

  self.tboard=Board(self,self.gridSize)

  hLayout.addWidget(self.tboard)

  self.sidePanel=SidePanel(self,self.gridSize)

  hlayout . add widget(self . side panel)

  self.statusbar=self.statusBar()

  self.tboard.msg2Statusbar[str]。连接(self.statusbar.showMessage)

  self.start()

  自我中心()

  Self.setWindowTitle(AI俄罗斯方块)

  self.show()

  self . setfixedsize(self . tboard . width()self . side panel . width(),

  self . side panel . height()self . status bar . height())

  定义中心(自身):

  screen=QDesktopWidget()。屏幕几何()

  size=self.geometry()

  self . move((screen . width()-size . width())//2,(screen . height()-size . height())//2)

  定义开始(自身):

  如果self.isPaused:

  返回

   self.isStarted = True

   self.tboard.score = 0

   BOARD_DATA.clear()

   self.tboard.msg2Statusbar.emit(str(self.tboard.score))

   BOARD_DATA.createNewPiece()

   self.timer.start(self.speed, self)

   def pause(self):

   if not self.isStarted:

   return

   self.isPaused = not self.isPaused

   if self.isPaused:

   self.timer.stop()

   self.tboard.msg2Statusbar.emit("paused")

   else:

   self.timer.start(self.speed, self)

   self.updateWindow()

   def updateWindow(self):

   self.tboard.updateData()

   self.sidePanel.updateData()

   self.update()

   def timerEvent(self, event):

   if event.timerId() == self.timer.timerId():

   if TETRIS_AI and not self.nextMove:

   self.nextMove = TETRIS_AI.nextMove()

   if self.nextMove:

   k = 0

   while BOARD_DATA.currentDirection != self.nextMove[0] and k < 4:

   BOARD_DATA.rotateRight()

   k += 1

   k = 0

   while BOARD_DATA.currentX != self.nextMove[1] and k < 5:

   if BOARD_DATA.currentX > self.nextMove[1]:

   BOARD_DATA.moveLeft()

   elif BOARD_DATA.currentX < self.nextMove[1]:

   BOARD_DATA.moveRight()

   k += 1

   # lines = BOARD_DATA.dropDown()

   lines = BOARD_DATA.moveDown()

   self.tboard.score += lines

   if self.lastShape != BOARD_DATA.currentShape:

   self.nextMove = None

   self.lastShape = BOARD_DATA.currentShape

   self.updateWindow()

   else:

   super(Tetris, self).timerEvent(event)

   def keyPressEvent(self, event):

   if not self.isStarted or BOARD_DATA.currentShape == Shape.shapeNone:

   super(Tetris, self).keyPressEvent(event)

   return

   key = event.key()

   if key == Qt.Key_P:

   self.pause()

   return

   if self.isPaused:

   return

   elif key == Qt.Key_Left:

   BOARD_DATA.moveLeft()

   elif key == Qt.Key_Right:

   BOARD_DATA.moveRight()

   elif key == Qt.Key_Up:

   BOARD_DATA.rotateLeft()

   elif key == Qt.Key_Space:

   self.tboard.score += BOARD_DATA.dropDown()

   else:

   super(Tetris, self).keyPressEvent(event)

   self.updateWindow()

  def drawSquare(painter, x, y, val, s):

   colorTable = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC,

   0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00]

   if val == 0:

   return

   color = QColor(colorTable[val])

   painter.fillRect(x + 1, y + 1, s - 2, s - 2, color)

   painter.setPen(color.lighter())

   painter.drawLine(x, y + s - 1, x, y)

   painter.drawLine(x, y, x + s - 1, y)

   painter.setPen(color.darker())

   painter.drawLine(x + 1, y + s - 1, x + s - 1, y + s - 1)

   painter.drawLine(x + s - 1, y + s - 1, x + s - 1, y + 1)

  class SidePanel(QFrame):

   def __init__(self, parent, gridSize):

   super().__init__(parent)

   self.setFixedSize(gridSize * 5, gridSize * BOARD_DATA.height)

   self.move(gridSize * BOARD_DATA.width, 0)

   self.gridSize = gridSize

   def updateData(self):

   self.update()

   def paintEvent(self, event):

   painter = QPainter(self)

   minX, maxX, minY, maxY = BOARD_DATA.nextShape.getBoundingOffsets(0)

   dy = 3 * self.gridSize

   dx = (self.width() - (maxX - minX) * self.gridSize) / 2

   val = BOARD_DATA.nextShape.shape

   for x, y in BOARD_DATA.nextShape.getCoords(0, 0, -minY):

   drawSquare(painter, x * self.gridSize + dx, y * self.gridSize + dy, val, self.gridSize)

  class Board(QFrame):

   msg2Statusbar = pyqtSignal(str)

   speed = 10

   def __init__(self, parent, gridSize):

   super().__init__(parent)

   self.setFixedSize(gridSize * BOARD_DATA.width, gridSize * BOARD_DATA.height)

   self.gridSize = gridSize

   self.initBoard()

   def initBoard(self):

   self.score = 0

   BOARD_DATA.clear()

   def paintEvent(self, event):

   painter = QPainter(self)

   # Draw backboard

   for x in range(BOARD_DATA.width):

   for y in range(BOARD_DATA.height):

   val = BOARD_DATA.getValue(x, y)

   drawSquare(painter, x * self.gridSize, y * self.gridSize, val, self.gridSize)

   # Draw current shape

   for x, y in BOARD_DATA.getCurrentShapeCoord():

   val = BOARD_DATA.currentShape.shape

   drawSquare(painter, x * self.gridSize, y * self.gridSize, val, self.gridSize)

   # Draw a border

   painter.setPen(QColor(0x777777))

   painter.drawLine(self.width()-1, 0, self.width()-1, self.height())

   painter.setPen(QColor(0xCCCCCC))

   painter.drawLine(self.width(), 0, self.width(), self.height())

   def updateData(self):

   self.msg2Statusbar.emit(str(self.score))

   self.update()

  if __name__ == __main__:

   # random.seed(32)

   app = QApplication([])

   tetris = Tetris()

   sys.exit(app.exec_())

  

  

2)Tetris_model.py​​

  

import random

  class Shape(object):

   shapeNone = 0

   shapeI = 1

   shapeL = 2

   shapeJ = 3

   shapeT = 4

   shapeO = 5

   shapeS = 6

   shapeZ = 7

   shapeCoord = (

   ((0, 0), (0, 0), (0, 0), (0, 0)),

   ((0, -1), (0, 0), (0, 1), (0, 2)),

   ((0, -1), (0, 0), (0, 1), (1, 1)),

   ((0, -1), (0, 0), (0, 1), (-1, 1)),

   ((0, -1), (0, 0), (0, 1), (1, 0)),

   ((0, 0), (0, -1), (1, 0), (1, -1)),

   ((0, 0), (0, -1), (-1, 0), (1, -1)),

   ((0, 0), (0, -1), (1, 0), (-1, -1))

   )

   def __init__(self, shape=0):

   self.shape = shape

   def getRotatedOffsets(self, direction):

   tmpCoords = Shape.shapeCoord[self.shape]

   if direction == 0 or self.shape == Shape.shapeO:

   return ((x, y) for x, y in tmpCoords)

   if direction == 1:

   return ((-y, x) for x, y in tmpCoords)

   if direction == 2:

   if self.shape in (Shape.shapeI, Shape.shapeZ, Shape.shapeS):

   return ((x, y) for x, y in tmpCoords)

   else:

   return ((-x, -y) for x, y in tmpCoords)

   if direction == 3:

   if self.shape in (Shape.shapeI, Shape.shapeZ, Shape.shapeS):

   return ((-y, x) for x, y in tmpCoords)

   else:

   return ((y, -x) for x, y in tmpCoords)

   def getCoords(self, direction, x, y):

   return ((x + xx, y + yy) for xx, yy in self.getRotatedOffsets(direction))

   def getBoundingOffsets(self, direction):

   tmpCoords = self.getRotatedOffsets(direction)

   minX, maxX, minY, maxY = 0, 0, 0, 0

   for x, y in tmpCoords:

   if minX > x:

   minX = x

   if maxX < x:

   maxX = x

   if minY > y:

   minY = y

   if maxY < y:

   maxY = y

   return (minX, maxX, minY, maxY)

  class BoardData(object):

   width = 10

   height = 22

   def __init__(self):

   self.backBoard = [0] * BoardData.width * BoardData.height

   self.currentX = -1

   self.currentY = -1

   self.currentDirection = 0

   self.currentShape = Shape()

   self.nextShape = Shape(random.randint(1, 7))

   self.shapeStat = [0] * 8

   def getData(self):

   return self.backBoard[:]

   def getValue(self, x, y):

   return self.backBoard[x + y * BoardData.width]

   def getCurrentShapeCoord(self):

   return self.currentShape.getCoords(self.currentDirection, self.currentX, self.currentY)

   def createNewPiece(self):

   minX, maxX, minY, maxY = self.nextShape.getBoundingOffsets(0)

   result = False

   if self.tryMoveCurrent(0, 5, -minY):

   self.currentX = 5

   self.currentY = -minY

   self.currentDirection = 0

   self.currentShape = self.nextShape

   self.nextShape = Shape(random.randint(1, 7))

   result = True

   else:

   self.currentShape = Shape()

   self.currentX = -1

   self.currentY = -1

   self.currentDirection = 0

   result = False

   self.shapeStat[self.currentShape.shape] += 1

   return result

   def tryMoveCurrent(self, direction, x, y):

   return self.tryMove(self.currentShape, direction, x, y)

   def tryMove(self, shape, direction, x, y):

   for x, y in shape.getCoords(direction, x, y):

   if x >= BoardData.width or x < 0 or y >= BoardData.height or y < 0:

   return False

   if self.backBoard[x + y * BoardData.width] > 0:

   return False

   return True

   def moveDown(self):

   lines = 0

   if self.tryMoveCurrent(self.currentDirection, self.currentX, self.currentY + 1):

   self.currentY += 1

   else:

   self.mergePiece()

   lines = self.removeFullLines()

   self.createNewPiece()

   return lines

   def dropDown(self):

   while self.tryMoveCurrent(self.currentDirection, self.currentX, self.currentY + 1):

   self.currentY += 1

   self.mergePiece()

   lines = self.removeFullLines()

   self.createNewPiece()

   return lines

   def moveLeft(self):

   if self.tryMoveCurrent(self.currentDirection, self.currentX - 1, self.currentY):

   self.currentX -= 1

   def moveRight(self):

   if self.tryMoveCurrent(self.currentDirection, self.currentX + 1, self.currentY):

   self.currentX += 1

   def rotateRight(self):

   if self.tryMoveCurrent((self.currentDirection + 1) % 4, self.currentX, self.currentY):

   self.currentDirection += 1

   self.currentDirection %= 4

   def rotateLeft(self):

   if self.tryMoveCurrent((self.currentDirection - 1) % 4, self.currentX, self.currentY):

   self.currentDirection -= 1

   self.currentDirection %= 4

   def removeFullLines(self):

   newBackBoard = [0] * BoardData.width * BoardData.height

   newY = BoardData.height - 1

   lines = 0

   for y in range(BoardData.height - 1, -1, -1):

   blockCount = sum([1 if self.backBoard[x + y * BoardData.width] > 0 else 0 for x in range(BoardData.width)])

   if blockCount < BoardData.width:

   for x in range(BoardData.width):

   newBackBoard[x + newY * BoardData.width] = self.backBoard[x + y * BoardData.width]

   newY -= 1

   else:

   lines += 1

   if lines > 0:

   self.backBoard = newBackBoard

   return lines

   def mergePiece(self):

   for x, y in self.currentShape.getCoords(self.currentDirection, self.currentX, self.currentY):

   self.backBoard[x + y * BoardData.width] = self.currentShape.shape

   self.currentX = -1

   self.currentY = -1

   self.currentDirection = 0

   self.currentShape = Shape()

   def clear(self):

   self.currentX = -1

   self.currentY = -1

   self.currentDirection = 0

   self.currentShape = Shape()

   self.backBoard = [0] * BoardData.width * BoardData.height

  BOARD_DATA = BoardData()

  

  

3)Tetris_ai.py​​

  

from tetris_model import BOARD_DATA, Shape

  import math

  from datetime import datetime

  import numpy as np

  class TetrisAI(object):

   def nextMove(self):

   t1 = datetime.now()

   if BOARD_DATA.currentShape == Shape.shapeNone:

   return None

   currentDirection = BOARD_DATA.currentDirection

   currentY = BOARD_DATA.currentY

   _, _, minY, _ = BOARD_DATA.nextShape.getBoundingOffsets(0)

   nextY = -minY

   # print("=======")

   strategy = None

   if BOARD_DATA.currentShape.shape in (Shape.shapeI, Shape.shapeZ, Shape.shapeS):

   d0Range = (0, 1)

   elif BOARD_DATA.currentShape.shape == Shape.shapeO:

   d0Range = (0,)

   else:

   d0Range = (0, 1, 2, 3)

   if BOARD_DATA.nextShape.shape in (Shape.shapeI, Shape.shapeZ, Shape.shapeS):

   d1Range = (0, 1)

   elif BOARD_DATA.nextShape.shape == Shape.shapeO:

   d1Range = (0,)

   else:

   d1Range = (0, 1, 2, 3)

   for d0 in d0Range:

   minX, maxX, _, _ = BOARD_DATA.currentShape.getBoundingOffsets(d0)

   for x0 in range(-minX, BOARD_DATA.width - maxX):

   board = self.calcStep1Board(d0, x0)

   for d1 in d1Range:

   minX, maxX, _, _ = BOARD_DATA.nextShape.getBoundingOffsets(d1)

   dropDist = self.calcNextDropDist(board, d1, range(-minX, BOARD_DATA.width - maxX))

   for x1 in range(-minX, BOARD_DATA.width - maxX):

   score = self.calculateScore(np.copy(board), d1, x1, dropDist)

   if not strategy or strategy[2] < score:

   strategy = (d0, x0, score)

   print("===", datetime.now() - t1)

   return strategy

   def calcNextDropDist(self, data, d0, xRange):

   res = {}

   for x0 in xRange:

   if x0 not in res:

   res[x0] = BOARD_DATA.height - 1

   for x, y in BOARD_DATA.nextShape.getCoords(d0, x0, 0):

   yy = 0

   while yy + y < BOARD_DATA.height and (yy + y < 0 or data[(y + yy), x] == Shape.shapeNone):

   yy += 1

   yy -= 1

   if yy < res[x0]:

   res[x0] = yy

   return res

   def calcStep1Board(self, d0, x0):

   board = np.array(BOARD_DATA.getData()).reshape((BOARD_DATA.height, BOARD_DATA.width))

   self.dropDown(board, BOARD_DATA.currentShape, d0, x0)

   return board

   def dropDown(self, data, shape, direction, x0):

   dy = BOARD_DATA.height - 1

   for x, y in shape.getCoords(direction, x0, 0):

   yy = 0

   while yy + y < BOARD_DATA.height and (yy + y < 0 or data[(y + yy), x] == Shape.shapeNone):

   yy += 1

   yy -= 1

   if yy < dy:

   dy = yy

   # print("dropDown: shape {0}, direction {1}, x0 {2}, dy {3}".format(shape.shape, direction, x0, dy))

   self.dropDownByDist(data, shape, direction, x0, dy)

   def dropDownByDist(self, data, shape, direction, x0, dist):

   for x, y in shape.getCoords(direction, x0, 0):

   data[y + dist, x] = shape.shape

   def calculateScore(self, step1Board, d1, x1, dropDist):

   # print("calculateScore")

   t1 = datetime.now()

   width = BOARD_DATA.width

   height = BOARD_DATA.height

   self.dropDownByDist(step1Board, BOARD_DATA.nextShape, d1, x1, dropDist[x1])

   # print(datetime.now() - t1)

   # Term 1: lines to be removed

   fullLines, nearFullLines = 0, 0

   roofY = [0] * width

   holeCandidates = [0] * width

   holeConfirm = [0] * width

   vHoles, vBlocks = 0, 0

   for y in range(height - 1, -1, -1):

   hasHole = False

   hasBlock = False

   for x in range(width):

   if step1Board[y, x] == Shape.shapeNone:

   hasHole = True

   holeCandidates[x] += 1

   else:

   hasBlock = True

   roofY[x] = height - y

   if holeCandidates[x] > 0:

   holeConfirm[x] += holeCandidates[x]

   holeCandidates[x] = 0

   if holeConfirm[x] > 0:

   vBlocks += 1

   if not hasBlock:

   break

   if not hasHole and hasBlock:

   fullLines += 1

   vHoles = sum([x ** .7 for x in holeConfirm])

   maxHeight = max(roofY) - fullLines

   # print(datetime.now() - t1)

   roofDy = [roofY[i] - roofY[i+1] for i in range(len(roofY) - 1)]

   if len(roofY) <= 0:

   stdY = 0

   else:

   stdY = math.sqrt(sum([y ** 2 for y in roofY]) / len(roofY) - (sum(roofY) / len(roofY)) ** 2)

   if len(roofDy) <= 0:

   stdDY = 0

   else:

   stdDY = math.sqrt(sum([y ** 2 for y in roofDy]) / len(roofDy) - (sum(roofDy) / len(roofDy)) ** 2)

   absDy = sum([abs(x) for x in roofDy])

   maxDy = max(roofY) - min(roofY)

   # print(datetime.now() - t1)

   score = fullLines * 1.8 - vHoles * 1.0 - vBlocks * 0.5 - maxHeight ** 1.5 * 0.02 \

   - stdY * 0.0 - stdDY * 0.01 - absDy * 0.2 - maxDy * 0.3

   # print(score, fullLines, vHoles, vBlocks, maxHeight, stdY, stdDY, absDy, roofY, d0, x0, d1, x1)

   return score

  TETRIS_AI = TetrisAI()

  

  

效果展示

  1)视频展示——

  

  【普通玩家VS高手玩家】一带传奇游戏《俄罗斯方块儿》AI版!

  2)截图展示——

  

  以上就是Python实现AI自动玩俄罗斯方块游戏的详细内容,更多关于Python俄罗斯方块的资料请关注盛行IT软件开发工作室其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • chatgpt是什么?为什么这么火?
  • 如何看待马斯克等全球千名科技人士联名呼吁暂停更强大的AI开发?
  • ChatGPT为什么注册不了?OpenAI ChatGPT的账号哪里可以注册?
  • OpenAI ChatGPT怎么注册账号?ChatGPT账号注册教程
  • chatgpt什么意思,什么是ChatGPT ?
  • Tiamat人工智能绘画网站,Tiamat自动作图生成器,网址是多少?
  • 盗梦师人工智能绘画网站,盗梦师自动作图生成器,网址是多少?
  • 无界版图人工智能绘画网站,无界版图自动作图生成器,网址是多少?
  • 滴墨社区人工智能绘画网站,滴墨社区自动作图生成器,网址是多少?
  • draft.art官网网址是多少?Draft人工智能绘画网站,Draft art自动作图生成器
  • 6pen.art人工智能绘画网站,6pen.art自动作图生成器,网址是多少?
  • 文心一格人工智能绘画网站,文心一格自动作图生成器,网址是多少?
  • NovelAI人工智能绘画网站,NovelAI自动作图生成器,网址是多少?
  • Parti人工智能绘画网站,Parti自动作图生成器,网址是多少?
  • Disco Diffusion 人工智能绘画网站,Disco Diffusion 自动作图生成器,网址是多少?
  • 留言与评论(共有 条评论)
       
    验证码: