Учебный Проект. Релиз 2: различия между версиями
Материал из wikiru.visual-prolog.com
м (Новая: Очередная версия Учебного проекта, функциональной идеей которого является простая игра. [[Игра "Полз...) |
(нет различий)
|
Версия 20:04, 1 октября 2009
Очередная версия Учебного проекта, функциональной идеей которого является простая игра.
Цель
Демонстрация простейших приемов программирования на языке Visual Prolog, в том числе:
- генерация случайных чисел.
- использование одного и того же интерфейса в разных классах
- использование фактов-переменных
- генерация простейших исключений
- простейшая обработка исключений
- использование констант
Особенности Release 2
- Стратегия поведения компьютера из Учебный Проект. Релиз 1, отличается здесь тем, что:
- Если первым ходит компьютер то он выбирает ход случайным образом
- Если нет хода, ведущего к выигрышу, то он выбирается случайно
- Модели поведения компьютера и человека построены как динамические классы
- Предикаты, явно относящиеся к пользовательскому интерфейсу, выделены в отдельный класс
- В данной версии использован размер поля 6х6 точек.
- В силу неэффективного алгоритма игры компьютера размер поля более 36 клеток (6x6, например) устанавливать не рекомендуется.
Установка
- Создать проект с пользовательским интерфейсом типа console
- В построенном проекте заменить полностью код файла "main.pro" кодом, предложенным ниже (для версий 7.2 и 7.1 следует взять соответствующий код ниже)
- При построении проекта ответить на предложение о включении дополнительных пакетов в проект "Add All".
/********************************************************* VIP 7.2 Compatable Copyright (c) 2007-2008 Prolog Development Center SPb SpbSolutions/Examples/Polyline Predicates, which represent the strategy resolveMove, moveCandidate, successfulMove, rule_nd, based on solutions proposed by Elena Efimova Written by: Victor Yukhtenko *********************************************************/ 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
/***************************************************************************** Совместимо с 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