В данном
уроке запрограммируем игру с компьютером в крестики—нолики на игровом поле размером
3x3 условных клетки. Эта не такая уж тривиальная игра является хорошим примером,
чтобы легко научить компьютер играть и воспользоваться возможностью выиграть,
если вы, по невнимательности, дадите ему этот шанс.
Конструируя
данное приложение, вы на практике освоите следующие операции:
В редакторе
форм создадим диалоговое окно крестики нолики
(рис. У11.1).
Поле игры будут образовывать девять элементов управления Caption (надпись).
Для видимости границ элементов управления Caption установите свойство BorderStyle
равным fmBorderStyleSingle.
В данной
игре запрограммируем только более сложную для компьютера ситуацию, когда первым
ходит игрок. В этой ситуации компьютеру надо умело обороняться, создавая ситуации
для внезапных атак. Играющему первым игроку достаточно все время атаковать,
поэтому его стратегия для программирования более легкая. Общий случай, когда
в параметрах игры устанавливается, кто ходит первым компьютер или человек, будет
оставлен в качестве хорошего самостоятельного задания для читателя.
Рис.
У11.1. Диалоговое окно Крестики — нолики в редакторе форм
Итак, в нашей
игре первый ход за пользователем. Ход осуществляется двойным щелчком по игровому
полю. Если игровое поле пусто, то в нем отображается крестик. Компьютер мгновенно
отвечает на ход игрока, постановкой нолика в другое игровое поле и т. д. О результате
игры компьютер информирует пользователя. При желании сыграть еще одну игру с
компьютером, нажмите кнопку переиграть, которая очистит игровые поля. На рис.
У11.2 приведен вид партии в крестики—нолики после второго шага игры.
Рис.
У11.2. Пример партии игры в крестики—нолики после второго шага игры
Крестик и
нолик, которые выводятся на игровом поле, содержатся в файлах cross.bmp и ou.bmp,
а их образы можно создать при помощи любого графического редактора.
В связи с
небольшим числом возможных стратегий в этой игре, составляя программу можно
пойти по пути наименьшего сопротивления: а именно, применить подход простого
перебора вариантов возможных действий. Если бы в игре было большое число стратегий,
то этот подход был бы неприменим, т. к. программа не смогла бы играть в режиме
реального времени.
Стратегия
компьютера в игре крестики—нолики очень проста:
Обсудим,
как приведенная ниже программа решает описанную задачу и что в ней происходит.
UserForm Initialize |
|
||
Нажатие кнопки
Переиграть запускает на выполнение процедуру 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
Разработать
программу игры крестики—нолики, в которой в зависимости от установок параметров
игры первый ход может делать либо компьютер, либр игрок (рис. У11.4). Игрок
также может выбрать, что он ставит в игровые поля: крестики или нолики. Программа
ведет учет числа побед как игрока, так и компьютера. Программа также подсчитывает
число ничейных партий.
Рис.
У11.4. Диалоговое окно Крестики — Нолики