存储具有属性的二维块字段的优雅方法是什么? (没有 类)
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 的方式与我想象的不同。所以我在解析时交换了它们。
我有一个这样的二维数组,用来存储一个小游戏的字段:
'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 的方式与我想象的不同。所以我在解析时交换了它们。