I had answered a fellow who wanted to know how you can write a word scramble in Visual Basic. For this problem, I will provide two examples, one in VB6, and the other in VB .Net. The VB6 version will simple take the string in a textbox and scramble the letters. The VB.Net version will take a string, separate each word, and scramble the words themselves. I thought this would be an interesting demonstration since working with character elements in VB strings has the tendency to be a bit of a pain. This will demonstrate using a character array to work with individual elements, using the StrConv function in VB6 to convert to a byte array, and using the StringBuilder class in VB.Net for more efficient string appends.
Below is the VB6 version 1:
Option Explicit
Private Sub CommandButton1_Click()
Dim x, pos As Integer
Dim char As String
Dim s() As String
'Re-dimension the array to the size of the string in the textbox
ReDim s(Len(TextBox1.Text)) As String
'Assign each character to an element in the array
For x = 1 To Len(TextBox1.Text)
s(x) = Mid(TextBox1.Text, x, 1)
Next
'For 1 to the size of the array, mix up the letters
For x = 1 To UBound(s)
'Pos is a random place in the array
pos = Int((Len(TextBox1.Text) - 1) * Rnd) + 1
'temporarily assign the temp character to our random letter
char = s(pos)
'Swap the characters, using the temp character to assign from the overwriten
'element
s(pos) = s(x)
s(x) = char
Next
'Clear the textbox and concat the value with each element in the array
TextBox1.Text = ""
For x = 1 To UBound(s)
TextBox1.Text = TextBox1.Text & s(x)
Next
End Sub
Private Sub UserForm_Click()
Randomize
End Sub
The above is a fairly simple. Take two elements in an array, and swaps them. This is pretty much the same as the VB.Net version below with a few exceptions. Alternatively, we can use the StrConv function to eliminate having to go through each element in the string and assign it to the array. This method is demonstrated below:
VB6 Version 2 Code:
Private Sub Command1_Click()
Dim b() As Byte
Dim temp As Byte
Dim s As String
Dim x, pos As Integer
s = Text1.Text
ReDim b(Len(s)) As Byte
b = StrConv(s, vbFromUnicode)
For x = LBound(b) To UBound(b)
pos = Int((Len(Text1.Text) - 1) * Rnd) + 1
temp = b(pos)
b(pos) = b(x)
b(x) = temp
Next
s = StrConv(b, vbUnicode)
End Sub
The above code is much cleaner in my opinion. In the StrConv() function, notice the use of the parameter vbFromUnicode and vbUnicode. The reason for this is that VB uses Unicode strings. Had we just assigned b the value of s, we would have an array twice as large, and the scramble code would need to take into account the additional byte that Unicode characters contain, otherwise we would have some undefined results.
Below is the VB .Net version 1. I used the first algorithm from above as the model:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Initialize the random number generator
Randomize()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim s_array() As String = Split(TextBox1.Text, " ")
Dim s, final As String
Dim c As Char
Dim x, i, pos As Integer
'We need to cycle through the array of strings set in the dim statement above
For x = LBound(s_array) To (UBound(s_array))
'If the current place in the array is greater than the lower bound and less than or
'equal to the last string, then we need to add a space in between words
If (x > LBound(s_array)) And (x <= UBound(s_array)) Then
TextBox1.Text = TextBox1.Text & " "
End If
'For each letter in the current word, cycle through and use a
'simple character swap with a random position in the string
For i = 0 To (s_array(x).Length - 1)
'Get random position in the string
pos = CInt(Int(s_array(x).Length * Rnd()))
'Store the character so swap temporarily so it does not get lost
c = s_array(x).Chars(pos)
'Set current letter with the letter to get swapped
s_array(x) = s_array(x).Insert(pos, s_array(x).Chars(i))
s_array(x) = s_array(x).Remove(pos + 1, 1)
'Set current letter to the stored letter, completing the swap
s_array(x) = s_array(x).Insert(i, c)
s_array(x) = s_array(x).Remove(i + 1, 1)
Next
'If we are on the first word, clear the textbox and set to current element
'in the array, otherwise concat the textbox with current value
If (x = LBound(s_array)) Then
TextBox1.Text = s_array(x)
Else
TextBox1.Text = TextBox1.Text & s_array(x)
End If
Next
End Sub
End Class
While the above code works, there are a few issues with it. First, just like in the VB6 version, the handling of individual characters is not clean. We can assign the string to an array of characters directly and be better off. Also, the use of inserts and removes for individual characters are ugly and inefficient. .Net strings are immutable, so for each insert and remove, a copy of the string is created, making things very slow. Fortunately .Net offers the StringBuilder class for doing just this sort of operation. Below is the modified .Net version taking advantage of the direct assignment to a character array and using the StringBuilder class.
Below is the Vb.Net code modified (Version 2):
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim s_array() As String = Split(TextBox1.Text, " ")
Dim b() As Char
Dim c As Char
Dim x, i, pos As Integer
Dim tmpStrngBldr As System.Text.StringBuilder = New System.Text.StringBuilder()
'We need to cycle through the array of strings set in the dim statement above
For x = LBound(s_array) To (UBound(s_array))
'If the current place in the array is greater than the lower bound and less than or
'equal to the last string, then we need to add a space in between words
If (x > LBound(s_array)) And (x <= UBound(s_array)) Then
tmpStrngBldr.Append(" ")
End If
b = s_array(x)
'For each letter in the current word, cycle through and use a
'simple character swap with a random position in the string
For i = LBound(b) To UBound(b)
'Get random position in the string
pos = CInt(Int(UBound(b) * Rnd()))
'Store the character so swap temporarily so it does not get lost
c = b(pos)
'Set current letter with the letter to get swapped
b(pos) = b(i)
'Set current letter to the stored letter, completing the swap
b(i) = c
Next
‘Store the swaped word in our stringbuilder
tmpStrngBldr.Append(b)
Next
'assign the textbox the value in our string builder
TextBox1.Text = tmpStrngBldr.ToString
tmpStrngBldr = Nothing
End Sub
Subscribe to:
Post Comments (Atom)
1 comment:
nice work! For the VB.net version, can you make it so that the array scrambles the words givin in the textbox as the whole words, not scrambled versions of the word. For example "Dog Cat Tree Climb" are in the textbox. How would i change the code so that the array keeps the words intact, but just changes the order of the words for example like this.... "Cat Climb Dog Tree" ?
Post a Comment