python + pygame 四人五子棋

下载pygame

pip install pygame==2.0.1

项目结构

  • background.png 为背景
  • icon.png 为窗口图标
  • stone.wav 为落子声
  • callbacks.py 处理算法
  • configs.py 定义游戏常量
  • game.py 为主程序
  • render.py 绘制游戏界面

下载素材

下载链接
提取码: x4f1

代码

configs.py

GAME_WIDTH = 19  # 几路棋盘
BACKGROUND_PATH = 'resources/background.png'  # 背景图片
ICON_PATH = 'resources/icon.png'  # 窗口图标
WIDTH = 720  # 窗口长
HEIGHT = 720  # 窗口宽
GRID_WIDTH = WIDTH // (GAME_WIDTH + 1)  # 网格边长
SOUND_PATH = 'resources/stone.wav'  # 落子音效
PLAYER1 = (0, 0, 0)  
PLAYER2 = (255, 255, 255)
PLAYER3 = (255, 0, 0)
PLAYER4 = (0, 0, 255)
ORDER = [PLAYER1, PLAYER2, PLAYER3, PLAYER4]  # 玩家落子顺序
TITLE = '四人五子棋'  # 窗口标题
FPS = 35  # fps
BOARD = [[None] * (GAME_WIDTH + 1) for _ in range(GAME_WIDTH + 1)]  # 棋盘列表
RADIUS = 16  # 棋子半径

callbacks.py

import pygame
from copy import deepcopy
from configs import *

def get_mouse_position():  # 获取鼠标位置
    return pygame.mouse.get_pos()

def get_row_column(*mouse_position):  # 根据x, y获得行列
    x, y = mouse_position
    return (int(round(x / (GRID_WIDTH + .0))),
            int(round(y / (GRID_WIDTH + .0))))

def is_game_over(color, board, *pos):  # 判断游戏是否结束
    flatten = lambda x: [y for i in x for y in flatten(i)] if type(x) is list else [x]
    temp_board = flatten(deepcopy(board))
    if not any(temp_board):
        return None
    temp_hor = 1
    temp_vert = 1
    temp_slash = 1
    temp_backslash = 1
    left = pos[0] - 1
    right = pos[0] + 1
    up = pos[1] - 1
    down = pos[1] + 1
    
    while left > 0 and board[left][pos[1]] == color:
        left -= 1
        temp_hor += 1
    while right < 20 and board[right][pos[1]] == color:
        right += 1
        temp_hor += 1
    while up > 0 and board[pos[0]][up] == color:
        up -= 1
        temp_vert += 1
    while down < 20 and board[pos[0]][down] == color:
        down += 1
        temp_vert += 1
    
    left = pos[0] - 1
    up = pos[1] - 1
    right = pos[0] + 1
    down = pos[1] + 1
    
    while left > 0 and up > 0 and board[left][up] == color:
        left -= 1
        up -= 1
        temp_backslash += 1
    while right < 20 and down < 20 and board[right][down] == color:
        right += 1
        down += 1
        temp_backslash += 1
    
    right = pos[0] + 1
    up = pos[1] - 1
    left = pos[0] - 1
    down = pos[1] + 1
    
    while right < 20 and up > 0 and board[right][up] == color:
        right += 1
        up -= 1
        temp_slash += 1
    while left > 0 and down < 20 and board[left][down] == color:
        left -= 1
        down += 1
        temp_slash += 1
    
    return max((temp_hor, temp_vert, temp_slash, temp_backslash)) >= 5

def get_player(color):  # 根据棋子颜色获得玩家名称
    return {
        PLAYER1: '玩家1',
        PLAYER2: '玩家2',
        PLAYER3: '玩家3',
        PLAYER4: '玩家4'
    }.get(color)

render.py

import pygame
from configs import *

def draw_board(screen: pygame.Surface, background: pygame.Surface):  # 绘制19×19棋盘
    screen.blit(background, (0, 0))  # 画背景
    rect_lines = [
        ((GRID_WIDTH, GRID_WIDTH), (GRID_WIDTH, HEIGHT - GRID_WIDTH)),
        ((GRID_WIDTH, GRID_WIDTH), (WIDTH - GRID_WIDTH, GRID_WIDTH)),
        ((GRID_WIDTH, HEIGHT - GRID_WIDTH),
         (WIDTH - GRID_WIDTH, HEIGHT - GRID_WIDTH)),
        ((WIDTH - GRID_WIDTH, GRID_WIDTH),
         (WIDTH - GRID_WIDTH, HEIGHT - GRID_WIDTH)),
    ]  # 网格线
    
    for line in rect_lines:
        pygame.draw.line(screen, (0, 0, 0), line[0], line[1], 2)
    
    for count in range(19):
        pygame.draw.line(screen, (0, 0, 0),
                         (GRID_WIDTH * (2 + count), GRID_WIDTH),
                         (GRID_WIDTH * (2 + count), HEIGHT - GRID_WIDTH))
        pygame.draw.line(screen, (0, 0, 0),
                         (GRID_WIDTH, GRID_WIDTH * (2 + count)),
                         (HEIGHT - GRID_WIDTH, GRID_WIDTH * (2 + count)))
    
    rect_circles = [
        (GRID_WIDTH * 4, GRID_WIDTH * 4),
        (WIDTH - GRID_WIDTH * 4, GRID_WIDTH * 4),
        (WIDTH - GRID_WIDTH * 4, HEIGHT - GRID_WIDTH * 4),
        (GRID_WIDTH * 4, HEIGHT - GRID_WIDTH * 4),
        (GRID_WIDTH * 10, GRID_WIDTH * 10),
        (GRID_WIDTH * 10, GRID_WIDTH * 4),
        (GRID_WIDTH * 4, GRID_WIDTH * 10),
        (GRID_WIDTH * 10, GRID_WIDTH * 16),
        (GRID_WIDTH * 16, GRID_WIDTH * 10)
    ]  # 9个点
    
    for circle in rect_circles:
        pygame.draw.circle(screen, (0, 0, 0), circle, 5)

def draw_movements(board, screen: pygame.Surface):  # 根据board绘制棋子
    for row, i in enumerate(board):
        for column, j in enumerate(i):
            if j:
                pygame.draw.circle(screen, j,
                                   (row * GRID_WIDTH, column * GRID_WIDTH),
                                   RADIUS)

game.py

import pygame
import sys
from pygame.locals import *
from copy import deepcopy
from configs import *
from callbacks import *
from render import *
from tkinter import Tk
from tkinter.messagebox import showinfo

def init():  # 初始化
    pygame.init()
    pygame.mixer.init()

def destroy():  # 关闭窗口
    pygame.quit()
    sys.exit()

init()
board = deepcopy(BOARD)

background = pygame.image.load(BACKGROUND_PATH)
background = pygame.transform.scale(background, (WIDTH, HEIGHT))  # 缩放
icon = pygame.image.load(ICON_PATH)
stone_sound = pygame.mixer.Sound(SOUND_PATH)

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(TITLE)
pygame.display.set_icon(icon)

clock = pygame.time.Clock()
counter = 0  # 记录落子玩家
tips = ''

while True:
    clock.tick(FPS)  # 设置FPS
    
    for event in pygame.event.get():
        if event.type == QUIT:
            destroy()
        elif event.type == KEYDOWN:
            if event.key == K_ESCAPE:  # ESC键退出
                destroy()
        elif event.type == MOUSEBUTTONDOWN:
            pos = get_mouse_position()
            row, column = get_row_column(*pos)
            if not board[row][column]:
                player = ORDER[counter]
                board[row][column] = player
                counter += 1
                stone_sound.play()
                if counter == len(ORDER):
                    counter = 0
                game_over = is_game_over(player, board, row, column)
                if game_over is None:
                    tips = '和棋'
                if game_over:
                    player = get_player(player)
                    if not tips:
                        tips = f'{player}赢了!'
                    Tk().withdraw()  # 隐藏tk窗口
                    showinfo('游戏结束', tips)
                    destroy()
    
    draw_board(screen, background)
    draw_movements(board, screen)
    pygame.display.update()

效果

pygame技巧

如果用上代码,控制台会输出:

pygame 2.0.1 (SDL 2.0.14, Python 3.8.3)
Hello from the pygame community. https://www.pygame.org/contribute.html

解决方案:
在game.py的第一、二行添加:

import os
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = 'true'
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值