23场SWIPROLOG比赛

huangapple go评论58阅读模式
英文:

The game of 23 matches in SWIPROLOG

问题

我尝试在SWIPROLOG中创建23匹配游戏(在此处编译:https://swish.swi-prolog.org/)。

这个游戏代表什么?
桌子上有23根火柴。有两名玩家,每名玩家都必须从桌子上拿几根火柴。每位玩家可以拿1、2或3根火柴。拿到倒数第二根火柴的玩家输掉游戏。

我已经将这个游戏实现为与计算机对战的游戏(一次计算机选择,一次用户选择,通过键盘输入匹配数量)。计算机选择匹配数量的特殊策略,以使用户输掉,即以一种方式拾取火柴,迫使用户选择倒数第二根火柴并输掉。这两者交替选择,直到其中一方输掉。

这基本上是我设法实现的内容。

在这段代码中的问题在于策略。我无法确定一种策略,使计算机总是赢。以下是一个示例。
如果桌子上有3根火柴,轮到计算机选择时,它拿走2根,从而输掉了比赛,而它应该拿走1根,用户输掉了比赛。

我的问题是:是否有可能确定一种更有效的策略,使计算机总是赢(或几乎总是赢)?如果可能的话,我将非常感谢您的建议,如果可能的话,还有代码。我是Prolog的初学者,也许有些东西我还没有理解。

(注意:代码部分已省略)

英文:

I tried to make the 23 matches game in SWIPROLOG (compiled here : https://swish.swi-prolog.org/).

What does this game represent?
There are 23 matches on the table. There are two players and each of them has to take a few matches from the table.
matches. Each player is allowed to take 1, 2, or 3 matches. The player who takes the last but one match loses the game.

I have implemented this as a game against the computer (once the computer chooses, once the user chooses, by entering the number of matches on the keyboard). It chooses the number of matches by a special strategy, in such a way, as to make the user lose, i.e. pick up matches in such a way, as to force the user to choose the penultimate match and lose. The 2 make choices until one of them loses.

That's pretty much what I managed to implement:

% Start game with 23 matches and computer as first player
joc :- joc(23, calculator, in_progress).

% Player's turn
joc(N, player, State) :-
    nl,
    write('There are '), write(N), write(' matches on the table.'), nl,
    (State == finished ->
        write('The game has ended.'), nl
    ;
        write('It is your turn. '), nl,
        read(M),
        (valid_move(M, N) ->
            N1 is N - M,
            write('You chose '), write(M), write(' matches.'), nl,
            (N1 =< 1 ->
                write('The game has ended. You '), (State == won -> write('won!'), nl ; write('lost!'), nl),
                joc(N1, calculator, finished)
            ;
                joc(N1, calculator, in_progress)
            )
        ;
            write('Invalid move. Please try again.'), nl,
            joc(N, player, State)
        )
    ).

% Computer's turn
joc(N, calculator, State) :-
    nl,
    write('There are '), write(N), write(' matches on the table.'), nl,
    (State == finished ->
        write('The game has ended.'), nl
    ;
        write('It is the computer\'s turn. '), nl,
        optimal_move(N, M),
        N1 is N - M,
        write('The computer chose '), write(M), write(' matches.'), nl,
        (N1 =< 1 ->
            write('The game has ended. The computer '), (State == won -> write('won!'), nl ; write('lost!'), nl),
            joc(N1, player, finished)
        ;
            joc(N1, player, in_progress)
        )
    ).

% Check if move is valid (between 1 and 3 matches, and not more than available matches)
valid_move(M, N) :-
    M >= 1,
    M =< 3,
    M =< N.

% Calculate computer's optimal move
optimal_move(N, M) :-
    X is N mod 4,
    (X > 1 -> M is min(X-1, 3) ; M is max(min(N-2, 3), 1)).

The problem in this code, is strategy. I could not identify a strategy, in which the computer would always win.
Here's an example.
If there are 3 matches on the table and it is the computer's turn to pick, it picks 2 and thus loses, while it should pick 1 and the user loses.

My question : is it possible to identify a more efficient startegy, in which the calcualtor would always win(or almost always?) If so, I would be grateful for suggestions, and if possible, code. I'm a beginner in prologue, maybe something will escape me.

答案1

得分: 0

以下是翻译好的部分:

快速分析:

matches23(N, T) :-
    between(1, 23, N),
    matches23_(N, T).

matches23_(N, T) :-
    % 我的步骤
    take_matches(N, T, N0),
    % 对手的步骤,确保对手不能获胜
    \+ matches23_(N0, _).

take_matches(N, T, N0) :-
    between(1, 3, T),
    N0 is N - T,
    % 确保至少剩下1个
    N0 @>= 1.

在swi-prolog中的结果:

?- findall(N-T, matches23(N, T), Ps).
Ps = [2-1, 3-2, 4-3, 6-1, 7-2, 8-3, 10-1, 11-2, 12-3, 
      14-1, 15-2, 16-3, 18-1, 19-2, 20-3, 22-1, 23-2].

所以,通过移除2根火柴开始23游戏,如果您遵循其他步骤,您将确保获胜 23场SWIPROLOG比赛

英文:

A quick analysis:

matches23(N, T) :-
    between(1, 23, N),
    matches23_(N, T).

matches23_(N, T) :-
    % My move
    take_matches(N, T, N0),
    % Opponent's move, ensuring opponent cannot win
    \+ matches23_(N0, _).

take_matches(N, T, N0) :-
    between(1, 3, T),
    N0 is N - T,
    % Leave at least 1 remaining
    N0 @>= 1.

Results in swi-prolog:

?- findall(N-T, matches23(N, T), Ps).
Ps = [2-1, 3-2, 4-3, 6-1, 7-2, 8-3, 10-1, 11-2, 12-3, 
      14-1, 15-2, 16-3, 18-1, 19-2, 20-3, 22-1, 23-2].

So, start the 23 game by removing 2 matches, and you have a guaranteed win if you follow the other steps 23场SWIPROLOG比赛

huangapple
  • 本文由 发表于 2023年4月6日 21:43:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/75950249.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定