面向对象设计面试

讲师:neetcode.io

口袋资源独家Neetcode付费课程独家中英文字幕配套资料齐全!

不到1/10的价格,即可享受同样的高品质课程,且可以完全拥有,随时随地都可以任意观看和分享。

设计连接四

背景

四子棋是一种在 7×6 网格上玩的流行游戏。两名玩家轮流将彩色圆盘放入网格中。第一个连续(垂直、水平或对角线)获得四张圆盘的玩家获胜。

连接四

要求

一些可能要问的问题:

  • 游戏规则是什么?
  • 网格的尺寸是多少?
  • 有多少名玩家?玩家 vs 电脑?玩家对玩家?
  • 我们有记录分数吗?

基本

  • 游戏将仅由两名玩家进行,玩家对玩家
  • 游戏板的尺寸应该是可变的
  • 目标是将 N 个圆盘连接成一排(垂直、水平或对角线)
    • N 是一个变量(例如连接 4、5、6 等)
  • 应该有一个分数跟踪系统
    • 当玩家达到目标分数后,他们就是胜利者

设计

高水平

  • 我们需要一个Grid类来维护二维板的状态
    • 棋盘单元可以是空的、黄色(由玩家 1 占据)或红色(由玩家 2 占据)
    • 网格还将负责检查获胜条件
  • 我们可以有一个Player类来代表玩家的棋子颜色
    • 这并不是非常重要,但封装信息通常是一个很好的做法
  • Game类将由GridPlayers组成
    • 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()

发表回复

后才能评论

  • 每一个课程页面,都有演示地址选项,点击链接可以跳转到课程发布网站查看详细课程列表。
  • 绝大部分课程都有试看内容,可以先点击试看,再决定是否购买。
  • 本站课程均存储在阿里云盘或百度网盘中,由于阿里云盘对分享的文件类型有限制,所以课程资料和字幕会存储到蓝奏云盘中。
  • 阿里云盘和蓝奏云盘都是不限速下载的,你既可以选择在阿里云盘中在线学习,也可以选择下载到本地学习。
  • 课程下载到本地可以挂载中英文双字幕,请点击查看Potplayer挂载中英文双字幕教程
  • 本站所有课程,均提供mp4格式视频文件,中英文双字幕,配套资料齐全,不加密。
  • 每一个课程右侧下载面板中,都会有清晰度标识,大部分都是1080P或者720P,还有少数是超高清的。
  • 本站课程购买之后,均可以免费更新,所有课程,皆配有中文字幕。
  • 请注意,课程的中文字幕是根据英文字幕用谷歌翻译生成的,本非人工翻译。谷歌翻译准确度尚可,学习观看,没有问题。
  • 由于数字资源具有可复制性,一旦购买,不接受退款要求,请在购买之前,认真了解课程内容,确定是否需要。
  • 当然,如果有特殊情况,可以查看网站底部联系方式,联系站长说明问题,我会为你妥善处理。
  • 赞助本站VIP会员,可以免费下载所有课程,详情请查看VIP介绍