存储具有属性的二维块字段的优雅方法是什么? (没有 类)

What is an elegant way to store a 2D field of blocks, that have attributes? (Without classes)

我有一个这样的二维数组,用来存储一个小游戏的字段:

'F = Forrest -> ConsoleColor.DarkGreen, notPassable
'G = Grass   -> ConsoleColor.Green, passable
'S = Sand    -> ConsoleColor.DarkYellow, passable
'W = Water   -> ConsoleColor.Cyan, notPassable
Dim level1(,) As String = {{"F", "F", "F", "F", "G", "G", "G", "F"},
                           {"F", "F", "F", "G", "G", "G", "G", "F"},
                           {"F", "F", "G", "W", "S", "G", "G", "G"},
                           {"G", "G", "W", "S", "S", "S", "F", "W"},
                           {"G", "G", "W", "S", "S", "G", "F", "W"},
                           {"F", "F", "G", "G", "S", "G", "F", "W"},
                           {"F", "F", "G", "G", "G", "G", "F", "W"},
                           {"F", "F", "F", "F", "G", "G", "F", "W"}}

现在我想给那些瓷砖属性(不止一个)。这样我就可以使用

level(1,1).color
level(1,1).isPassable
'etc

例如。

所以我不想用字符串填充它,而是用结构填充它?但这看起来就像一场噩梦。

执行此操作的最佳方法是什么?

(我现在尽量避开类,因为我正在学习vb.net,我们还没有对类做太多。)

只需更改数组的数据类型。快速 search/replace 完成了剩下的工作。

Private field(,) As ConsoleColor
    Private Sub FillArray()
        'F = Forrest -> ConsoleColor.DarkGreen
        'G = Grass   -> ConsoleColor.Green
        'S = Sand    -> ConsoleColor.DarkYellow
        'W = Water   -> ConsoleColor.Cyan
        field = {{ConsoleColor.DarkGreen, ConsoleColor.DarkGreen, ConsoleColor.DarkGreen, ConsoleColor.DarkGreen, ConsoleColor.Green, ConsoleColor.Green, ConsoleColor.Green, ConsoleColor.DarkGreen},
                {ConsoleColor.DarkGreen, ConsoleColor.DarkGreen, ConsoleColor.DarkGreen, ConsoleColor.Green, ConsoleColor.Green, ConsoleColor.Green, ConsoleColor.Green, ConsoleColor.DarkGreen},
                {ConsoleColor.DarkGreen, ConsoleColor.DarkGreen, ConsoleColor.Green, ConsoleColor.Cyan, ConsoleColor.DarkYellow, ConsoleColor.Green, ConsoleColor.Green, ConsoleColor.Green},
                {ConsoleColor.Green, ConsoleColor.Green, ConsoleColor.Cyan, ConsoleColor.DarkYellow, ConsoleColor.DarkYellow, ConsoleColor.DarkYellow, ConsoleColor.DarkGreen, ConsoleColor.Cyan},
                {ConsoleColor.Green, ConsoleColor.Green, ConsoleColor.Cyan, ConsoleColor.DarkYellow, ConsoleColor.DarkYellow, ConsoleColor.Green, ConsoleColor.DarkGreen, ConsoleColor.Cyan},
                {ConsoleColor.DarkGreen, ConsoleColor.DarkGreen, ConsoleColor.Green, ConsoleColor.Green, ConsoleColor.DarkYellow, ConsoleColor.Green, ConsoleColor.DarkGreen, ConsoleColor.Cyan},
                {ConsoleColor.DarkGreen, ConsoleColor.DarkGreen, ConsoleColor.Green, ConsoleColor.Green, ConsoleColor.Green, ConsoleColor.Green, ConsoleColor.DarkGreen, ConsoleColor.Cyan},
                {ConsoleColor.DarkGreen, ConsoleColor.DarkGreen, ConsoleColor.DarkGreen, ConsoleColor.DarkGreen, ConsoleColor.Green, ConsoleColor.Green, ConsoleColor.DarkGreen, ConsoleColor.Cyan}}
End Sub

然后使用你的数组

Sub Main()
        FillArray()
        Console.ForegroundColor = field(1, 1)
End Sub

不需要.color。

看起来您正在尝试设置 游戏板。因此,在 OOP 中更容易将其视为对象。这是我正在慢慢研究的一个。

重要的是,与游戏板的大小相比,我的数组太大了。这使得检查有效移动不必检查数组边缘的 运行,仅检查阻塞元素。

如您所见,我还引用了 Piece,这是一个 class/object,就像您想对字段元素执行的操作一样。这仍在进行中,我正在尝试几种不同的方法来做事,因此注释掉了代码。

下面代码中的

pBoard 相当于您的 field.

Public Class Board
    Private pBoard(,) As Piece
    'Private pPieces As List(Of Piece)
    Private Const pEMPTYSPACE As PieceID = 0
    Private Const pBLOCK As PieceID = -1
    'Private pBlockPiece As New Piece(pBLOCK, PieceAlignment.Block, PieceListIndex.None)
    'Private pEmptyPiece As New Piece(pEMPTYSPACE, PieceAlignment.Null, PieceListIndex.None)


    Property UIElement As Control

    Public Structure PieceQuartet
        Dim QuartetSet As Boolean
        Dim North As Piece
        Dim South As Piece
        Dim West As Piece
        Dim East As Piece
        'Public ReadOnly Property HasValue As Boolean
        '    Get
        '        Return Not (North Is Nothing Or South Is Nothing Or West Is Nothing Or East Is Nothing)
        '    End Get
        'End Property
    End Structure

    Public Structure PieceLegalMovesQuartet
        Dim QuartetSet As Boolean
        Dim North As Boolean
        Dim South As Boolean
        Dim West As Boolean
        Dim East As Boolean
    End Structure

    Public Sub New(rows As Integer, columns As Integer) ', blockPiece As Piece)
        ReDim pBoard(rows + 2, columns + 2) ' 0-based, setting a strong boundary around the real board (1..8 or 1..10 matrix).
        ' set empty field
        For iterator1 = 0 To rows + 1
            For iterator2 = 0 To columns + 1
                pBoard(iterator1, iterator2) = EmptyPiece 'Nothing
            Next
        Next
        ' set boundaries
        For iterator1 = 0 To columns + 1
            pBoard(0, iterator1) = BlockPiece 'blockPiece
            pBoard(rows + 1, iterator1) = BlockPiece 'blockPiece
        Next
        For iterator1 = 0 To rows + 1
            pBoard(iterator1, 0) = BlockPiece 'blockPiece
            pBoard(iterator1, columns + 1) = BlockPiece 'blockPiece
        Next
    End Sub

    Public Function AddPiece(row As Integer, column As Integer, piece As Piece) As Boolean
        Dim tVacant As Boolean
        tVacant = pBoard(row, column) Is Nothing OrElse pBoard(row, column).Alignment = PieceAlignment.Null
        If tVacant Then pBoard(row, column) = piece
        Return tVacant
    End Function

    Public Sub RemovePiece(row As Integer, column As Integer)
        pBoard(row, column) = EmptyPiece 'Nothing
    End Sub

    Public Function GetPiece(row As Integer, column As Integer) As Piece
        Return pBoard(row, column)
    End Function

    Public Function Neighbours(row As Integer, column As Integer) As PieceQuartet
        Dim tQuartet As New PieceQuartet
        If row <= 0 Or column <= 0 Or row >= pBoard.GetUpperBound(1) Or column >= pBoard.GetUpperBound(2) Then
            tQuartet = Nothing ' not allowed to be on or outside the boundary of the board.
        Else
            tQuartet.QuartetSet = True
            tQuartet.North = pBoard(row - 1, column)
            tQuartet.South = pBoard(row + 1, column)
            tQuartet.West = pBoard(row, column - 1)
            tQuartet.East = pBoard(row, column + 1)
        End If
        Return tQuartet
    End Function

    Function Neighbours(tuple As Tuple(Of Integer, Integer)) As PieceQuartet
        Return Neighbours(tuple.Item1, tuple.Item2)
    End Function

End Class

我现在用一个结构解决了它,并使用解析器转换数组:

Private Structure Board
    Public color As Byte
    Public isPassable As Boolean
    'etc
End Structure

Sub Main()
    'F = Forrest -> ConsoleColor.DarkGreen, notPassable
    'G = Grass   -> ConsoleColor.Green, passable
    'S = Sand    -> ConsoleColor.DarkYellow, passable
    'W = Water   -> ConsoleColor.Cyan, notPassable
    Dim level1(,) As String = {{"F", "F", "F", "F", "G", "G"},
                               {"F", "F", "F", "G", "G", "G"},
                               {"F", "F", "G", "W", "S", "G"},
                               {"G", "G", "W", "S", "S", "S"},
                               {"G", "G", "W", "S", "S", "G"},
                               {"F", "F", "G", "G", "S", "G"},
                               {"F", "F", "G", "G", "G", "G"},
                               {"F", "F", "F", "F", "G", "G"}}

    Dim level(,) As Board
    level = ParseLevel(level1)

    'Data can now be accessed like this:
    'level(x, y).color // level(x, y).isPassable

    'Test
    For y As Integer = 0 To level.GetUpperBound(1)
        For x As Integer = 0 To level.GetUpperBound(0)
            Console.SetCursorPosition(x * 3, y)
            If level(x, y).isPassable Then
                Console.ForegroundColor = ConsoleColor.Green
            Else
                Console.ForegroundColor = ConsoleColor.Red
            End If
            Console.Write($"{level(x, y).color:00} ")
        Next
    Next

    'Keep console open until input
    Console.ReadKey()
End Sub

Private Function ParseLevel(input As String(,)) As Board(,)
    Dim output(input.GetUpperBound(1), input.GetUpperBound(0)) As Board 'swapping dimensions here

    For x As Integer = 0 To input.GetUpperBound(1)
        For y As Integer = 0 To input.GetUpperBound(0)
            Select Case input(y, x) 'swapping x and y here
                Case "F" 'Forrest
                    output(x, y).color = ConsoleColor.DarkGreen
                    output(x, y).isPassable = False
                    'etc
                Case "G" 'Grass
                    output(x, y).color = ConsoleColor.Green
                    output(x, y).isPassable = True
                    'etc
                Case "S" 'Sand
                    output(x, y).color = ConsoleColor.Yellow
                    output(x, y).isPassable = True
                    'etc
                Case "W" 'Water
                    output(x, y).color = ConsoleColor.Cyan
                    output(x, y).isPassable = False
                    'etc
            End Select
        Next
    Next

    Return output
End Function

我还注意到数组存储 x 和 y 的方式与我想象的不同。所以我在解析时交换了它们。