鱼C论坛

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

[作品展示] python中国象棋游戏

[复制链接]
发表于 前天 18:09 | 显示全部楼层 |阅读模式

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

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

x
import tkinter as tk
from tkinter import messagebox
import random

class ChineseChess:
    def __init__(self, master):
        self.master = master
        self.master.title("中国象棋")
        self.canvas = tk.Canvas(master, width=670, height=750, bg="#EDAA56")
        self.canvas.pack()

        # 游戏状态
        self.board = {}
        self.current_player = "red"
        self.selected_piece = None

        # 初始化棋盘
        self.init_board()
        self.draw_board()

        # 绑定事件
        self.canvas.bind("<Button-1>", self.on_click)

    def init_board(self):
        # 初始化棋子位置(红方在下方)
        initial_setup = [
            # 红方棋子
            ((0, 9), "车", "red"), ((1, 9), "马", "red"), ((2, 9), "相", "red"),
            ((3, 9), "仕", "red"), ((4, 9), "帅", "red"), ((5, 9), "仕", "red"),
            ((6, 9), "相", "red"), ((7, 9), "马", "red"), ((8, 9), "车", "red"),
            ((1, 7), "炮", "red"), ((7, 7), "炮", "red"),
            *[((i * 2, 6), "兵", "red") for i in range(0, 5)],

            # 黑方棋子
            ((0, 0), "车", "black"), ((1, 0), "马", "black"), ((2, 0), "象", "black"),
            ((3, 0), "士", "black"), ((4, 0), "将", "black"), ((5, 0), "士", "black"),
            ((6, 0), "象", "black"), ((7, 0), "马", "black"), ((8, 0), "车", "black"),
            ((1, 2), "炮", "black"), ((7, 2), "炮", "black"),
            *[((i * 2, 3), "卒", "black") for i in range(0, 5)]
        ]

        for pos, piece, color in initial_setup:
            self.board[pos] = {"type": piece, "color": color}
        print('self.board=', self.board)

    def draw_board(self):
        self.canvas.delete("all")
        # 绘制棋盘线条
        for i in range(10):
            y = 50 + i * 70
            self.canvas.create_line(50, y, 50 + 8 * 70, y, width=2, fill='green')

        for i in range(9):
            x = 50 + i * 70
            self.canvas.create_line(x, 50, x, 50 + 4 * 70, width=2, fill='green')
            self.canvas.create_line(x, 50 + 5 * 70, x, 50 + 9 * 70, width=2, fill='green')

        self.canvas.create_line(50, 50 + 4 * 70, 50, 50 + 5 * 70, width=2, fill='green')
        self.canvas.create_line(50 + 8 * 70, 50 + 4 * 70, 50 + 8 * 70, 50 + 5 * 70, width=2, fill='green')
        # 绘制九宫斜线
        self.canvas.create_line(50 + 3 * 70, 50, 50 + 5 * 70, 50 + 2 * 70, width=2, fill='green')
        self.canvas.create_line(50 + 3 * 70, 50 + 2 * 70, 50 + 5 * 70, 50, width=2, fill='green')
        self.canvas.create_line(50 + 3 * 70, 50 + 7 * 70, 50 + 5 * 70, 50 + 9 * 70, width=2, fill='green')
        self.canvas.create_line(50 + 3 * 70, 50 + 9 * 70, 50 + 5 * 70, 50 + 7 * 70, width=2, fill='green')

        # 绘制棋子
        for (x, y), piece in self.board.items():
            self.draw_piece(x, y, piece["type"], piece["color"])

        # 绘制当前玩家提示
        self.canvas.create_text(335, 730, text=f"当前玩家:{self.current_player}", font=("simhei", 14), fill="blue")

    def draw_piece(self, x, y, piece_type, color):
        x_pixel = 50 + x * 70
        y_pixel = 50 + y * 70
        self.canvas.create_oval(x_pixel - 32, y_pixel - 32, x_pixel + 32, y_pixel + 32,
                                fill=color, outline=color)
        text_color = "white"
        self.canvas.create_text(x_pixel, y_pixel, text=piece_type,
                                font=("楷体", 28), fill=text_color)

    def on_click(self, event):
        x = round((event.x - 50) / 70)
        y = round((event.y - 50) / 70)
        pos = (x, y)

        if not (0 <= x <= 8 and 0 <= y <= 9):
            return

        if not self.selected_piece:
            if pos in self.board and self.board[pos]["color"] == self.current_player:
                self.selected_piece = pos
                self.highlight_position(pos)
        else:
            start_pos = self.selected_piece
            if self.is_valid_move(start_pos, pos):
                self.move_piece(start_pos, pos)
                self.check_game_over()
                # 切换玩家并触发AI移动
                self.current_player = "black"
                self.draw_board()
                if self.current_player == "black":
                    self.master.after(100, self.ai_move)
            self.selected_piece = None
            self.draw_board()

    def highlight_position(self, pos):
        x, y = pos
        x_pixel = 50 + x * 70
        y_pixel = 50 + y * 70
        self.canvas.create_rectangle(x_pixel - 35, y_pixel - 35, x_pixel + 35, y_pixel + 35,
                                     outline="yellow", width=3)

    def is_valid_move(self, start, end, board=None):
        if board is None:
            board = self.board
        if start not in board:
            return False
        piece = board[start]
        target_piece = board.get(end)

        if target_piece and target_piece["color"] == piece["color"]:
            return False

        move_type = piece["type"]
        if move_type == "车":
            return self.validate_rook(start, end, board)
        elif move_type in ("马", "馬"):
            return self.validate_knight(start, end, board)
        elif move_type in ("象", "相"):
            return self.validate_elephant(start, end, piece["color"], board)
        elif move_type in ("士", "仕"):
            return self.validate_advisor(start, end, piece["color"], board)
        elif move_type in ("将", "帅"):
            return self.validate_king(start, end, piece["color"], board)
        elif move_type == "炮":
            return self.validate_cannon(start, end, board)
        elif move_type in ("兵", "卒"):
            return self.validate_pawn(start, end, piece["color"], board)
        return False

    def validate_rook(self, start, end, board):
        x1, y1 = start
        x2, y2 = end
        if x1 != x2 and y1 != y2:
            return False

        step = 1 if x2 > x1 or y2 > y1 else -1
        if x1 == x2:
            for y in range(y1 + step, y2, step):
                if (x1, y) in self.board:
                    return False
        else:
            for x in range(x1 + step, x2, step):
                if (x, y1) in self.board:
                    return False
        return True

    def validate_knight(self, start, end, board):
        x1, y1 = start
        x2, y2 = end
        dx = abs(x2 - x1)
        dy = abs(y2 - y1)

        if not ((dx == 2 and dy == 1) or (dx == 1 and dy == 2)):
            return False

        # 检查蹩脚
        if dx == 2:
            mx = (x1 + x2) // 2
            if (mx, y1) in self.board:
                return False
        else:
            my = (y1 + y2) // 2
            if (x1, my) in self.board:
                return False
        return True

    def validate_elephant(self, start, end, color, board):
        x1, y1 = start
        x2, y2 = end
        dx = abs(x2 - x1)
        dy = abs(y2 - y1)

        if dx != 2 or dy != 2:
            return False

        # 检查田心
        mx, my = (x1 + x2) // 2, (y1 + y2) // 2
        if (mx, my) in self.board:
            return False

        # 不能过河
        if (color == "black" and y2 > 4) or (color == "red" and y2 < 5):
            return False
        return True

    def validate_advisor(self, start, end, color, board):
        x1, y1 = start
        x2, y2 = end
        dx = abs(x2 - x1)
        dy = abs(y2 - y1)

        if dx != 1 or dy != 1:
            return False

        # 九宫范围
        if color == "black":
            return 3 <= x2 <= 5 and 0 <= y2 <= 2
        else:
            return 3 <= x2 <= 5 and 7 <= y2 <= 9

    def validate_king(self, start, end, color, board):
        x1, y1 = start
        x2, y2 = end
        dx = abs(x2 - x1)
        dy = abs(y2 - y1)

        if dx + dy != 1:
            return False

        # 九宫范围
        if color == "black":
            return 3 <= x2 <= 5 and 0 <= y2 <= 2
        else:
            return 3 <= x2 <= 5 and 7 <= y2 <= 9

    def validate_cannon(self, start, end, board):
        x1, y1 = start
        x2, y2 = end
        if x1 != x2 and y1 != y2:
            return False

        count = 0
        if x1 == x2:
            step = 1 if y2 > y1 else -1
            for y in range(y1 + step, y2, step):
                if (x1, y) in self.board:
                    count += 1
        else:
            step = 1 if x2 > x1 else -1
            for x in range(x1 + step, x2, step):
                if (x, y1) in self.board:
                    count += 1

        target_piece = self.board.get(end)
        if target_piece:
            return count == 1  # 吃子需要隔一个棋子
        else:
            return count == 0  # 移动不能有棋子阻挡

    def validate_pawn(self, start, end, color, board):
        x1, y1 = start
        x2, y2 = end
        dx = abs(x2 - x1)
        dy = y2 - y1 if color == "black" else y1 - y2

        # 只能移动一格
        if dx + abs(y2 - y1) != 1:
            return False

        # 前进方向判断
        if color == "black":
            if y1 <= 4:  # 未过河
                return y2 == y1 + 1 and x2 == x1
            else:  # 过河后
                return dy == 1 or (dy == 0 and dx == 1)
        else:
            if y1 >= 5:  # 未过河
                return y2 == y1 - 1 and x2 == x1
            else:  # 过河后
                return dy == 1 or (dy == 0 and dx == 1)

    def move_piece(self, start, end):
        self.board[end] = self.board[start]
        del self.board[start]

    def check_game_over(self):
        # 检查是否存在将帅
        has_red_king = any(p["type"] == "帅" for p in self.board.values())
        has_black_king = any(p["type"] == "将" for p in self.board.values())

        if not has_red_king:
            self.show_winner("black")
        elif not has_black_king:
            self.show_winner("red")

    def show_winner(self, winner):
        messagebox.showinfo("游戏结束", f"{winner}方获胜!")
        self.master.destroy()

    # 新增AI相关方法
    def ai_move(self):
        best_score = -float('inf')
        best_moves = []
        for start in list(self.board.keys()):
            piece = self.board[start]
            if piece["color"] != self.current_player:
                continue
            for x in range(9):
                for y in range(10):
                    end = (x, y)
                    if self.is_valid_move(start, end):
                        score = self.evaluate_move(start, end)
                        if score > best_score:
                            best_score = score
                            best_moves = [(start, end)]
                        elif score == best_score:
                            best_moves.append((start, end))
        if best_moves:
            best_move = random.choice(best_moves)
            self.move_piece(best_move[0], best_move[1])
            self.check_game_over()
            self.current_player = "red"
            self.draw_board()

    def evaluate_move(self, start, end):
        temp_board = {pos: dict(data) for pos, data in self.board.items()}
        current_color = temp_board[start]["color"]
        score = 0

        # 吃子得分
        target_piece = temp_board.get(end)
        if target_piece and target_piece["color"] != current_color:
            score += self.get_piece_value(target_piece)

        # 模拟移动
        temp_board[end] = temp_board[start]
        del temp_board[start]

        # 检查是否被对方吃
        opponent_color = "red" if current_color == "black" else "black"
        for pos in list(temp_board.keys()):
            piece = temp_board[pos]
            if piece["color"] == opponent_color:
                if self.is_valid_move(pos, end, temp_board):
                    score -= self.get_piece_value(temp_board[end]) * 0.5  # 被吃风险折扣

        return score

    def get_piece_value(self, piece):
        values = {
            "将": 1000, "帅": 1000,
            "车": 90, "炮": 45, "马": 40,
            "士": 20, "仕": 20, "象": 20, "相": 20,
            "卒": 10, "兵": 10
        }
        return values.get(piece["type"], 0)

if __name__ == "__main__":
    root = tk.Tk()
    game = ChineseChess(root)
    root.mainloop()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 前天 22:57 | 显示全部楼层
不错,感谢分享~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-2-23 21:57

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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