品尝 GNU Prolog (2)

    五、GNU Prolog 程序制作 GUI 界面的方式比较新颖、合理。

它本身轻便小巧,没有专门的 GUI 功能机制,但它可以调用 GTK-Server ,使其程序实现 GUI 界面。

GTK-Server 需要另行下载安装。地址是:http://www.gtk-server.org/

下面,以程序 tictactoe.pl 为例,介绍 GNU Prolog 生成 GUI 界面的“借用式”机制。

:-dynamic(x/1, o/1, signals/5, labels/1).

:-initialization(start).

start:-
init(Pin, Pout),
gui(Pin, Pout),
callback(Pin, Pout).

init(Pin, Pout):-
% Start server in STDIN mode, let it return answer ending with '.'
exec('gtk-server stdin post=.', Pout, Pin, _, _),
% Switch to line buffering
set_stream_buffering(Pout, line).

% Communicate with GTK-server
api(Pin, Pout, Txt, Result):-
% Write string to stdin, terminate with newline
write(Pout, Txt), write(Pout, '/n'),
% Flush buffers
flush_output(Pout),
% Read info
read(Pin, Result).

% This is the concatenate predicate
cat([], _).
cat([H|T], Stream):-
write(Stream, H),
cat(T, Stream).

% Concatenate list and communicate
gtk(Pin, Pout, List, Result):-
open_output_atom_stream(Stream),
cat(List, Stream),
close_output_atom_stream(Stream, Text),
api(Pin, Pout, Text, Result).

%********************************* GUI definition
%
% Define the GUI using the gtk-server
%

gui(Pin, Pout):-
% Initialize GTK
gtk(Pin, Pout, [' gtk_init NULL NULL'], _),
% Define window
gtk(Pin, Pout, [' gtk_window_new 0'], WIN),
gtk(Pin, Pout, [' gtk_window_set_title ', WIN, ' "GNU Prolog TicTacToe"'], _),
gtk(Pin, Pout, [' gtk_widget_set_usize ', WIN, ' 250 200'], _),
gtk(Pin, Pout, [' gtk_window_set_position ', WIN, ' 1'], _),
% Define Table
gtk(Pin, Pout, [' gtk_table_new 50 65 1'], TABLE),
gtk(Pin, Pout, [' gtk_container_add ', WIN, ' ', TABLE], _),
% Define DIALOG
gtk(Pin, Pout, [' gtk_message_dialog_new ', WIN, ' 0 0 1 "GNU Prolog TicTacToe using the GTK-server./r/rFor more info see http://www.gtk-server.org." ""'], DIALOG),
% Define NEW button
gtk(Pin, Pout, [' gtk_button_new_with_label "New"'], BUTTON2),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', BUTTON2, ' 50 62 3 13'], _),
% Define ABOUT button
gtk(Pin, Pout, [' gtk_button_new_with_label About'], BUTTON3),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', BUTTON3, ' 50 62 14 24'], _),
% Define EXIT button
gtk(Pin, Pout, [' gtk_button_new_with_label Exit'], BUTTON1),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', BUTTON1, ' 50 62 30 40'], _),
% Define frame
gtk(Pin, Pout, [' gtk_frame_new NULL'], FRAME),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', FRAME, ' 48 64 1 42'], _),
% Remember all widgets with callbacks for mainloop
asserta(signals(WIN, BUTTON2, BUTTON1, BUTTON3, DIALOG)),
% Define status bar
gtk(Pin, Pout, [' gtk_statusbar_new'], STATUS),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', STATUS, ' 0 65 44 50'], _),
gtk(Pin, Pout, [' gtk_statusbar_get_context_id ', STATUS, ' main_window'], CID),
gtk(Pin, Pout, [' gtk_statusbar_push ', STATUS, ' ', CID, ' "Start by pressing the squares..."'], _),
% Define labels
gtk(Pin, Pout, [' gtk_button_new " "'], BUT1),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', BUT1, ' 1 16 1 14'], _),
gtk(Pin, Pout, [' gtk_button_new " "'], BUT2),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', BUT2, ' 16 31 1 14'], _),
gtk(Pin, Pout, [' gtk_button_new " "'], BUT3),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', BUT3, ' 31 46 1 14'], _),
gtk(Pin, Pout, [' gtk_button_new " "'], BUT4),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', BUT4, ' 1 16 14 28'], _),
gtk(Pin, Pout, [' gtk_button_new " "'], BUT5),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', BUT5, ' 16 31 14 28'], _),
gtk(Pin, Pout, [' gtk_button_new " "'], BUT6),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', BUT6, ' 31 46 14 28'], _),
gtk(Pin, Pout, [' gtk_button_new " "'], BUT7),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', BUT7, ' 1 16 28 42'], _),
gtk(Pin, Pout, [' gtk_button_new " "'], BUT8),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', BUT8, ' 16 31 28 42'], _),
gtk(Pin, Pout, [' gtk_button_new " "'], BUT9),
gtk(Pin, Pout, [' gtk_table_attach_defaults ', TABLE, ' ', BUT9, ' 31 46 28 42'], _),
% Remember labels
asserta(labels([BUT1, BUT2, BUT3, BUT4, BUT5, BUT6, BUT7, BUT8, BUT9, STATUS, CID])),
% Show widgets
gtk(Pin, Pout, [' gtk_widget_show_all ', WIN], _),
gtk(Pin, Pout, [' gtk_widget_grab_focus ', BUTTON3], _).

% Retrieve callback
callback(Pin, Pout):-
% Wait for callback signal
gtk(Pin, Pout, [' gtk_server_callback wait'], EVENT),
loop(Pin, Pout, EVENT).

% Check on callback for EXIT button
loop(Pin, Pout, EVENT):-
% Retrieve callback widget
signals(_, _, BUTTON, _, _),
% Was the EXIT button pressed?
EVENT == BUTTON, leave(Pin, Pout), !.

% Check on callback for WINDOW
loop(Pin, Pout, EVENT):-
% Retrieve data needed for callback
signals(WIN, _, _, _, _),
% Find out if coordinates were entered
EVENT == WIN, leave(Pin, Pout), !.

% Check on callback for NEW GAME
loop(Pin, Pout, EVENT):-
% Retrieve data needed for callback
signals(_, BUTTON, _, _, _),
% Yes pressed, start over
EVENT == BUTTON, restart(Pin, Pout), !.

% Check on callback for ABOUT button
loop(Pin, Pout, EVENT):-
% Retrieve data needed for callback
signals(_, _, _, BUTTON, DIALOG),
% Yes pressed, show dialog
EVENT == BUTTON, gtk(Pin, Pout, [' gtk_widget_show ', DIALOG], _), fail.

% Check on callback for DIALOG
loop(Pin, Pout, EVENT):-
% Retrieve data needed for callback
signals(_, _, _, _, DIALOG),
% Yes pressed, hide dialog
EVENT == DIALOG, gtk(Pin, Pout, [' gtk_widget_hide ', DIALOG], _), fail.

% Check on callback for playfield1
loop(Pin, Pout, EVENT):-
% Retrieve data needed for callback
labels([BUTTON, _, _, _, _, _, _, _, _, _, _]),
% Yes, generate move
EVENT == BUTTON, play(Pin, Pout, BUTTON), fail.

% Check on callback for playfield2
loop(Pin, Pout, EVENT):-
% Retrieve data needed for callback
labels([_, BUTTON, _, _, _, _, _, _, _, _, _]),
% Yes, generate move
EVENT == BUTTON, play(Pin, Pout, BUTTON), fail.

% Check on callback for playfield3
loop(Pin, Pout, EVENT):-
% Retrieve data needed for callback
labels([_, _, BUTTON, _, _, _, _, _, _, _, _]),
% Yes, generate move
EVENT == BUTTON, play(Pin, Pout, BUTTON), fail.

% Check on callback for playfield4
loop(Pin, Pout, EVENT):-
% Retrieve data needed for callback
labels([_, _, _, BUTTON, _, _, _, _, _, _, _]),
% Yes, generate move
EVENT == BUTTON, play(Pin, Pout, BUTTON), fail.

% Check on callback for playfield5
loop(Pin, Pout, EVENT):-
% Retrieve data needed for callback
labels([_, _, _, _, BUTTON, _, _, _, _, _, _]),
% Yes, generate move
EVENT == BUTTON, play(Pin, Pout, BUTTON), fail.

% Check on callback for playfield6
loop(Pin, Pout, EVENT):-
% Retrieve data needed for callback
labels([_, _, _, _, _, BUTTON, _, _, _, _, _]),
% Yes, generate move
EVENT == BUTTON, play(Pin, Pout, BUTTON), fail.

% Check on callback for playfield7
loop(Pin, Pout, EVENT):-
% Retrieve data needed for callback
labels([_, _, _, _, _, _, BUTTON, _, _, _, _]),
% Yes, generate move
EVENT == BUTTON, play(Pin, Pout, BUTTON), fail.

% Check on callback for playfield8
loop(Pin, Pout, EVENT):-
% Retrieve data needed for callback
labels([_, _, _, _, _, _, _, BUTTON, _, _, _]),
% Yes, generate move
EVENT == BUTTON, play(Pin, Pout, BUTTON), fail.

% Check on callback for playfield9
loop(Pin, Pout, EVENT):-
% Retrieve data needed for callback
labels([_, _, _, _, _, _, _, _, BUTTON, _, _]),
% Yes, generate move
EVENT == BUTTON, play(Pin, Pout, BUTTON), fail.

% No callbacks found? Goto retrieve a callback
loop(Pin, Pout, _):-
callback(Pin, Pout).

leave(Pin, Pout):-
% Exit GTK
gtk(Pin, Pout, [' gtk_exit 0'], _),
% Exit Prolog - if you do not want to exit, use a cut (!).
halt.

%********************************* Parse input
%
% Find out which move was played
%
play(Pin, Pout, Button):-
% Find the correct playfield
labels(Labels), nth(Move, Labels, Button),
% Check if empty and fill in
empty(Move), asserta(x(Move)),
% Set correct label
gtk(Pin, Pout, [' gtk_button_set_label ', Button, ' X'], _),
% Computer plays
not(end_game(Pin, Pout)), move(A), asserta(o(A)),
% Find the correct label
nth(A, Labels, Compu),
% Set correct label
gtk(Pin, Pout, [' gtk_button_set_label ', Compu, ' O'], _),
end_game(Pin, Pout).

restart(Pin, Pout):-
% Retrieve data
labels([BUT1, BUT2, BUT3, BUT4, BUT5, BUT6, BUT7, BUT8, BUT9, STATUS, CID]),
% Empty all labels
gtk(Pin, Pout, [' gtk_button_set_label ', BUT1, ' " "'], _),
gtk(Pin, Pout, [' gtk_button_set_label ', BUT2, ' " "'], _),
gtk(Pin, Pout, [' gtk_button_set_label ', BUT3, ' " "'], _),
gtk(Pin, Pout, [' gtk_button_set_label ', BUT4, ' " "'], _),
gtk(Pin, Pout, [' gtk_button_set_label ', BUT5, ' " "'], _),
gtk(Pin, Pout, [' gtk_button_set_label ', BUT6, ' " "'], _),
gtk(Pin, Pout, [' gtk_button_set_label ', BUT7, ' " "'], _),
gtk(Pin, Pout, [' gtk_button_set_label ', BUT8, ' " "'], _),
gtk(Pin, Pout, [' gtk_button_set_label ', BUT9, ' " "'], _),
gtk(Pin, Pout, [' gtk_statusbar_pop ', STATUS, ' ', CID], _),
gtk(Pin, Pout, [' gtk_statusbar_push ', STATUS, ' ', CID, ' "New game started..."'], _),
% Empty dynamic play board
retractall(x(_)), retractall(o(_)), callback(Pin, Pout).
%********************************* Extra support predicates
%
% Define the NOT predicate
%
not(X) :-
call(X), !, fail.
not(_).

%********************************* The intelligence starts here
%
% Define possible '3 in a rows'.
%
line(1,2,3).
line(4,5,6).
line(7,8,9).
line(1,4,7).
line(2,5,8).
line(3,6,9).
line(1,5,9).
line(3,5,7).
%
% Which move to play (we only need 1 solution, so use the cut '!').
%
move(A) :- good(A), empty(A), !.
%
% Define good move.
%
good(A) :- make_three(A).
good(A) :- block_enemy(A).
good(A) :- split_two(A).
good(A) :- make_two(A).
good(5).
good(1).
good(3).
good(7).
good(9).
good(2).
good(4).
good(6).
good(8).
%
% Check for two white stones in a row
%
make_three(A) :- o(B), o(C), line(A, B, C).
make_three(B) :- o(A), o(C), line(A, B, C).
make_three(C) :- o(A), o(B), line(A, B, C).
%
% Block two black stones
%
block_enemy(A) :- x(B), x(C), line(A, B, C).
block_enemy(B) :- x(A), x(C), line(A, B, C).
block_enemy(C) :- x(A), x(B), line(A, B, C).
%
% Split 2 fields
%
split_two(1) :- x(2), x(4).
split_two(3) :- x(2), x(6).
split_two(7) :- x(4), x(8).
split_two(9) :- x(6), x(8).
%
% Try to attack
%
make_two(A) :- o(B), line(A, B, C), empty(C).
make_two(C) :- o(B), line(A, B, C), empty(A).
make_two(A) :- empty(B), line(A, B, C), o(C).
make_two(C) :- empty(B), line(A, B, C), o(A).
%
% Check on empty place.
%
empty(X) :- not(x(X)), not(o(X)).

%********************************* End of game query's
% Find out if the game is finished
%
end_game(Pin, Pout):-
tictactoe(Pin, Pout).
end_game(Pin, Pout):-
filled_board(Pin, Pout).
%
% Is there a 'tictactoe'?
%
tictactoe(Pin, Pout):- 
x(A), x(B), x(C), line(A, B, C),
labels([_, _, _, _, _, _, _, _, _, STATUS, CID]),
gtk(Pin, Pout, [' gtk_statusbar_pop ', STATUS, ' ', CID], _),
gtk(Pin, Pout, [' gtk_statusbar_push ', STATUS, ' ', CID, ' "You have won!"'], _).
tictactoe(Pin, Pout):- 
o(A), o(B), o(C), line(A, B, C),
labels([_, _, _, _, _, _, _, _, _, STATUS, CID]),
gtk(Pin, Pout, [' gtk_statusbar_pop ', STATUS, ' ', CID], _),
gtk(Pin, Pout, [' gtk_statusbar_push ', STATUS, ' ', CID, ' "I have won!"'], _).
%
% The board is full?
%
filled_board(Pin, Pout):-
full(1), full(2), full(3), full(4), full(5), full(6), full(7), full(8), full(9),
labels([_, _, _, _, _, _, _, _, _, STATUS, CID]),
gtk(Pin, Pout, [' gtk_statusbar_pop ', STATUS, ' ', CID], _),
gtk(Pin, Pout, [' gtk_statusbar_push ', STATUS, ' ', CID, ' "Even game."'], _).

full(X) :- x(X).
full(X) :- o(X).

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值