Организация диалога. Объект 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.