Урок 11.

Тема: Игра в крестики и нолики

Цель урока

В данном уроке запрограммируем игру с компьютером в крестики—нолики на игровом поле размером 3x3 условных клетки. Эта не такая уж тривиальная игра является хорошим примером, чтобы легко научить компьютер играть и воспользоваться возможностью выиграть, если вы, по невнимательности, дадите ему этот шанс.

Конструируя данное приложение, вы на практике освоите следующие операции:

Практика

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

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

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

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

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

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

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

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

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

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

UserForm Initialize

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

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

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. Диалоговое окно Крестики — Нолики