15. 6. 1.    Миниатюрный интерпретатор языка   AL0

Реализация на Прологе миниатюрного, не зависящего от конкретной игры интерпретатора языка AL0 показана на Рисунок 15.6. Эта программа осуществляет также взаимодействие с пользователем во время игры. Центральная задача этой программы - использовать знания, записанные в таблице советов, то есть интерпретировать программу на языке советов AL0 с целью построения форсированных деревьев и их "исполнения" в процессе игры. Базовый алгоритм порождения форсированных деревьев аналогичен поиску с предпочтением в И / ИЛИ-графах гл. 13, при этом форсированное дерево соответствует решающему И / ИЛИ-дереву. Этот алгоритм также напоминает алгоритм построения решающего дерева ответа на вопрос пользователя, применявшийся в оболочке экспертной системы (гл. 14).

Программа на Рисунок 15.6 составлена в предположении, что она играет белыми, а ее противник - черными. Программа запускается процедурой

line(); % Миниатюрный интерпретатор языка AL0
%
% Эта программа играет, начиная с заданной позиции,
% используя знания, записанные на языке AL0

        :- ор( 200, xfy, :).
        :- ор( 220, xfy, ..).
        :- ор( 185, fx, если).
        :- ор( 190, xfx, то).
        :- ор( 180, xfy, или).
        :- ор( 160, xfy, и).
        :- ор( 140, fx, не).


        игра( Поз) :-                                                   % Играть, начиная с Поз
                игра( Поз, nil).
                                          % Начать с пустого форсированного дерева

        игра( Поз, ФорсДер) :-
                отобр( Поз),
                ( конец_игры( Поз),
                             % Конец игры?
                        write( 'Конец игры'),  nl,  !;
                  сделать_ход( Поз, ФорсДер, Поз1, ФорсДер1),  !,
                        игра( Поз1, ФорсДер1) ).


% Игрок ходит в соответствии с форсированным деревом

        сделать_ход( Поз, Ход .. ФДер1, Поз1, ФДер1) :-
                чей_ход( Поз, б),
                                  % Программа играет белыми
                разрход( Поз, Ход, Поз1),
                показать_ход( Ход).


% Прием хода противника

        сделать_ход( Поз, ФДер, Поз1, ФДер1) :-
                чей_ход( Поз, ч),
                write( 'Ваш ход:'),
                read( Ход),
                ( разрход( Поз, Ход, Поз1),
                        поддер( ФДер, Ход, ФДер1),  !;

                                          % Вниз по форс. дереву
                  write( 'Неразрешенный ход'), nl,
                        сделать_ход( Поз, ФДер, Поз1, ФДер1) ).


% Если текущее форсированное дерево пусто, построить новое

        сделать_ход( Поз, nil, Поз1, ФДер1) :-
                чей_ход( Поз, б),
                восст_глуб( Поз, Поз0),

                                        % Поз0 = Поз с глубиной 0
                стратегия( Поз0, ФДер),  !,
                                        % Новое форсированное дерево
                сделать_ход( Поз0, ФДер, Поз1, ФДер1).

% Выбрать форсированное поддерево, соответствующее Ход' у

        поддер( ФДеревья, Ход, Фдер) :-
                принадлежит( Ход . . Фдер, ФДеревья),  !.


        поддер( _, _, nil).

        стратегия( Поз, ФорсДер) :-
                                        % Найти форс. дерево для Поз
                Прав : если Условие то СписСов,
                                        % Обращение к таблице советов
                удовл( Условие, Поз, _ ),  !,
                                        % Сопоставить Поз с предварительным условием
                принадлежит( ИмяСовета, СписСов),
                                        % По очереди попробовать элем. советы
                nl, write( 'Пробую'), write( ИмяСовета),
                выполн_совет( ИмяСовета, Поз, ФорсДер),  !.


        выполн_совет( ИмяСовета, Поз, Фдер) :-
                совет( ИмяСовета, Совет),

                                        % Найти элементарный совет
                выполн( Совет, Поз, Поз, ФДер).
                % "выполн" требует две позиции для сравнивающих предикатов

        выполн( Совет, Поз, КорнПоз, ФДер) :-
                поддержка( Совет, ЦП),
                удовл( ЦП, Поз, КорнПоз),

                                        % Сопоставить Поз с целью-поддержкой
                выполн1( Совет, Поз, КорнПоз, ФДер).

        выполн1( Совет, Поз, КорнПоз, nil) :-
                главцель( Совет, ГлЦ),
                удовл( ГлЦ, Поз, КорнПоз),  !.

                                        % Главная цель удовлетворяется

        выполн1( Совет, Поз, КорнПоз, Ход .. ФДеревья) :-
                чей_ход( Поз, б),  !,
                                 % Программа играет белыми
                ходы_игрока( Совет, ХодыИгрока),
                                        % Ограничения на ходы игрока
                ход( ХодыИгрока, Поз, Ход, Поз1),
                                        % Ход, удовлетворяющий ограничению
                выполн( Совет, Поз1, КорнПоз, ФДеревья).

        выполн1( Совет, Поз, КорнПоз, ФДеревья) :-
                чей_ход( Поз, ч),  !,
                                % Противник играет черными
                ходы_противника( Совет, ХодыПр),
                bagof ( Ход . . Поз1, ход( ХодыПр, Поз, Ход, Поз1), ХПспис),
                выполн_все( Совет, ХПспис, КорнПоз, ФДеревья).

                                        % Совет выполним во всех преемниках Поз

        выполн_все( _, [ ], _, [ ]).

        выполн_все( Совет, [Ход . . Поз | ХПспис], КорнПоз,
                                                                [Ход . . ФД | ФДД] ) :-
                выполн( Совет, Поз, КорнПоз, ФД),
                выполн_все( Совет, ХПспис, КорнПоз, ФДД).


% Интерпретация главной цели и цели-поддержки:
% цель - это И / ИЛИ / НЕ комбинация. имен предикатов

        удовл( Цель1 и Цель2, Поз, КорнПоз) :-  !,
                удовл( Цель1, Поз, КорнПоз),
                удовл( Цель2, Поз, КорнПоз).


        удовл( Цель1 или Цель2, Поз, КорнПоз) :-  !,
                ( удовл( Цель1, Поз, КорнПоз);
                удовл( Цель2, Поз, КорнПоз) ).


        удовл( не Цель, Поз, КорнПоз) :-  !,
                not удовл( Цель, Поз, КорнПоз ).


        удовл( Пред, Поз, КорнПоз) :-
                ( Усл =.. [Пред, Поз];

                                            % Большинство предикатов не зависит от КорнПоз
                    Усл =.. [Пред, Поз, КорнПоз] ),
                call( Усл).


% Интерпретация ограничений на ходы

        ход( Ходы1 и Ходы2, Поз, Ход, Поз1) :-  !,
                ход( Ходы1, Поз, Ход, Поз1),
                ход( Ходы2, Поз, Ход, Поз1).


        ход( Ходы1 затем Ходы2, Поз, Ход, Поз1) :-  !,
                ( ход( Ходы1, Поз, Ход, Поз1);
                  ход( Ходы2, Поз, Ход, Поз1) ).


% Доступ к компонентам элементарного совета

        главцель( ГлЦ : _, ГлЦ).

        поддержка( ГлЦ : ЦП : _, ЦП).

        ходы_игрока( ГлЦ : ЦП : ХодыИгрока : _, Ходы Игрока).

        ходы_противника( ГлЦ : ЦП: ХодыИгр : ХодыПр :_,
                                          ХодыПр).


        принадлежит( X, [X | Спис]).

        принадлежит( X, [Y | Спис]) :-
                принадлежит( X, Спис).


line();