You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SWIPROLOG实现23根火柴游戏:求电脑必胜策略及代码优化

23根火柴游戏:电脑必胜策略与代码优化

必胜策略分析

游戏核心规则:桌上初始有23根火柴,两人轮流取1-3根,取到倒数第二根火柴的玩家输掉游戏(即取完后剩余1根时,取火柴的玩家因取了倒数第二根输掉;取完后剩余0根时,取火柴的玩家因取了包含倒数第二根的所有火柴,同样输掉)。

要让电脑近乎必胜,核心是迫使玩家进入必败态:当轮到玩家行动时,桌上火柴数为2、6、10、14、18、22(满足N ≡ 2 mod 4)。此时无论玩家取1、2、3根,电脑都取4-M根(M为玩家取的数量),让下一轮剩余火柴数仍保持≡2 mod4,最终玩家会面对2根火柴,无论怎么取都会输掉。

电脑作为先手时,第一次取1根,剩余22根(必败态),之后每轮保持两人取火柴总数为4,即可牢牢掌控游戏节奏。

优化后的完整代码

% 启动游戏:初始23根火柴,电脑先手
joc :- joc(23, calculator, in_progress).

% 玩家回合:游戏结束状态
joc(N, player, finished) :-
    nl,
    write('There are '), write(N), write(' matches on the table.'), nl,
    write('The game has ended.'), nl.

% 玩家回合:进行中状态
joc(N, player, in_progress) :-
    nl,
    write('There are '), write(N), write(' matches on the table.'), nl,
    write('It is your turn. Enter number of matches to take (1-3): '), nl,
    read(M),
    (valid_move(M, N) ->
        N1 is N - M,
        write('You took '), write(M), write(' matches.'), nl,
        (check_loss(N1) ->
            write('Game over! You took the second last match, you lose.'), nl,
            joc(N1, calculator, finished)
        ;
            joc(N1, calculator, in_progress)
        )
    ;
        write('Invalid move! Please take 1-3 matches, and no more than available.'), nl,
        joc(N, player, in_progress)
    ).

% 电脑回合:游戏结束状态
joc(N, calculator, finished) :-
    nl,
    write('There are '), write(N), write(' matches on the table.'), nl,
    write('The game has ended.'), nl.

% 电脑回合:进行中状态
joc(N, calculator, in_progress) :-
    nl,
    write('There are '), write(N), write(' matches on the table.'), nl,
    write('It is the computer\'s turn.'), nl,
    optimal_move(N, M),
    N1 is N - M,
    write('The computer took '), write(M), write(' matches.'), nl,
    (check_loss(N1) ->
        write('Game over! The computer took the second last match, you win.'), nl,
        joc(N1, player, finished)
    ;
        joc(N1, player, in_progress)
    ).

% 验证移动合法性:取1-3根,且不超过剩余火柴数
valid_move(M, N) :-
    M >= 1,
    M =< 3,
    M =< N.

% 判断当前取火柴的玩家是否输掉:取完后剩余≤1根,说明取了倒数第二根
check_loss(N1) :-
    N1 =< 1.

% 电脑最优移动策略:让剩余火柴数保持为必败态(≡2 mod4)
optimal_move(N, M) :-
    Rem is N mod 4,
    (Rem =:= 0 -> M = 2;   % N=4→取2剩2,N=8→取2剩6,以此类推
     Rem =:= 1 -> M = 3;   % N=5→取3剩2,N=9→取3剩6,以此类推
     Rem =:= 2 -> between(1, 3, M), valid_move(M, N); % 已在必败态,随机取合法值
     Rem =:= 3 -> M = 1).  % N=3→取1剩2,N=7→取1剩6,以此类推

代码关键说明

  • 回合逻辑:分玩家和电脑两个分支处理,清晰区分游戏结束与进行中状态,避免原代码的状态判断混乱。
  • 胜负判定:通过check_loss/1直接判断取完火柴后的剩余数量,逻辑更直观准确。
  • 最优策略:optimal_move/2根据剩余火柴数的模4结果计算移动量,确保每一步都将玩家推向必败态,解决了原代码中剩3根时电脑错误取2根的问题。

内容的提问来源于stack exchange,提问作者John

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 13:37:03