Реализация игры 2048 с помощью Excel VBA

Я пытаюсь реализовать игра 2048 в Excel VBA.

Рисунок 1

Каждое логическое значение ИСТИНА / ЛОЖЬ в строках 2, 4, 6 и 8 используется для определения, что данные каждой ячейки в строках 1, 3, 5 и 7 равны 0 или нет.

Экспериментальная реализация

Sub MergeUp()
    Dim loop_num
    Dim loop_num2
    For loop_num2 = 1 To 3
        For loop_num = 1 To 4
            If Cells(6, loop_num) = True Then
                Cells(5, loop_num) = Cells(7, loop_num)
                Cells(7, loop_num) = 0
            End If
            If Cells(4, loop_num) = True Then
                Cells(3, loop_num) = Cells(5, loop_num)
                Cells(5, loop_num) = 0
            End If
            If Cells(2, loop_num) = True Then
                Cells(1, loop_num) = Cells(3, loop_num)
                Cells(3, loop_num) = 0
            End If
        Next
    Next
    For loop_num = 1 To 4
        If Cells(1, loop_num) = Cells(3, loop_num) Then
            Cells(1, loop_num) = Cells(1, loop_num) + Cells(3, loop_num)
            Cells(9, "C") = Cells(9, "C") + Cells(3, loop_num)
            Cells(3, loop_num) = 0
        End If
        If Cells(3, loop_num) = Cells(5, loop_num) Then
            Cells(3, loop_num) = Cells(3, loop_num) + Cells(5, loop_num)
            Cells(9, "C") = Cells(9, "C") + Cells(5, loop_num)
            Cells(5, loop_num) = 0
        End If
        If Cells(5, loop_num) = Cells(7, loop_num) Then
            Cells(5, loop_num) = Cells(5, loop_num) + Cells(7, loop_num)
            Cells(9, "C") = Cells(9, "C") + Cells(7, loop_num)
            Cells(7, loop_num) = 0
        End If
    Next
    For loop_num2 = 1 To 3
        For loop_num = 1 To 4
            If Cells(6, loop_num) = True Then
                Cells(5, loop_num) = Cells(7, loop_num)
                Cells(7, loop_num) = 0
            End If
            If Cells(4, loop_num) = True Then
                Cells(3, loop_num) = Cells(5, loop_num)
                Cells(5, loop_num) = 0
            End If
            If Cells(2, loop_num) = True Then
                Cells(1, loop_num) = Cells(3, loop_num)
                Cells(3, loop_num) = 0
            End If
        Next
    Next
    Call rand_num
End Sub
Sub MergeDown()
    Dim loop_num
    Dim loop_num2
    For loop_num2 = 1 To 3
        For loop_num = 1 To 4
            If Cells(4, loop_num) = True Then
                Cells(3, loop_num) = Cells(1, loop_num)
                Cells(1, loop_num) = 0
            End If
            If Cells(6, loop_num) = True Then
                Cells(5, loop_num) = Cells(3, loop_num)
                Cells(3, loop_num) = 0
            End If
            If Cells(8, loop_num) = True Then
                Cells(7, loop_num) = Cells(5, loop_num)
                Cells(5, loop_num) = 0
            End If
        Next
    Next
    For loop_num = 1 To 4
        If Cells(7, loop_num) = Cells(5, loop_num) Then
            Cells(7, loop_num) = Cells(7, loop_num) + Cells(5, loop_num)
            Cells(9, "C") = Cells(9, "C") + Cells(5, loop_num)
            Cells(5, loop_num) = 0
        End If
        If Cells(5, loop_num) = Cells(3, loop_num) Then
            Cells(5, loop_num) = Cells(5, loop_num) + Cells(3, loop_num)
            Cells(9, "C") = Cells(9, "C") + Cells(3, loop_num)
            Cells(3, loop_num) = 0
        End If
        If Cells(3, loop_num) = Cells(1, loop_num) Then
            Cells(3, loop_num) = Cells(3, loop_num) + Cells(1, loop_num)
            Cells(9, "C") = Cells(9, "C") + Cells(1, loop_num)
            Cells(1, loop_num) = 0
        End If
    Next
    For loop_num2 = 1 To 3
        For loop_num = 1 To 4
            If Cells(4, loop_num) = True Then
                Cells(3, loop_num) = Cells(1, loop_num)
                Cells(1, loop_num) = 0
            End If
            If Cells(6, loop_num) = True Then
                Cells(5, loop_num) = Cells(3, loop_num)
                Cells(3, loop_num) = 0
            End If
            If Cells(8, loop_num) = True Then
                Cells(7, loop_num) = Cells(5, loop_num)
                Cells(5, loop_num) = 0
            End If
        Next
    Next
    Call rand_num
End Sub
Sub MergeLeft()
    For loop_num2 = 1 To 3
        For loop_num = 1 To 7 Step 2
            If Cells(loop_num + 1, "C") = True Then
                Cells(loop_num, "C") = Cells(loop_num, "D")
                Cells(loop_num, "D") = 0
            End If
            If Cells(loop_num + 1, "B") = True Then
                Cells(loop_num, "B") = Cells(loop_num, "C")
                Cells(loop_num, "C") = 0
            End If
            If Cells(loop_num + 1, "A") = True Then
                Cells(loop_num, "A") = Cells(loop_num, "B")
                Cells(loop_num, "B") = 0
            End If
        Next
    Next
    For loop_num = 1 To 7 Step 2
        If Cells(loop_num, "A") = Cells(loop_num, "B") Then
            Cells(loop_num, "A") = Cells(loop_num, "A") + Cells(loop_num, "B")
            Cells(9, "C") = Cells(9, "C") + Cells(loop_num, "B")
            Cells(loop_num, "B") = 0
        End If
        If Cells(loop_num, "B") = Cells(loop_num, "C") Then
            Cells(loop_num, "B") = Cells(loop_num, "B") + Cells(loop_num, "C")
            Cells(9, "C") = Cells(9, "C") + Cells(loop_num, "C")
            Cells(loop_num, "C") = 0
        End If
        If Cells(loop_num, "C") = Cells(loop_num, "D") Then
            Cells(loop_num, "C") = Cells(loop_num, "C") + Cells(loop_num, "D")
            Cells(9, "C") = Cells(9, "C") + Cells(loop_num, "D")
            Cells(loop_num, "D") = 0
        End If
    Next
    For loop_num2 = 1 To 3
        For loop_num = 1 To 7 Step 2
            If Cells(loop_num + 1, "C") = True Then
                Cells(loop_num, "C") = Cells(loop_num, "D")
                Cells(loop_num, "D") = 0
            End If
            If Cells(loop_num + 1, "B") = True Then
                Cells(loop_num, "B") = Cells(loop_num, "C")
                Cells(loop_num, "C") = 0
            End If
            If Cells(loop_num + 1, "A") = True Then
                Cells(loop_num, "A") = Cells(loop_num, "B")
                Cells(loop_num, "B") = 0
            End If
        Next
    Next
    Call rand_num
End Sub
Sub MergeRight()
    For loop_num2 = 1 To 3
        For loop_num = 1 To 7 Step 2
            If Cells(loop_num + 1, "B") = True Then
                Cells(loop_num, "B") = Cells(loop_num, "A")
                Cells(loop_num, "A") = 0
            End If
            If Cells(loop_num + 1, "C") = True Then
                Cells(loop_num, "C") = Cells(loop_num, "B")
                Cells(loop_num, "B") = 0
            End If
             If Cells(loop_num + 1, "D") = True Then
                Cells(loop_num, "D") = Cells(loop_num, "C")
                Cells(loop_num, "C") = 0
            End If
        Next
    Next
    For loop_num = 1 To 7 Step 2
        If Cells(loop_num, "C") = Cells(loop_num, "D") Then
            Cells(loop_num, "D") = Cells(loop_num, "D") + Cells(loop_num, "C")
            Cells(9, "C") = Cells(9, "C") + Cells(loop_num, "C")
            Cells(loop_num, "C") = 0
        End If
        If Cells(loop_num, "B") = Cells(loop_num, "C") Then
            Cells(loop_num, "C") = Cells(loop_num, "C") + Cells(loop_num, "B")
            Cells(9, "C") = Cells(9, "C") + Cells(loop_num, "B")
            Cells(loop_num, "B") = 0
        End If
        If Cells(loop_num, "A") = Cells(loop_num, "B") Then
            Cells(loop_num, "B") = Cells(loop_num, "B") + Cells(loop_num, "A")
            Cells(9, "C") = Cells(9, "C") + Cells(loop_num, "A")
            Cells(loop_num, "A") = 0
        End If
    Next
    For loop_num2 = 1 To 3
        For loop_num = 1 To 7 Step 2
            If Cells(loop_num + 1, "B") = True Then
                Cells(loop_num, "B") = Cells(loop_num, "A")
                Cells(loop_num, "A") = 0
            End If
            If Cells(loop_num + 1, "C") = True Then
                Cells(loop_num, "C") = Cells(loop_num, "B")
                Cells(loop_num, "B") = 0
            End If
             If Cells(loop_num + 1, "D") = True Then
                Cells(loop_num, "D") = Cells(loop_num, "C")
                Cells(loop_num, "C") = 0
            End If
        Next
    Next
    Call rand_num
End Sub
Public Sub rand_num()
    Dim cell_row(4)
    cell_row(1) = 1
    cell_row(2) = 3
    cell_row(3) = 5
    cell_row(4) = 7
    Dim rand_number(2)
    rand_number(1) = cell_row(Int((4 - 1 + 1) * Rnd + 1))
    rand_number(2) = Int((4 - 1 + 1) * Rnd + 1)
    While (Cells(rand_number(1) + 1, rand_number(2)) = False)
    rand_number(1) = cell_row(Int((4 - 1 + 1) * Rnd + 1))
    rand_number(2) = Int((4 - 1 + 1) * Rnd + 1)
    Wend
    Cells(rand_number(1), rand_number(2)) = Int((2 - 1 + 1) * Rnd + 1)
    Randomize [Timer]
End Sub
Sub Clear()
    For loop_num = 1 To 4
        Cells(1, loop_num) = 0
        Cells(3, loop_num) = 0
        Cells(5, loop_num) = 0
        Cells(7, loop_num) = 0
    Next
    Cells(9, "C") = 0
    Call rand_num
    Call rand_num
End Sub

Все предложения приветствуются.

1 ответ
1

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

Переменные

Dim loop_num
Dim loop_num2
Dim rand_number(2) 'etc.

Хотя это и не требуется явно, переменные в VBA могут иметь типы, как и в строго типизированных языках, таких как c++. Включение типов в код дает два преимущества:

  • Повышает производительность, поскольку типизированные переменные работают быстрее и занимают меньше памяти
  • Возможно, что более важно, помогает документировать код; если мы знаем loop_num целое число или rand_num является плавающей точкой, то мы можем предположить некоторые вещи о том, для чего они могут быть использованы. Это значительно упрощает чтение, поддержку и улучшение кода.

Так что предпочитаю:

Dim loop_num As Long
Dim loop_num2 As Long
Dim rand_number(2) As Single

Пока мы это делаем, эти имена переменных не очень информативны, не так ли? Конечно loop_num говорит мне, что это, вероятно, увеличенная переменная в цикле for, но я уже вижу это, просто посмотрев! Лучше использовать описательные имена, которые сделают код самодокументированным и легким для понимания. Я действительно не знаю, для чего нужны все эти переменные, так как сейчас я сосредотачиваюсь на общих проблемах, но, возможно, что-то вроде:

Dim worksheetRow As Long
Dim iterationPassNumber As Long

…было бы лучше.

Также в нескольких местах вы не объявляете переменные; помимо того, что вы не можете объявить тип, отказ от принудительного объявления переменных может привести к пропуску опечаток, loop_counter против loop_cuonter. Добавлять Option Explicit в верхней части модуля (модулей), чтобы принудительно объявить переменную и помочь вам обнаружить опечатки.


Магические числа

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

Dim cell_row(4)
cell_row(1) = 1    'ok I guess, thanks to a fairly descriptive variable name
cell_row(2) = 3
cell_row(3) = 5
cell_row(4) = 7
Dim rand_number(2)   'um sure, 2 of them why not
rand_number(1) = cell_row(Int((4 - 1 + 1) * Rnd + 1))   'I'm at a loss... What do these numbers mean?!
rand_number(2) = Int((4 - 1 + 1) * Rnd + 1)
While (Cells(rand_number(1) + 1, rand_number(2)) = False)
rand_number(1) = cell_row(Int((4 - 1 + 1) * Rnd + 1))
rand_number(2) = Int((4 - 1 + 1) * Rnd + 1)
Wend
Cells(rand_number(1), rand_number(2)) = Int((2 - 1 + 1) * Rnd + 1)

Представьте, что вы читаете этот код в первый раз (как и я сейчас) — вы хоть представляете, что делает эта функция. Я вижу случайные числа, помещаемые в ячейки, какой-то цикл, который выглядит так, будто он никогда не остановится, я понятия не имею, какова должна быть логика этого кода. я имею в виду

Int((4 - 1 + 1) ' * [...]

Почему??

Добавление комментариев, объясняющих, почему ваш код делает то, что он делает, или, что еще лучше, переименование этих чисел в константы:

Const randomNumberScalingFactor As Long = 4 'or 4 + SomeMagicNumber - AnotherMagicNumber

… затем (например)

randomColumnIndexInSheet = Int(ColumnCount * Rnd + ColumnOffset))

СУХОЙ

Не повторяйся; MergeUp/Down иMergeLeft/Right содержат много повторений, но с немного разными комбинациями A,B,C,D. Было бы лучше использовать их как аргументы для одного Sub, чтобы вы могли повторно использовать код для выполнения нескольких задач.

Например:

For loop_num2 = 1 To 3
    For loop_num = 1 To 7 Step 2
        If Cells(loop_num + 1, "B") = True Then
            Cells(loop_num, "B") = Cells(loop_num, "A")
            Cells(loop_num, "A") = 0
        End If
        If Cells(loop_num + 1, "C") = True Then
            Cells(loop_num, "C") = Cells(loop_num, "B")
            Cells(loop_num, "B") = 0
        End If
         If Cells(loop_num + 1, "D") = True Then
            Cells(loop_num, "D") = Cells(loop_num, "C")
            Cells(loop_num, "C") = 0
        End If
    Next

For loop_num2 = 1 To 3
    For loop_num = 1 To 7 Step 2
        If Cells(loop_num + 1, "C") = True Then
            Cells(loop_num, "C") = Cells(loop_num, "D")
            Cells(loop_num, "D") = 0
        End If
        If Cells(loop_num + 1, "B") = True Then
            Cells(loop_num, "B") = Cells(loop_num, "C")
            Cells(loop_num, "C") = 0
        End If
        If Cells(loop_num + 1, "A") = True Then
            Cells(loop_num, "A") = Cells(loop_num, "B")
            Cells(loop_num, "B") = 0
        End If
    Next
Next

может стать примерно таким:

Sub MoveSidewaysWithMapping(ByVal first As String, ByVal second As String, ByVal third As String, ByVal fourth As String)
    '[...]
    For loop_num2 = 1 To 3
        For loop_num = 1 To 7 Step 2
            If Cells(loop_num + 1, third) = True Then
                Cells(loop_num, third) = Cells(loop_num, fourth)
                Cells(loop_num, fourth) = 0
            End If
            If Cells(loop_num + 1, second) = True Then
                Cells(loop_num, second) = Cells(loop_num, third)
                Cells(loop_num, third) = 0
            End If
            If Cells(loop_num + 1, first) = True Then
                Cells(loop_num, first) = Cells(loop_num, second)
                Cells(loop_num, second) = 0
            End If
        Next
    Next
    'etc...

называется как

'move left:
 MoveSidewaysWithMapping "A","B","C","D"

'move right
 MoveSidewaysWithMapping "D","C","B","A"

вы поняли (ps the Call ключевое слово как в Call rand_num устарело, оно вам больше не нужно, и это хорошо, чтобы удалить IMO, потому что это лишний беспорядок для вашего мозга)

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


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

Надеюсь, что это поможет, дайте мне знать, если вам нужны разъяснения (PS, я не уверен, сколько из этого будет для вас новым, поскольку я вижу, что вы уже задали много вопросов по CR, и это довольно общий / базовый совет, но я понимаю, что если вы просто балуетесь новым языком, вы можете потратить большую часть своего времени, пытаясь заставить его работать, и забыть некоторые важные стилистические основы!)

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *