-
Notifications
You must be signed in to change notification settings - Fork 9
Update 1.9.8 #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Update 1.9.8 #3
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,11 @@ | ||
| { | ||
| "scale": 1.404, | ||
| "auto_scale": true, | ||
| "virtual": true, | ||
| "level": 4, | ||
| "peace": 60, | ||
| "algo": 0 | ||
| { | ||
| "scale": 0.5, | ||
| "auto_scale": false, | ||
| "virtual": true, | ||
| "level": 5, | ||
| "peace": 60, | ||
| "algo": 0, | ||
| "protect_king_when_check": false, | ||
| "ai_max_time": 1, | ||
| "allow_skip": true | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,15 +18,16 @@ | |
| 2. help.md: 帮助文本 | ||
| 3. statistic.json: 统计数据 | ||
| 4. audio/*.wav: 音效文件 | ||
| 5. data 棋局库 | ||
| 5. data/.../*.fen 棋局库 | ||
|
|
||
| """ | ||
|
|
||
| # 版本号 | ||
| __version__ = '1.8' | ||
| __version__ = '1.9.8' | ||
| # 作者 | ||
| __author__ = '小康2022' | ||
| __author__ = '非主刘Non_main_liu' | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 你这是什么意思呢? |
||
| # 更新日期 | ||
| __update__ = '2024/04/25' | ||
| __update__ = '2025/06/28' | ||
|
|
||
| if __name__ == '__main__': | ||
| from winsound import Beep | ||
|
|
@@ -36,7 +37,5 @@ | |
|
|
||
| # 更新统计数据 | ||
| statistic(Launch=1) | ||
| # 启动一下winsound模块 | ||
| Beep(37, 0) | ||
| # 启动主窗口 | ||
| Window() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,25 +8,38 @@ | |
| from configure import config, statistic | ||
| from tools import virtual | ||
|
|
||
| # 新增:将军时优先保护将的开关(可从config读取,默认True) | ||
| protect_king_when_check = config.get('protect_king_when_check', True) | ||
|
|
||
|
|
||
| def get_protect_king_when_check(): | ||
| try: | ||
| import GUI | ||
| return getattr(GUI.Global, 'protect_king_when_check', config.get('protect_king_when_check', True)) | ||
| except Exception: | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 一个建议:尽量减少使用 |
||
| return config.get('protect_king_when_check', True) | ||
|
|
||
|
|
||
| def rule(chesses: list[list], chess, flag_: bool = False) -> list[tuple[bool, int, int]]: | ||
| """ 返回可走位置 """ | ||
| pos: list[tuple[bool, int, int]] = [] | ||
|
|
||
| def ifappend(step: tuple[bool, int, int]) -> bool: | ||
| """ 应将判定 """ | ||
| if not get_protect_king_when_check(): | ||
| return True | ||
| if flag_: | ||
| color = '#FF0000' if chess.color == '#000000' else '#000000' | ||
| if color in virtual(chesses, chess, step, warn): | ||
| if color in virtual(chesses, chess, list(step), warn): | ||
| return False | ||
| return True | ||
|
|
||
| def append(x: int, y: int, flag: bool | None = None) -> None: | ||
| """ 添加位置 """ | ||
| if flag and ifappend(step := (flag, x, y)): | ||
| pos.append(step) | ||
| elif chess_ := chesses[chess.y+y][chess.x+x]: | ||
| (step := (True, x, y)) | ||
| elif (chess_ := chesses[chess.y+y][chess.x+x]): | ||
| step = (True, x, y) | ||
| if chess_.color != chess.color and ifappend(step): | ||
| pos.append(step) | ||
| elif ifappend(step := (False, x, y)): | ||
|
|
@@ -110,6 +123,18 @@ def warn(chesses: list[list], color: str | None = None) -> list[str]: | |
| def peace() -> bool: | ||
| """ 和棋判定 """ | ||
| import GUI | ||
| # 新增:判定双方是否都没��能过河的棋子(马、车、炮、兵) | ||
| chesses = GUI.Global.chesses if hasattr(GUI.Global, 'chesses') else None | ||
| if chesses: | ||
| def has_cross_river_piece(color): | ||
| for line in chesses: | ||
| for chess in line: | ||
| if chess and chess.color == color and chess.name in '马馬车車炮砲兵卒': | ||
| # 红方(#FF0000)过河:y<=4,黑方(#000000)过河:y>=5 | ||
| if (color == '#FF0000' and ((chess.name in '兵' and chess.y <= 4) or (chess.name in '马車炮' and chess.y <= 4))) or \ | ||
| (color == '#000000' and ((chess.name in '卒' and chess.y >= 5) or (chess.name in '馬車砲' and chess.y >= 5))): | ||
| return True | ||
| return False | ||
| if GUI.Global.count >= config['peace']*2: | ||
| return True | ||
| if (ind := GUI.Global.index) >= 11: | ||
|
|
@@ -120,11 +145,45 @@ def peace() -> bool: | |
|
|
||
| def dead(chesses: list[list], color: str) -> str | None: | ||
| """ 绝杀判定(接收攻击者,返回攻击者) """ | ||
| # 死将或将被吃都判负 | ||
| # 1. 检查己方将/帅是否还在 | ||
| king_alive = False | ||
| for line in chesses: | ||
| for chess in line: | ||
| if chess and chess.color == color and chess.name in '将帥': | ||
| king_alive = True | ||
| break | ||
| if king_alive: | ||
| break | ||
| if not king_alive: | ||
| # 己方将/帅已被吃,返回对方颜色 | ||
| for line in chesses: | ||
| for chess in line: | ||
| if chess and chess.color != color: | ||
| return chess.color | ||
| return '#000000' if color == '#FF0000' else '#FF0000' # 兜底 | ||
| # 2. 检查己方将/帅是否被对方吃掉(被攻击) | ||
| king_pos = None | ||
| for line in chesses: | ||
| for chess in line: | ||
| if chess and chess.color == color and chess.name in '将帥': | ||
| king_pos = (chess.x, chess.y) | ||
| break | ||
| if king_pos: | ||
| break | ||
| for line in chesses: | ||
| for chess in line: | ||
| if chess and chess.color != color: | ||
| for step in rule(chesses, chess): | ||
| tx, ty = chess.x + step[1], chess.y + step[2] | ||
| if king_pos and (tx, ty) == king_pos: | ||
| return chess.color | ||
| # 原有绝杀判定逻辑 | ||
| for line in chesses: | ||
| for chess in line: | ||
| if chess and chess.color != color: | ||
| for step in rule(chesses, chess): | ||
| if not virtual(chesses, chess, step, warn, color): | ||
| if not virtual(chesses, chess, list(step), warn, color): | ||
| return | ||
| return color | ||
|
|
||
|
|
@@ -138,7 +197,8 @@ def gameover(color: str | None = None) -> None: | |
| who = '你' | ||
| if not color: | ||
| statistic(Peace=1) | ||
| return messagebox.showinfo('游戏结束', '本局和棋!\t') | ||
| messagebox.showinfo('游戏结束', '本局和棋!\t') | ||
| return | ||
| if GUI.Global.mode in 'LOCAL TEST': | ||
| tone, win = '', '获胜!' | ||
| who = '红方' if color == '#FF0000' else '黑方' | ||
|
|
@@ -173,7 +233,7 @@ def switch() -> None: | |
| elif GUI.Global.mode == 'LAN': | ||
| GUI.Global.player = '我方' if GUI.Global.player == '对方' else '对方' | ||
| else: | ||
| GUI.Global.player = '红方' if GUI.Global.player == '黑方' else '黑方' | ||
| GUI.Global.player = '红���' if GUI.Global.player == '黑方' else '黑方' | ||
| else: | ||
| if GUI.Global.first: | ||
| if GUI.Global.mode in 'LAN COMPUTER END': | ||
|
|
@@ -188,7 +248,13 @@ def gameset(code: str | None = None) -> None: | |
| """ 游戏设定 """ | ||
| if code: | ||
| import GUI | ||
| GUI.Global.first = bool(int(code[0])) | ||
| # 兼容旧code长度 | ||
| if len(code) > 13: | ||
| protect_king_flag = code[-1] | ||
| code = code[:-1] | ||
| GUI.Global.protect_king_when_check = (protect_king_flag == '1') | ||
| # 修复:根据code[0]����置Global.first,确保先手选择生效 | ||
| GUI.Global.first = (code[0] == '1') | ||
| lis = [(0, 9), (8, 9), (0, 0), (8, 0), (1, 7), (7, 7), | ||
| (1, 2), (7, 2), (1, 9), (7, 9), (1, 0), (7, 0)] | ||
| for i, v in enumerate(code): | ||
|
|
@@ -201,6 +267,18 @@ def gameset(code: str | None = None) -> None: | |
| def modechange(mode: str, code: str | None = None) -> None: | ||
| """ 改变模式 """ | ||
| import GUI | ||
| # 机机自弈参数解析 | ||
| if mode == 'AIVS' and code and '|' in code: | ||
| # code: ai1_algo|ai1_depth|ai1_time|ai2_algo|ai2_depth|ai2_time | ||
| ai1_algo, ai1_depth, ai1_time, ai2_algo, ai2_depth, ai2_time = code.split('|') | ||
| GUI.Global.ai_vs_ai_conf = { | ||
| 'red': {'algo': ai1_algo, 'depth': int(ai1_depth), 'max_time': int(ai1_time)}, | ||
| 'black': {'algo': ai2_algo, 'depth': int(ai2_depth), 'max_time': int(ai2_time)} | ||
| } | ||
| code = None # 不再传递给gameset | ||
| else: | ||
| if hasattr(GUI.Global, 'ai_vs_ai_conf'): | ||
| delattr(GUI.Global, 'ai_vs_ai_conf') | ||
| if mode != 'END': | ||
| GUI.Window.chess() | ||
| GUI.Global.cache.clear() | ||
|
|
@@ -210,19 +288,24 @@ def modechange(mode: str, code: str | None = None) -> None: | |
| GUI.Global.choose = None | ||
| gameset(code) | ||
| statistic(**{'Play': 1, mode: 1}) | ||
| mode = '双人对弈' if mode == 'LOCAL' else '联机对抗' if mode == 'LAN' else '人机对战' if mode in 'COMPUTER' else '残局挑战' if mode == 'END' else 'AI测试' | ||
| GUI.Window.root.title('中国象棋 - %s' % mode) | ||
| mode_title = '双人对弈' if mode == 'LOCAL' else '联机对抗' if mode == 'LAN' else '人机对战' if mode in 'COMPUTER' else '残局挑战' if mode == 'END' else 'AI测试' if mode == 'TEST' else '机机自弈' if mode == 'AIVS' else mode | ||
| GUI.Window.root.title('中国象棋 - %s' % mode_title) | ||
| GUI.Global.player = None | ||
| GUI.Window.tip('— 提示 —\n游戏模式已更新\n为“%s”模式' % mode) | ||
| GUI.Window.tip('— 提示 —\n游戏模式已更新\n为“%s”模式' % mode_title) | ||
| switch() | ||
| if GUI.Global.mode in 'COMPUTER END' and not GUI.Global.first: | ||
| GUI.Window.root.after( | ||
| 500, Thread(target=lambda: GUI.Window.AImove('#000000'), daemon=True).start) | ||
| # 机机自弈自动开始 | ||
| if GUI.Global.mode == 'AIVS': | ||
| GUI.Window.root.after( | ||
| 500, Thread(target=lambda: GUI.Window.AImove('#FF0000', True), daemon=True).start) | ||
|
|
||
|
|
||
| def revoke(flag: bool = False) -> None: | ||
| """ 撤销(悔棋) """ | ||
| import GUI | ||
| import LAN | ||
| if flag or (GUI.Global.player and GUI.Global.mode in 'LOCAL' and GUI.Global.index >= 0): | ||
| if GUI.Global.choose: | ||
| GUI.Global.choose.virtual_delete() | ||
|
|
@@ -243,6 +326,21 @@ def revoke(flag: bool = False) -> None: | |
| revoke(True) | ||
| GUI.Window.root.after(600, revoke, True) | ||
| statistic(Revoke=-1) | ||
| elif GUI.Global.mode == 'LAN' and not flag: | ||
| # 联机模式下,主动方请求悔棋 | ||
| LAN.API.send(type='revoke_request') | ||
| GUI.Window.tip('— 提示 —\n已向对方请求悔棋,等待同意...') | ||
| def wait_reply(): | ||
| reply = LAN.API.recv() | ||
| if reply.get('type') == 'revoke_reply': | ||
| if reply.get('agree'): | ||
| revoke(True) | ||
| GUI.Window.tip('— 提示 —\n对方同意悔棋') | ||
| else: | ||
| GUI.Window.tip('— 提示 —\n对方拒绝悔棋') | ||
| else: | ||
| GUI.Window.tip('— 提示 —\n网络异常,悔棋失败') | ||
| GUI.Window.root.after(100, wait_reply) | ||
| else: | ||
| GUI.Window.tip('— 提示 —\n当前模式或状态下\n无法进行悔棋操作!') | ||
| GUI.Window.root.bell() | ||
|
|
@@ -251,6 +349,7 @@ def revoke(flag: bool = False) -> None: | |
| def recovery(flag: bool = False) -> None: | ||
| """ 恢复(悔棋) """ | ||
| import GUI | ||
| import LAN | ||
| if flag or (GUI.Global.player and GUI.Global.mode == 'LOCAL' and -1 <= GUI.Global.index < len(GUI.Global.cache)-1): | ||
| if GUI.Global.choose: | ||
| GUI.Global.choose.virtual_delete() | ||
|
|
@@ -267,6 +366,41 @@ def recovery(flag: bool = False) -> None: | |
| recovery(True) | ||
| GUI.Window.root.after(600, recovery, True) | ||
| statistic(Recovery=-1) | ||
| elif GUI.Global.mode == 'LAN' and not flag: | ||
| # 联机模式下,主动方请求���复 | ||
| LAN.API.send(type='recovery_request') | ||
| GUI.Window.tip('— 提示 —\n已向对方请求恢复,等待同意...') | ||
| def wait_reply(): | ||
| reply = LAN.API.recv() | ||
| if reply.get('type') == 'recovery_reply': | ||
| if reply.get('agree'): | ||
| recovery(True) | ||
| GUI.Window.tip('— 提示 —\n对方同意恢复') | ||
| else: | ||
| GUI.Window.tip('— 提示 —\n对方拒绝恢复') | ||
| else: | ||
| GUI.Window.tip('— 提示 —\n网络异常,恢复失败') | ||
| GUI.Window.root.after(100, wait_reply) | ||
| else: | ||
| GUI.Window.tip('— 提示 —\n当前模式或状态下\n无法进行撤销悔棋操作!') | ||
| GUI.Window.root.bell() | ||
|
|
||
|
|
||
| def skip_turn() -> None: | ||
| """停一手(跳过当前回合)""" | ||
| import GUI | ||
| if not config.get('allow_skip', False): | ||
| GUI.Window.tip('— 提示 —\n未开启停一手功能,请在设置中开启。') | ||
| return | ||
| if GUI.Global.mode not in ('LOCAL', 'COMPUTER', 'LAN') or not GUI.Global.player: | ||
| GUI.Window.tip('— 提示 —\n当前模式或状态下\n无法进行停一手操作!') | ||
| GUI.Window.root.bell() | ||
| return | ||
| # 清除选中状态 | ||
| if GUI.Global.choose: | ||
| GUI.Global.choose.virtual_delete() | ||
| GUI.Global.choose.highlight(False, inside=False) | ||
| GUI.Global.choose = None | ||
| switch() | ||
| statistic(Skip=1) | ||
| GUI.Window.tip('— 提示 —\n已成功停一手,轮到对方。') | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,21 @@ | ||
| { | ||
| "Launch": 0, | ||
| "Play": 0, | ||
| "First": 0, | ||
| "Time": 0, | ||
| "LAN": 0, | ||
| "LOCAL": 0, | ||
| "COMPUTER": 0, | ||
| "END": 0, | ||
| "TEST": 0, | ||
| "Win": 0, | ||
| "Lose": 0, | ||
| "Peace": 0, | ||
| "Eat": 0, | ||
| "Move": 0, | ||
| "Revoke": 0, | ||
| "Recovery": 0, | ||
| "Warn": 0, | ||
| "AI": 0 | ||
| { | ||
| "Launch": 47, | ||
| "Play": 29, | ||
| "First": 14, | ||
| "Time": 357, | ||
| "LAN": 0, | ||
| "LOCAL": 5, | ||
| "COMPUTER": 23, | ||
| "END": 1, | ||
| "TEST": 0, | ||
| "Win": 0, | ||
| "Lose": 3, | ||
| "Peace": 0, | ||
| "Eat": 26, | ||
| "Move": 0, | ||
| "Revoke": 0, | ||
| "Recovery": 0, | ||
| "Warn": 10, | ||
| "AI": 0, | ||
| "Skip": 1 | ||
|
Comment on lines
+1
to
+20
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 数据没有清空 |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
一个建议:尽量不要在代码中间引入模块