国际象棋python源码
2026-08-08 16:51:54
发布于:四川
象棋部分
本代码由Dream It Possible团队全权负责,如有问题请在评论区或私信项目负责人<bits/sdtc++.h>
- [更新]象棋部分终于更新好了,下午就将网址汇总
- [简介]就是普通象棋的玩法
- [部分更新]更新了部分代码
- [警告|warning]所有象棋部分的代码还在公测阶段,可能存在问题
- [修改]修改了中国象棋初始的旗子摆放位置
- [修改文章]修改了中国象棋文章中的代码(原来放成国际象棋代码了,已修改)
第一次写这么大工程量的棋类大全不好玩勿喷,可能还有一点BUG
国际象棋代码
import tkinter as tk
from tkinter import messagebox, simpledialog
import socket
import threading
import json
PIECES = {
'R': '♖', 'N': '♘', 'B': '♗', 'Q': '♕', 'K': '♔', 'P': '♙',
'r': '♜', 'n': '♞', 'b': '♝', 'q': '♛', 'k': '♚', 'p': '♟',
'.': ''
}
PIECE_VALUE = {
'P': 100, 'N': 320, 'B': 330, 'R': 500, 'Q': 900, 'K': 20000,
'p': -100, 'n': -320, 'b': -330, 'r': -500, 'q': -900, 'k': -20000
}
PORT = 23456
class ChessGUI:
def __init__(self, root):
self.root = root
self.root.title("国际象棋|本地双人 / AI / 局域网联机")
self.game_over = False
self.ai_thinking = False
self.mode_ai = False # AI模式开关
self.mode_net = False # 局域网联机开关
self.net_side = None # 联机时:'white' / 'black',自己执哪方
self.net_socket = None
self.net_running = False
# 顶部按钮栏
frame_top = tk.Frame(root)
frame_top.pack()
self.btn_switch_mode = tk.Button(frame_top, text="切换AI/双人模式", command=self.switch_mode)
self.btn_switch_mode.grid(row=0, column=0, padx=3)
self.btn_reset = tk.Button(frame_top, text="重置棋局", command=self.reset_game)
self.btn_reset.grid(row=0, column=1, padx=3)
self.btn_host = tk.Button(frame_top, text="创建联机(服务器)", command=self.start_host)
self.btn_host.grid(row=0, column=2, padx=3)
self.btn_connect = tk.Button(frame_top, text="连接服务器(客户端)", command=self.start_client)
self.btn_connect.grid(row=0, column=3, padx=3)
self.btn_net_close = tk.Button(frame_top, text="断开联机", command=self.close_network, state=tk.DISABLED)
self.btn_net_close.grid(row=0, column=4, padx=3)
self.status_label = tk.Label(root, text="模式:双人对战|白方回合", font=("SimHei", 13))
self.status_label.pack()
self.cell_size = 70
self.canvas = tk.Canvas(root, width=self.cell_size * 8, height=self.cell_size * 8)
self.canvas.pack()
self.canvas.bind("<Button-1>", self.on_click)
self.reset_game()
def reset_game(self):
self.game_over = False
self.ai_thinking = False
self.selected = None
self.highlight = []
self.board = [
['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'],
['p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'],
['.', '.', '.', '.', '.', '.', '.', '.'],
['.', '.', '.', '.', '.', '.', '.', '.'],
['.', '.', '.', '.', '.', '.', '.', '.'],
['.', '.', '.', '.', '.', '.', '.', '.'],
['P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'],
['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R']
]
self.white_turn = True
self.w_castle_k = True
self.w_castle_q = True
self.b_castle_k = True
self.b_castle_q = True
self.en_passant_col = -1
self.update_status_text()
self.draw_board()
def switch_mode(self):
if self.mode_net:
messagebox.showwarning("提示","联机模式下不能切换AI/双人,请先断开联机!")
return
self.mode_ai = not self.mode_ai
self.reset_game()
def update_status_text(self):
if self.game_over:
return
if self.mode_net:
side_txt = "我方执白" if self.net_side=="white" else "我方执黑"
turn_txt = "白方回合" if self.white_turn else "黑方回合"
if self.is_in_check(self.white_turn):
turn_txt += " 【将军!】"
self.status_label.config(text=f"模式:局域网联机|{side_txt}|{turn_txt}")
else:
mode_text = "AI对战(玩家白)" if self.mode_ai else "双人对战"
turn_text = "白方回合" if self.white_turn else "黑方回合"
if self.is_in_check(self.white_turn):
turn_text += " 【将军!】"
self.status_label.config(text=f"模式:{mode_text}|{turn_text}")
# ---------------- 网络部分 ----------------
def start_host(self):
if self.mode_net:
return
self.mode_net = True
self.mode_ai = False
self.net_side = "white" # 服务器执白
self.btn_host.config(state=tk.DISABLED)
self.btn_connect.config(state=tk.DISABLED)
self.btn_net_close.config(state=tk.NORMAL)
self.reset_game()
th = threading.Thread(target=self.host_thread, daemon=True)
th.start()
def host_thread(self):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
s.bind(("0.0.0.0", PORT))
s.listen(1)
self.root.after(0, lambda:messagebox.showinfo("服务器","已启动!请把本机内网IP告诉客户端,端口{}".format(PORT)))
conn, addr = s.accept()
self.net_socket = conn
self.net_running = True
self.root.after(0,lambda:messagebox.showinfo("连接成功",f"客户端 {addr} 已接入,你执白,请开始游戏"))
recv_th = threading.Thread(target=self.net_recv_loop, daemon=True)
recv_th.start()
except Exception as e:
self.root.after(0,lambda:self.net_error(f"服务器启动失败:{e}"))
finally:
s.close()
def start_client(self):
if self.mode_net:
return
ip = simpledialog.askstring("连接服务器","输入服务器IP地址:")
if not ip:
return
self.mode_net = True
self.mode_ai = False
self.net_side = "black" # 客户端执黑
self.btn_host.config(state=tk.DISABLED)
self.btn_connect.config(state=tk.DISABLED)
self.btn_net_close.config(state=tk.NORMAL)
self.reset_game()
th = threading.Thread(target=self.client_thread,args=(ip,),daemon=True)
th.start()
def client_thread(self,host_ip):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host_ip,PORT))
self.net_socket = sock
self.net_running = True
self.root.after(0,lambda:messagebox.showinfo("连接成功","已连上服务器,你执黑,请等待白方走棋"))
recv_th = threading.Thread(target=self.net_recv_loop, daemon=True)
recv_th.start()
except Exception as e:
self.root.after(0,lambda:self.net_error(f"连接失败:{e}"))
def net_error(self,msg):
messagebox.showerror("网络错误",msg)
self.close_network()
def close_network(self):
self.net_running = False
if self.net_socket:
try:
self.net_socket.close()
except:pass
self.net_socket = None
self.mode_net = False
self.net_side = None
self.btn_host.config(state=tk.NORMAL)
self.btn_connect.config(state=tk.NORMAL)
self.btn_net_close.config(state=tk.DISABLED)
self.reset_game()
def net_send(self,obj):
if not self.net_running or not self.net_socket:
return
try:
data = (json.dumps(obj)+"\n").encode("utf-8")
self.net_socket.sendall(data)
except:
self.root.after(0,lambda:self.net_error("发送消息失败,对方断开连接"))
def net_recv_loop(self):
buf = b""
while self.net_running:
try:
chunk = self.net_socket.recv(1024)
if not chunk:
break
buf += chunk
while b"\n" in buf:
line,buf = buf.split(b"\n",1)
msg = json.loads(line.decode("utf-8"))
self.root.after(0,lambda m=msg:self.handle_net_msg(m))
except Exception:
break
self.root.after(0,lambda:self.net_error("对方断开连接"))
def handle_net_msg(self,msg):
typ = msg.get("type")
if typ == "move":
sr,sc,tr,tc = msg["sr"],msg["sc"],msg["tr"],msg["tc"]
self.execute_move(sr,sc,tr,tc)
self.white_turn = not self.white_turn
self.selected = None
self.highlight = []
self.check_game_end()
self.update_status_text()
self.draw_board()
# ---------------- 原有国际象棋逻辑完全保留 ----------------
def is_white(self, c):
return c.isupper()
def is_black(self, c):
return c.islower()
def find_king(self, is_white):
target = 'K' if is_white else 'k'
for r in range(8):
for c in range(8):
if self.board[r][c] == target:
return r, c
return -1, -1
def is_square_attacked(self, tr, tc, by_white):
for r in range(8):
for c in range(8):
p = self.board[r][c]
if p == '.':continue
if by_white:
if not self.is_white(p):continue
else:
if not self.is_black(p):continue
dr = tr - r
dc = tc - c
adr = abs(dr)
adc = abs(dc)
if p in ('N','n'):
if (adr == 2 and adc ==1) or (adr ==1 and adc ==2):
return True
elif p == 'P':
if dr == -1 and (dc ==1 or dc ==-1):
return True
elif p == 'p':
if dr == 1 and (dc ==1 or dc ==-1):
return True
elif p in ('K','k'):
if adr <=1 and adc <=1:
return True
if p in ('R','r','Q','q'):
if dr ==0 or dc ==0:
step_r = 0 if dr==0 else (1 if dr>0 else -1)
step_c = 0 if dc==0 else (1 if dc>0 else -1)
cr, cc = r+step_r, c+step_c
while cr != tr or cc != tc:
if self.board[cr][cc] != '.':break
cr += step_r; cc += step_c
else:
return True
if p in ('B','b','Q','q'):
if adr == adc:
step_r = 1 if dr>0 else -1
step_c = 1 if dc>0 else -1
cr, cc = r+step_r, c+step_c
while cr != tr or cc != tc:
if self.board[cr][cc] != '.':break
cr += step_r; cc += step_c
else:
return True
return False
def is_in_check(self, white_turn):
kr, kc = self.find_king(white_turn)
return self.is_square_attacked(kr, kc, not white_turn)
def raw_move_valid(self, sr, sc, tr, tc):
piece = self.board[sr][sc]
target = self.board[tr][tc]
if piece == '.':return False
if self.white_turn:
if not self.is_white(piece):return False
if self.is_white(target):return False
else:
if not self.is_black(piece):return False
if self.is_black(target):return False
if sr == tr and sc == tc:return False
dr = tr - sr; dc = tc - sc
adr = abs(dr); adc = abs(dc)
if piece in ('N','n'):
return (adr == 2 and adc ==1) or (adr ==1 and adc ==2)
elif piece in ('B','b'):
if adr != adc:return False
step_r = 1 if dr>0 else -1
step_c = 1 if dc>0 else -1
cr, cc = sr+step_r, sc+step_c
while cr != tr or cc != tc:
if self.board[cr][cc] != '.':return False
cr += step_r; cc += step_c
return True
elif piece in ('R','r'):
if dr !=0 and dc !=0:return False
step_r = 0 if dr==0 else (1 if dr>0 else -1)
step_c = 0 if dc==0 else (1 if dc>0 else -1)
cr, cc = sr+step_r, sc+step_c
while cr != tr or cc != tc:
if self.board[cr][cc] != '.':return False
cr += step_r; cc += step_c
return True
elif piece in ('Q','q'):
if dr !=0 and dc !=0 and adr != adc:return False
step_r = 0
if dr>0: step_r=1
elif dr<0: step_r=-1
step_c=0
if dc>0: step_c=1
elif dc<0: step_c=-1
cr, cc = sr+step_r, sc+step_c
while cr != tr or cc != tc:
if self.board[cr][cc] != '.':return False
cr += step_r; cc += step_c
return True
elif piece in ('K','k'):
return adr <=1 and adc <=1
elif piece == 'P':
if sc == tc and target == '.':
if dr == -1:return True
if sr ==6 and dr ==-2 and self.board[sr-1][sc]=='.':return True
if adc ==1 and dr == -1:
if target != '.':return True
if self.en_passant_col == tc and sr ==3:return True
return False
elif piece == 'p':
if sc == tc and target == '.':
if dr == 1:return True
if sr ==1 and dr ==2 and self.board[sr+1][sc]=='.':return True
if adc ==1 and dr == 1:
if target != '.':return True
if self.en_passant_col == tc and sr ==4:return True
return False
return False
def simulate_move(self, sr, sc, tr, tc):
save_src = self.board[sr][sc]
save_dst = self.board[tr][tc]
old_ep = self.en_passant_col
ep_flag = False
if save_src in ('P','p') and self.board[tr][tc]=='.' and sc != tc:
ep_flag = True
if save_src == 'P':
self.board[tr+1][tc] = '.'
else:
self.board[tr-1][tc] = '.'
self.board[tr][tc] = self.board[sr][sc]
self.board[sr][sc] = '.'
check = not self.is_in_check(self.white_turn)
self.board[sr][sc] = save_src
self.board[tr][tc] = save_dst
if ep_flag:
if save_src == 'P':
self.board[tr+1][tc] = 'p'
else:
self.board[tr-1][tc] = 'P'
self.en_passant_col = old_ep
return check
def can_castle(self, king_side):
if self.is_in_check(self.white_turn):return False
kr, kc = self.find_king(self.white_turn)
if self.white_turn:
if king_side:
if not self.w_castle_k: return False
if self.board[7][5]!='.' or self.board[7][6]!='.': return False
if self.is_square_attacked(7,5, not self.white_turn) or self.is_square_attacked(7,6, not self.white_turn): return False
else:
if not self.w_castle_q: return False
if self.board[7][1]!='.' or self.board[7][2]!='.' or self.board[7][3]!='.': return False
if self.is_square_attacked(7,3, not self.white_turn) or self.is_square_attacked(7,2, not self.white_turn): return False
else:
if king_side:
if not self.b_castle_k: return False
if self.board[0][5]!='.' or self.board[0][6]!='.': return False
if self.is_square_attacked(0,5, not self.white_turn) or self.is_square_attacked(0,6, not self.white_turn): return False
else:
if not self.b_castle_q: return False
if self.board[0][1]!='.' or self.board[0][2]!='.' or self.board[0][3]!='.': return False
if self.is_square_attacked(0,3, not self.white_turn) or self.is_square_attacked(0,2, not self.white_turn): return False
return True
def get_legal_moves(self, sr, sc):
moves = []
piece = self.board[sr][sc]
if piece in ('K','k'):
if self.can_castle(True):
moves.append((sr, sc+2))
if self.can_castle(False):
moves.append((sr, sc-2))
for tr in range(8):
for tc in range(8):
if self.raw_move_valid(sr, sc, tr, tc):
if self.simulate_move(sr, sc, tr, tc):
moves.append((tr, tc))
return moves
def get_all_legal_moves(self):
all_moves = []
for r in range(8):
for c in range(8):
p = self.board[r][c]
if p == '.': continue
if self.white_turn and not self.is_white(p): continue
if not self.white_turn and not self.is_black(p): continue
for (tr,tc) in self.get_legal_moves(r,c):
all_moves.append((r,c,tr,tc))
return all_moves
def has_any_legal(self):
return len(self.get_all_legal_moves())>0
def execute_move(self, sr, sc, tr, tc):
piece = self.board[sr][sc]
if piece in ('K','k') and abs(sc-tc)==2:
if tc > sc:
self.board[tr][tc] = piece
self.board[sr][sc] = '.'
self.board[tr][tc-1] = self.board[tr][7]
self.board[tr][7] = '.'
else:
self.board[tr][tc] = piece
self.board[sr][sc] = '.'
self.board[tr][tc+1] = self.board[tr][0]
self.board[tr][0] = '.'
else:
if piece in ('P','p') and self.board[tr][tc]=='.' and sc != tc:
if piece == 'P':
self.board[tr+1][tc] = '.'
else:
self.board[tr-1][tc] = '.'
self.board[tr][tc] = self.board[sr][sc]
self.board[sr][sc] = '.'
if piece == 'K':
self.w_castle_k = False
self.w_castle_q = False
if piece == 'k':
self.b_castle_k = False
self.b_castle_q = False
if piece == 'R':
if sr ==7 and sc ==0: self.w_castle_q = False
if sr ==7 and sc ==7: self.w_castle_k = False
if piece == 'r':
if sr ==0 and sc ==0: self.b_castle_q = False
if sr ==0 and sc ==7: self.b_castle_k = False
self.en_passant_col = -1
if piece == 'P' and sr ==6 and tr ==4:
self.en_passant_col = sc
if piece == 'p' and sr ==1 and tr ==3:
self.en_passant_col = sc
if piece == 'P' and tr ==0:
prom = simpledialog.askstring("兵升变","请输入 Q/R/B/N (后/车/象/马):")
if prom and prom.upper() in ['Q','R','B','N']:
self.board[tr][tc] = prom.upper()
else:
self.board[tr][tc] = 'Q'
if piece == 'p' and tr ==7:
self.board[tr][tc] = 'q'
def check_game_end(self):
in_check = self.is_in_check(self.white_turn)
any_move = self.has_any_legal()
if in_check and not any_move:
winner = "黑方" if self.white_turn else "白方"
messagebox.showinfo("游戏结束", f"将死!{winner}获胜!")
self.game_over = True
return True
elif not in_check and not any_move:
messagebox.showinfo("游戏结束", "困毙!和棋!")
self.game_over = True
return True
return False
# AI极小极大
def evaluate_board(self):
score = 0
for r in range(8):
for c in range(8):
ch = self.board[r][c]
if ch != '.':
score += PIECE_VALUE[ch]
return score
def minimax(self, depth, alpha, beta, is_max_turn):
moves = self.get_all_legal_moves()
if depth == 0 or len(moves)==0:
return self.evaluate_board(), None
best_move = None
if is_max_turn:
max_eval = -100000
for (sr,sc,tr,tc) in moves:
old_white = self.white_turn
old_wk, old_wq = self.w_castle_k, self.w_castle_q
old_bk, old_bq = self.b_castle_k, self.b_castle_q
old_ep = self.en_passant_col
old_board = [row.copy() for row in self.board]
self.execute_move(sr,sc,tr,tc)
self.white_turn = not self.white_turn
eval_val,_ = self.minimax(depth-1, alpha, beta, False)
self.board = old_board
self.white_turn = old_white
self.w_castle_k,self.w_castle_q = old_wk,old_wq
self.b_castle_k,self.b_castle_q = old_bk,old_bq
self.en_passant_col = old_ep
if eval_val > max_eval:
max_eval = eval_val
best_move = (sr,sc,tr,tc)
alpha = max(alpha, eval_val)
if beta <= alpha:
break
return max_eval, best_move
else:
min_eval = 100000
for (sr,sc,tr,tc) in moves:
old_white = self.white_turn
old_wk, old_wq = self.w_castle_k, self.w_castle_q
old_bk, old_bq = self.b_castle_k, self.b_castle_q
old_ep = self.en_passant_col
old_board = [row.copy() for row in self.board]
self.execute_move(sr,sc,tr,tc)
self.white_turn = not self.white_turn
eval_val,_ = self.minimax(depth-1, alpha, beta, True)
self.board = old_board
self.white_turn = old_white
self.w_castle_k,self.w_castle_q = old_wk,old_wq
self.b_castle_k,self.b_castle_q = old_bk,old_bq
self.en_passant_col = old_ep
if eval_val < min_eval:
min_eval = eval_val
best_move = (sr,sc,tr,tc)
beta = min(beta, eval_val)
if beta <= alpha:
break
return min_eval, best_move
def ai_do_turn(self):
if self.game_over or self.ai_thinking:
return
self.ai_thinking = True
self.status_label.config(text="AI思考中...")
self.root.update()
_, best_move = self.minimax(depth=2, alpha=-100000, beta=100000, is_max_turn=False)
if best_move is not None:
sr,sc,tr,tc = best_move
self.execute_move(sr,sc,tr,tc)
self.white_turn = not self.white_turn
self.ai_thinking = False
if self.check_game_end():
return
self.update_status_text()
self.draw_board()
def draw_board(self):
if self.game_over:
return
self.canvas.delete("all")
for r in range(8):
for c in range(8):
x1 = c * self.cell_size
y1 = r * self.cell_size
x2 = x1 + self.cell_size
y2 = y1 + self.cell_size
fill = "#f0d9b5" if (r + c) % 2 == 0 else "#b58863"
if (r, c) in self.highlight:
fill = "#87ce70"
self.canvas.create_rectangle(x1, y1, x2, y2, fill=fill, outline="black")
ch = self.board[r][c]
text = PIECES[ch]
color = "white" if self.is_white(ch) else "black"
self.canvas.create_text((x1+x2)//2, (y1+y2)//2, text=text, font=("SimHei",40), fill=color)
def on_click(self, event):
if self.game_over or self.ai_thinking:
return
# 联机模式:不是自己回合,禁止操作
if self.mode_net:
my_turn = (self.white_turn and self.net_side=="white") or (not self.white_turn and self.net_side=="black")
if not my_turn:
return
# AI模式:非玩家回合禁止点击
if self.mode_ai and not self.white_turn:
return
col = event.x // self.cell_size
row = event.y // self.cell_size
if not (0 <= row < 8 and 0 <= col < 8):
return
piece = self.board[row][col]
if self.selected is None:
if (self.white_turn and self.is_white(piece)) or (not self.white_turn and self.is_black(piece)):
self.selected = (row, col)
self.highlight = self.get_legal_moves(row, col)
else:
sr, sc = self.selected
if row == sr and col == sc:
self.selected = None
self.highlight = []
else:
if (row, col) in self.highlight:
self.execute_move(sr, sc, row, col)
# 如果是联机模式,把走法发给对方
if self.mode_net:
self.net_send({"type":"move","sr":sr,"sc":sc,"tr":row,"tc":col})
self.white_turn = not self.white_turn
self.selected = None
self.highlight = []
if self.check_game_end():
return
self.update_status_text()
self.draw_board()
if self.mode_ai and not self.white_turn:
self.root.after(200, self.ai_do_turn)
return
else:
if (self.white_turn and self.is_white(piece)) or (not self.white_turn and self.is_black(piece)):
self.selected = (row, col)
self.highlight = self.get_legal_moves(row, col)
else:
self.selected = None
self.highlight = []
self.draw_board()
if __name__ == "__main__":
win = tk.Tk()
app = ChessGUI(win)
win.mainloop()
顺便吐槽一下ACGO的文章怎么还有字数限制呀?
这里空空如也




















有帮助,赞一个