Учебный Проект. Релиз 2: различия между версиями

Материал из wikiru.visual-prolog.com

м
м
 
(не показаны 2 промежуточные версии этого же участника)
Строка 1: Строка 1:
{{copyright}}
{{PolylineTemplateRu
 
|goal=
Очередная версия Учебного проекта, функциональной идеей которого является простая игра.
Демонстрация свойств языка Visual Prolog и простейших приемов программирования, в том числе:
 
|goalContent=
[[Игра "Ползунок". Правила игры|Правила игры ...]]
*генерация случайных чисел;
 
*интерфейс класса;
==Цель==
*использование одного и того же интерфейса в разных классах;
Демонстрация простейших приемов программирования на языке Visual Prolog, в том числе:
*использование фактов-переменных;
*генерация случайных чисел.
*генерация простейших исключений;
*использование одного и того же интерфейса в разных классах
*простейшая обработка исключений;
*использование фактов-переменных
*использование констант.
*генерация простейших исключений
|code=
*простейшая обработка исключений
*использование констант
 
==Особенности Release 2==  
*Стратегия поведения компьютера из [[Учебный Проект. Релиз 1]], отличается здесь тем, что:
*Стратегия поведения компьютера из [[Учебный Проект. Релиз 1]], отличается здесь тем, что:
**Если первым ходит компьютер то он выбирает ход случайным образом
** Модели поведения компьютера и человека построены как динамические классы;
**Если нет хода, ведущего к выигрышу, то он выбирается случайно
** Предикаты, явно относящиеся к пользовательскому интерфейсу, выделены в отдельный класс;
* Модели поведения компьютера и человека построены как динамические классы
*В данной версии использован размер поля 6х6 точек;
* Предикаты, явно относящиеся к пользовательскому интерфейсу, выделены в отдельный класс
*В данной версии использован размер поля 6х6 точек.
*В силу неэффективного алгоритма игры компьютера размер поля более 36 клеток (6x6, например) устанавливать не рекомендуется.
*В силу неэффективного алгоритма игры компьютера размер поля более 36 клеток (6x6, например) устанавливать не рекомендуется.
|functionality=
*Если первым ходит компьютер то он выбирает ход случайным образом;
*Если у модели компьютера нет хода, ведущего к выигрышу, то он выбирается случайно.
|install={{PolylineInstall}}


==Установка==
|open=
*Создать проект с пользовательским интерфейсом типа console
{{Polyline1_10Open|project='''Examples\Polyline\Polyline2\Polyline2.prj'''}}
*В построенном проекте заменить полностью код файла "main.pro" кодом, предложенным ниже (для версий 7.2 и 7.1 следует взять соответствующий код ниже)
 
*При построении проекта ответить на предложение о включении дополнительных пакетов в проект "Add All".  
{{Polyline1-06Copy_Paste}}
|run=Запуск приложения из среды по '''E''' или запустить исполняемое приложение из директории EXE.
<vip>
<vip>
/*********************************************************
/*********************************************************
VIP 7.2 Compatable
Copyright (c) Victor Yukhtenko
Copyright (c) 2007-2008 Prolog Development Center SPb


SpbSolutions/Examples/Polyline
SpbSolutions/Examples/Polyline
Строка 40: Строка 38:
   rule_nd,
   rule_nd,
based on solutions proposed by Elena Efimova
based on solutions proposed by Elena Efimova
Written by: Victor Yukhtenko                       
*********************************************************/
*********************************************************/
goal
goal
Строка 511: Строка 507:
end implement humanInterface
end implement humanInterface
</vip>
</vip>
 
|enver=
<vip>
/*****************************************************************************
Совместимо с VIP 7.1
Written by: Victor Yukhtenko
 
Предикаты определения стратегии
  resolveMove,
  moveCandidate,
  successfulMove,
  rule_nd,
основаны на решениях, предложенных Еленой Ефимовой
******************************************************************************/
goal
    mainExe::run(main::run).
 
implement main
open core
 
constants
    className = "Ползунок".
    classVersion = "1.0".
 
clauses
    classInfo(className, classVersion).
 
clauses
    run():-
        console::init(), 
        game::run().
end implement main
/***********************************
Класс Game управляет ходом игры
***********************************/
class game
    open core
 
constants
    maxRow_C:positive=6.
    maxColumn_C:positive=6.
 
domains
    cell = c(positive,positive).
    moveType_D=
        ordinary_S;
        winner_S.
 
properties
    polyline_P:cell*.
 
predicates
    run:().
    set:(string CellAsString).
    rule_nd: (cell,cell) nondeterm (i,o) (i,i).
    ruleLimited_nd:(cell,cell)->cell nondeterm.
 
end class game
 
implement game
open core
 
constants
    className = "Game".
    classVersion = "1.0".
 
clauses
    classInfo(className, classVersion).
 
class facts
    human_V:player:=erroneous.
    computer_V:player:=erroneous.
    polyline_P:cell*:=[].
    endOfGame_V:boolean:=false.
   
clauses
    run():-
        human_V:=human::new(),
        computer_V:=computer::new(),
        playerTurn().
 
class predicates
    playerTurn:().
clauses
    playerTurn():-
        PlayerTurnStr=humanInterface::getInput(humanInterface::playerTurn_S),
        not(PlayerTurnStr=""),
        try
            hasDomain(positive,PlayerTurn),
            PlayerTurn=toTerm(PlayerTurnStr),
            if PlayerTurn=2 then
                Player=human_V,
                StarterName="Computer" % because of it is used NextPlayer in the Play predicate
            else
                Player=computer_V,
                StarterName="Human"
            end if,
            humanInterface::showStage(),
            !,
            humanInterface::announceStarter(StarterName),
            play(Player)
        catch _TraceID1 do
            humanInterface::announceChoiceError(humanInterface::errorMustBeNumber_S)
        end try,
            !,
            polyline_P:=[],
            endOfGame_V:=false,
            playerTurn().
    playerTurn().
 
class predicates
    play:(player Player).
clauses
    play(Player):-
        endOfGame_V=true,
        !,
        if Player=human_V then
            humanInterface::announceWin("Human")
        else
            humanInterface::announceWin("Computer")
        end if.
    play(Player):-
        if Player=human_V then
            NextPlayer=computer_V,
            Name="Computer"
        else
            NextPlayer=human_V,
            Name="Человек"
        end if,
        !,
        humanInterface::announceMovingPlayer(Name),
        NextPlayer:move(),
        play(NextPlayer).
 
clauses
    set(InputString):-
        Cell=toTerm(InputString),
        handleInput (Cell).
 
class predicates
    handleInput:(cell Cell).
clauses
    handleInput(Cell):-
        list::isMember(Cell,polyline_P),
        try
            _=makePolyLine(Cell,polyline_P) % Если Cell не может быть принят как допустимый
                                            % ход, то возникает exception, которое
                                            % игнорируется использованием fail
        catch _TraceID do
            fail
        end try,
        !,
        endOfGame_V:=true,
        humanInterface::showMove(Cell,winner_S).
    handleInput (Cell):-
        polyline_P:=makePolyLine(Cell,polyline_P),
        !,
        humanInterface::showMove(Cell,ordinary_S).
 
class predicates
    makePolyLine: (cell,cell*)-> cell* multi.
clauses
    makePolyLine(c(X,Y),[])=[c(X,Y)]:-
        X>0,X<=maxColumn_C,
        Y>0,Y<=maxRow_C,
        !.
    makePolyLine(NewCell,[SingleCell])=[NewCell,SingleCell]:-
        game::rule_nd(SingleCell, NewCell),
        !.
    makePolyLine(NewCell,[Left, RestrictingCell | PolyLineTail])=[NewCell, Left, RestrictingCell | PolyLineTail]:-
        NewCell=ruleLimited_nd(Left,RestrictingCell).
    makePolyLine(NewCell,PolyLine)=list::reverse([NewCell,Left, RestrictingCell | PolyLineTail]):-
        [Left, RestrictingCell | PolyLineTail]= list::reverse(PolyLine),
        NewCell=ruleLimited_nd(Left,RestrictingCell).
    makePolyLine(NewCell,_PolyLine)= _PolyLine1:-
        exception::raise(classInfo,wrongMoveException,[namedValue("data",string(toString(NewCell)))]).
 
class predicates
    wrongMoveException:exception.
clauses
    wrongMoveException
        (
        classInfo,
        predicate_Name(),
        "Точка % не может быть продолжением маршрута!"
        ).
 
clauses
    ruleLimited_nd(Cell,RestrictingCell)=NewCell:-
        rule_nd(Cell,NewCell),
            not(NewCell = RestrictingCell).
 
clauses
    rule_nd(c(X, Y), c(X + 1, Y)):- X < maxColumn_C.       
    rule_nd(c(X, Y), c(X, Y + 1)):- Y < maxrow_C.           
    rule_nd(c(X, Y), c(X - 1, Y)):- X > 1.
    rule_nd(c(X, Y), c(X, Y - 1)):- Y > 1.   
 
end implement game
 
/******************************************
  Interface Игрок
  Игрок в ответ на предложение move()
  должен ответить классу game вызовом
  предиката set(Ответный Ход)
******************************************/
interface player
 
predicates
    move:().
end interface player
 
/********************************
  Класс Человек (Human)
********************************/
class human:player
open core
 
end class human
 
implement human
open core, exception
 
clauses
    move():-
        InputString=humanInterface::getInput(humanInterface::playerMove_S),
        try
            game::set(InputString)
        catch TraceID do
            handleException(TraceID),
            fail
        end try,
        !.
    move():-
        move().
           
class predicates
    handleException:(exception::traceId TraceID).
clauses
    handleException(TraceID):-
        foreach Descriptor=exception::getDescriptor_nd(TraceID) do
            Descriptor = exception::descriptor(
                _ClassInfo1,
                exception::exceptionDescriptor(_ClassInfo2,_PredicateName,Description),
                _Kind,
                ExtraInfo,
                _GMTTime,
                _ExceptionDescription,
                _ThreadId),
            if
                ExtraInfo=[namedValue("data",string(CellPointer))]
            then
                ErrorMsg=string::format(Description,CellPointer),
                humanInterface::announceError(ErrorMsg)
            else
                humanInterface::announceError("")
            end if
        end foreach.
 
end implement human
 
/******************************************
  Класс Сomputer
******************************************/
class computer:player
open core
end class computer
 
implement computer
open core
 
constants
    className = "Ползунок".
    classVersion = "1.0".
clauses
    classInfo(className, classVersion).
 
clauses
    move():-
        Cell=resolveMove(),
        game::set(toString(Cell)).
 
predicates
    resolveMove:()->game::cell.
clauses
    resolveMove()=Cell:-
        Cell=successfulMove(game::polyline_P),
        !.
    resolveMove()=Cell:-
        moveCandidate(game::polyline_P,_PolyLine,Cell),
        !.
    resolveMove()=game::c(X+1,Y+1):-
        X=math::random(game::maxColumn_C-1),
        Y=math::random(game::maxRow_C-1).
 
class predicates
    successfulMove: (game::cell*)->game::cell nondeterm.
clauses
    successfulMove(PolyLine)=Cell:-
        moveCandidate(PolyLine,_PolyLine1,Cell),
            list::isMember(Cell, PolyLine),
            !.
    successfulMove(PolyLine)=Cell:-
        moveCandidate(PolyLine, PolyLine1, Cell),
            not(_=successfulMove(PolyLine1)).
 
class predicates
    moveCandidate: (game::cell*,game::cell* [out],game::cell [out]) nondeterm.
clauses
    moveCandidate([Cell],[Cell,NewCell], NewCell):-
        game::rule_nd(Cell, NewCell),
        !.
    moveCandidate([Left, RestrictingCell | PolyLine],[NewCell,Left, RestrictingCell| PolyLine], NewCell):-
        NewCell=game::ruleLimited_nd(Left,RestrictingCell).
    moveCandidate(PolyLine,list::reverse([NewCell,Left, RestrictingCell |PolyLineTail]),NewCell):-
        [Left, RestrictingCell |PolyLineTail] = list::reverse(PolyLine),
        NewCell=game::ruleLimited_nd(Left,RestrictingCell).
 
end implement computer
 
/******************************************
  Класс HumanInterface обеспечивает контакт
  человека с компьютером
******************************************/
class humanInterface
open core
 
predicates
    showStage:().
    showMove:(game::cell,game::moveType_D).
    getInput:(inputType_D)->string InputString.
 
domains
    inputType_D=
        playerMove_S;
        playerTurn_S.
 
predicates
    announceStarter:(string Name).
    announceMovingPlayer:(string Name).
    announceWin:(string Name).
    announceError:(string Description).
    announceError:().
 
domains
    choiceError_D=
        errorMustBeNumber_S;
        errorPlayerTurn_S.
predicates
    announceChoiceError:(choiceError_D).
 
end class humanInterface
 
implement humanInterface
open core
 
constants
    cellMarkedOrdinary_C="*".
    cellMarkedWinner_C="O".
 
constants % messages
    movingPlayer_C="% думает".
    beginner_C="Первый ход: %".
    error_C="Ошибка, % ".
    congratulation_C="Игрок % выиграл!".
 
    playerMove_C="Введите координаты клетки как c(X,Y): ".
    playerTurn_C="\nКто первый ходит (1-человек, 2-компьютер, Enter-выход)?:".
 
    errorMustBeNumber_C="\nДолжен быть номер! Повторите ввод:".
    errorPlayerTurn_C="\nТакого игрока нет! Повторите ввод:".
 
constants
    verticalSpace_C=2.
    horizontalSpace_C=3.
    emptyLineLenght_C=80.
 
constants % Position of Line
    starterLine_C=1.
    announceLine_C=starterLine_C+1.
    actionLine_C=announceLine_C+1.
    polylineLine_C=actionLine_C+1.
 
clauses
    getInput(InputType)=Input:-
        inputInvitation(InputType),
        Input = console::readLine(),
        console::clearInput().
 
class predicates
    inputInvitation:(inputType_D).
clauses
    inputInvitation(playermove_S):-
        clearMessageArea(actionLine_C),
        writeMessage(actionLine_C,"%",playermove_C).
    inputInvitation(playerTurn_S):-
        console::clearOutput(),
        console::write(playerTurn_C).
 
clauses
    showStage():-
        console::clearOutput(),
        foreach I = std::fromTo(1, game::maxColumn_C) do
            console::setLocation(console::location(horizontalSpace_C*I, 0)),
            console::write(I)
        end foreach,
        foreach J = std::fromTo(1, game::maxRow_C) do   
            console::setLocation(console::location(0, verticalSpace_C*J)),
            console::write(J)
        end foreach.
 
clauses
    showMove(game::c(X,Y),_Type):-
        console::setLocation(console::location(horizontalSpace_C*X, verticalSpace_C*Y)),
        fail.
    showMove(_Cell,game::ordinary_S):-
        console::write(cellMarkedOrdinary_C).
    showMove(_Cell,game::winner_S):-
        console::write(cellMarkedWinner_C).
 
clauses
    announceStarter(Name):-
        clearMessageArea(starterLine_C),
        writeMessage(starterLine_C,beginner_C,Name).
 
clauses
    announceChoiceError(errorMustBeNumber_S):-
        console::write(errorMustBeNumber_C),
        _ = console::readLine().
    announceChoiceError(errorPlayerTurn_S):-
        console::write(errorPlayerTurn_C),
        _ = console::readLine().
 
clauses
    announceError():-
        announceError("").
 
    announceError(ErrorText):-
        clearMessageArea(announceLine_C),
        writeMessage(announceLine_C,error_C,ErrorText).
       
clauses
    announceWin(Name):-
        clearMessageArea(announceLine_C),
        writeMessage(announceLine_C,congratulation_C,Name),
        showPolyLine(),
        _ = console::readLine().
 
clauses
    announceMovingPlayer(Name):-
        clearMessageArea(announceLine_C),
        clearMessageArea(actionLine_C),
        writeMessage(actionLine_C,movingPlayer_C,Name).
 
class predicates
    showPolyLine:().
clauses
    showPolyLine():-
        clearMessageArea(actionLine_C),
        writeMessage(polylineLine_C,"%",toString(game::polyline_P)).
 
class predicates
    clearMessageArea:(positive AreaID).
clauses
    clearMessageArea(AreaID):-
        console::setLocation(console::location(0,game::maxRow_C*verticalSpace_C+AreaID)),
        console::write(string::create(emptyLineLenght_C," ")).
 
class predicates
    writeMessage:(positive AreaID,string FormatString,string ParameterString).
clauses
    writeMessage(AreaID,FormatString,ParameterString):-
        console::setLocation(console::location(0, game::maxRow_C*verticalSpace_C+AreaID)),
        console::writef(FormatString,ParameterString).
 
end implement humanInterface
</vip>
==Ссылки==
[[en:Game Polyline. release 2]]
[[en:Game Polyline. release 2]]
[[Category:Проекты]]
}}
[[Category:Игры]]

Текущая версия на 14:19, 31 марта 2011

Автор: Виктор Юхтенко. Email victor@pdc.spb.su

Очередная версия Учебного проекта, функциональной идеей которого является простая игра.

Правила игры ...

Цель

Демонстрация свойств языка Visual Prolog и простейших приемов программирования, в том числе:

  • генерация случайных чисел;
  • интерфейс класса;
  • использование одного и того же интерфейса в разных классах;
  • использование фактов-переменных;
  • генерация простейших исключений;
  • простейшая обработка исключений;
  • использование констант.

Функции

  • Если первым ходит компьютер то он выбирает ход случайным образом;
  • Если у модели компьютера нет хода, ведущего к выигрышу, то он выбирается случайно.

Код

  • Проверено на версии Visual Prolog 7.3 build 7302.
  • Стратегия поведения компьютера из Учебный Проект. Релиз 1, отличается здесь тем, что:
    • Модели поведения компьютера и человека построены как динамические классы;
    • Предикаты, явно относящиеся к пользовательскому интерфейсу, выделены в отдельный класс;
  • В данной версии использован размер поля 6х6 точек;
  • В силу неэффективного алгоритма игры компьютера размер поля более 36 клеток (6x6, например) устанавливать не рекомендуется.

Установка

Если Вам нужен полный набор проектов серии Polyline (персональная версия), сгрузите и разархивируйте файлы архивов, пользуясь ссылками на форуме PDC ЗДЕСЬ

  • VipSpbSDK_PE_73_Examples_Polyline_1_14.zip
  • VipSpbSDK_PE_73_Tools_Polyline_1_14.zip]

в удобную для Вас директорию.

Коммерческая версия представлена в виде одного архива и может быть получена Здесь.

Оплата в любой из указанных валют. При оплате с рублевой кредитной карты валюта оплаты конвертируется в рубли по курсу банка-эмитента карты.

Директория с именем VipSpbSDK будет создана автоматически.

Если у Вас установлен VipSpbSDK, то следует открыть проект Examples\Polyline\Polyline2\Polyline2.prj

Если у Вас нет полного набора примеров из VipSpbSDK, то для помещения игры в проект необходимо:

  • Создать проект с пользовательским интерфейсом типа console
  • Построить проект
  • В построенном проекте заменить полностью код файла "main.pro" кодом, предложенным ниже.
  • Запустить вновь построение проекта. При построении проекта ответить на предложение о включении дополнительных пакетов в проект "Add All".

Запуск

Запуск приложения из среды по E или запустить исполняемое приложение из директории EXE.

/*********************************************************
Copyright (c) Victor Yukhtenko
 
SpbSolutions/Examples/Polyline
 
Predicates, which represent the strategy
  resolveMove,
  moveCandidate,
  successfulMove,
  rule_nd,
based on solutions proposed by Elena Efimova
*********************************************************/
goal
    mainExe::run(main::run).
 
implement main
open core
 
constants
    className = "PolyLine".
    classVersion = "1.0".
 
clauses
    classInfo(className, classVersion).
 
clauses
    run():-
        console::init(),
        game::run().
end implement main
 
/**************************************
The Game class manages the playing process
**************************************/
class game
    open core
 
predicates
    classInfo : core::classInfo.
 
constants
    maxRow_C:positive=6.
    maxColumn_C:positive=6.
 
domains
    cell = c(positive,positive).
    moveType_D=
        ordinary_S;
        winner_S.
 
properties
    polyline_P:cell*.
 
predicates
    run:().
    set:(string CellAsString).
    rule_nd: (cell,cell) nondeterm (i,o) (i,i).
    ruleLimited_nd:(cell,cell)->cell nondeterm.
 
end class game
 
implement game
open core
 
constants
    className = "Game".
    classVersion = "1.0".
 
clauses
    classInfo(className, classVersion).
 
class facts
    human_V:player:=erroneous.
    computer_V:player:=erroneous.
    polyline_P:cell*:=[].
    endOfGame_V:boolean:=false.
 
clauses
    run():-
        human_V:=human::new(),
        computer_V:=computer::new(),
        playerTurn().
 
class predicates
    playerTurn:().
clauses
    playerTurn():-
        PlayerTurnStr=humanInterface::getInput(humanInterface::playerTurn_S),
        not(PlayerTurnStr=""),
        try
            hasDomain(positive,PlayerTurn),
            PlayerTurn=toTerm(PlayerTurnStr),
            if PlayerTurn=2 then
                Player=human_V,
                StarterName="Computer" % because of it is used NextPlayer in the Play predicate
            else
                Player=computer_V,
                StarterName="Human"
            end if,
            humanInterface::showStage(),
            !,
            humanInterface::announceStarter(StarterName),
            play(Player)
        catch _TraceID1 do
            humanInterface::announceChoiceError(humanInterface::errorMustBeNumber_S)
        end try,
            !,
            polyline_P:=[],
            endOfGame_V:=false,
            playerTurn().
    playerTurn().
 
class predicates
    play:(player Player).
clauses
    play(Player):-
        endOfGame_V=true,
        !,
        if Player=human_V then
            humanInterface::announceWin("Human")
        else
            humanInterface::announceWin("Computer")
        end if.
    play(Player):-
        if Player=human_V then
            NextPlayer=computer_V,
            Name="Computer"
        else
            NextPlayer=human_V,
            Name="Human"
        end if,
        !,
        humanInterface::announceMovingPlayer(Name),
        NextPlayer:move(),
        play(NextPlayer).
 
clauses
    set(InputString):-
        Cell=toTerm(InputString),
        handleInput (Cell).
 
class predicates
    handleInput:(cell Cell).
clauses
    handleInput(Cell):-
        list::isMember(Cell,polyline_P),
        try
            _=makePolyLine(Cell,polyline_P)   % If the Cell is not acceptable,
                                                            % then exception appears and we ignore it
                                                            % using fail
        catch _TraceID do
            fail
        end try,
        !,
        endOfGame_V:=true,
        humanInterface::showMove(Cell,winner_S).
    handleInput (Cell):-
        polyline_P:=makePolyLine(Cell,polyline_P),
        !,
        humanInterface::showMove(Cell,ordinary_S).
 
class predicates
    makePolyLine: (cell,cell*)-> cell* multi.
clauses
    makePolyLine(c(X,Y),[])=[c(X,Y)]:-
        X>0,X<=maxColumn_C,
        Y>0,Y<=maxRow_C,
        !.
    makePolyLine(NewCell,[SingleCell])=[NewCell,SingleCell]:-
        game::rule_nd(SingleCell, NewCell),
        !.
    makePolyLine(NewCell,[Left, RestrictingCell | PolyLineTail])=[NewCell, Left, RestrictingCell | PolyLineTail]:-
        NewCell=ruleLimited_nd(Left,RestrictingCell).
    makePolyLine(NewCell,PolyLine)=list::reverse([NewCell,Left, RestrictingCell | PolyLineTail]):-
        [Left, RestrictingCell | PolyLineTail]= list::reverse(PolyLine),
        NewCell=ruleLimited_nd(Left,RestrictingCell).
    makePolyLine(NewCell,_PolyLine)= _PolyLine1:-
        exception::raise(classInfo,wrongMoveException,[namedValue("data",string(toString(NewCell)))]).
 
class predicates
    wrongMoveException:exception.
clauses
    wrongMoveException
        (
        classInfo,
        predicate_Name(),
        "The point % can not prolong the polyline!"
        ).
 
clauses
    ruleLimited_nd(Cell,RestrictingCell)=NewCell:-
        rule_nd(Cell,NewCell),
            not(NewCell = RestrictingCell).
 
clauses
    rule_nd(c(X, Y), c(X + 1, Y)):- X < maxColumn_C.
    rule_nd(c(X, Y), c(X, Y + 1)):- Y < maxrow_C.
    rule_nd(c(X, Y), c(X - 1, Y)):- X > 1.
    rule_nd(c(X, Y), c(X, Y - 1)):- Y > 1.
 
end implement game
 
/******************************************
  Interface Player
  Player in responce to predicate call move()
  must  reply by calling set(ResponceMove)
******************************************/
interface player
 
predicates
    move:().
end interface player
 
/********************************
  The Class Human
********************************/
class human:player
open core
 
end class human
 
implement human
open core, exception
 
clauses
    move():-
        InputString=humanInterface::getInput(humanInterface::playerMove_S),
        try
            game::set(InputString)
        catch TraceID do
            handleException(TraceID),
            fail
        end try,
        !.
    move():-
        move().
 
class predicates
    handleException:(exception::traceId TraceID).
clauses
    handleException(TraceID):-
        foreach Descriptor=exception::getDescriptor_nd(TraceID) do
            Descriptor = exception::descriptor(
                _ClassInfo1,
                exception::exceptionDescriptor(_ClassInfo2,_PredicateName,Description),
                _Kind,
                ExtraInfo,
                _GMTTime,
                _ExceptionDescription,
                _ThreadId),
            if
                ExtraInfo=[namedValue("data",string(CellPointer))]
            then
                ErrorMsg=string::format(Description,CellPointer),
                humanInterface::announceError(ErrorMsg)
            else
                humanInterface::announceError("")
            end if
        end foreach.
 
end implement human
 
/******************************************
  Class Сomputer
******************************************/
class computer:player
predicates
    classInfo : core::classInfo.
end class computer
 
implement computer
open core
 
constants
    className = "Computer".
    classVersion = "1.0".
 
clauses
    classInfo(className, classVersion).
 
clauses
    move():-
        Cell=resolveMove(),
        game::set(toString(Cell)).
 
predicates
    resolveMove:()->game::cell.
clauses
    resolveMove()=Cell:-
        Cell=successfulMove(game::polyline_P),
        !.
    resolveMove()=Cell:-
        moveCandidate(game::polyline_P,_PolyLine,Cell),
        !.
    resolveMove()=game::c(X+1,Y+1):-
        X=math::random(game::maxColumn_C-1),
        Y=math::random(game::maxRow_C-1).
 
class predicates
    successfulMove: (game::cell*)->game::cell nondeterm.
clauses
    successfulMove(PolyLine)=Cell:-
        moveCandidate(PolyLine,_PolyLine1,Cell),
            list::isMember(Cell, PolyLine),
            !.
    successfulMove(PolyLine)=Cell:-
        moveCandidate(PolyLine, PolyLine1, Cell),
            not(_=successfulMove(PolyLine1)).
 
class predicates
    moveCandidate: (game::cell*,game::cell* [out],game::cell [out]) nondeterm.
clauses
    moveCandidate([Cell],[Cell,NewCell], NewCell):-
        game::rule_nd(Cell, NewCell),
        !.
    moveCandidate([Left, RestrictingCell | PolyLine],[NewCell,Left, RestrictingCell| PolyLine], NewCell):-
        NewCell=game::ruleLimited_nd(Left,RestrictingCell).
    moveCandidate(PolyLine,list::reverse([NewCell,Left, RestrictingCell |PolyLineTail]),NewCell):-
        [Left, RestrictingCell |PolyLineTail] = list::reverse(PolyLine),
        NewCell=game::ruleLimited_nd(Left,RestrictingCell).
 
end implement computer
 
/******************************************
  Class HumanInterface supports the communication
  of the human with the computer
******************************************/
class humanInterface
open core
 
predicates
    showStage:().
    showMove:(game::cell,game::moveType_D).
    getInput:(inputType_D)->string InputString.
 
domains
    inputType_D=
        playerMove_S;
        playerTurn_S.
 
predicates
    announceStarter:(string Name).
    announceMovingPlayer:(string Name).
    announceWin:(string Name).
    announceError:(string Description).
    announceError:().
 
domains
    choiceError_D=
        errorMustBeNumber_S;
        errorPlayerTurn_S.
predicates
    announceChoiceError:(choiceError_D).
 
end class humanInterface
 
implement humanInterface
open core
 
constants
    cellMarkedOrdinary_C="*".
    cellMarkedWinner_C="O".
 
constants % messages
    movingPlayer_C="% is thinking".
    beginner_C="First move done by: %".
    error_C="Error, % ".
    congratulation_C="Player % has won!".
 
    playerMove_C="Enter the move as  c(X,Y): ".
    playerTurn_C="\nWho is moving first (1-human, 2-computer, Enter-exit)?:".
 
    errorMustBeNumber_C="\nIt must be numeric! Please repeat the input:".
    errorPlayerTurn_C="\nNo player with this ID! Please repeat the input:".
 
constants
    verticalSpace_C=2.
    horizontalSpace_C=3.
    emptyLineLenght_C=80.
 
constants % Position of Line
    starterLine_C=1.
    announceLine_C=starterLine_C+1.
    actionLine_C=announceLine_C+1.
    polylineLine_C=actionLine_C+1.
 
clauses
    getInput(InputType)=Input:-
        inputInvitation(InputType),
        Input = console::readLine(),
        console::clearInput().
 
class predicates
    inputInvitation:(inputType_D).
clauses
    inputInvitation(playermove_S):-
        clearMessageArea(actionLine_C),
        writeMessage(actionLine_C,"%",playermove_C).
    inputInvitation(playerTurn_S):-
        console::clearOutput(),
        console::write(playerTurn_C).
 
clauses
    showStage():-
        console::clearOutput(),
        foreach I = std::fromTo(1, game::maxColumn_C) do
            console::setLocation(console_native::coord(horizontalSpace_C*I, 0)),
            console::write(I)
        end foreach,
        foreach J = std::fromTo(1, game::maxRow_C) do
            console::setLocation(console_native::coord(0, verticalSpace_C*J)),
            console::write(J)
        end foreach.
 
clauses
    showMove(game::c(X,Y),_Type):-
        console::setLocation(console_native::coord(horizontalSpace_C*X, verticalSpace_C*Y)),
        fail.
    showMove(_Cell,game::ordinary_S):-
        console::write(cellMarkedOrdinary_C).
    showMove(_Cell,game::winner_S):-
        console::write(cellMarkedWinner_C).
 
clauses
    announceStarter(Name):-
        clearMessageArea(starterLine_C),
        writeMessage(starterLine_C,beginner_C,Name).
 
clauses
    announceChoiceError(errorMustBeNumber_S):-
        console::write(errorMustBeNumber_C),
        _ = console::readLine().
    announceChoiceError(errorPlayerTurn_S):-
        console::write(errorPlayerTurn_C),
        _ = console::readLine().
 
clauses
    announceError():-
        announceError("").
 
    announceError(ErrorText):-
        clearMessageArea(announceLine_C),
        writeMessage(announceLine_C,error_C,ErrorText).
 
clauses
    announceWin(Name):-
        clearMessageArea(announceLine_C),
        writeMessage(announceLine_C,congratulation_C,Name),
        showPolyLine(),
        _ = console::readLine().
 
clauses
    announceMovingPlayer(Name):-
        clearMessageArea(announceLine_C),
        clearMessageArea(actionLine_C),
        writeMessage(actionLine_C,movingPlayer_C,Name).
 
class predicates
    showPolyLine:().
clauses
    showPolyLine():-
        clearMessageArea(actionLine_C),
        writeMessage(polylineLine_C,"%",toString(game::polyline_P)).
 
class predicates
    clearMessageArea:(positive AreaID).
clauses
    clearMessageArea(AreaID):-
        console::setLocation(console_native::coord(0,game::maxRow_C*verticalSpace_C+AreaID)),
        console::write(string::create(emptyLineLenght_C," ")).
 
class predicates
    writeMessage:(positive AreaID,string FormatString,string ParameterString).
clauses
    writeMessage(AreaID,FormatString,ParameterString):-
        console::setLocation(console_native::coord(0, game::maxRow_C*verticalSpace_C+AreaID)),
        console::writef(FormatString,ParameterString).
 
end implement humanInterface