Книга знаний |
|
Инф. технологии |
|
Программа игры в крестики-нолики, состоящая из трех основных классов:
<br>- PlayButton (рисует фигуры) <br>- MainWindow (создает игровое поле с кнопками, выполняет некоторые системные задачи, рисует "линию победы", обрабатывает ход человека и делает ход от лица компьютера) <br>- Game (содержит массив field, представляющий игровое поле, возвращает или устанавливает фигуру, проверяет на победу) | Автор статьи: Волшебник Последняя редакция №1 от 03.10.23 URL: http://kb.mista.ru/article.php?id=983 |
from PyQt6.QtCore import QPoint, QSize, Qt
from PyQt6.QtGui import QFont, QPainter, QPen
from PyQt6.QtWidgets import QApplication, QGridLayout, QMainWindow, QLabel, QPushButton,
QVBoxLayout, QWidget
from enum import Enum
import random
import time
#
====================================================================================================
=============
class Figure(Enum):
X = 1
O = 2
class GameState(Enum):
PLAYING = 1
HUMAN_WINNER = 2
COMPUTER_WINNER = 3
DRAW = 4
class VictoryType(Enum):
COLUMN = 1
ROW = 2
DIAGONAL_From_LeftTop = 3 # \
DIAGONAL_From_RightTop = 4 # /
#
====================================================================================================
=============
class PlayButton(QPushButton):
def __init__(self, y, x):
super().__init__()
self.y = y
self.x = x
self.setFixedSize(QSize(50,50))
def drawFigure(self, fig):
if fig == Figure.X:
self.setText("×")
self.setFont(QFont("Arial", 40))
elif fig == Figure.O:
self.setText("◯")
self.setFont(QFont("Arial", 25))
else:
self.setText("")
#
====================================================================================================
=============
class MainWindow(QMainWindow):
def __init__(I):
super().__init__()
I.setWindowTitle("Tic-tac-toe")
I.mainLayout = QVBoxLayout()
I.initElements();
container = QWidget()
container.setLayout(I.mainLayout)
I.setCentralWidget(container)
I.startNewGame()
# ---------------------------------------
def initElements(I):
# кнопка New game
I.btNewGame = QPushButton("New game")
I.btNewGame.clicked.connect(I.startNewGame)
I.mainLayout.addWidget(I.btNewGame)
# игровое поле с кнопками
I.initGamePanel()
# строка состояния
I.statusString = QLabel()
I.mainLayout.addWidget(I.statusString)
I.updateStatusString("")
# ---------------------------------------
def initGamePanel(I):
I.CellButtons = {(y,x): PlayButton(y,x) for y in [1, 2, 3] for x in [1, 2, 3]}
layoutField = QGridLayout()
for coord in I.CellButtons:
button = I.CellButtons[coord]
button.clicked.connect(lambda checked, bt = button: I.HumanMove(bt))
layoutField.addWidget(button,button.y,button.x)
I.mainLayout.addLayout(layoutField)
# ---------------------------------------
def updateGamePanel(I):
for y in [1, 2, 3]:
for x in [1, 2, 3]:
cell = (y,x)
figure = I.game.field[cell]
button = I.CellButtons[cell]
button.drawFigure(figure)
button.setEnabled(figure is None)
I.repaint()
# ---------------------------------------
def updateStatusString(I, text):
I.statusString.setText(text)
I.repaint()
# ---------------------------------------
def startNewGame(I):
I.game = Game()
I.updateGamePanel()
I.updateStatusString("")
# ---------------------------------------
def AfterMove(I):
I.updateGamePanel()
X_wins, vType, n = I.game.checkVictory(Figure.X)
if X_wins:
I.updateStatusString("You won!")
I.repaint()
# victory line will be painted in paintEvent
return GameState.HUMAN_WINNER
(O_wins, vType, n) = I.game.checkVictory(Figure.O)
if O_wins:
I.updateStatusString("Computer won!")
I.repaint()
# victory line will be painted in paintEvent
return GameState.COMPUTER_WINNER
if len(I.game.getFreeCells()) == 0:
I.updateStatusString("Draw!")
return GameState.DRAW
return GameState.PLAYING
# ---------------------------------------
def drawVictoryLine(I, vType, n):
lineWidth = 10
lineColor = Qt.GlobalColor.red
pen = QPen(lineColor, lineWidth, Qt.PenStyle.SolidLine)
qp = QPainter()
qp.begin(I)
qp.setPen(pen)
if vType == VictoryType.COLUMN:
bt1 = I.CellButtons[(1, n)]
bt2 = I.CellButtons[(3, n)]
x = bt1.pos().x() + bt1.width() // 2
beginPoint = QPoint(x, bt1.pos().y())
endPoint = QPoint(x, bt2.pos().y()+bt2.height())
elif vType == VictoryType.ROW:
bt1 = I.CellButtons[(n, 1)]
bt2 = I.CellButtons[(n, 3)]
y = bt1.pos().y()+bt1.width()//2
beginPoint = QPoint(bt1.pos().x(), y)
endPoint = QPoint(bt2.pos().x() + bt2.width(), y)
elif vType == VictoryType.DIAGONAL_From_LeftTop: # \
bt1 = I.CellButtons[(1, 1)]
bt2 = I.CellButtons[(3, 3)]
beginPoint = QPoint(bt1.pos().x(), bt1.pos().y())
endPoint = QPoint(bt2.pos().x() + bt2.width(), bt2.pos().y()+bt2.height())
elif vType == VictoryType.DIAGONAL_From_RightTop: # /
bt1 = I.CellButtons[(1, 3)]
bt2 = I.CellButtons[(3, 1)]
beginPoint = QPoint(bt1.pos().x() + bt1.width(), bt1.pos().y())
endPoint = QPoint(bt2.pos().x(), bt2.pos().y()+bt2.height())
else:
raise NotImplementedError
qp.drawLine(beginPoint, endPoint)
qp.end()
# ---------------------------------------
def paintEvent(I, event):
for fig in list(Figure):
victory, VictoryType, n = I.game.checkVictory(fig)
if victory:
I.drawVictoryLine(VictoryType, n)
break
# ---------------------------------------
def ComputerMove(I):
selectedCell = I.game.getRandomFreeCell()
I.game.setFigure(selectedCell, Figure.O)
I.AfterMove()
# ---------------------------------------
def HumanMove(I, button):
cell = (button.y, button.x)
if I.game.getFigure(cell) is not None: return
I.game.setFigure(cell, Figure.X)
if I.AfterMove() == GameState.PLAYING:
time.sleep(0.25) # imitation of thinking
I.ComputerMove()
#
====================================================================================================
=============
class Game:
def __init__(self):
self.field = {(y,x):None for y in [1, 2, 3] for x in [1, 2, 3]}
def getFreeCells(self):
return [cell for cell in self.field if self.getFigure(cell)==None]
def getRandomFreeCell(self):
freeCells = self.getFreeCells()
return random.choice(freeCells)
def checkVictory(self, figure) -> tuple:
F = self.field
for y in [1, 2, 3]:
if F[(y, 1)] == F[(y, 2)] == F[(y, 3)] == figure: return (True,
VictoryType.ROW, y)
for x in [1, 2, 3]:
if F[(1, x)] == F[(2, x)] == F[(3, x)] == figure: return (True,
VictoryType.COLUMN, x)
if F[(1, 1)] == F[(2, 2)] == F[(3, 3)] == figure: return (True,
VictoryType.DIAGONAL_From_LeftTop, None) # \
if F[(1, 3)] == F[(2, 2)] == F[(3, 1)] == figure: return (True,
VictoryType.DIAGONAL_From_RightTop, None) # /
return (False, None, None)
def getFigure(self, cell):
return self.field[cell]
def setFigure(self, cell, figure):
self.field[cell] = figure
#
====================================================================================================
=============
app = QApplication([])
window = MainWindow()
window.show()
app.exec()
Описание
| Рубрикатор
| Поиск
| ТелепатБот
| Захваченные статьи
| Установки
| Форум
|