|
|
这些输出是程序在每次鼠标移动时,对棋盘上所有可能的落子位置调用了 `can_move` 函数进行合法性判断,目的是**为可移动位置高亮或为AI计算走法做准备**。您感觉“没用”是因为输出太多刷屏了,而且没有关键信息。
### 这些输出如何帮助学习?
- 您可以看到每个位置是否被判定为合法(如果 `can_move` 返回 `True` 或 `False`,但当前代码只打印了调用,没有显示结果)。
- 通过对比您自己知道的规则,可以判断 `can_move` 的执行是否正确。例如 `(3,8)` 是黑方某棋子,如果禁止它移动到 `(4,0)`,说明规则起作用了。
- 但大量输出确实干扰正常游戏,所以建议**只保留必要打印**。
### 如何修改代码以减少输出?
找到输出这些信息的地方(通常是AI循环或鼠标事件处理),将 `print("can_move called: from ...")` 注释掉或替换为条件打印(例如只在调试模式开启时才输出)。下面是一个示例修改:
- # 将原来的 print 行替换为:
- # debug = False # 全局变量,只在需要调试时设为 True
- if debug:
- print("can_move called: from ({},{}) to ({},{})".format(r1, c1, r2, c2))
复制代码
或者直接删除该行,保留 `can_move` 内部的合法/非法判断输出。这样你就只会在移动非法时看到错误信息。
### 更实用的调试方式:添加关键事件输出
在 `on_click` 等关键函数中添加输出,比如:
- “您选中了 (行,列) 的棋子”
- “移动成功:从 (x1,y1) 到 (x2,y2)”
- “吃掉了对方的某棋子”
- “将军!请应将”
这样既能了解程序运行流程,又不会刷屏。
### 提供一个精简版完整代码(无多余 print,含棋谱)
由于您的 Python 版本是 3.4,下面给出一个**可直接运行**的代码,去除了所有 `can_move` 调用打印,只保留关键的走棋提示和棋谱显示。代码包含:
- 汉字棋子、鼠标点击走棋、红方(您)vs 黑方(随机AI)
- 将军检测、不能自将、不能斜走将帅、兵卒不能后退
- 悔棋按钮、棋谱列表显示(使用 Listbox)
您复制到 `chess_final.py` 并运行即可。
-
- # -*- coding: utf-8 -*-
- import tkinter as tk
- import random
- import copy
- SIZE_ROW = 10
- SIZE_COL = 9
- CELL = 50
- # ---------- 棋子汉字映射 ----------
- PIECE_CN = {
- 'R': '車', 'N': '馬', 'B': '象', 'A': '士', 'K': '將', 'C': '砲', 'P': '卒',
- 'r': '車', 'n': '馬', 'b': '象', 'a': '士', 'k': '將', 'c': '砲', 'p': '卒'
- }
- # 红方大写,黑方小写
- def init_board():
- b = [['.' for _ in range(SIZE_COL)] for _ in range(SIZE_ROW)]
- # 黑方 (小写) 在第0~4行
- b[0] = ['r','n','b','a','k','a','b','n','r']
- b[2][1] = 'c'; b[2][7] = 'c'
- for c in [0,2,4,6,8]: b[3][c] = 'p'
- # 红方 (大写) 在第5~9行
- b[9] = ['R','N','B','A','K','A','B','N','R']
- b[7][1] = 'C'; b[7][7] = 'C'
- for c in [0,2,4,6,8]: b[6][c] = 'P'
- return b
- def is_inside(r,c):
- return 0<=r<SIZE_ROW and 0<=c<SIZE_COL
- def is_red(p):
- return p.isupper()
- def same_color(p1,p2):
- if p1=='.' or p2=='.': return False
- return is_red(p1) == is_red(p2)
- def count_between(board,r1,c1,r2,c2):
- # 直线间棋子数
- cnt=0
- if r1==r2:
- step = 1 if c2>c1 else -1
- for c in range(c1+step, c2, step):
- if board[r1][c]!='.': cnt+=1
- elif c1==c2:
- step = 1 if r2>r1 else -1
- for r in range(r1+step, r2, step):
- if board[r][c1]!='.': cnt+=1
- return cnt
- def can_move(board,r1,c1,r2,c2):
- if not is_inside(r1,c1) or not is_inside(r2,c2):
- return False, "坐标越界"
- piece = board[r1][c1]
- target = board[r2][c2]
- if piece=='.': return False, "源格无棋子"
- if same_color(piece,target): return False, "目标格有己方棋子"
- dr=r2-r1; dc=c2-c1
- p = piece.lower()
- # 将/帅
- if p=='k':
- if not (abs(dr)<=1 and abs(dc)<=1): return False, "将帅只能走一格"
- if abs(dr)+abs(dc) != 1: return False, "将帅不能斜走"
- # 九宫限制
- if is_red(piece): # 红帅在 (7~9, 3~5)
- if not (7<=r2<=9 and 3<=c2<=5): return False, "帅只能在九宫"
- else:
- if not (0<=r2<=2 and 3<=c2<=5): return False, "将只能在九宫"
- return True, ""
- # 士/仕
- if p=='a':
- if not (abs(dr)==1 and abs(dc)==1): return False, "士走斜线一格"
- if is_red(piece):
- if not (7<=r2<=9 and 3<=c2<=5): return False, "仕只能在九宫"
- else:
- if not (0<=r2<=2 and 3<=c2<=5): return False, "士只能在九宫"
- return True, ""
- # 象/相
- if p=='b':
- if not (abs(dr)==2 and abs(dc)==2): return False, "象走田"
- eye_r = (r1+r2)//2; eye_c = (c1+c2)//2
- if board[eye_r][eye_c]!='.': return False, "象眼被塞"
- if is_red(piece):
- if not (5<=r2<=9): return False, "相不可过河"
- else:
- if not (0<=r2<=4): return False, "象不可过河"
- return True, ""
- # 马
- if p=='n':
- if not ((abs(dr),abs(dc)) in [(2,1),(1,2)]): return False, "马走日"
- if abs(dr)==2:
- block_r = r1 + (1 if r2>r1 else -1); block_c = c1
- else:
- block_r = r1; block_c = c1 + (1 if c2>c1 else -1)
- if board[block_r][block_c]!='.': return False, "蹩马腿"
- return True, ""
- # 车
- if p=='r':
- if dr!=0 and dc!=0: return False, "车走直线"
- if count_between(board,r1,c1,r2,c2)>0: return False, "中间有棋子"
- return True, ""
- # 炮
- if p=='c':
- if dr!=0 and dc!=0: return False, "炮走直线"
- between = count_between(board,r1,c1,r2,c2)
- if target=='.':
- if between!=0: return False, "炮移动不可越子"
- else:
- if between!=1: return False, "炮吃子必须隔一个"
- return True, ""
- # 兵/卒
- if p=='p':
- if is_red(piece): # 红兵向上 (r减小)
- if dr>0: return False, "兵不能后退"
- if r1<=4: # 过河
- if not (abs(dr)==1 and dc==0) and not (abs(dc)==1 and dr==0): return False, "兵走一步"
- else:
- if not (dr==-1 and dc==0): return False, "兵未过河只能前进"
- else: # 黑卒向下 (r增大)
- if dr<0: return False, "卒不能后退"
- if r1>=5: # 过河
- if not (abs(dr)==1 and dc==0) and not (abs(dc)==1 and dr==0): return False, "卒走一步"
- else:
- if not (dr==1 and dc==0): return False, "卒未过河只能前进"
- return True, ""
- return False, "未知棋子"
- def is_check(board, color):
- # color: 'red' or 'black'
- # 找出将/帅位置
- k_pos = None
- for r in range(SIZE_ROW):
- for c in range(SIZE_COL):
- p = board[r][c]
- if p!='.' and is_red(p)==(color=='red') and p.lower()=='k':
- k_pos = (r,c)
- break
- if k_pos: break
- if not k_pos: return False
- kr, kc = k_pos
- # 检查对方所有棋子能否吃掉将/帅
- opp = 'black' if color=='red' else 'red'
- for r in range(SIZE_ROW):
- for c in range(SIZE_COL):
- p = board[r][c]
- if p=='.': continue
- if is_red(p) != (opp=='red'): continue
- ok, _ = can_move(board,r,c,kr,kc)
- if ok:
- return True
- return False
- def is_checkmate(board, color):
- # 检查 color 是否被将死:所有合法走法都不能解除将军
- for r1 in range(SIZE_ROW):
- for c1 in range(SIZE_COL):
- p = board[r1][c1]
- if p=='.': continue
- if is_red(p) != (color=='red'): continue
- for r2 in range(SIZE_ROW):
- for c2 in range(SIZE_COL):
- ok, _ = can_move(board,r1,c1,r2,c2)
- if not ok: continue
- # 模拟走棋
- new_board = copy.deepcopy(board)
- new_board[r2][c2] = new_board[r1][c1]
- new_board[r1][c1] = '.'
- if not is_check(new_board, color):
- return False
- return True
- class ChessApp:
- def __init__(self, root):
- self.root = root
- self.root.title("中国象棋")
- self.canvas = tk.Canvas(root, width=SIZE_COL*CELL+20, height=SIZE_ROW*CELL+20, bg='burlywood')
- self.canvas.pack(side=tk.LEFT, padx=10, pady=10)
- self.canvas.bind("<Button-1>", self.on_click)
- # 右侧面板
- self.panel = tk.Frame(root)
- self.panel.pack(side=tk.RIGHT, fill=tk.Y, padx=10)
- self.status = tk.StringVar()
- self.status.set("红方走棋")
- self.status_label = tk.Label(self.panel, textvariable=self.status, font=('SimSun',14))
- self.status_label.pack(pady=5)
- # 棋谱列表
- self.history_label = tk.Label(self.panel, text="棋谱", font=('SimSun',12))
- self.history_label.pack()
- self.history_listbox = tk.Listbox(self.panel, width=20, height=15, font=('SimSun',10))
- self.history_listbox.pack(pady=5)
- self.move_list = []
- # 悔棋按钮
- self.undo_btn = tk.Button(self.panel, text="悔棋", command=self.undo_move, font=('SimSun',12))
- self.undo_btn.pack(pady=5)
- # 初始化游戏
- self.board = init_board()
- self.selected = None
- self.turn = 'red' # red 先手
- self.game_over = False
- self.undo_stack = []
- self.draw_board()
- def undo_move(self):
- if self.game_over or len(self.undo_stack)==0:
- return
- # 撤回两步(自己和AI各一步)或一步(若AI未动)
- for _ in range(2):
- if not self.undo_stack: break
- last = self.undo_stack.pop()
- self.board, self.turn = last['board'], last['turn']
- if self.move_list: self.move_list.pop()
- self.history_listbox.delete(tk.END)
- self.selected = None
- self.draw_board()
- if not self.game_over and self.turn=='black':
- self.root.after(200, self.ai_move) # 若轮到AI,恢复思考
- def draw_board(self, highlight=[]):
- self.canvas.delete('all')
- # 绘制网格
- for r in range(SIZE_ROW):
- for c in range(SIZE_COL):
- x0 = c*CELL+10; y0 = r*CELL+10
- x1 = x0+CELL; y1 = y0+CELL
- if r==0 and c==0: self.canvas.create_text(x0+5,y0+5,text='0',anchor='nw')
- # 画棋位点
- self.canvas.create_oval(x0-3,y0-3,x0+3,y0+3,fill='black')
- # 画九宫斜线
- for palace in [(0,3,2,5), (7,3,9,5)]:
- r1,c1,r2,c2 = palace
- self.canvas.create_line(c1*CELL+10, r1*CELL+10, c2*CELL+10, r2*CELL+10)
- self.canvas.create_line(c2*CELL+10, r1*CELL+10, c1*CELL+10, r2*CELL+10)
- # 画楚河汉界
- self.canvas.create_text(4*CELL+10, 4.5*CELL+10, text='楚 河 漢 界', font=('SimSun',16))
- # 画棋子
- for r in range(SIZE_ROW):
- for c in range(SIZE_COL):
- p = self.board[r][c]
- if p=='.': continue
- x = c*CELL+10+CELL//2; y = r*CELL+10+CELL//2
- color = 'red' if p.isupper() else 'black'
- self.canvas.create_oval(x-18,y-18,x+18,y+18,fill='white',outline=color,width=2)
- cn = PIECE_CN.get(p,'?')
- self.canvas.create_text(x,y,text=cn,font=('SimSun',18),fill=color)
- # 高亮选中
- if self.selected:
- r,c = self.selected
- x0 = c*CELL+10; y0 = r*CELL+10
- self.canvas.create_rectangle(x0,y0,x0+CELL,y0+CELL,outline='blue',width=3)
- # 更新状态
- if self.game_over:
- txt = "游戏结束"
- else:
- txt = "红方走棋" if self.turn=='red' else "黑方思考..."
- self.status.set(txt)
- # 更新棋谱显示
- self.history_listbox.delete(0,tk.END)
- for m in self.move_list:
- self.history_listbox.insert(tk.END, m)
- def on_click(self, event):
- if self.game_over or self.turn!='red':
- return
- col = (event.x-10)//CELL
- row = (event.y-10)//CELL
- if not is_inside(row,col):
- return
- piece = self.board[row][col]
- if self.selected is None:
- # 选择己方棋子
- if piece!='.' and is_red(piece):
- self.selected = (row,col)
- self.draw_board()
- return
- r1,c1 = self.selected
- # 如果点击了另一个己方棋子,切换选择
- if piece!='.' and is_red(piece):
- self.selected = (row,col)
- self.draw_board()
- return
- # 尝试移动
- ok, msg = can_move(self.board, r1,c1, row,col)
- if not ok:
- self.status.set("移动失败: " + msg)
- return
- # 模拟移动,检查是否自将
- new_board = copy.deepcopy(self.board)
- new_board[row][col] = new_board[r1][c1]
- new_board[r1][c1] = '.'
- if is_check(new_board, 'red'):
- self.status.set("不能自将")
- return
- # 记录悔棋
- self.undo_stack.append({'board':copy.deepcopy(self.board), 'turn':self.turn})
- # 执行移动
- self.board = new_board
- self.selected = None
- # 记录棋谱
- src = "({},{})".format(r1,c1)
- dst = "({},{})".format(row,col)
- self.move_list.append("红方 {} -> {}".format(src,dst))
- # 检查是否吃将/帅
- if piece!='.' and piece.lower()=='k':
- self.game_over = True
- self.move_list.append("红胜")
- self.draw_board()
- self.status.set("红方获胜!")
- self.ask_restart()
- return
- # 切换玩家
- self.turn = 'black'
- self.draw_board()
- # 检查黑方是否被将死
- if is_checkmate(self.board, 'black'):
- self.game_over = True
- self.move_list.append("将死黑方,红胜")
- self.draw_board()
- self.status.set("红方获胜!")
- self.ask_restart()
- return
- # AI 走棋
- self.root.after(300, self.ai_move)
- def ai_move(self):
- if self.game_over or self.turn!='black':
- return
- # 随机走一个合法走法(可改为简单估值AI)
- moves = []
- for r1 in range(SIZE_ROW):
- for c1 in range(SIZE_COL):
- p = self.board[r1][c1]
- if p=='.' or is_red(p): continue
- for r2 in range(SIZE_ROW):
- for c2 in range(SIZE_COL):
- ok, _ = can_move(self.board, r1,c1, r2,c2)
- if not ok: continue
- new_board = copy.deepcopy(self.board)
- new_board[r2][c2] = new_board[r1][c1]
- new_board[r1][c1] = '.'
- if not is_check(new_board, 'black'):
- moves.append((r1,c1,r2,c2))
- if not moves:
- self.game_over = True
- self.move_list.append("黑方无棋可走,红胜")
- self.draw_board()
- self.status.set("红方获胜!")
- self.ask_restart()
- return
- r1,c1,r2,c2 = random.choice(moves)
- self.undo_stack.append({'board':copy.deepcopy(self.board), 'turn':self.turn})
- self.board[r2][c2] = self.board[r1][c1]
- self.board[r1][c1] = '.'
- src = "({},{})".format(r1,c1)
- dst = "({},{})".format(r2,c2)
- self.move_list.append("黑方 {} -> {}".format(src,dst))
- # 检查是否吃红帅
- if self.board[r2][c2].lower()=='k':
- self.game_over = True
- self.move_list.append("黑胜")
- self.draw_board()
- self.status.set("黑方获胜!")
- self.ask_restart()
- return
- self.turn = 'red'
- self.draw_board()
- # 检查红方是否被将死
- if is_checkmate(self.board, 'red'):
- self.game_over = True
- self.move_list.append("将死红方,黑胜")
- self.draw_board()
- self.status.set("黑方获胜!")
- self.ask_restart()
- def ask_restart(self):
- if tk.messagebox.askyesno("游戏结束", "重新开始一局吗?"):
- self.board = init_board()
- self.selected = None
- self.turn = 'red'
- self.game_over = False
- self.undo_stack.clear()
- self.move_list.clear()
- self.draw_board()
- if __name__ == '__main__':
- root = tk.Tk()
- app = ChessApp(root)
- root.mainloop()
复制代码
### 如何使用?
1. 将以上代码复制,保存为 `chess_final.py`。
2. 在命令行执行 `python chess_final.py` 或双击文件运行。
3. 红方(您)点击己方棋子再点击目标格子即可走棋,黑方自动应战。
4. 右侧面板显示棋谱,点击“悔棋”可撤回上一步(您和黑方各一步)。
5. 游戏结束时会弹出询问是否重新开始。
这段代码**已经去掉了所有多余的调试输出**,只保留关键状态信息。如果您还想学习函数调用流程,可以在 `can_move` 函数开始添加一行条件打印,例如:
- if debug:
- print("can_move called: from ({},{}) to ({},{})".format(r1, c1, r2, c2))
复制代码
并将 `debug` 设为 `False` 关闭,需要时改为 `True` 观察。祝您学习愉快!
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 |
|