面向对象设计面试
讲师:neetcode.io
口袋资源独家Neetcode付费课程,独家中英文字幕,配套资料齐全!
用不到1/10的价格,即可享受同样的高品质课程,且可以完全拥有,随时随地都可以任意观看和分享。
设计连接四
背景
四子棋是一种在 7×6 网格上玩的流行游戏。两名玩家轮流将彩色圆盘放入网格中。第一个连续(垂直、水平或对角线)获得四张圆盘的玩家获胜。
要求
一些可能要问的问题:
- 游戏规则是什么?
- 网格的尺寸是多少?
- 有多少名玩家?玩家 vs 电脑?玩家对玩家?
- 我们有记录分数吗?
基本
- 游戏将仅由两名玩家进行,玩家对玩家
- 游戏板的尺寸应该是可变的
- 目标是将 N 个圆盘连接成一排(垂直、水平或对角线)
- N 是一个变量(例如连接 4、5、6 等)
- 应该有一个分数跟踪系统
- 当玩家达到目标分数后,他们就是胜利者
设计
高水平
- 我们需要一个Grid类来维护二维板的状态
- 棋盘单元可以是空的、黄色(由玩家 1 占据)或红色(由玩家 2 占据)
- 网格还将负责检查获胜条件
- 我们可以有一个Player类来代表玩家的棋子颜色
- 这并不是非常重要,但封装信息通常是一个很好的做法
- Game类将由Grid和Players组成
- Game类将负责游戏循环并跟踪得分
代码
我们将使用枚举来表示GridPosition。
import enum
class GridPosition(enum.Enum):
EMPTY = 0
YELLOW = 1
RED = 2
网格将维护棋盘和所有棋子的状态。它还将检查获胜条件。也许将该checkWin
方法命名为更合适checkNConnected
,因为网格本身不需要知道游戏规则是什么。
class Grid:
def __init__(self, rows, columns):
self._rows = rows
self._columns = columns
self._grid = None
self.initGrid()
def initGrid(self):
self._grid = [[GridPosition.EMPTY for _ in range(self._columns)] for _ in range(self._rows)]
def getGrid(self):
return self._grid
def getColumnCount(self):
return self._columns
def placePiece(self, column, piece):
if column < 0 or column >= self._columns:
raise ValueError('Invalid column')
if piece == GridPosition.EMPTY:
raise ValueError('Invalid piece')
for row in range(self._rows-1, -1, -1):
if self._grid[row][column] == GridPosition.EMPTY:
self._grid[row][column] = piece
return row
def checkWin(self, connectN, row, col, piece):
count = 0
# Check horizontal
for c in range(self._columns):
if self._grid[row][c] == piece:
count += 1
else:
count = 0
if count == connectN:
return True
# Check vertical
count = 0
for r in range(self._rows):
if self._grid[r][col] == piece:
count += 1
else:
count = 0
if count == connectN:
return True
# Check diagonal
count = 0
for r in range(self._rows):
c = row + col - r
if c >= 0 and c < self._columns and self._grid[r][c] == piece:
count += 1
else:
count = 0
if count == connectN:
return True
# Check anti-diagonal
count = 0
for r in range(self._rows):
c = col - row + r
if c >= 0 and c < self._columns and self._grid[r][c] == piece:
count += 1
else:
count = 0
if count == connectN:
return True
return False
玩家只是封装了玩家的信息,更重要的是封装了玩家的棋子颜色。
class Player:
def __init__(self, name, pieceColor):
self._name = name
self._pieceColor = pieceColor
def getName(self):
return self._name
def getPieceColor(self):
return self._pieceColor
Game类将用于玩游戏。它将跟踪玩家、得分和网格。它还将负责游戏循环。通过构造函数传入的游戏参数使我们能够灵活地玩具有稍微不同的规则和维度的游戏。虽然我们可以在Game
类中实例化棋盘,但最好通过构造函数传递它。这意味着Game类不需要知道如何实例化棋盘。即使我们只玩两个玩家,我们仍然可以使用列表来存储玩家。这不是必需的,但它很简单,并且使我们能够灵活地在将来添加更多玩家。
class Game:
def __init__(self, grid, connectN, targetScore):
self._grid = grid
self._connectN = connectN
self._targetScore = targetScore
self._players = [
Player('Player 1', GridPosition.YELLOW),
Player('Player 2', GridPosition.RED)
]
self._score = {}
for player in self._players:
self._score[player.getName()] = 0
def printBoard(self):
print('Board:\n')
grid = self._grid.getGrid()
for i in range(len(grid)):
row = ''
for piece in grid[i]:
if piece == GridPosition.EMPTY:
row += '0 '
elif piece == GridPosition.YELLOW:
row += 'Y '
elif piece == GridPosition.RED:
row += 'R '
print(row)
print('')
def playMove(self, player):
self.printBoard()
print(f"{player.getName()}'s turn")
colCnt = self._grid.getColumnCount()
moveColumn = int(input(f"Enter column between {0} and {colCnt - 1} to add piece: "))
moveRow = self._grid.placePiece(moveColumn, player.getPieceColor())
return (moveRow, moveColumn)
def playRound(self):
while True:
for player in self._players:
row, col = self.playMove(player)
pieceColor = player.getPieceColor()
if self._grid.checkWin(self._connectN, row, col, pieceColor):
self._score[player.getName()] += 1
return player
def play(self):
maxScore = 0
winner = None
while maxScore < self._targetScore:
winner = self.playRound()
print(f"{winner.getName()} won the round")
maxScore = max(self._score[winner.getName()], maxScore)
self._grid.initGrid() # reset grid
print(f"{winner.getName()} won the game")
最后,我们可以创建网格,设置游戏参数并玩游戏。
grid = Grid(6, 7)
game = Game(grid, 4, 2)
game.play()
声明:口袋资源网(koudaizy.com)提供的所有课程、素材等资源全部来源于互联网,赞助VIP仅用于对口袋资源服务器带宽及网站运营等费用支出做支持,从本站下载资源,说明你已同意本条款。