0

我已经用尽了所有选择,并且非常渴望帮助,因为我无法弄清楚代码中的错误在哪里,或者是否有我不明白的地方。

我正在尝试创建一个“我认为它是黄鼠狼!” 模仿理查德·道金斯 80 年代后期关于进化的纪录片。目标是通过遗传算法取得进展,直到算法通过变异和适应度锦标赛猜出正确答案。

现在,问题来了:

    Private Function fitnessTourney(ByVal editGuess() As Guess, ByVal popIndex As Integer, ByVal tourneySize As Integer, ByVal popNum As Integer)
    Dim randInt(tourneySize - 1) As Integer
    Dim loopCount1 As Integer = 0
    Dim fitnessWinner As New Guess
    fitnessWinner.setFitness(-50)

...而且,这个循环是我遇到严重错误的地方...

    For i = 0 To tourneySize - 1
        Randomize()
        randInt(i) = Int(Rnd() * popNum)
        While editGuess(randInt(i)).Used = True
            If loopCount1 > tourneySize Then
                loopCount1 = 0
                For i2 = 0 To popNum - 1
                    editGuess(i2).setUsed(False)
                Next
                i = -1
                Continue For
            End If
            loopCount1 += 1
            randInt(i) = Int(Rnd() * popNum)
        End While
        editGuess(randInt(i)).determineFitness(correctPhrase)
        editGuess(randInt(i)).setUsed(True)
    Next
    For i = 0 To popNum - 1
        editGuess(i).setUsed(False)
    Next

这个循环试图做的是挑选出四个随机的 editGuess 对象数组实例。这个循环试图防止一个被多次使用,因为人口正在与 10 个成员中的一个竞争(应该是 4 个被选中的候选人中的最高适应度获胜)。

严重的错误是我神秘地得到了一个无限循环,其中任何 editGuess(randInt(i)).Used 实例将始终评估为真。如果它循环太多次,我试图通过将所有实例重置为 False 来解决这个问题。

难点是我会让所有实例在调试器中评估为 False。然后,当我到达“editGuess(randInt(i)).setUsed(True)”(与“editGuess(randInt(i)).Used = True”完全相同)时,它为数组的每个成员设置这个值.

有没有人可以看到正在发生的事情?我非常接近完成这个!

这是猜测类:

    Public Class Guess
Dim Fitness As Integer
Dim strLength As Integer
Dim strArray(30) As String
Dim guessStr As String
Dim Used As Boolean
Public Sub New()
    Fitness = 0
    guessStr = ""
    strLength = 0
    Used = 0
End Sub
Public Sub determineFitness(ByVal correctPhrase As String)
    Dim lowerVal
    If guessStr.Length <= correctPhrase.Length Then
        lowerVal = guessStr.Length
    Else
        lowerVal = correctPhrase.Length
    End If
    strArray = guessStr.Split("")
    Fitness = 0 - Math.Abs(correctPhrase.Length - guessStr.Length)
    For i = 0 To lowerVal - 1
        If correctPhrase(i) = guessStr(i) Then
            Fitness = Fitness + 1
        End If
    Next
End Sub
Public Sub Mutate(ByVal mutatepercentage As Decimal, ByVal goodLetters As String)
    If mutatepercentage > 100 Then
        mutatepercentage = 100
    End If
    If mutatepercentage < 0 Then
        mutatepercentage = 0
    End If
    mutatepercentage = mutatepercentage / 100
    If Rnd() < mutatepercentage Then
        strLength = Int(Rnd() * 25) + 5
        If strLength < guessStr.Length Then
            guessStr = guessStr.Remove(strLength - 1)
        End If
    End If
    For i = 0 To strLength - 1
        If Rnd() < mutatepercentage Then
            If i < guessStr.Length Then
                guessStr = guessStr.Remove(i, 1).Insert(i, goodLetters(Int(Rnd() * goodLetters.Length)))
            Else
                guessStr = guessStr & goodLetters(Int(Rnd() * goodLetters.Length))
            End If
        End If
    Next
End Sub
Public Sub setFitness(ByVal num As Integer)
    Fitness = num
End Sub
Public Sub setStrLength(ByVal num As Integer)
    strLength = num
End Sub
Public Sub initializeText()

End Sub
Public Sub setUsed(ByVal bVal As Boolean)
    Used = bVal
End Sub

结束类

最后,这里是函数的调用位置和方式

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    population1(counter) = fitnessTourney(population1, counter, 4, 10)
    population2(counter) = fitnessTourney(population2, counter, 4, 10)
    population1(counter).Mutate(2, goodLetters)
    population2(counter).Mutate(20, goodLetters)
    Label1.Text = population1(counter).guessStr
    Label2.Text = population2(counter).guessStr
    counter += 1
    If counter > 9 Then
        counter = 0
    End If
End Sub

结束类

编辑1:谢谢你们的评论。

这是我用于表单的自定义构造函数。这用于填充使用 editGuess 传递给 FitnessTourney 函数的人口数组。

Public Sub New()
    InitializeComponent()
    Randomize()
    For i = 0 To 9
        population1(i) = New Guess
        population2(i) = New Guess
    Next
    counter = 0
    correctPhrase = "Methinks it is a weasel!"
    goodLetters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ !@#$%^&*()_+-=?></.,;\|`'~"
    goodLettersArr = goodLetters.Split("")
    For i = 0 To 9
        population1(i).setStrLength(Int(Rnd() * 25) + 5)
        population2(i).setStrLength(Int(Rnd() * 25) + 5)
        For i2 = 0 To population1(i).strLength
            population1(i).guessStr = population1(i).guessStr & goodLetters(Int(Rnd() * goodLetters.Length))
        Next
        For i2 = 0 To population2(i).strLength
            population2(i).guessStr = population2(i).guessStr & goodLetters(Int(Rnd() * goodLetters.Length))
        Next
        Label1.Text = population1(i).guessStr
        Label2.Text = population2(i).guessStr
    Next
    population1(0).guessStr = correctPhrase
    population1(0).determineFitness(correctPhrase)
End Sub
4

1 回答 1

0

我还没有彻底研究过你的所有代码,但一个大问题是你是Randomize从循环中调用的。每次调用时Randomize,它都会用当前时间重新播种随机数。因此,如果您在时钟更改之前多次调用它,您将使用该时间继续获得序列中的第一个“随机”数字,该数字将始终评估为相同的数字。生成“随机”数时,您希望尽可能少地重新播种随机数生成器。最好只在应用程序启动时播种一次。

附带说明一下,您不应该使用旧的 VB6 样式RandomizeRnd方法。这些仅在 VB.NET 中提供以实现向后兼容性。您应该改为使用Random该类。它也更容易使用。使用Random该类,您甚至不需要调用类似随机化的方法,因为它会在您实例化对象时自动为自己播种。因此,在Random类的情况下,要小心的是确保在进入可能使用它的任何循环之前只实例化一次对象。如果您Random在循环中创建一个新对象,它同样会继续生成相同的数字。

于 2013-02-19T13:21:42.353 回答