I'm new to these boards so if I'm doing anything wrong here please let me know.
I'm currently trying to produce a word game in VB 6, very much like Word Challenge on Facebook for those familiar. ATM I'm making a test program which loads a dictionary file into a 2D array so (4, 1) is 4 letter word, (5, 1) 5 letter word and so on. Code below
Code:
Option Explicit
Dim WordDictionary As String
Dim DictionaryWord As String
Dim Words() As String
Dim Index(3 To 6) As Integer
Dim WordLength As Integer
Dim ArrayUpper As Integer
Dim ArrayLower As Integer
Dim ArrayRange As Integer
Private Sub Form_Load()
WordDictionary = App.Path & "\WordDictionaryFiles\Dashed.txt"
End Sub
Private Sub cmdTest_Click()
Index(3) = 1
Index(4) = 1
Index(5) = 1
Index(6) = 1
Open WordDictionary For Input As #1
Do While Not EOF(1)
Line Input #1, DictionaryWord
WordLength = Len(DictionaryWord)
ReDim Preserve Words(3 To 6, 1 To Index(WordLength)) As String
Words(WordLength, Index(WordLength)) = DictionaryWord
Index(WordLength) = Index(WordLength) + 1
Loop
Close #1
From my tests this should work (setting watches on the different variables as filling in a grid as it loads each cell of the array). However from here I made a test in order to return the 3 to 6 letter words each individually on click of each command button. This seems to work fine for the 3 letter words but 4, 5 and 6 are all presenting issues, printing just one word and a series of blank lines. Code as follows,
Code:
Private Sub cmd3Letters_Click()
ArrayLower = LBound(Words, 2)
ArrayUpper = UBound(Words, 2)
For ArrayRange = ArrayLower To ArrayUpper
Form1.Print Words(3, ArrayRange)
Next ArrayRange
End Sub
Private Sub cmd4Letters_Click()
ArrayLower = LBound(Words, 2)
ArrayUpper = UBound(Words, 2)
For ArrayRange = ArrayLower To ArrayUpper
Form1.Print Words(4, ArrayRange)
Next ArrayRange
End Sub
Private Sub cmd5Letters_Click()
ArrayLower = LBound(Words, 2)
ArrayUpper = UBound(Words, 2)
For ArrayRange = ArrayLower To ArrayUpper
Form1.Print Words(5, ArrayRange)
Next ArrayRange
End Sub
Private Sub cmd6Letters_Click()
ArrayLower = LBound(Words, 2)
ArrayUpper = UBound(Words, 2)
For ArrayRange = ArrayLower To ArrayUpper
Form1.Print Words(6, ArrayRange)
Next ArrayRange
End Sub
Atm I'm pretty stumped and I've been thinking on this for several days, I have a suspicion that I need to use a variable (jagged) array, but I am not aware of how to do this. I've attatched a zip with the files so you can view the program in it's entirety.
I work with arrays, but do not much experience using
ReDim Preserve -- I typically oversize the array and just
populate it.
Nonetheless, the highlighted line from your loop seems
to be problematic ...
Code:
Open WordDictionary For Input As #1
Do While Not EOF(1)
Line Input #1, DictionaryWord
WordLength = Len(DictionaryWord)
ReDim Preserve Words(3 To 6, 1 To Index(WordLength)) As String
Words(WordLength, Index(WordLength)) = DictionaryWord
Index(WordLength) = Index(WordLength) + 1
Loop
Close #1
Perhaps it should just read as
Code:
ReDim Preserve Words(WordLength, 1 To Index(WordLength)) As String
That is, instead of trying to ReDim all of the 1st-D elements, only
ReDim the 1st-D element that applies.
Hmm thanks for the advice, just trying to think it through atm,
Spoo: "ReDim Preserve Words(WordLength, 1 To Index(WordLength)) As String" I think I remember thinking this through, but I will try to implement it when I have access to the program again tommorow.
I think I might have dismissed it worrying that this would say preserve the values in 5, 1 to 5 for example, but then clear 3 and 4, _'s values. Am I wrong here.
And opus: I'm trying to think of this in a visual code sense, can you give a brief example as to how I would have to code this so just the last dimension is Redim preserved or would this clear the other cells in the array?
In honestly think I should note I am a bit of a VB newbie, mostly self taught in the odd hours I have spare. Some code comes to me kinda naturally where I can logically think things through. But it doesn't seem to be working here.
I've had variable/jagged arrays mentioned for storing/managing information like this from some and it seems to make sense but I have never attempted, not can I find any basic guide to show how to get started about implementing a one.
As I mentioned, I don't work much with ReDim Preserve, but
the more I think about it, I'm inclined to think that my suggestion
will have little (if any) effect.
Granted, per Opus's comment, you are properly only trying to
increase "last dimension", but I am now thinking that the problem
may lie in your cmdButton subs -- the "print out" subs.
Have you checked to see if the array itself is properly populated?
That is, do Words(4,2), Words(4,3) etc contain values? You can
quickly do this by looking in the Locals Window.
Well I tested to ensure that the words were being loaded into the array correctly by setting a watch to stop the program each time the value of "Words(3, Index(WordLength))", Words(4, Index(WordLength)) and so on changed, I then added the word that is showed on each stop a drawn representation of the array in the relevant cells.
After doing my drawn representation of the array came out as I had expected, and to confuse me more so, the 3 letter words all print in the exact order that my drawn representation shows that it should... so that must be right... This is why I'm having so much confusion. I'm sorry if I'm overlooking your suggestion of how to check the values, but again I will be looking when I have the opportunity. It is just very much unusual, in my opinion, the way that it's not seeming to work for any other word length but the 3.
Open WordDictionary For Input As #1
Do While Not EOF(1)
Line Input #1, DictionaryWord
WordLength = Len(DictionaryWord)
ReDim Preserve Words(3 To 6, 1 To Index(WordLength)) As String
Words(WordLength, Index(WordLength)) = DictionaryWord
Index(WordLength) = Index(WordLength) + 1
Loop
Close #1
The problem with this code is that the array will sometimes become smaller. If you already have five 4-letter words when you get your third 3-letter word, the array will go from (3 To 6, 1 To 5) down to (3 To 6, 1 To 3). This causes loss of data, and this is why some of your longer words are missing.
You can easily avoid making the array smaller by testing the upper bound first:
Code:
ReDim Words(3 To 6, 1 To 1)
Open WordDictionary For Input As #1
Do While Not EOF(1)
Line Input #1, DictionaryWord
WordLength = Len(DictionaryWord)
If Index(WordLength) > UBound(Words, 2) Then
ReDim Preserve Words(3 To 6, 1 To Index(WordLength))
End If
Words(WordLength, Index(WordLength)) = DictionaryWord
Index(WordLength) = Index(WordLength) + 1
Loop
Close #1
That should solve your immediate problem. There is, however, no need to separate the words by length. You'll be better off will all of the words in a one-dimensional array.
Alternatively, if you do want to separate by length you could use a UDT array with a Dynamic Array as a member, rather than a 2D array. Also, 'ReDim Preserve' is fairly slow so minimising the number times you use it is a good idea.
The code below is an example of using a UDT and 'over dimensioning' the Dynamic Arrays such that they only have to be ReDim Preserve(d) once. The use of Constants for the Minimum and Maximum number of characters in a word gives an opportunity to extend easily. (eg if you want to include 7 letter words, just change the Constant 'MAX' to 7)
Code:
Option Explicit
Private Const MIN As Integer = 3 'Minimum number of characters in a word
Private Const MAX As Integer = 6 'Maximum number of characters in a word
Private Type Words
Count As Long
List() As String
End Type
Private uWords(MIN To MAX) As Words
Private Sub Command1_Click()
Dim intFile As Integer
Dim intI As Integer
Dim lngI As Long
Dim intLen As Integer
Dim strData As String
Dim strRecords() As String
intFile = FreeFile
'
' Open the data file, read the entire contents
' and split into records
'
Open "C:\dashed.txt" For Input As intFile
strData = Input(LOF(intFile), intFile)
Close intFile
strRecords = Split(strData, vbNewLine)
'
' 'Over Dimension' each dynamic array in the Words List(s)
'
For intI = MIN To MAX
ReDim uWords(intI).List(UBound(strRecords))
Next intI
'
' Populate the Words List(s)
' Note that any blank lines in the data file are ignored
' and any word less than 'MIN' or greater than 'MAX' characters
' (after removing leading and / or trailing spaces) is ignored
'
For lngI = 0 To UBound(strRecords)
strRecords(lngI) = Trim$(strRecords(lngI))
If strRecords(lngI) <> vbNullString Then
intLen = Len(strRecords(lngI))
If intLen >= MIN And intLen <= MAX Then
uWords(intLen).List(uWords(intLen).Count) = strRecords(lngI)
uWords(intLen).Count = uWords(intLen).Count + 1
End If
End If
Next lngI
'
' ReDim the Words List(s) to the actual number
' of elements populated
'
For intI = MIN To MAX
If uWords(intI).Count > 0 Then
ReDim Preserve uWords(intI).List(uWords(intI).Count - 1)
End If
Next intI
Command2.Enabled = True
MsgBox "UDT Populated"
End Sub
Private Sub Command2_Click()
'
' Output the UDT to the Immediate Window
'
Dim intI As Integer
Dim lngJ As Long
For intI = MIN To MAX
Debug.Print CStr(intI) & " Letter Words:(" & CStr(uWords(intI).Count) & ")"
If uWords(intI).Count > 0 Then
For lngJ = 0 To UBound(uWords(intI).List)
Debug.Print , uWords(intI).List(lngJ)
Next lngJ
End If
Debug.Print
Next intI
End Sub
Private Sub Form_Load()
Command2.Enabled = False
End Sub
Last edited by Doogle; Oct 14th, 2011 at 01:07 AM.
Reason: Added Constants