В данном
уроке запрограммируем игру с компьютером в крестики—нолики на игровом поле размером
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. Диалоговое окно Крестики — Нолики
Релятивисты и позитивисты утверждают, что "мысленный эксперимент" весьма полезный интрумент для проверки теорий (также возникающих в нашем уме) на непротиворечивость. В этом они обманывают людей, так как любая проверка может осуществляться только независимым от объекта проверки источником. Сам заявитель гипотезы не может быть проверкой своего же заявления, так как причина самого этого заявления есть отсутствие видимых для заявителя противоречий в заявлении.
Это мы видим на примере СТО и ОТО, превратившихся в своеобразный вид религии, управляющей наукой и общественным мнением. Никакое количество фактов, противоречащих им, не может преодолеть формулу Эйнштейна: "Если факт не соответствует теории - измените факт" (В другом варианте " - Факт не соответствует теории? - Тем хуже для факта").
Максимально, на что может претендовать "мысленный эксперимент" - это только на внутреннюю непротиворечивость гипотезы в рамках собственной, часто отнюдь не истинной логики заявителя. Соответсвие практике это не проверяет. Настоящая проверка может состояться только в действительном физическом эксперименте.
Эксперимент на то и эксперимент, что он есть не изощрение мысли, а проверка мысли. Непротиворечивая внутри себя мысль не может сама себя проверить. Это доказано Куртом Гёделем.
Понятие "мысленный эксперимент" придумано специально спекулянтами - релятивистами для шулерской подмены реальной проверки мысли на практике (эксперимента) своим "честным словом". Подробнее читайте в FAQ по эфирной физике.