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()