过默 发表于 2026-7-25 07:48:34

button

python中国象棋,怎么写呢?pythonpygame界面怎么绘制?

woshiamaola 发表于 2026-7-25 10:52:59

让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,None 表示空
def init_board():
    b = [ * COLS for _ in range(ROWS)]
    def put(r, c, color, name):
      b = (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
            if p:
                x, y = pos_to_px(r, c)
                color = RED if p == '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, 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:
                cnt += 1
    else:
      for r in range(min(r1, r2) + 1, max(r1, r2)):
            if board:
                cnt += 1
    return cnt

def valid_move(r1, c1, r2, c2):
    piece = board
    if not piece:
      return False
    color, name = piece
    target = board
    if target and target == 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:
                return False
      else:
            if board:
                return False
      return True

    if name in ('相', '象'):
      if (abs(dr), abs(dc)) != (2, 2):
            return False
      if board:   # 塞象眼
            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 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 = in ('帥', '將', '帅', '将')]
    reds = == 'r']
    blacks = == '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 = board
                        board = None
                        selected = None
                        turn = 'b' if turn == 'r' else 'r'
                        winner = check_winner()
                  elif board and board == turn:
                        selected = (r, c)   # 改选
                  else:
                        selected = None
                else:
                  if board and board == 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()
页: [1]
查看完整版本: button