首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Gomoku (连接5)游戏在游戏中的实现

Gomoku (连接5)游戏在游戏中的实现
EN

Code Review用户
提问于 2021-07-10 18:53:35
回答 2查看 1.8K关注 0票数 12

我试图在游戏中实现一个简单的Gomoku游戏(连接5),并希望得到一些帮助。到目前为止,基本的功能是很好的工作与2名球员之间的对立。

全码

代码语言:javascript
复制
import numpy as np
import pygame
import sys
import math

# initialize the pygame program
pygame.init()

# static variables
ROW_COUNT = 15
COL_COUNT = 15

# define screen size
BLOCKSIZE = 50 # individual grid
S_WIDTH = COL_COUNT * BLOCKSIZE # screen width
S_HEIGHT = ROW_COUNT * BLOCKSIZE # screen height
PADDING_RIGHT = 200 # for game menu
SCREENSIZE = (S_WIDTH + PADDING_RIGHT,S_HEIGHT)
RADIUS = 20 # game piece radius

# colors
BLACK = (0,0,0)
WHITE = (255,255,255)
BROWN = (205,128,0)

# create a board array
def create_board(row, col):
    board = np.zeros((row,col))
    return board

# draw a board in pygame window
def draw_board(screen):
    for x in range(0,S_WIDTH,BLOCKSIZE):
        for y in range(0,S_HEIGHT,BLOCKSIZE):
            rect = pygame.Rect(x, y, BLOCKSIZE, BLOCKSIZE)
            pygame.draw.rect(screen,BROWN,rect)

    # draw inner grid lines
    # draw vertical lines
    for x in range(BLOCKSIZE // 2, S_WIDTH - BLOCKSIZE // 2 + BLOCKSIZE, BLOCKSIZE):
        line_start = (x, BLOCKSIZE // 2)
        line_end = (x,S_HEIGHT-BLOCKSIZE // 2)
        pygame.draw.line(screen, BLACK, line_start,line_end,2)

    # draw horizontal lines
    for y in range(BLOCKSIZE // 2, S_HEIGHT - BLOCKSIZE // 2 + BLOCKSIZE, BLOCKSIZE):
        line_start = (BLOCKSIZE // 2,y)
        line_end = (S_WIDTH-BLOCKSIZE // 2,y)
        pygame.draw.line(screen, BLACK, line_start,line_end,2)
    pygame.display.update()

# drop a piece
def drop_piece(board, row, col, piece):
    board[row][col] = piece

# draw a piece on board
def draw_piece(screen,board):
    # draw game pieces at mouse location
    for x in range(COL_COUNT):
        for y in range(ROW_COUNT):
            circle_pos = (x * BLOCKSIZE + BLOCKSIZE//2, y * BLOCKSIZE + BLOCKSIZE//2)
            if board[y][x] == 1:
                pygame.draw.circle(screen, BLACK, circle_pos, RADIUS)
            elif board[y][x] == 2:
                pygame.draw.circle(screen, WHITE, circle_pos, RADIUS)
    pygame.display.update()

# check if it is a valid location
def is_valid_loc(board, row, col):
    return board[row][col] == 0

# victory decision
def who_wins(board, piece):
    # check for horizontal win
    for c in range(COL_COUNT - 4):
        for r in range(ROW_COUNT):
            if board[r][c] == piece and board[r][c+1] == piece and board[r][c+2] == piece and board[r][c+3] == piece\
                and board[r][c+4] == piece:
                return True

    # check for vertical win
    for c in range(COL_COUNT):
        for r in range(ROW_COUNT-4):
            if board[r][c] == piece and board[r+1][c] == piece and board[r+2][c] == piece and board[r+3][c] == piece\
                and board[r+4][c] == piece:
                return True

    # check for positively sloped diagonal wih
    for c in range(COL_COUNT-4):
        for r in range(4,ROW_COUNT):
            if board[r][c] == piece and board[r-1][c+1] == piece and board[r-2][c+2] == piece and board[r-3][c+3] == piece\
                and board[r-4][c+4] == piece:
                return True

    # check for negatively sloped diagonal win
    for c in range(COL_COUNT-4):
        for r in range(ROW_COUNT-4):
            if board[r][c] == piece and board[r+1][c+1] == piece and board[r+2][c+2] == piece and board[r+3][c+3] == piece\
                and board[r+4][c+4] == piece:
                return True

def main():
    # game variables
    game_over = False
    turn = 0 # turn == 0 for player 1, turn == 1 for player 2
    piece_1 = 1 # black
    piece_2 = 2 # white

    # FPS
    FPS = 60
    frames_per_sec = pygame.time.Clock()

    # board 2D array
    board = create_board(ROW_COUNT,COL_COUNT)
    print(board)

    # game screen
    SCREEN = pygame.display.set_mode(SCREENSIZE)
    SCREEN.fill(WHITE)
    pygame.display.set_caption('Gomoku (Connet 5)')
    # icon = pygame.image.load('icon.png')
    # pygame.display.set_icon(icon)

    # font
    my_font = pygame.font.Font('freesansbold.ttf', 32)

    # text message
    label_1 = my_font.render('Black wins!', True, WHITE, BLACK)
    label_2 = my_font.render('White wins!', True, WHITE, BLACK)

    # display the screen
    draw_board(SCREEN)

    # game loop
    while not game_over:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

            elif event.type == pygame.MOUSEBUTTONDOWN:
                x_pos = event.pos[0]
                y_pos = event.pos[1]

                col = int(math.floor(x_pos / BLOCKSIZE))
                row = int(math.floor(y_pos / BLOCKSIZE))

                # turn decision, if black(1)/white(2) piece already placed, go back to the previous turn
                if board[row][col] == 1:
                    turn = 0
                if board[row][col] == 2:
                    turn = 1

                # Ask for Player 1 move
                if turn == 0:
                    # check if its a valid location then drop a piece
                    if is_valid_loc(board, row, col):
                        drop_piece(board, row, col, piece_1)
                        draw_piece(SCREEN,board)

                        if who_wins(board,piece_1):
                            print('Black wins!')
                            SCREEN.blit(label_1, (280,50))
                            pygame.display.update()
                            game_over = True

                # Ask for Player 2 move
                else:
                    # check if its a valid location then drop a piece
                    if is_valid_loc(board, row, col):
                        drop_piece(board, row, col, piece_2)
                        draw_piece(SCREEN,board)

                        if who_wins(board,piece_2):
                            print('White wins!')
                            SCREEN.blit(label_2, (280,50))
                            pygame.display.update()
                            game_over = True

                print(board)

                # increment turn
                turn += 1
                turn = turn % 2

                if game_over:
                    pygame.time.wait(4000)

        frames_per_sec.tick(FPS)

if __name__ == '__main__':
    main()

游戏截图:

注释

比赛似乎进行得很好。我将一些代码移到main()中,以便为下一步创建一个重新启动功能。

另外,我还想创建一些附加特性:

  • 撤消函数:撤消上一次移动
  • 重做功能:还原被undo()函数删除的部分
  • 在当前的部分上留下一个标记。示例:

任何批评/帮助都是非常欢迎的!

EN

回答 2

Code Review用户

发布于 2021-07-11 13:07:21

当您使用代码检查胜利时,我可以提出一个小小的改进:

代码语言:javascript
复制
        if board[r][c] == piece and board[r][c+1] == piece and board[r][c+2] == piece and board[r][c+3] == piece\
            and board[r][c+4] == piece:

您正在检查所有指定的位置是否等于piece,因此您可以编写一个助手:

代码语言:javascript
复制
def all_equal(xs, y):
    return all(x == y for x in xs)

并重复使用此函数进行各种检查,减少这种逻辑概念的重复,并使代码更加简洁和可读性更强。

另一种减少重复的方法是在这个代码块中:

代码语言:javascript
复制
            if turn == 0:
                # check if its a valid location then drop a piece
                if is_valid_loc(board, row, col):
                    drop_piece(board, row, col, piece_1)
                    draw_piece(SCREEN,board)

                    if who_wins(board,piece_1):
                        print('Black wins!')
                        SCREEN.blit(label_1, (280,50))
                        pygame.display.update()
                        game_over = True

            # Ask for Player 2 move
            else:
                # check if its a valid location then drop a piece
                if is_valid_loc(board, row, col):
                    drop_piece(board, row, col, piece_2)
                    draw_piece(SCREEN,board)

                    if who_wins(board,piece_2):
                        print('White wins!')
                        SCREEN.blit(label_2, (280,50))
                        pygame.display.update()
                        game_over = True

你可以

代码语言:javascript
复制
if turn == 0:
    piece = piece_1
    name = "Black"
    label = label_1
else:
    piece = piece_2
    name = "White"
    label = label_2

然后:

代码语言:javascript
复制
                if is_valid_loc(board, row, col):
                    drop_piece(board, row, col, piece)
                    draw_piece(SCREEN,board)

                    if who_wins(board,piece):
                        print(name + ' wins!')
                        SCREEN.blit(label, (280,50))
                        pygame.display.update()
                        game_over = True

这就清楚地表明,玩家被用相同的程序逻辑处理,并且只有一些变量在处理两个播放器的轮转之间发生变化。

从总体上看,代码看起来非常干净,一开始就很好地划分了关注点和清晰的常量。

票数 7
EN

Code Review用户

发布于 2021-07-11 23:45:08

为了检查玩家是否赢了,你不需要每次都扫描整个棋盘。只对刚刚放置在所有方向(水平,垂直,正斜面对角线和负斜面对角线)的部分进行扫描就足够了。

下面是这个想法的一个示例实现:

代码语言:javascript
复制
from enum import Enum, auto


class Direction(Enum):
    N = auto()
    NE = auto()
    E = auto()
    SE = auto()
    S = auto()
    SW = auto()
    W = auto()
    NW = auto()

    @property
    def vector(self):
        return {
            Direction.N: (-1, 0),
            Direction.NE: (-1, 1),
            Direction.E: (0, 1),
            Direction.SE: (1, 1),
            Direction.S: (1, 0),
            Direction.SW: (1, -1),
            Direction.W: (0, -1),
            Direction.NW: (-1, -1),
        }[self]


def count(board, row, col, direction):
    """
    Return the number of consecutive pieces matching the starting piece's
    color, starting from (but not including) the starting piece, and going
    in the given direction.

    row: starting piece's row
    col: starting piece's column
    """

    def on_board(row, col):
        return 0 <= row < ROW_COUNT and 0 <= col < COL_COUNT

    piece_color = board[row][col]
    row_delta, col_delta = direction.vector

    count = 0
    row, col = row + row_delta, col + col_delta
    while on_board(row, col) and board[row][col] == piece_color:
        count += 1
        row, col = row + row_delta, col + col_delta

    return count


def is_win(board, row, col):
    """
    Returns True if the piece played on (row, col) wins the game.
    """

    def is_win_helper(board, row, col, d1, d2):
        return count(board, row, col, d1) + 1 + count(board, row, col, d2) >= 5

    return (
        # horizontal win
        is_win_helper(board, row, col, Direction.W, Direction.E)
        # vertical win
        or is_win_helper(board, row, col, Direction.N, Direction.S)
        # positively sloped diagonal win
        or is_win_helper(board, row, col, Direction.SW, Direction.NE)
        # negatively sloped diagonal win
        or is_win_helper(board, row, col, Direction.NW, Direction.SE)
    )

然后,您可以通过以下操作检查刚才在(row, col)打球的球员是否赢了:

代码语言:javascript
复制
if is_win(board, row, col):
    # ...
票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/263936

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档