在 Visual Basic 中为 Go 游戏填充颜色
Flood fill for the game Go in Visual Basic
我是 Visual Basic 的业余爱好者。我正在尝试重新创建 Go 的游戏,并且我已经创建了棋盘并且能够在网格的交叉点上放置石头。
我现在想开始捕获被包围的石头。我在网上看过,发现洪水填充是解决此问题的最佳方法。但是,我已经在网上看了好几天了,但找不到任何可以使用或操作来创建它的东西。我不懂任何其他编程语言,所以我不能使用 Java 等的代码位。我发现的 Visual Basic 的位信息对我来说意义不大,因为我还是个初学者。
我曾尝试自己开始,从"If one stone were to be captured"的情况开始。我有两个板的表示,一个声明为 "grid",另一个声明为 "placed_stone".
"Grid"是用户点击放置棋子的实际棋盘。 placed_stone 是这个板的副本,但我用“0”、“1”和“2”分别表示空、黑和白。我正在使用 Windows Forms 来重新创建这个游戏。这是我为捕获石头而编写的代码段:
Private Sub Panel1_Click(sender As Object, e As EventArgs) Handles Panel1.Click
Dim board As Panel = DirectCast(sender, Panel)
' Figure out where the user clicked: min = 0, max = (gridsize - 1)
Dim pt As Point = board.PointToClient(Cursor.Position)
Dim colWidth As Integer = (1 / (GridSize + 1)) * board.Size.Width
Dim rowHeight As Integer = (1 / (GridSize + 1)) * board.Size.Height
Dim gridPosition As New Point(Math.Min(Math.Max((pt.X / colWidth) - 1, 0), GridSize - 1), Math.Min(Math.Max((pt.Y / rowHeight) - 1, 0), GridSize - 1))
Dim newcoordsx As Integer
Dim newcoordsy As Integer
' Now do something with gridPosition:
If Not Grid(gridPosition.X)(gridPosition.Y).HasValue Then 'If gird(x,y) is empty
illegalmovelbl.Hide() ' Hides the "Illegal Move" Label
If cp = True Then ' If current player is Black
这是我卡住的部分,我意识到针对每种情况的编码都将花费太长时间。我设法为一种情况编写了代码:
newcoordsx = gridPosition.X + 1
If placed_stone(newcoordsx, gridPosition.Y) = 2 Then
newcoordsy = gridPosition.Y + 1
If placed_stone(newcoordsx, newcoordsy) = 1 Then
newcoordsy = gridPosition.Y - 1
If placed_stone(newcoordsx, newcoordsy) = 1 Then
newcoordsx = gridPosition.X + 2
If placed_stone(newcoordsx, gridPosition.Y) = 1 Then
newcoordsx = gridPosition.X + 1
Grid(gridPosition.X)(gridPosition.Y) = True 'Place a black stone at Grid(x,y)
Grid(newcoordsx)(gridPosition.Y) = Nothing
placed_stone(newcoordsx, gridPosition.Y) = 0
pass = False
cp = False
passbtn.BackColor = Color.White 'The passbutton changes colour to white
passbtn.ForeColor = Color.Black 'The passbutton font changes colour to black
End If
End If
End If
End If
'Grid(gridPosition.X)(gridPosition.Y) = True ' Place a black stone at Grid(x,y)
'placed_stone(gridPosition.X, gridPosition.Y) = 1
'pass = False
'cp = False
'passbtn.BackColor = Color.White ' The passbutton changes colour to white
'passbtn.ForeColor = Color.Black ' The passbutton font changes colour to black
ElseIf cp = False Then ' If current player is White
Grid(gridPosition.X)(gridPosition.Y) = False ' Place a white stone at Grid(x,y)
placed_stone(gridPosition.X, gridPosition.Y) = 2
pass = False
cp = True
passbtn.BackColor = Color.Black ' The passbutton changes colour to black
passbtn.ForeColor = Color.White ' The passbutton font changes colour to white
End If
ElseIf Grid(gridPosition.X)(gridPosition.Y).HasValue Then ' If gird(x,y) isn't empty
illegalmovelbl.Show() ' Shows the "Illegal Move" Label
MsgBox("Place your stone in a vacant point") ' Displays error message
End If
board.Invalidate() ' Force the board to redraw itself
End Sub
我尝试过使用 Wikipedia 的算法进行洪水填充,我了解其工作原理,但我不知道如何在 Visual Basic 中对其进行编程。
Flood-fill (node, target-color, replacement-color):
1. If target-color is equal to replacement-color, return.
2. If the color of node is not equal to target-color, return.
3. Set the color of node to replacement-color.
4. Perform Flood-fill (one step to the south of node, target-color, replacement-color).
Perform Flood-fill (one step to the north of node, target-color, replacement-color).
Perform Flood-fill (one step to the west of node, target-color, replacement-color).
Perform Flood-fill (one step to the east of node, target-color, replacement-color).
5. Return.
当然,在围棋中,不是在区域中着色,而是在捕获时必须移除石头,并且不是从刚放置捕获的石头开始填充,而是从最近的石头开始你想捕获的石头。
能否简单介绍一下如何在Visual Basic中使用flood fill,以及如何将其应用到围棋游戏中?
如果有人想查看整个代码,请告诉我。如果有任何建议,我将不胜感激!
我不熟悉 rules/game-play 围棋游戏,所以我不确定您想要完成什么,但是如果您认为填充式算法是什么你需要,那么我至少可以就如何做到这一点提供一些建议。您的代码需要做的主要事情是将其分解为更细粒度的方法。单击面板时您尝试执行的步骤是什么?肯定不止一件事。有许多不同的事情正在发生——每一个都可以通过一个单独的专用方法来执行。例如,如果您有这样的方法:
Private Function GetGridPosition(board As Panel, cursorPosition As Point) As Point
Dim pt As Point = board.PointToClient(Cursor.Position)
Dim colWidth As Integer = (1 / (GridSize + 1)) * board.Size.Width
Dim rowHeight As Integer = (1 / (GridSize + 1)) * board.Size.Height
Return New Point(Math.Min(Math.Max((pt.X / colWidth) - 1, 0), GridSize - 1), Math.Min(Math.Max((pt.Y / rowHeight) - 1, 0), GridSize - 1))
End Function
然后,在 Panel1_Click
事件处理程序中,您可以大大简化代码的开头,如下所示:
Private Sub Panel1_Click(sender As Object, e As EventArgs) Handles Panel1.Click
Dim board As Panel = DirectCast(sender, Panel)
Dim gridPosition As Point = GetGridPosition(board, Cursor.Position)
' ...
当然,这会使代码更有条理且更易于阅读,但这并不能使您更接近洪水填充算法,对吗?好吧,是的,这大部分是正确的,但是组织和可读性本身就是有价值的目标,所以无论如何让我们继续......我们需要执行的下一步是让玩家移动,然后,如果移动成功,我们需要切换到另一个播放器。那么,让我们首先创建切换玩家的方法:
Private Sub SwitchPlayer()
pass = False
cp = Not cp
passbtn.BackColor = GetPlayerForeColor(cp)
passbtn.ForeColor = GetPlayerBackColor(cp)
End Sub
Private Function GetPlayerForeColor(player as Boolean) As Color
If player Then
Return Color.White
Else
Return Color.Black
End If
End Function
Private Function GetPlayerBackColor(player as Boolean) As Color
If player Then
Return Color.Black
Else
Return Color.White
End If
End Function
你会注意到我偷偷 (Chrome 自动拼写告诉我这不是一个词,但我的美国成长经历不同) 一对我在那里的其他方法。我敢肯定他们的目的很明显。但就此打住。很明显?您会注意到注释消失了,但代码的含义仍然很明显。这就是我们所说的自我记录代码的意思。注释在必要时很棒,但在完全不需要时更好。
所以,假设现在我们有这样的方法:
Private Function MakeMove(gridPosition As Grid, player As Boolean) As Boolean
' return true if the move was successful
End Function
那么整个 Panel1_Click
事件处理程序可能如下所示:
Private Sub Panel1_Click(sender As Object, e As EventArgs) Handles Panel1.Click
Dim board As Panel = DirectCast(sender, Panel)
Dim gridPosition As Point = GetGridPosition(board, Cursor.Position)
If MakeMove(gridPosition, cp) Then
SwitchPlayer()
Else
ShowIllegalMoveMessage()
End If
End Sub
Private Sub ShowIllegalMoveMessage()
illegalmovelbl.Show() 'Shows the "Illegal Move" Label
MsgBox("Place your stone in a vacant point") 'Displays error message
End Sub
好的,现在我们进入正题。那么,搬家时需要采取哪些步骤呢?好吧,我不知道,因为我不了解游戏。我把这个练习留给你,但是,如果你的倾向是正确的,并且你需要某种洪水填充算法,那么这可能意味着你需要某种可以一遍又一遍地重复的 PlaceStone
动作,所以这应该是它自己的方法:
Private Sub PlaceStone(gridPosition As Point, player As Boolean)
' Do something
End Sub
显然 Do something
是所有这一切的关键部分,也是我无法帮助您的部分。但是,如果它是一个洪水填充算法,我可以给你一个非常重要的提示。在它要在那里做的所有其他事情中,它将再次调用 PlaceStone
,传递给它一个不同的网格位置(周围位置之一)。例如,像这样:
Private Sub PlaceStone(gridPosition As Point, player As Boolean)
Dim north As Position = GetNorthPosition(gridPosition)
If Floodable(north, player) Then
PlaceStone(north, player)
End If
' ...
End Sub
当一个方法像那样调用自身时,我们称之为递归。但是,除非您开始将代码拆分为专用的小方法,每个方法都有自己的封装任务,否则您无法真正添加递归。所以,首先组织起来,然后添加递归。
我是 Visual Basic 的业余爱好者。我正在尝试重新创建 Go 的游戏,并且我已经创建了棋盘并且能够在网格的交叉点上放置石头。
我现在想开始捕获被包围的石头。我在网上看过,发现洪水填充是解决此问题的最佳方法。但是,我已经在网上看了好几天了,但找不到任何可以使用或操作来创建它的东西。我不懂任何其他编程语言,所以我不能使用 Java 等的代码位。我发现的 Visual Basic 的位信息对我来说意义不大,因为我还是个初学者。
我曾尝试自己开始,从"If one stone were to be captured"的情况开始。我有两个板的表示,一个声明为 "grid",另一个声明为 "placed_stone".
"Grid"是用户点击放置棋子的实际棋盘。 placed_stone 是这个板的副本,但我用“0”、“1”和“2”分别表示空、黑和白。我正在使用 Windows Forms 来重新创建这个游戏。这是我为捕获石头而编写的代码段:
Private Sub Panel1_Click(sender As Object, e As EventArgs) Handles Panel1.Click
Dim board As Panel = DirectCast(sender, Panel)
' Figure out where the user clicked: min = 0, max = (gridsize - 1)
Dim pt As Point = board.PointToClient(Cursor.Position)
Dim colWidth As Integer = (1 / (GridSize + 1)) * board.Size.Width
Dim rowHeight As Integer = (1 / (GridSize + 1)) * board.Size.Height
Dim gridPosition As New Point(Math.Min(Math.Max((pt.X / colWidth) - 1, 0), GridSize - 1), Math.Min(Math.Max((pt.Y / rowHeight) - 1, 0), GridSize - 1))
Dim newcoordsx As Integer
Dim newcoordsy As Integer
' Now do something with gridPosition:
If Not Grid(gridPosition.X)(gridPosition.Y).HasValue Then 'If gird(x,y) is empty
illegalmovelbl.Hide() ' Hides the "Illegal Move" Label
If cp = True Then ' If current player is Black
这是我卡住的部分,我意识到针对每种情况的编码都将花费太长时间。我设法为一种情况编写了代码:
newcoordsx = gridPosition.X + 1
If placed_stone(newcoordsx, gridPosition.Y) = 2 Then
newcoordsy = gridPosition.Y + 1
If placed_stone(newcoordsx, newcoordsy) = 1 Then
newcoordsy = gridPosition.Y - 1
If placed_stone(newcoordsx, newcoordsy) = 1 Then
newcoordsx = gridPosition.X + 2
If placed_stone(newcoordsx, gridPosition.Y) = 1 Then
newcoordsx = gridPosition.X + 1
Grid(gridPosition.X)(gridPosition.Y) = True 'Place a black stone at Grid(x,y)
Grid(newcoordsx)(gridPosition.Y) = Nothing
placed_stone(newcoordsx, gridPosition.Y) = 0
pass = False
cp = False
passbtn.BackColor = Color.White 'The passbutton changes colour to white
passbtn.ForeColor = Color.Black 'The passbutton font changes colour to black
End If
End If
End If
End If
'Grid(gridPosition.X)(gridPosition.Y) = True ' Place a black stone at Grid(x,y)
'placed_stone(gridPosition.X, gridPosition.Y) = 1
'pass = False
'cp = False
'passbtn.BackColor = Color.White ' The passbutton changes colour to white
'passbtn.ForeColor = Color.Black ' The passbutton font changes colour to black
ElseIf cp = False Then ' If current player is White
Grid(gridPosition.X)(gridPosition.Y) = False ' Place a white stone at Grid(x,y)
placed_stone(gridPosition.X, gridPosition.Y) = 2
pass = False
cp = True
passbtn.BackColor = Color.Black ' The passbutton changes colour to black
passbtn.ForeColor = Color.White ' The passbutton font changes colour to white
End If
ElseIf Grid(gridPosition.X)(gridPosition.Y).HasValue Then ' If gird(x,y) isn't empty
illegalmovelbl.Show() ' Shows the "Illegal Move" Label
MsgBox("Place your stone in a vacant point") ' Displays error message
End If
board.Invalidate() ' Force the board to redraw itself
End Sub
我尝试过使用 Wikipedia 的算法进行洪水填充,我了解其工作原理,但我不知道如何在 Visual Basic 中对其进行编程。
Flood-fill (node, target-color, replacement-color):
1. If target-color is equal to replacement-color, return.
2. If the color of node is not equal to target-color, return.
3. Set the color of node to replacement-color.
4. Perform Flood-fill (one step to the south of node, target-color, replacement-color).
Perform Flood-fill (one step to the north of node, target-color, replacement-color).
Perform Flood-fill (one step to the west of node, target-color, replacement-color).
Perform Flood-fill (one step to the east of node, target-color, replacement-color).
5. Return.
当然,在围棋中,不是在区域中着色,而是在捕获时必须移除石头,并且不是从刚放置捕获的石头开始填充,而是从最近的石头开始你想捕获的石头。
能否简单介绍一下如何在Visual Basic中使用flood fill,以及如何将其应用到围棋游戏中?
如果有人想查看整个代码,请告诉我。如果有任何建议,我将不胜感激!
我不熟悉 rules/game-play 围棋游戏,所以我不确定您想要完成什么,但是如果您认为填充式算法是什么你需要,那么我至少可以就如何做到这一点提供一些建议。您的代码需要做的主要事情是将其分解为更细粒度的方法。单击面板时您尝试执行的步骤是什么?肯定不止一件事。有许多不同的事情正在发生——每一个都可以通过一个单独的专用方法来执行。例如,如果您有这样的方法:
Private Function GetGridPosition(board As Panel, cursorPosition As Point) As Point
Dim pt As Point = board.PointToClient(Cursor.Position)
Dim colWidth As Integer = (1 / (GridSize + 1)) * board.Size.Width
Dim rowHeight As Integer = (1 / (GridSize + 1)) * board.Size.Height
Return New Point(Math.Min(Math.Max((pt.X / colWidth) - 1, 0), GridSize - 1), Math.Min(Math.Max((pt.Y / rowHeight) - 1, 0), GridSize - 1))
End Function
然后,在 Panel1_Click
事件处理程序中,您可以大大简化代码的开头,如下所示:
Private Sub Panel1_Click(sender As Object, e As EventArgs) Handles Panel1.Click
Dim board As Panel = DirectCast(sender, Panel)
Dim gridPosition As Point = GetGridPosition(board, Cursor.Position)
' ...
当然,这会使代码更有条理且更易于阅读,但这并不能使您更接近洪水填充算法,对吗?好吧,是的,这大部分是正确的,但是组织和可读性本身就是有价值的目标,所以无论如何让我们继续......我们需要执行的下一步是让玩家移动,然后,如果移动成功,我们需要切换到另一个播放器。那么,让我们首先创建切换玩家的方法:
Private Sub SwitchPlayer()
pass = False
cp = Not cp
passbtn.BackColor = GetPlayerForeColor(cp)
passbtn.ForeColor = GetPlayerBackColor(cp)
End Sub
Private Function GetPlayerForeColor(player as Boolean) As Color
If player Then
Return Color.White
Else
Return Color.Black
End If
End Function
Private Function GetPlayerBackColor(player as Boolean) As Color
If player Then
Return Color.Black
Else
Return Color.White
End If
End Function
你会注意到我偷偷 (Chrome 自动拼写告诉我这不是一个词,但我的美国成长经历不同) 一对我在那里的其他方法。我敢肯定他们的目的很明显。但就此打住。很明显?您会注意到注释消失了,但代码的含义仍然很明显。这就是我们所说的自我记录代码的意思。注释在必要时很棒,但在完全不需要时更好。
所以,假设现在我们有这样的方法:
Private Function MakeMove(gridPosition As Grid, player As Boolean) As Boolean
' return true if the move was successful
End Function
那么整个 Panel1_Click
事件处理程序可能如下所示:
Private Sub Panel1_Click(sender As Object, e As EventArgs) Handles Panel1.Click
Dim board As Panel = DirectCast(sender, Panel)
Dim gridPosition As Point = GetGridPosition(board, Cursor.Position)
If MakeMove(gridPosition, cp) Then
SwitchPlayer()
Else
ShowIllegalMoveMessage()
End If
End Sub
Private Sub ShowIllegalMoveMessage()
illegalmovelbl.Show() 'Shows the "Illegal Move" Label
MsgBox("Place your stone in a vacant point") 'Displays error message
End Sub
好的,现在我们进入正题。那么,搬家时需要采取哪些步骤呢?好吧,我不知道,因为我不了解游戏。我把这个练习留给你,但是,如果你的倾向是正确的,并且你需要某种洪水填充算法,那么这可能意味着你需要某种可以一遍又一遍地重复的 PlaceStone
动作,所以这应该是它自己的方法:
Private Sub PlaceStone(gridPosition As Point, player As Boolean)
' Do something
End Sub
显然 Do something
是所有这一切的关键部分,也是我无法帮助您的部分。但是,如果它是一个洪水填充算法,我可以给你一个非常重要的提示。在它要在那里做的所有其他事情中,它将再次调用 PlaceStone
,传递给它一个不同的网格位置(周围位置之一)。例如,像这样:
Private Sub PlaceStone(gridPosition As Point, player As Boolean)
Dim north As Position = GetNorthPosition(gridPosition)
If Floodable(north, player) Then
PlaceStone(north, player)
End If
' ...
End Sub
当一个方法像那样调用自身时,我们称之为递归。但是,除非您开始将代码拆分为专用的小方法,每个方法都有自己的封装任务,否则您无法真正添加递归。所以,首先组织起来,然后添加递归。