Реализация игры 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, и это довольно общий / базовый совет, но я понимаю, что если вы просто балуетесь новым языком, вы можете потратить большую часть своего времени, пытаясь заставить его работать, и забыть некоторые важные стилистические основы!)

    Один комментарий к “Реализация игры 2048 с помощью Excel VBA”

    1. The VBA code for 2048 has some good structure but is quite repetitive. Consider refactoring the merge logic to reduce duplication.
      NYT Spelling Bee

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

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