Страницы

вторник, 19 августа 2014 г.

Игра Пятнашки

Игра «Пятнашки» (MS Excel, VBA)

Напишем очень простую игру «Пятнашки». Язык - VBA, среда разработки MS Excel.
Описание игры: есть поле размером 4х4 ячейки, на котором располагаются фишки с номерами от 1 до 15. Одна ячейка свободна. В начале игры фишки перемешаны случайным образом. Необходимо выстроить их по порядку от 1 до 15. Перемещать фишку можно только на свободное место.
Выделим на листе Excel диапазон из 16 ячеек и присвоим ему имя, например Pole. Сделаем обводку границ и установим жирный шрифт. Роль фишек будут играть числа в ячейках.
Что нам нужно сделать?
Во-первых, создать процедуру перемешивания ячеек.
Во-вторых, создать процедуру хода, то есть передвижения фишки.
В-третьих, наконец, нужна функция проверки на выигрыш, которая будет определять, все ли фишки выстроены в нужном порядке.
Добавим на лист кнопку, назовем BStart и присвоим ей процедуру нажатия (BStart_Click).
В процедуре нужно сначала очистить все ячейки диапазона, затем в цикле получать случайные числа и записывать их в ячейки. Перед занесением нужно проверить, не внесено ли такое число ранее. Поскольку такую проверку нужно выполнять очень часто, то вынесем ее в отдельную функцию. Она будет принимать значение числа и возвращать 1, если такое число уже было, и 0, если оно встречается впервые.
Функция Checking(number)

Function Checking(number As Integer) As Integer
Dim r As Integer, c As Integer
For r = 1 To 4
    For c = 1 To 4
        If Range("Pole").Cells(r, c).Value = number Then
        Checking = 1
        Exit Function
        End If
    Next c
Next r
Checking = 0
End Function
В цикле перебираем все ячейки диапазона. Если ячейка содержит такое число, то возвращаем 1. Иначе возвращаем 0.
Процедура перемешивания:
Private Sub BStart_Click()
Dim r As Integer, c As Integer, num As Integer
Randomize
For r = 1 To 4
    For c = 1 To 4
        Range("Pole").Cells(r, c).Value = 100
    Next c
Next r
For r = 1 To 4
    For c = 1 To 4
        num = Int(16 * Rnd)
        Do While Checking(num)
           num = Int(16 * Rnd)
        Loop
        Range("Pole").Cells(r, c).Value = num
    Next c
Next r
For r = 1 To 4
    For c = 1 To 4
        If Range("Pole").Cells(r, c).Value = 0 Then
           Range("Pole").Cells(r, c).Value = ""
        End If
    Next c
Next r
End Sub
Сначала проводим инициализацию счетчика случайных чисел с помощью функции Randomize.
Затем присваиваем всем ячейкам какое-нибудь число вне диапазона, например, 100. Затем в цикле перебираем ячейки диапазона и каждой присваиваем случайное значение от 0 до 15. Используем функцию Rnd(). Эта функция возвращает значение меньше единицы, но большее или равное нулю.
Синтаксис функции
Int((upperbound - lowerbound + 1) * Rnd + lowerbound)
Где upperbound – это наибольшая граница, а lowerbound – наименьшая граница диапазона. Нам нужно число от 0 до 15, значит используем int((15-0+1)*Rnd + 0. То есть 16 * Rnd.
Затем проверяем число на совпадение. Повторяем случайный выбор, пока функция Cheking()  не вернет 0.
В конце еще раз перебираем ячейки, чтобы заменить 0 на пустую ячейку.
Каждый ход проверяем на победу. Текст функции:
Public Function WinCheck() As Integer
Dim r As Integer, c As Integer, i As Integer
i = 1
For r = 1 To 4
    For c = 1 To 4
        If (Range("Pole").Cells(r, c).Value <> i Or Range("Pole").Cells(r, c).Value = "") And i <> 16 Then
            WinCheck = 0
            Exit Function
        End If
        i = i + 1
    Next c
Next r
WinCheck = 1
End Function
Переменную i увеличиваем от 1 до 16 и сравниваем каждую ячейку. Если число в ячейке не совпадает с i или ячейка пустая, то возвращаем 0. Дополнительное условие – i не должно быть равно 16, так как это последняя ячейка, и в случае выигрыша она должна быть пустой.
Последняя функция – ход игрока. Для хода нужно нажать правой кнопкой мыши на ячейку, которую нужно передвинуть. Если рядом есть свободное место, то число передвинется туда, а ячейка станет пустой.
Используем процедуру BeforeRightClick, то есть обработка перед нажатием правой кнопки.
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)

Dim row1 As Integer, col1 As Integer
If ActiveCell.Row > 2 And ActiveCell.Row < 7 And ActiveCell.Column > 1 And ActiveCell.Column < 7 Then
    row1 = ActiveCell.Row
    col1 = ActiveCell.Column
    If row1 > 3 Then
        If Cells(row1 - 1, col1).Value = "" Then
            Cells(row1 - 1, col1).Value = ActiveCell.Value
            ActiveCell.Value = ""
        End If
    End If
    If row1 < 6 Then
        If Cells(row1 + 1, col1).Value = "" Then
            Cells(row1 + 1, col1).Value = ActiveCell.Value
            ActiveCell.Value = ""
        End If
    End If
    If col1 > 2 Then
        If Cells(row1, col1 - 1).Value = "" Then
            Cells(row1, col1 - 1).Value = ActiveCell.Value
            ActiveCell.Value = ""
        End If
    End If
    If col1 < 5 Then
        If Cells(row1, col1 + 1).Value = "" Then
            Cells(row1, col1 + 1).Value = ActiveCell.Value
            ActiveCell.Value = ""
        End If
    End If
    Cancel = True
    If WinCheck() Then
        MsgBox "Вы победили!"
    End If
End If
End Sub
Сначала определяем, где находился курсор в момент нажатия. Если вне пределов диапазона, то ничего не делаем. Если внутри, то определяем строку и столбец нажатой ячейки и ищем свободную ячейку рядом. Если ячейка найдена, то устанавливаем там число, а текущую ячейку очищаем.
Чтобы не появлялось контекстное мене, делаем “Cancel = true”.
После хода вызываем функцию проверки на победу. Если функция вернула нуль (то есть истину), то показываем сообщение о победе.
Результат:

Игра "Пятнашки" на языке VBA в MS Excel