Организация диалога. Объект Assistant
Как Рокки ведет диалог?
Я уже сказал, что никаких серьезных трудностей не возникло при введении Помощника для организации диалога. Достаточно просто, заменить сообщение, выдаваемое функцией MsgBox на сообщение, выдаваемое Помощником, используя его баллончики. Но здесь есть одно "но"! При работе с Помощником появляется больше возможностей и, поневоле, хочется организовать более живой и интересный диалог - использовать картинки, дать пользователю возможность выбора, проявить интеллект и предлагать подсказки в возникающих ситуациях.
О том, как в сообщения, появляющиеся в баллончиках, включать рисунки, было уже рассказано в этой лекции. Было также достаточно подробно рассказано и о том, как дать возможность пользователю выбирать и как затем анализировать его выбор. Поэтому давайте поговорим об "интеллекте" Помощника. Это трудная задача. Но в нашем простом примере она решаема. Давайте возложим на Помощника обязанность не только следить за соблюдением правил игры и выдавать сообщения при их нарушениях, но и пусть он дает советы, подсказывая, какой ход следует сделать в той или иной ситуации.
Общий подход решения последней задачи понятен, - необходимо следить за состоянием системы, в нашем случае игры. Когда пользователь обращается к Помощнику за советом, то, зная текущее состояние S, можно попытаться найти разумное решение R. Иногда, как в нашей простой игре, существует точное решение и, зная S, можно однозначно определить R, как функцию от S. В тех случаях, когда для поиска решения необходим перебор вариантов, проведение сложных вычислений или просто квалификация пользователя невысока, советы Помощника могут быть весьма ценными. Интеллектуальные Помощники незаменимы в играх и обучающих системах. Конечно, в серьезных задачах квалифицированный пользователь может принимать лучшие решения, но и там подсказки Помощника могут быть полезными.
В игре "Волк, Коза и Капуста" достаточно было ввести одну переменную, следящую за состоянием игры, изменять ее значение по ходу игры, и при обращении к Помощнику за советом, выдавать подсказку на основе анализа значения этой переменной.
Вот какие изменения пришлось сделать в реализации игры. Во-первых, я добавил новый модуль Dialogs, в который поместил процедуры и константы, необходимые для ведения диалога. Некоторые изменения пришлось ввести и в текст модуля WGC. В раздел объявлений этого модуля добавлены следующие строчки:
Public StateOfPlay As String 'Состояние игры Public Answer As MsoBalloonButtonType 'Выбор пользователя 'Другие общие параметры Public WidthOfRiver 'Ширина реки Public MyPath As String 'каталог, хранящий исходный документ и другие файлы игрыЛистинг 7.8.
Изменения внесены и в процедуру инициализации:
Public Sub InitialStates() 'Задаем начальные состояния объектов и их образов StateOfMan = "LeftBank" StateOfWolf = "LeftBank" StateOfGoat = "LeftBank" StateOfCabbage = "LeftBank" StateOfBoat = "LeftBank" CountInBoat = 0 StateOfPlay = "InitState" 'Инициализация объектов формы With WGCForm .Man.Top = .LeftBank.Top + 15: .Man.Left = .LeftBank.Left + 10 .Man.Visible = True .Wolf.Top = .LeftBank.Top + 80: .Wolf.Left = .LeftBank.Left + 10 .Wolf.Visible = True .Goat.Top = .LeftBank.Top + 140: .Goat.Left = .LeftBank.Left + 10 .Goat.Visible = True .Cabbage.Top = .LeftBank.Top + 200: .Cabbage.Left = .LeftBank.Left + 10 .Cabbage.Visible = True .Boat.Top = .LeftBank.Top + 130: .Boat.Left = .LeftBank.Left + .LeftBank.Width .Boat.Visible = True WidthOfRiver = .Width - .LeftBank.Width - .RightBank.Width _ - .Boat.Width 'Поместить Рокки на остров Assistant.FileName = "Rocky.acs" 'Debug.Print Assistant.Left, Assistant.Top Assistant.Move XLeft:=.Left + .Island.Left + .Island.Width / 2, _ YTop:=.Top + .Island.Top + .Island.Height - 10 Assistant.Animation = msoAnimationCharacterSuccessMajor 'Assistant.AssistWithAlerts = False 'Assistant.AssistWithHelp = False 'Debug.Print Assistant.Left, Assistant.Top End With 'Путь к каталогу MyPath = ActiveDocument.Path 'Сформировать баллончики - диалоговые окна Call FormBalloons 'Инициализировать диалог Call Dialog1 End SubЛистинг 7.9.
Я улучшил инициализацию, задав относительное расположение объектов, что позволяет менять размеры игрового поля, сохраняя взаимное расположение объектов. Наиболее серьезные дополнения выделены цветом фона. Как видите, здесь вводится объект Assistant и, используя метод Move, он помещается на свое место - остров, при этом задается его анимационное поведение. Далее вызываются две процедуры модуля Dialogs. В первой из них формируются объекты - баллончики разного типа, во второй - инициализируется начальный диалог Помощника, приглашающий к началу игры.
Других изменений в процедурах этого модуля не было, если не считать замены вызовов функции MsgBox на вызовы соответствующих функций модуля Dialogs, как, например, в процедуре TestingState:
Public Sub TestingState() 'Тестирование состояний With WGCForm 'Волк съел козу If (StateOfWolf = StateOfGoat) And (StateOfWolf < > StateOfMan) Then .Goat.Visible = False 'MsgBox Prompt:=Mes1 + vbCrLf + Mes3, Buttons:=vbCritical + vbOKOnly, Title:=Mes13 Call Dialog5 InitialStates End If 'Коза съела капусту If (StateOfCabbage = StateOfGoat) And (StateOfCabbage < < StateOfMan) Then .Cabbage.Visible = False 'MsgBox Prompt:=Mes1 + vbCrLf + Mes4, Buttons:=vbCritical + vbOKOnly, Title:=Mes13 Call Dialog6 InitialStates End If 'Слишком много пассажиров! If (CountInBoat > 2) Then If StateOfMan = "InBoat" Then .Man.Visible = False If StateOfWolf = "InBoat" Then .Wolf.Visible = False If StateOfGoat = "InBoat" Then .Goat.Visible = False If StateOfCabbage = "InBoat" Then .Cabbage.Visible = False 'MsgBox Prompt:=Mes1 + vbCrLf + Mes5, Buttons:=vbCritical + vbOKOnly, Title:=Mes13 Call Dialog7 InitialStates End If 'Конец игры - Все пассажиры собрались на правом берегу If (StateOfMan = "RightBank") And (StateOfWolf = "RightBank") And _ (StateOfGoat = "RightBank") And (StateOfCabbage = "RightBank") Then 'MsgBox Prompt:=Mes2 + vbCrLf + Mes6, Buttons:=vbExclamation + vbOKOnly, Title:=Mes14 Call Dialog8 End If End With End SubЛистинг 7.10.
Приведем теперь текст модуля Dialogs:
Option Explicit 'Константы для организации диалогов Public Const Mes1 = "Ужасно, нелепо и грустно! " Public Const Mes2 = "Прекрасно, как славно,отлично! " Public Const Mes3 = " Волк съел козу! " Public Const Mes4 = " Коза съела капусту! " Public Const Mes5 = " Лодка перевернулась и все утонули! " Public Const Mes6 = " Вам это удалось! Все переправились!" Public Const Mes7 = " Не удалось дотащить " Public Const Mes8 = " Человека! " Public Const Mes9 = " Волка! " Public Const Mes10 = " Козу! " Public Const Mes11 = " Капусту! " Public Const Mes12 = " Повторите попытку! " Public Const Mes13 = " Беда!" Public Const Mes14 = " Радость! " Public Const Mes15 = " Лодку! " Public Const Txt1 = "Привет! Я Рокки." & vbCrLf _ & "Щелкни по острову, если захочешь поговорить со мной." Public Const Txt2 = "Волк, Коза и Капуста!" 'Public Const Txt3 = "{wmf " & MyPath & "\goat.wmf}" 'Public Const Txt4 = "{wmf " & MyPath & "\cabbage.wmf}" Public Const Txt5 = "" 'Массив баллончиков - диалоговых окон Рокки Public RockyBalloons(1 To 10) As Balloon Public Sub Dialog() 'Начальный диалог при открытии игры 'Анализ состояния игры Select Case StateOfPlay Case "InitState" Call Dialog1 Case "State1" Call Dialog2 Case "State2" Call Dialog9 Case "StateFinish" Call Dialog10 Case Else End Select End Sub Public Sub OneBall() Dim Text1 As String, Text2 As String, Text3 As String Dim Text4 As String, Text5 As String Dim MyPath As String MyPath = ActiveDocument.Path 'Формирование свойства Text Text1 = "Хочешь знать, как перевезти с берега на берег" ' Вставка графики в середину текста Text2 = "{wmf " & MyPath & "\wolf.wmf}" & " Волка," & vbCrLf Text3 = "{wmf "& MyPath & "\goat.wmf}" & " Козу" & " И " Text4 = "{wmf " & MyPath & "\cabbage.wmf}" & " Капусту?" & vbCrLf & vbCrLf 'Text5 = "Соблюдая 3 правила?" Dim FirstBall As Balloon Set FirstBall = Assistant.NewBalloon With FirstBall .Heading = "Волк, Коза и Капуста" .Icon = msoIconAlert .Text = Text1 & Text2 & Text3 & Text4 .Button = msoButtonSetYesNo .Show End With End Sub Public Sub FormBalloons() 'Инициализация баллончиков Dim I As Integer For I = 1 To 10 Set RockyBalloons(I) = Assistant.NewBalloon RockyBalloons(I).Heading = Txt2 RockyBalloons(I).Icon = msoIconAlertInfo Next I FormBall1 FormBall2 FormBall3 FormBall4 FormBall5 FormBall6 FormBall7 'FormBall8 End Sub Public Sub FormBall1() 'Формирование свойства Text - знакомство With RockyBalloons(1) .Text = Txt1 .Button = msoButtonSetOK End With End Sub Public Sub Dialog1() RockyBalloons(1).Show StateOfPlay = "State1" 'Игра началась End Sub Public Sub FormBall2() Dim Text1 As String, Text2 As String, Text3 As String Dim Text4 As String, Text5 As String 'Формирование свойства Text Text1 = "Нужно срочно перевезти с берега на берег" ' Вставка графики в середину текста Text2 = "{wmf " & MyPath & "\wolf.wmf}" & " Волка," & vbCrLf Text3 = "{wmf " & MyPath &"\goat.wmf}" & " Козу" & " И " Text4 = "{wmf " & MyPath & "\cabbage.wmf}" & " Капусту?" & vbCrLf & vbCrLf Text5 = "Хочешь знать правила игры?" With RockyBalloons(2) .Text = Text1 & Text2 & Text3 & Text4 & Text5 .Button = msoButtonSetYesNo End With End Sub Public Sub Dialog2() Answer = RockyBalloons(2).Show Select Case Answer Case msoBalloonButtonYes 'Нажата кнопка Yes 'Показать правила игры Call Dialog3 Case msoBalloonButtonNo 'Нажата кнопка No 'Предложить начать играть Call Dialog4 End Select End Sub Public Sub FormBall3() Dim Text1 As String, Text2 As String, Text3 As String Dim Text4 As String, Text5 As String 'Формирование переменных Text Text1 = "В лодке, используемой для перевоза," & _ " может находиться не более двух путников" & _ " (человек, волк, коза и капуста - это путники)." & vbCrLf _ & "При попытке посадить большее число путников лодка перевернется. " Text2 = "Если оставить в лодке или на берегу волка и козу без присмотра человека," & _ vbCrLf &"то волк немедленно съест козу." Text3 = "Если оставить в лодке или на берегу капусту и козу без присмотра человека," & _ vbCrLf & "то коза немедленно съест капусту." Text4 = "Без человека лодка не может переплыть на другой берег." Text5 = "Начинайте играть! Желаю успеха!" With RockyBalloons(3) .BalloonType = msoBalloonTypeNumbers .Labels(1).Text = Text1 .Labels(2).Text = Text2 .Labels(3).Text = Text3 .Labels(4).Text = Text4 .Labels(5).Text = Text5 End With End Sub Public Sub Dialog3() RockyBalloons(3).Show StateOfPlay = "State2" 'Правила заданы End Sub Public Sub FormBall4() RockyBalloons(4).Text = "Начинайте играть! Желаю успеха!" End Sub Public Sub Dialog4() RockyBalloons(4).Show StateOfPlay = "State2" 'Правила заданы End Sub Public Sub FormBall5() RockyBalloons(5).Icon = msoIconAlertCritical End Sub Public Sub Dialog5() RockyBalloons(5).Text = Mes1 + vbCrLf + Mes3 RockyBalloons(5).Show StateOfPlay = "State1" 'Начало игры End Sub Public Sub Dialog6() RockyBalloons(5).Text = Mes1 + vbCrLf + Mes4 RockyBalloons(5).Show StateOfPlay = "State1" 'Начало игры End Sub Public Sub Dialog7() RockyBalloons(5).Text = Mes1 + vbCrLf + Mes5 RockyBalloons(5).Show StateOfPlay = "State1" 'Начало игры End Sub Public Sub FormBall6() RockyBalloons(6).Icon = msoIconAlert RockyBalloons(6).Text = Mes2 + vbCrLf + Mes6 End Sub Public Sub Dialog8() RockyBalloons(6).Show StateOfPlay = "StateFinish" 'Конец игры End Sub Public Sub Dialog9() 'Совет! 'Rule1: Если волк и коза на одном берегу, то увези козу. 'Rule2: Если капуста и коза на одном берегу, то увези капусту. If (StateOfWolf = StateOfGoat) Then RockyBalloons(7).Text = "Увези козу!" ElseIf (StateOfCabbage = StateOfGoat) Then RockyBalloons(7).Text = "Увези капусту!" Else RockyBalloons(7).Text = "Тут моя помощь не нужна!" End If RockyBalloons(7).Show End Sub Public Sub FormBall7() RockyBalloons(7).Icon = msoIconTip End Sub Public Sub Dialog10() RockyBalloons(6).Text = "Приходите, поиграем еще раз! Рокки будет ждать." RockyBalloons(6).Show StateOfPlay = "StateFinish" 'Конец игры End SubЛистинг 7.11.
Я не буду комментировать процедуры этого модуля. Все что нужно было сказать, уже сказано. Отмечу только процедуру Dialog9, которая вызывается, когда Рокки должен дать совет. Заметьте, его интеллектуальность определяется двумя правилами типа "если… то". Если не выполняются условия ни одного из этих правил, то Рокки полагает, что ситуация очень простая и его советы не нужны, поскольку можно принимать любое решение, допустимое правилами игры.
На этом мы и закончим разговор об организации диалогов с использованием возможностей объекта Assistant.