Самоучитель VBA

Практика



В редакторе форм создадим диалоговое окно крестики нолики

(рис. У11.1). Поле игры будут образовывать девять элементов управления Caption (надпись). Для видимости границ элементов управления Caption установите свойство BorderStyle равным fmBorderStyleSingle.

В данной игре запрограммируем только более сложную для компьютера ситуацию, когда первым ходит игрок. В этой ситуации компьютеру надо умело обороняться, создавая ситуации для внезапных атак. Играющему первым игроку достаточно все время атаковать, поэтому его стратегия для программирования более легкая. Общий случай, когда в параметрах игры устанавливается, кто ходит первым компьютер или человек, будет оставлен в качестве хорошего самостоятельного задания для читателя.

Рис. У11.1. Диалоговое окно Крестики — нолики в редакторе форм

Итак, в нашей игре первый ход за пользователем. Ход осуществляется двойным щелчком по игровому полю. Если игровое поле пусто, то в нем отображается крестик. Компьютер мгновенно отвечает на ход игрока, постановкой нолика в другое игровое поле и т. д. О результате игры компьютер информирует пользователя. При желании сыграть еще одну игру с компьютером, нажмите кнопку переиграть, которая очистит игровые поля. На рис. У11.2 приведен вид партии в крестики—нолики после второго шага игры.

Рис. У11.2. Пример партии игры в крестики—нолики после второго шага игры

Крестик и нолик, которые выводятся на игровом поле, содержатся в файлах cross.bmp и ou.bmp, а их образы можно создать при помощи любого графического редактора.

В связи с небольшим числом возможных стратегий в этой игре, составляя программу можно пойти по пути наименьшего сопротивления: а именно, применить подход простого перебора вариантов возможных действий. Если бы в игре было большое число стратегий, то этот подход был бы неприменим, т. к. программа не смогла бы играть в режиме реального времени.

Стратегия компьютера в игре крестики—нолики очень проста:



  • Если в игре сложилась ситуация, когда на очередном ходе он может проставить в ряд три нолика, компьютер ставит их и выигрывает.



  • Если игрок на очередном ходе угрожает поставить подряд три крестика, а у компьютера есть возможность помешать этому, поставив нолик, он это делает.

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

  • После каждого хода как игрока, так и компьютера необходимо производить проверку на возможный результат игры.

    Обсудим, как приведенная ниже программа решает описанную задачу и что в ней происходит.



    UserForm Initialize



    1. Активизирует диалоговое окно.

      Очищает все надписи от рисунков и текста, обнуляет все переменные.



    Нажатие кнопки Переиграть запускает на выполнение процедуру

    CommandButtonl_Click



    Очищает все надписи от рисунков и текста, обнуляет все переменные.



    Нажатие кнопки выход запускает на

    выполнение процедуру

    CoramandButton2_Click



    Закрывает диалоговое окно.



    От процедуры

    Labell_DblClick

    до

    Label9 DblClick



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

    Если нет, то компьютер делает свой ответный ход. Проверяет, привел ли ход компьютера к его победе, если да, то выдается соответствующее сообщение (рис. У11.3) и игра завершается.



    Strategy 1

    и

    Strategy



    Генерируют первый и последующие ходы соответственно.



    Проверка



    Проверяет, нет ли в игре победителей.



    НачальноеСостояние



    Очищает все надписи от рисунков и текста, обнуляет все переменные.



    Состояние



    В массиве Статус отмечаются расставленные в ячейках игрового — 10, а пусто — 0. Процедура Состояние находит суммы элементов массива на диагоналях, в строках и столбцах.



    Диагональ!



    Определяет в зависимости от состояние, надо ли компьютеру ходить по главной диагонали и, если надо, то в какую ячейку.



    Диагональ 2



    Определяет в зависимости от состояние, надо ли компьютеру ходить по второй диагонали и, если надо, то в какую ячейку.



    Бок, Верх



    Определяет в зависимости от Состояние, надо ли компьютеру ходить и, если надо, то в какую ячейку.

    <




    Рис. У11.3. Пример сообщения о результате игры

    ' Переменные уровня модуля

    '

    Dim Поле (1 То 3, 1 То 3) As Ob j ect

    Dim Статус(1 To 3, 1 To 3) As Integer

    Dim k As Integer

    Dim i As Integer

    Dim j As Integer

    Dim Su(0 To 4, 0 To 4} As Integer

    '

    Private Sub CommandButtonl_Click()

    ' Процедура переигрывания

    'НачальноеСостояние

    End Sub

    '

    Private Sub CoirniandButton2_Click()

    '

    ' Закрытие диалогового окна

    '

    UserForml.Hide

    End Sub

    Private Sub Labell_DblClick(ByVal Cancel As MSForms.ReturnBoolean)

    Dim Inf As Boolean

    If Статус(1, 1) = 0 Then

    Поле(1, 1).Picture = LoadPicture("cross.bmp")

    Статус(1, 1) = 1

    k = k + 1

    Проверка Inf

    If Inf = True Then Exit Sub

    Strategy

    Проверка Inf

    If Inf = True Then Exit Sub

    End If

    End Sub

    '

    Private Sub Label2_DblClick(ByVal Cancel As MSForms.ReturnBoolean)

    Dim Inf As Boolean

    If Статус(1, 2) = 0 Then

    Поле(1, 2).Picture = LoadPicture("cross.bmp")

    Статус(1, 2) = 1

    k = k + 1

    Проверка Inf

    If Inf = True Then Exit Sub

    Strategy

    Проверка Inf

    If Inf = True Then Exit Sub

    End If

    End Sub

    '

    Private Sub Label3_DblClick(ByVal Cancel As MSForms.ReturnBoolean)

    Dim Inf As Boolean

    If Статус(1, 3) = 0 Then

    Поле(1, 3).Picture = LoadPicture("cross.bmp")

    Статус(1, 3) = 1

    k = k + 1

    'Проверка Inf

    If Inf = True Then Exit Sub

    Strategy

    'Проверка Inf

    If Inf = True Then Exit Sub End If End Sub

    Private Sub Label4_DblClick(ByVal Cancel As MSForms.ReturnBoolean)

    Dim Inf As Boolean

    If Статус(2, 1) = 0 Then

    Поле(2, 1).Picture = LoadPicture("cross.bmp")

    Статус(2, 1) = 1

    k = k + 1

    'Проверка Inf

    If Inf = True Then Exit Sub

    Strategy

    'Проверка Inf

    If Inf = True Then Exit Sub End If

    End Sub

    '

    Private Sub

    Label5_DblClick(ByVal Cancel As MSForms.ReturnBoolean)

    Dim Inf As Boolean

    If Статус(2, 2) = 0 Then

    Поле(2, 2).Picture = LoadPicture("cross.bmp")

    Статус(2, 2) = 1

    k = k + 1

    'Проверка Inf

    If Inf = True Then Exit Sub



    Strategy

    'Проверка Inf

    If Inf = True Then Exit Sub

    End If

    End Sub

    '

    Private Sub

    Label6_DblClick(ByVal Cancel As MSForms.ReturnBoolean)

    Dim Inf As Boolean

    If Статус(2, 3) = 0 Then

    Поле(2, 3).Picture = LoadPicture("cross.bmp")

    Статус(2, 3) = 1

    k = k + 1

    'Проверка Inf

    If Inf = True Then Exit Sub

    Strategy

    'Проверка Inf

    If Inf = True Then Exit Sub

    End If

    End Sub

    Private Sub Label7_DblClick(ByVal Cancel As MSForms.ReturnBoolean)

    Dim Inf As Boolean

    If Статус(3, 1) = 0 Then

    Поле(3, 1).Picture = LoadPicture("cross.bmp")

    Статус(3, 1) = 1

    k = k + 1

    'Проверка Inf

    If Inf = True Then Exit Sub

    Strategy

    'Проверка Inf

    If Inf = True Then Exit Sub

    End If

    End Sub

    '

    Private Sub Label8_DblClick(ByVal Cancel As MSForms.ReturnBoolean)

    Dim Inf As Boolean

    If Статус(3, 2) = 0 Then

    Поле(3, 2).Picture = LoadPicture("cross.bmp")

    Статус(3, 2) = 1

    k = k + 1

    'Проверка Inf

    If Inf = True Then Exit Sub

    Strategy

    'Проверка Inf

    If Inf = True Then Exit Sub End If End Sub

    Private Sub Label9_DblClick(ByVal Cancel As MSForms.ReturnBoolean)

    Dim Inf As Boolean

    If Статус(3, 3) = 0 Then

    Поле(3, 3).Picture = LoadPicture("cross.bmp")

    Статус(3, 3) = 1

    k = k + 1

    'Проверка Inf

    If Inf = True Then Exit Sub

    Strategy

    'Проверка Inf

    If Inf = True Then Exit Sub

    End If

    End Sub

    '

    Sub UserFona Initialize 0

    Set Поле(1, 1) = Label1

    Set Поле(1, 2) = Label2

    Set Поле(1, 3) = Label3

    Set Поле(2, 1) = Label4

    Set Поле(2, 2) = Label5

    Set Поле(2, 3) = Label6

    Set Поле(3, 1) = Label7

    Set Поле(3, 2) = Label8

    Set Поле(3, 3) = Label9

    ' НачальноеСостояние

    End Sub

    '

    Sub Strategy()

    Dim flag As Boolean

    '

    ' Стратегия первого хода

    If k = 1 Then

    Strategy_1

    Exit Sub

    End If

    '

    If k = 2 And Su(0, 0) = 12 And Статус(2, 2) = 1 Then

    Поле(1, 3).Picture = LoadPicture("ou.bmp")

    Статус(1, 3) = 10

    Exit Sub End If

    '

    If k = 2 And Статус(2, 2) = 10 And (Su(0, 0) = 12 Or Su{0, 4) = 12) Then



    Поле(1, 2).Picture = LoadPicture("ou.bmp")

    Статус(1, 2) = 10

    Exit Sub End If

    '

    If k = 2 And Статус (2, 2) = 10 And Su(0, 0) = 11 And __

    (Статус(3, 2) = 1 Or Статус(2, 1) = 1) Then

    Поле(3, 1).Picture = LoadPicture("ou.bmp")

    Статус(3, 1) = 10

    Exit Sub End If

    '

    'Состояние

    '

    Диагональ1 20, 10,.flag

    If flag = True Then Exit Sub

    Диагональ2 20, 10, flag

    If flag = True Then Exit Sub

    '

    For j = 1 To 3

    Бок 20, 10, j, flag

    If flag = .True Then Exit Sub Next j

    '

    For i = 1 To 3

    Верх 20, 10, i, flag

    If flag = True Then Exit Sub

    Next i '

    Диагональ1 2, 10, flag

    If flag = True Then Exit Sub

    '

    Диагональ2 2, 10, flag

    If flag = True Then Exit Sub

    '

    For j = 1 To 3

    Бок 2, 10, j, flag

    If flag = True Then Exit Sub

    Next j '

    For i =-1 To 3

    Верх 2, 10, i, flag

    If flag = True Then Exit Sub

    Next i

    Диагональ1 10, 10, flag

    If flag = True Then Exit Sub

    '

    Диагональ2 10, 10, flag

    If flag = True Then Exit Sub

    '

    For j = 1 To 3

    Бок 10, 10, j, flag

    If flag = True Then Exit Sub

    Next j

    '

    For i = 1 To 3

    Верх 10, 10, i, flag

    If flag = True Then Exit Sub

    Next i

    For i = 1 To 3 For j = 1 To 3

    If Статус(i, j) = 0 Then

    Поле(i, j).Picture = LoadPicture("ou.bmp") Статус(i, j) = 10

    Exit Sub

    End If

    Next j

    Next i

    '

    End Sub

    Sub Strategy_l()

    '

    If Статус(2, 2) = 0 Then

    Поле(2, 2).Picture = LoadPicture("ou.bmp")

    Статус(2, 2) = 10 Else

    Поле(1, 1).Picture = LoadPicture("ou.bmp")

    Статус(1, 1) = 10 End If

    End Sub '

    Sub Проверка(ByRef Inf As Boolean)

    ' Процедура проверяет, не выиграл ли кто-то

    ' Если аргумент Inf равен True, то выигравший есть

    ' Если аргумент Inf равен False, то пока выигравшего нет

    '

    Inf = False

    Состояние

    '

    If Su(0, 0) = 3 Or Su(0, 0) = 30 Then

    Сообщение Su(0, 0)

    Inf = True

    Exit Sub End If

    '

    If Su(0, 4) = 3 Or Su(0, 4) = 30 Then Сообщение Su(0, 4)

    Inf = True

    Exit Sub

    End If

    '

    For j = 1 To 3

    If Su(0, j) =3 Or Su(0, j) = 30 Then Сообщение Su(0, j)



    Inf = .True

    Exit Sub End If

    Next j '

    For i = 1 To 3

    If Su(i, 0) = 3 Or Su(i, 0) = 30 Then Сообщение Su(i, 0)

    Inf = True

    Exit Sub

    End If

    Next i

    '

    ' Проверка, не завершилась ли игра

    '

    For i = 1 То 3

    For j = 1 То 3

    If Статус(i, j) = 0 Then Exit Sub

    Next j

    Next i

    MsgBox "Пока фифти-фифти", vbExclamation, "Крестики-Нолики"

    Inf = True

    '

    End Sub

    '

    Sub Сообщение(Inf As Integer)

    ' Возможные сообщения о победителе

    ' Если Inf=3, то поздравления принимает игрок

    ' Если Inf=30, то поздравления принимает компьютер

    If Inf = 3 Then

    MsgBox "Поздравляю с выигрышем", vbExclamation, "Крестики-Нолики"

    Exit Sub

    End If

    If Inf = 30 Then

    MsgBox "Компьютер пока сильнее", vbExclamation, "Крестики-Нолики"

    Exit Sub End If

    End Sub '

    Sub НачальноеСостояние()

    '

    ' Обнуление данных и очистка картинок

    '

    For i = 1 То 3

    For j = 1 То 3

    Поле(i, j).Caption = ""

    Поле(i, j).Picture = LoadPicture("")

    Поле(i, j ) .BorderStyle = fmBorderStyleSingle

    Статус(i, j) = 0 Next j

    Next i

    k = 0

    For i = 0 To 4

    For j = 0 To 4

    Su(i, j) = 0

    Next j

    Next i

    End Sub

    '

    Sub Состояние()

    '

    Su(0, 0) = 0

    For i = 1 To 3

    Su(0, 0) = Su(0, 0) + Статус(1, i)

    Next i

    '

    Su(0, 4) =0

    For i = 1 To 3

    Su(0, 4) = Su(0, 4) + Статус(1, 4 - i)

    Next i

    For j = 1 To 3

    Su(0, j) = 0

    For i = 1 To 3

    Su(0, j) = Su(0, j) + Статус(i, j)

    Next i

    Next j

    '

    For i = 1 To 3

    Su(i, 0) = 0

    For j = 1 To 3

    Su(i, 0) = Su(i, 0) + Статус(i, j) Next j

    Next i

    '

    End Sub

    Sub Диагональ1( ByRef p, ByRef q, ByRef flag As Boolean)

    flag = False

    If Su(0, 0) = p Then

    For i = 1 To 3

    ' If Статус(i, i) = 0 Then

    Поле(1, i).Picture = LoadPicture("ou.bmp")

    Статус(i, i) = q flag = True

    Exit Sub

    End If

    Next i

    End If

    End Sub '

    Sub Диагональ2(ByRef p, ByRef q, ByRef flag As Boolean)

    flag = False If Su(0, 4) = p Then

    For i = 1 To 3

    If Статус(i, 4 - i) = 0 Then

    Поле(i, 4 - i).Picture = LoadPicture("ou.bmp")



    Статус(i, 4 - i) = q

    flag = True Exit Sub

    End If Next i End If End Sub

    Sub Бок( ByRef p, ByRef q, ByRef j, ByRef flag As Boolean)

    flag =. False

    If Su(0, j) = p Then

    For i = 1 To 3

    If Статус(i, j) = 0 Then

    Поле(i, j).Picture = LoadPicture ("ou.bmp")

    Статус(i, j) = q

    flag = True

    Exit Sub

    End If

    Next i

    End If

    End Sub '

    Sub Верх(ByRef p, ByRef q, ByRef i, ByRef flag As Boolean)

    flag = False

    If Su(i, 0) = p Then

    For j = 1 To 3

    If Статус (i, j) = 0 Then

    Поле(1, j).Picture = LoadPicture("ou.bmp")

    Статус(i, j) = q

    flag = True

    Exit Sub

    End If

    Next j

    End If

    End Sub




    Содержание раздела