Prolog 序言-检查X和O游戏中的获胜条件

Prolog 序言-检查X和O游戏中的获胜条件,prolog,Prolog,我有一个简单的tic-tac-toe游戏,网上有很多使用min-maxing的例子,但是我只想用一个简单的例子来说明我自己的理解。 我已经在一个3x3框中显示了该板,该框具有用户可以通过以下方式选择的编号系统: :- dynamic o/1. :- dynamic x/1. % The computer has made a turn, print O printBox(N) :- o(N), write('[o]'). % The player makes a turn, print X p

我有一个简单的tic-tac-toe游戏,网上有很多使用min-maxing的例子,但是我只想用一个简单的例子来说明我自己的理解。 我已经在一个3x3框中显示了该板,该框具有用户可以通过以下方式选择的编号系统:

:- dynamic o/1.
:- dynamic x/1.

% The computer has made a turn, print O
printBox(N) :- o(N), write('[o]').
% The player makes a turn, print X
printBox(N) :- x(N), write('[x]').
% We just want to print the empty board
printBox(N) :- blankSpace(N), write('[_]').


buildBoard :- printBox(1),printBox(2),printBox(3),nl,
          printBox(4),printBox(5),printBox(6),nl,
          printBox(7),printBox(8),printBox(9),nl.

playersMove :- 
read(X), 
blankSpace(X), 
assert(x(X)).
当用户从上述选项(1-9)中选择时,棋盘上会填充一个X表示人类玩家,一个O表示计算机。 现在我也有了获胜的事实:

winningLine(1,2,3).
winningLine(4,5,6).
winningLine(7,8,9).
%Winning rows from left to right
winningLine(1,4,7).
winningLine(2,5,8).
winningLine(3,6,9).
%Winning diagnolly
winningLine(7,5,3).
winningLine(9,5,1).
所以在每次移动之后,我想检查是否有一个赢线组合被玩过,即棋盘是否包含任何赢线组合,以及玩家是否有该组合。我一直在考虑这个问题,这里可以使用findall方法,但我愿意接受建议

我的问题:如何检查董事会的获胜条件?

简单答案 由于您使用的是全局游戏位置,因此我们可以假设存在一个谓词
checked(Player,Square)
,该谓词保存iff Player
Player
已检查Square
Square

然后,为了查看玩家是否赢了游戏,您只需询问是否存在一条赢线,其中所有三个方块都由同一玩家检查:

is_win(Player) :-
    winning_line(P1,P2,P3),
    checked(Player,P1),
    checked(Player,P2),
    checked(Player,P3).
您可以使用
assertz
生成
checked/2

:- dynamic checked/2.

player_move(Player, Square) :- assertz(checked(Player, Square)).
更好的方法 但是,如果您不想模拟简单的游戏,您应该在单个数据项中表示您的状态,而不是将其放入全局数据库中,例如:

initial_state(board([empty, empty, empty],
                    [empty, empty, empty],
                    [empty, empty, empty]).
并相应地调整
player\u move
选中的

/* Should make a new board from Position0 by adding the move */
player_move(Player, Square, Position0, Position) :- ...  

/* Should check if a player has checked a square inside Position */
checked(Player, Square, Position) :- ...
简单的答案 由于您使用的是全局游戏位置,因此我们可以假设存在一个谓词
checked(Player,Square)
,该谓词保存iff Player
Player
已检查Square
Square

然后,为了查看玩家是否赢了游戏,您只需询问是否存在一条赢线,其中所有三个方块都由同一玩家检查:

is_win(Player) :-
    winning_line(P1,P2,P3),
    checked(Player,P1),
    checked(Player,P2),
    checked(Player,P3).
您可以使用
assertz
生成
checked/2

:- dynamic checked/2.

player_move(Player, Square) :- assertz(checked(Player, Square)).
更好的方法 但是,如果您不想模拟简单的游戏,您应该在单个数据项中表示您的状态,而不是将其放入全局数据库中,例如:

initial_state(board([empty, empty, empty],
                    [empty, empty, empty],
                    [empty, empty, empty]).
并相应地调整
player\u move
选中的

/* Should make a new board from Position0 by adding the move */
player_move(Player, Square, Position0, Position) :- ...  

/* Should check if a player has checked a square inside Position */
checked(Player, Square, Position) :- ...
使用上述全局状态表示法,您基本上必须调用
赢线(I,J,K)
以获得三重索引,然后对于所有这些索引,
x(x)
(其中
x
替换为
I
J
K
)应保持不变;或者对于所有指数
o(X)
应为hols,如:

xwin :-
    winningLine(I, J, K),
    x(I),
    x(J),
    x(K).
nwin :-
    winningLine(I, J, K),
    o(I),
    o(J),
    o(K).
win :-
    xwin.
win :-
    owin.
因此这里
xwin/0
是满意的,假设
x
的玩家有一条赢线,
owin/0
是满意的,假设
o
的玩家有一条赢线,
win/0
是满意的,如果任何玩家赢了

但就我个人而言,我认为使用全局状态并不是解决问题的优雅方式(实际上,在大多数编程范式中,如果不是所有编程范式的话)。在这里,您不能使用Prolog强大的回溯机制,而且如果您想搜索用户是否仍然存在获胜的方法,那么您不能简单地复制电路板,并在复制的电路板上运行解算器。

使用上述全局状态表示,基本上,你必须调用
赢线(I,J,K)
来获得三重索引,然后对于所有这些索引,
x(x)
(用
I
替换
x
J
K
)应该保持不变;或者对于所有指数
o(X)
应为hols,如:

xwin :-
    winningLine(I, J, K),
    x(I),
    x(J),
    x(K).
nwin :-
    winningLine(I, J, K),
    o(I),
    o(J),
    o(K).
win :-
    xwin.
win :-
    owin.
因此这里
xwin/0
是满意的,假设
x
的玩家有一条赢线,
owin/0
是满意的,假设
o
的玩家有一条赢线,
win/0
是满意的,如果任何玩家赢了


但就我个人而言,我认为使用全局状态并不是解决问题的优雅方式(实际上,在大多数编程范式中,如果不是所有编程范式的话)。在这里,你不能使用Prolog强大的回溯机制,而且如果你想搜索用户是否还有获胜的方法,你就不能简单地复制电路板,并在复制的电路板上运行解算器。

我认为简单的模式匹配可能会更容易。谢谢你的快速回复,你能不能帮我理解一下,这是如何在赢线规则中实现的?你到底是如何代表你的董事会的?你如何表示
x
o
和blank?我用更多的代码更新了这个问题,向你展示了这一点。基本上,我有动态X和O变量,当板被创建时,我放在一个字符串“[]”中,当用户输入1到9之间的一个数字时,将板重新构建成[X],进入空白数字的位置。我不相信这是一个好的方法,因为在这里你创建了一个全局状态,它还将导致大量的断言/1
s和收回/1
s,并且很容易出错,特别是当您想要搜索解决方案时。一个更简单的解决方案是构造一个通过调用传递并更新/统一的对象。我认为简单的模式匹配可能会更容易。感谢您的快速回复,您能否帮助我了解如何在Winning Line规则中实现这一点?您如何准确地表示您的董事会?你如何表示
x
o
和blank?我用更多的代码更新了这个问题,向你展示了这一点。基本上,我有动态的X和O变量,当板被创建时,我放在一个字符串“[]”中,当用户输入1到9之间的一个数字时,板被重建成[X],进入空白数字的位置。我不相信这是一个好的方法,因为这里是CR。