 |
|
 |
oakkie25 Level: Protégé
 Registered: 13-03-2008 Posts: 4
|
Loops pls help
I am a newbie and having some problems with loops
I have to create a board with 16 cells in 4 regions in 2x2 grids
Which I already have, it is like a mini sudoku game, I was trying to put random numbers in 3 of the cells (the other 13 are pre-populated) everytime you hit the new game button, currently progamhas all cells blank and only randomly places 3-4 numbers in the boards.......so
since the assignment says I only need five valid boards with 13 cells pre-populated and 3 blanks I was thinking to pre-create the 5 boards and somehow loop them everytime the new game button hit it would put up one of the 5 boards... I have no idea how I would do this... any help would be greatly appreciated.
code below for random numbers in the cells but none are prepopulated....
#Region "Declared Variables"
#End Region
Private Sub Reset()
Dim board(4, 4) As Integer
NewGame = board
Button1.Text = ""
Button2.Text = ""
Button3.Text = ""
Button4.Text = ""
Button5.Text = ""
Button6.Text = ""
Button7.Text = ""
Button8.Text = ""
Button9.Text = ""
Button10.Text = ""
Button11.Text = ""
Button12.Text = ""
Button13.Text = ""
Button14.Text = ""
Button15.Text = ""
Button16.Text = ""
End Sub
Private Sub NewGamebtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NewGamebtn.Click
Dim RandomNumber As Integer
Dim x As Integer
Dim y As Integer
Reset()
For x = 1 To 4
RandomNumber = 1 + CInt(Rnd() * 16)
Select Case RandomNumber
Case 1
If Button1.Text = "" Then
Button1.Text = x.ToString
NewGame(0, 1) = x
Else
x = x + 1
y = y + 1
End If
Case 2
If Button2.Text = "" Then
Button2.Text = x.ToString
NewGame(0, 2) = x
Else
x = x + 1
End If
Case 3
If Button3.Text = "" Then
Button3.Text = x.ToString
NewGame(0, 3) = x
Else
x = x - 1
End If
Case 4
If Button4.Text = "" Then
Button4.Text = x.ToString
NewGame(0, 4) = x
Else
x = x - 1
End If
Case 5
If Button5.Text = "" Then
Button1.Text = x.ToString
NewGame(1, 1) = x
Else
x = x - 1
End If
Case 6
If Button6.Text = "" Then
Button6.Text = x.ToString
NewGame(1, 2) = x
Else
x = x - 1
End If
Case 7
If Button7.Text = "" Then
Button7.Text = x.ToString
NewGame(1, 3) = x
Else
x = x - 1
End If
Case 8
If Button8.Text = "" Then
Button8.Text = x.ToString
NewGame(1, 4) = x
Else
x = x - 1
End If
Case 9
If Button9.Text = "" Then
Button9.Text = x.ToString
NewGame(2, 1) = x
Else
x = x - 1
End If
Case 10
If Button10.Text = "" Then
Button10.Text = x.ToString
NewGame(2, 2) = x
Else
x = x - 1
End If
Case 11
If Button11.Text = "" Then
Button11.Text = x.ToString
NewGame(2, 3) = x
Else
x = x - 1
End If
Case 12
If Button12.Text = "" Then
Button12.Text = x.ToString
NewGame(2, 4) = x
Else
x = x - 1
End If
Case 13
If Button13.Text = "" Then
Button13.Text = x.ToString
NewGame(3, 1) = x
Else
x = x - 1
End If
Case 14
If Button14.Text = "" Then
Button14.Text = x.ToString
NewGame(3, 2) = x
Else
x = x - 1
End If
Case 15
If Button15.Text = "" Then
Button15.Text = x.ToString
NewGame(3, 3) = x
Else
x = x - 1
End If
Case 16
If Button16.Text = "" Then
Button16.Text = x.ToString
NewGame(3, 4) = x
Else
x = x - 1
End If
End Select
Next x
End Sub
End Class
|
|
13-03-2008 at 03:19 PM |
|
|
stickleprojects Level: Moderator

 Registered: 09-09-2002 Posts: 1015
|
Re: Loops pls help
HI,
Lets break the problem down into pieces and deal with those.
1. Hold 16 integer values between 0 and 9
2. Display 16 integer values in a 4x4 grid
3. Each integer value adheres to a valid rule (to be defined as Sudoku rule or some such)
4. Only values that adhere to the Sudoku rules can be stored.
5. Allow the user to enter an integer value for any of the 16 positions, providing that rule 4 is still enforced.
Looking at the plural nouns in this explanation, there appear to be more than one VALUE (rules 1 & 2), but each is to be treated seperately (as implied by rules 3 & 4), therefore we need many VALUE items.
Many of 1 thing = Array
There is only 1 rule for the display (rule 2) so ignore display for the moment, but we're probably dealing with an Array type structure anyway for display.
The code to create an array in VB is:
Dim any_old_name() as data_Type
|
Start a new EXE project
Add a single textbox to the default form, and name it "txtValue"
change it's index to 0
Copy and paste this textbox 16 times, to give you 16 textboxes
Position the textboxes in a grid so that they are numbered 1-4 in the first row, 5-8 in the second, and so forth
Set the visible property of txtValue with index of 0 to false
view the code designer for the default form.
In the form declarations section enter the following:
Dim m_Values(16) as Integer
|
Rule 1 states that it must hold 16 integers, hence the numbers 16 (places to hold information) and Integer (what type of information to hold).
Rule 3 indicates that some business logic will be needed to determine what values may be stored where within our array, so lets put a skeleton function that will check this rule for us. Enter the following code into the form:
private function SudokuRuleOk (intNewValue as Integer, intPosition as integer) as boolean
' Returns TRUE if the business rule has been satisfied
' Until we find out the full rules, just return True
' intNewValue is the value to put into the values array
' intPosition is where to put the value
SudokuRuleOk = true
end function
|
.. and in good modular programming style, a function to check the business rule before setting the value...
private function SetValue (intNewValue as Integer, intPosition as integer) as boolean
' Rule 1 indicates what range of values are allowed
if intNewValue < 0 or intNewValue > 9 then
SetValue = false
else
if SudokuRuleOk (intNewvalue, intPosition) then
m_Values(intPosition) = intNewValue
SetValue = True
else
SetValue = false
end if
end if
end function
|
.. and more good practice to add a GetValue routine too ...
Private Function GetValue(intPosition As Integer) As Integer
GetValue = m_Values(intPosition)
End Function
|
At the moment, your project doesn't do very much, but there is not much left to complete (as usual, the difficulty is in the details).
Add the following skeleton functions to the form:
private sub ClearValues()
end sub
private sub GenerateValues()
end sub
private sub DisplayValues()
end sub
|
Now in the form_load, add the following to call these routines:
private sub Form_Load
ClearValues
GenerateValues
DisplayValues
end sub
|
ClearValues is a small routine that initialises the values back to -1 (-1 is invalid), key in the revised code:
private sub ClearValues
dim intIndex as integer
for intIndex = 1 to 16
ClearValue(intIndex)
next intIndex
end sub
Private Sub ClearValue(intIndex As Integer)
m_Values(intIndex) = -1
End Sub
Private Function ValueIsClear(intIndex As Integer) As Boolean
If m_Values(intIndex) = -1 Then ValueIsClear = True
End Function
|
DisplayValues lets the user "see" the grid and quite straightforward, key in the revised code
Private Sub DisplayValues()
Dim intIndex As Integer
Dim intTextBoxIndex As Integer
For intIndex = 1 To 16
intTextBoxIndex = GetTextBoxIndexFromValueIndex(intIndex)
If ValueIsClear(intIndex) = False Then
Me.txtValue(intTextBoxIndex).Text = m_Values(intIndex)
Else
Me.txtValue(intTextBoxIndex).Text = ""
End If
Next intIndex
End Sub
Private Function GetTextBoxIndexFromValueIndex(intIndex As Integer) As Integer
GetTextBoxIndexFromValueIndex = intIndex
End Function
Private Function GetValueIndexFromTextBoxIndex(intIndex As Integer) As Integer
GetValueIndexFromTextBoxIndex = intIndex
End Function
|
The DisplayValues will not display invalid values, so our initial grid will be blank on screen until we generate values for it. I've also added the helper functinos to convert between the array index and the textbox on screen.
These are trivial helper functions at the moment, but we'll get to that later.. suffice to say, it's good practice
The following implementation of GenerateValues tries random valid numbers against the business rule (sudoku) and if successful, stores the value in the array
private sub GenerateValues
dim intIndex as integer
dim intValue as integer
dim intNumberOfTries as integer
Randomize
' Loop through the positions in the array
for intindex = 1 to 16
' Make sure we don't have an infinite loop, by counting the number of times
' we tried to put a value in
intNumberOfTries = 0
do
' Get the next value to try (between 0 and 9)
intValue = GetRandomValue(0,9)
' Increment the number of times we've tried
intNumberOfTries = intNumberOfTries +1
' Repeat the loop until SetValue succeeds, or we run out of tries
loop until (SetValue (intValue, intIndex) = True) or intNumberOfTries > 100
if intNumberOfTries >= 100 then
msgbox "GenerateValues aborted. Couldn't find a value for position " & intIndex
exit sub
end if
next
end sub
Private Function GetRandomValue(intMin As Integer, intMax As Integer) As Integer
Dim intValue As Integer
intValue = CInt((intMax - intMin) * Rnd + intMin)
GetRandomValue = intValue
End Function
|
TIP: I've put some code in (intNumberOfTries) to stop the loop continuing forever. You should always do this if your loop doesn't have a fixed number of execution times
If you run your project now, you should see your form, with 16 textboxes on it with numbers in between 0 and 9 (ish).
Now, part of the spec was to randomly clear out some of these values for the user to complete.
so add the following function, and modify the form_load to call it before display
private sub RandomlyClearSomeValues (intHowManyToClear as integer)
dim intIndex as Integer
dim intNumberCleared as integer
dim intNumberOfTries as integer
intNumberCleared=0
do while (intNumberCleared < intHowManyToClear) and (intNumberOfTries < 100)
' Get a random number between 0 and 16
intIndex = GetRandomValue (1,16)
' If its not already cleared
if ValueIsClear(intIndex)=false then
ClearValue (intIndex)
intNumberCleared = intNumberCleared+1
intNumberOfTries = 0
else
intNumberOfTries = intNumberOfTries+1
end if
loop
if intNumberOfTries >= 100 then
msgbox "RandomlyClearSomeVAlues aborted. infinite loop!
end if
end sub
Private Function ValueIsClear(intIndex As Integer) As Boolean
If m_Values(intIndex) = -1 Then ValueIsClear = True
End Function
Private Sub Form_Load()
ClearValues
GenerateValues
RandomlyClearSomeValues 3
DisplayValues
End Sub
|
At the moment, the user can type any old number/text into each text box, so we should tell them when something is wrong.
To detect when a user has changed a value you should use the validate event on the textbox, so add the following code, to check the value and tell the user if they are incorrect:
Private Sub txtValue_Validate(Index As Integer, Cancel As Boolean)
Dim intValue As Integer
Dim strUserText As String
Dim intIndex As Integer
strUserText = Me.txtValue(Index).Text
' Translate the index of the textbox into the position in the array
intIndex = GetValueIndexFromTextBoxIndex(index)
' If the user has entered some text
If Len(strUserText) > 0 Then
If IsNumeric(strUserText) Then
intValue = CInt(strUserText)
Else
MsgBox "You must enter a number"
Cancel = True
Exit Sub
End If
' Tell them if they are wrong
If SetValue(intValue, Index) = False Then
MsgBox "You cannot put that value there!"
Cancel = True
End If
Else
ClearValue (intIndex)
End If
End Sub
|
Nearly there. The only remaining implementation is to populate the empty function SudokuRuleOk
The following functions should help:
Private Function GetRowIndexFromArrayIndex(ByVal intIndex As Integer, ByVal intColsPerRow As Integer) As Integer
Dim intRow As Integer
Dim intRemainder As Integer
intIndex = intIndex - 1
' Get the remainder after the division
intRemainder = intIndex Mod intColsPerRow
' Remove the remainder, means that index is now in "rows"
intIndex = intIndex - intRemainder
intRow = intIndex / intColsPerRow
GetRowIndexFromArrayIndex = intRow
End Function
Private Function GetColIndexFromArrayIndex(ByVal intIndex As Integer, ByVal intColsPerRow As Integer) As Integer
Dim intCol As Integer
Dim intRow As Integer
intRow = GetRowIndexFromArrayIndex(intIndex, intColsPerRow)
intCol = intIndex - (intColsPerRow * intRow) - 1
GetColIndexFromArrayIndex = intCol
End Function
|
They return a zero-based number to indicate the row or col (ie. the first row is rowindex 0, first col is colindex 0)
You should be able to use these functions from within the SudokuRuleOk routine to determine whether the value is correct or not.
I've implemented 1 of the rules for you.
Private Function SudokuRuleOk(intNewValue As Integer, intPosition As Integer) As Boolean
' Returns TRUE if the business rule has been satisfied
' Until we find out the full rules, just return True
' intNewValue is the value to put into the values array
' intPosition is where to put the value
Dim intRow As Integer
Dim intCol As Integer
Dim blnOk As Boolean
intRow = GetRowIndexFromArrayIndex(intPosition, 4)
intCol = GetColIndexFromArrayIndex(intPosition, 4)
blnOk = True
' First rule, value cannot already be in row or col
' Find the value in the array
Dim intValueFound As Integer
Dim intFRow As Integer
Dim intFCol As Integer
Dim intIndex As Integer
If blnOk Then
For intIndex = 1 To 16
intValueFound = GetValue(intIndex)
If intNewValue = intValueFound Then
intFRow = GetRowIndexFromArrayIndex(intIndex, 4)
intFCol = GetColIndexFromArrayIndex(intIndex, 4)
If intFRow = intRow Or intFCol = intCol Then
blnOk = False
Exit For
End If
End If
Next
End If
If blnOk Then
' Check another rule
End If
SudokuRuleOk = blnOk
End Function
|
Hope this helps
Kieron
____________________________
Build it better, faster, quicker, easier.. then fix it (non-offical MS mission statement)
|
|
19-03-2008 at 09:15 AM |
|
|
oakkie25 Level: Protégé
 Registered: 13-03-2008 Posts: 4
|
Re: Loops pls help
Yes this helps alot, thanks!
I was going about it a totally different way since my last code didn't work, I was trying to use arrays to pregenerate 5 boards with 13 cells filled in and 3 blank and everytime the "new game" button was hit a new pregenerated bd pops up! I am going to check out the code you showed me because I am not having much luck with the arrays either.
Thanks again you were a big help!
oakkie
|
|
19-03-2008 at 08:03 PM |
|
|
oakkie25 Level: Protégé
 Registered: 13-03-2008 Posts: 4
|
Re: Loops pls help
I do have 2 questions can I use buttons instead of Textboxes?
I tried naming it btnValue instead of textValue and it gives error stating it is not part of the form?
and also how do I incorporate the "new game button" in the code so when I hit the new game button a new game pops up with 13 pre-populated cells and 3 blank ones
note: my game only calls for numbers 1- 4 which I already changed in the code
|
|
21-03-2008 at 12:34 AM |
|
|
|
|
 |
 |