鱼C论坛

 找回密码
 立即注册
查看: 28|回复: 1

button

[复制链接]
发表于 4 小时前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
python中国象棋,怎么写呢?pythonpygame界面怎么绘制?
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层
让ai生成了一个完整的,可以跑跑看
# -*- coding: utf-8 -*-
"""
中国象棋 - Python + Pygame 实现
点击选中己方棋子,再点击目标位置走子。红方先行。
"""
import pygame
import sys

pygame.init()

# ---------- 常量 ----------
GRID = 60                    # 每格像素
MARGIN = 40                  # 棋盘外边距
COLS, ROWS = 9, 10           # 9列10行的交叉点
BOARD_W = (COLS - 1) * GRID  # 8格宽
BOARD_H = (ROWS - 1) * GRID  # 9格高
WIDTH = BOARD_W + MARGIN * 2
HEIGHT = BOARD_H + MARGIN * 2
RADIUS = 26                  # 棋子半径

BG = (240, 210, 150)         # 棋盘底色
LINE = (60, 40, 20)
RED = (200, 30, 30)
BLACK = (20, 20, 20)
HL = (30, 160, 60)           # 选中高亮

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("中国象棋")

# 字体(尝试系统中文字体)
def load_font(size):
    for name in ["simhei", "microsoftyahei", "pingfang sc", "wenquanyi micro hei", "arial unicode ms"]:
        try:
            f = pygame.font.SysFont(name, size)
            if f.render("車", True, (0, 0, 0)).get_width() > 0:
                return f
        except Exception:
            continue
    return pygame.font.Font(None, size)

FONT = load_font(40)

# ---------- 棋盘状态 ----------
# 每个棋子: (color, name)  color: 'r'/'b'
# 用二维数组 board[row][col],None 表示空
def init_board():
    b = [[None] * COLS for _ in range(ROWS)]
    def put(r, c, color, name):
        b[r][c] = (color, name)
    # 黑方(上方 row 0-4)
    order = ['車', '馬', '象', '士', '將', '士', '象', '馬', '車']
    for c, n in enumerate(order):
        put(0, c, 'b', n)
    put(2, 1, 'b', '砲'); put(2, 7, 'b', '砲')
    for c in range(0, 9, 2):
        put(3, c, 'b', '卒')
    # 红方(下方 row 5-9)
    order_r = ['車', '馬', '相', '仕', '帥', '仕', '相', '馬', '車']
    for c, n in enumerate(order_r):
        put(9, c, 'r', n)
    put(7, 1, 'r', '炮'); put(7, 7, 'r', '炮')
    for c in range(0, 9, 2):
        put(6, c, 'r', '兵')
    return b

board = init_board()
turn = 'r'
selected = None  # (row, col)

# ---------- 坐标转换 ----------
def pos_to_px(r, c):
    return MARGIN + c * GRID, MARGIN + r * GRID

def px_to_pos(x, y):
    c = round((x - MARGIN) / GRID)
    r = round((y - MARGIN) / GRID)
    if 0 <= r < ROWS and 0 <= c < COLS:
        return r, c
    return None

# ---------- 绘制棋盘 ----------
def draw_board():
    screen.fill(BG)
    # 横线
    for r in range(ROWS):
        x1, y = pos_to_px(r, 0)
        x2, _ = pos_to_px(r, COLS - 1)
        pygame.draw.line(screen, LINE, (x1, y), (x2, y), 2)
    # 竖线(河界处上下断开,最外两条贯通)
    for c in range(COLS):
        x, y1 = pos_to_px(0, c)
        _, y2 = pos_to_px(ROWS - 1, c)
        if c == 0 or c == COLS - 1:
            pygame.draw.line(screen, LINE, (x, y1), (x, y2), 2)
        else:
            _, ym1 = pos_to_px(4, c)
            _, ym2 = pos_to_px(5, c)
            pygame.draw.line(screen, LINE, (x, y1), (x, ym1), 2)
            pygame.draw.line(screen, LINE, (x, ym2), (x, y2), 2)
    # 九宫斜线
    for (r0, r1) in [(0, 2), (7, 9)]:
        x1, y1 = pos_to_px(r0, 3)
        x2, y2 = pos_to_px(r1, 5)
        pygame.draw.line(screen, LINE, (x1, y1), (x2, y2), 2)
        x1, y1 = pos_to_px(r0, 5)
        x2, y2 = pos_to_px(r1, 3)
        pygame.draw.line(screen, LINE, (x1, y1), (x2, y2), 2)
    # 楚河汉界
    mid = load_font(30)
    t1 = mid.render("楚河", True, LINE)
    t2 = mid.render("漢界", True, LINE)
    _, ytop = pos_to_px(4, 0)
    screen.blit(t1, (MARGIN + GRID * 1.5, ytop + 15))
    screen.blit(t2, (MARGIN + GRID * 5.5, ytop + 15))

# ---------- 绘制棋子 ----------
def draw_pieces():
    for r in range(ROWS):
        for c in range(COLS):
            p = board[r][c]
            if p:
                x, y = pos_to_px(r, c)
                color = RED if p[0] == 'r' else BLACK
                pygame.draw.circle(screen, (235, 220, 180), (x, y), RADIUS)
                pygame.draw.circle(screen, color, (x, y), RADIUS, 3)
                txt = FONT.render(p[1], True, color)
                rect = txt.get_rect(center=(x, y))
                screen.blit(txt, rect)
    # 选中高亮
    if selected:
        x, y = pos_to_px(*selected)
        pygame.draw.circle(screen, HL, (x, y), RADIUS + 3, 3)

# ---------- 走子规则 ----------
def in_palace(r, c, color):
    if color == 'r':
        return 7 <= r <= 9 and 3 <= c <= 5
    return 0 <= r <= 2 and 3 <= c <= 5

def count_between(r1, c1, r2, c2):
    cnt = 0
    if r1 == r2:
        for c in range(min(c1, c2) + 1, max(c1, c2)):
            if board[r1][c]:
                cnt += 1
    else:
        for r in range(min(r1, r2) + 1, max(r1, r2)):
            if board[r][c1]:
                cnt += 1
    return cnt

def valid_move(r1, c1, r2, c2):
    piece = board[r1][c1]
    if not piece:
        return False
    color, name = piece
    target = board[r2][c2]
    if target and target[0] == color:      # 不能吃己方
        return False
    dr, dc = r2 - r1, c2 - c1

    if name in ('車', '车'):
        if r1 != r2 and c1 != c2:
            return False
        return count_between(r1, c1, r2, c2) == 0

    if name in ('馬', '马'):
        if (abs(dr), abs(dc)) not in [(2, 1), (1, 2)]:
            return False
        # 蹩马腿
        if abs(dr) == 2:
            if board[r1 + dr // 2][c1]:
                return False
        else:
            if board[r1][c1 + dc // 2]:
                return False
        return True

    if name in ('相', '象'):
        if (abs(dr), abs(dc)) != (2, 2):
            return False
        if board[r1 + dr // 2][c1 + dc // 2]:   # 塞象眼
            return False
        # 不能过河
        if color == 'r' and r2 < 5:
            return False
        if color == 'b' and r2 > 4:
            return False
        return True

    if name in ('仕', '士'):
        if (abs(dr), abs(dc)) != (1, 1):
            return False
        return in_palace(r2, c2, color)

    if name in ('帥', '將', '帅', '将'):
        # 将帅对脸
        if c1 == c2 and abs(dr) >= 1 and dc == 0:
            pass
        if (abs(dr), abs(dc)) not in [(1, 0), (0, 1)]:
            # 允许飞将吃对方将
            if c1 == c2 and target and target[1] in ('帥', '將', '帅', '将'):
                return count_between(r1, c1, r2, c2) == 0
            return False
        return in_palace(r2, c2, color)

    if name in ('炮', '砲'):
        if r1 != r2 and c1 != c2:
            return False
        n = count_between(r1, c1, r2, c2)
        if target:
            return n == 1       # 吃子需翻山
        return n == 0

    if name in ('兵', '卒'):
        if color == 'r':
            if r1 >= 5:          # 未过河,只能向前
                return dr == -1 and dc == 0
            else:                # 过河后可左右
                return (dr == -1 and dc == 0) or (dr == 0 and abs(dc) == 1)
        else:
            if r1 <= 4:
                return dr == 1 and dc == 0
            else:
                return (dr == 1 and dc == 0) or (dr == 0 and abs(dc) == 1)
    return False

# ---------- 胜负判断 ----------
def check_winner():
    kings = [p for row in board for p in row if p and p[1] in ('帥', '將', '帅', '将')]
    reds = [k for k in kings if k[0] == 'r']
    blacks = [k for k in kings if k[0] == 'b']
    if not reds:
        return 'b'
    if not blacks:
        return 'r'
    return None

# ---------- 主循环 ----------
def main():
    global turn, selected
    winner = None
    clock = pygame.time.Clock()
    while True:
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                pygame.quit(); sys.exit()
            if e.type == pygame.MOUSEBUTTONDOWN and winner is None:
                pos = px_to_pos(*e.pos)
                if not pos:
                    continue
                r, c = pos
                if selected:
                    sr, sc = selected
                    if (r, c) == (sr, sc):
                        selected = None
                    elif valid_move(sr, sc, r, c):
                        board[r][c] = board[sr][sc]
                        board[sr][sc] = None
                        selected = None
                        turn = 'b' if turn == 'r' else 'r'
                        winner = check_winner()
                    elif board[r][c] and board[r][c][0] == turn:
                        selected = (r, c)   # 改选
                    else:
                        selected = None
                else:
                    if board[r][c] and board[r][c][0] == turn:
                        selected = (r, c)

        draw_board()
        draw_pieces()
        if winner:
            f = load_font(50)
            msg = ("红方胜!" if winner == 'r' else "黑方胜!")
            t = f.render(msg, True, RED if winner == 'r' else BLACK)
            screen.blit(t, t.get_rect(center=(WIDTH // 2, HEIGHT // 2)))
        pygame.display.flip()
        clock.tick(30)

if __name__ == "__main__":
    main()
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2026-7-25 12:43

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表