Text 9, 479 rader
Skriven 2004-11-03 06:06:00 av Randy Birch (1:278/230)
Ärende: Re: Newbie Question Conti
=================================
I had twenty minutes so some comments and code ... first, a few things wrong
....
1) there is no need to set the values of declared variables to 0 in the form
load -- this occurs naturally on the Dim'ming of the variable.
2) there is never a need to call form_load from another event
3) randomize should only be called once per running of the application (from
form_load). This seeds the random number generator; subsequent re-calling
provides no benefit
4) right now go to Tools > Options and check the option "require variable
declaration". This places an Option Explicit statement at the head of each
new form or module, and will prevent your use of variables that have not
been defined (such as the 'question' variable in the QGen routine). Do it!
5) if you do not define the data type of a variable (called type declaring)
VB's default is to use the variant data type. Variants are take much more
space than regular variables adding to overhead in your application, as well
as (often) to errors due to what is called "evil type casting". For
example, if you declare and use:
Dim x, y
x = 10
y = x + "20"
Print y
.... what should you get as the result? What if the code was:
Dim x
x = "10"
y = x + "20"
Print y
I can guarantee the results are not the same.
Now, to your questions.
The first thing to do is offload the production of your random number to
function you design specifically for this purpose. This allows you to refine
the code generating the random number as you develop the app within its own
routine, as well as prevent duplication of code - e.g. you may want or need
to generate a random number from more than once place.
Therefore, for example, instead of:
Dim A
A = Int((5 - 1 + 1) * Rnd + 1)
question = A
.... you can delete that code and instead use:
question = GetRandomNumber(1, 5)
.... where the GetRandomNumber function is defined as:
Private Function GetRandomNumber(lower As Long, upper As Long) As Long
'check to assure the input is valid
If (IsNumeric(lower) And _
IsNumeric(upper)) And _
(lower < upper) Then
'get a random number between lower and upper
GetRandomNumber = Int((upper - lower + 1) _
* Rnd(1) + lower)
End If
End Function
This does not address the second part of your request -- preventing the
duplication of numbers.
The gist of dupe checking is to
a) track the numbers generated thus far
b) generate a new number
c) see if the number from b has been used
d) if it has, go back to b
e) continue until c = false
f) check to see if all are used, in which case we're done
Here's some code you can play with for this purpose. I recommend that to see
what's going on you start a new project and add 1 list box (List1) and 1
command button (Command1) with the code below. Once you see what the code
doing you can easily move it to your project. More info on this follows the
code:
Option Explicit
Private questionsAsked(1 To 5) As Boolean
Private Sub Form_Load()
Randomize
End Sub
Private Sub Command1_Click()
Dim question As Long
question = GetRandomUnusedNumber(1, 5)
If question <> -999 Then
List1.AddItem question
Else
List1.AddItem "all questions asked"
'reset to allow new questions
Erase questionsAsked()
End If
End Sub
Private Function GetRandomNumber(lower As Long, upper As Long) As Long
'check to assure the input is valid
If (IsNumeric(lower) And _
IsNumeric(upper)) And _
(lower < upper) Then
'get a random number between lower and upper
GetRandomNumber = Int((upper - lower + 1) _
* Rnd(1) + lower)
End If
End Function
Private Function GetRandomUnusedNumber(lower As Long, upper As Long) As Long
Dim tmp As Integer
Dim cnt As Integer
Dim bAllNumbersUsed As Boolean
Do
tmp = GetRandomNumber(lower, upper)
'has it already been used?
If questionsAsked(tmp) = False Then
'the number is unused, so
'set the flag indicating it
'has been used, and return
'the number selected
questionsAsked(tmp) = True
GetRandomUnusedNumber = tmp
Exit Do
End If
'if this far there is the possibility
'that all the numbers have been used,
'so that needs to be tested too
For cnt = lower To upper
If questionsAsked(cnt) = False Then
bAllNumbersUsed = True
Exit For
End If
Next
If bAllNumbersUsed = False Then
'all have been used, so return
'a unique number indicating so
GetRandomUnusedNumber = -999
Exit Do
End If
Loop
End Function
Now, to get that into your code you want to do three things:
1) delete your current random number code from the top of your QGen routine
2) add this code to the top instead ...
question = GetRandomUnusedNumber(1, 5)
3) wrap the remaining code in that routine within an If .. Then test as per
the demo code, so the Else part executes when all the numbers have been
used, e.g. ...
question = GetRandomUnusedNumber(1, 5)
If question <> -999 Then
Select Case question
Case 1
txtQuestion.Text = "For _____ so loved the ...
ans1.Caption = "James"
ans2.Caption = "Peter"
ans3.Caption = "God"
ans4.Caption = "Jesus"
QNum = 1
Case 2 .... and so on
End Select
else
Msgbox "all questions asked"
end if
Now, with all that said there is an easier way for you to handle the select
case part. VB provides a special data type called a User-Defined Type (or
UDT) which can hold a combination of other data types and be referred to
using a common name. In your case your question, possible answers, qnumber
and the correct answer number coudl be defined in a pair of UDTs (in the
general declarations section of the form) as thus:
private type Answers
choices(1 to 4) as string
end type
private type QuestionSets
qNumber as long
correctAnswerNo as long
sQuestion as string
ans as Answers
end type
Private qset(1 to 5) as QuestionSets
Now, instead of coding the app's select case etc with hard-coded strings,
you would assign those in the form load (or a 'Reset' routine you
developed), eg...
qset(1).qnumber = 1
qset(1).correctAnswerNo = 3
qset(1).sQuestion = "For _____ so loved the world ..."
qset(1).ans.choices(1) = "James"
qset(1).ans.choices(2) = "Peter"
qset(1).ans.choices(3) = "God"
qset(1).ans.choices(4) = "Jesus"
.... and so on for questions 2 through 5. The first number in the variable
(qset(xx)) is the question number; the 1-4 in choices are the possible
answers. Now, armed with the question random number from the code above all
you need to do is directly reference the type without the UDT to achieve the
same results, e.g.
question = GetRandomUnusedNumber(1, 5)
If question <> -999 Then
txtQuestion.Text = qset(question).sQuestion
ans1.Caption = qset(question).ans.choices(1)
ans2.Caption = qset(question).ans.choices(2)
ans3.Caption = qset(question).ans.choices(3)
ans4.Caption = qset(question).ans.choices(4)
else
msgbox "all questions asked
end if
As the question number changes, those four lines of code take care of
displaying the appropriate data.
What's more, because you are also saving the correct answer number with the
UDT, your routine to check for the correct answers can also be significantly
reduced.
As it is now, you use multiple If Then statements for the answer checking
routine (AnswerGen). If you use option buttons to allow the user to select
the correct answer, make these changes ...
- delete your current ans1 through ans4 controls
- instead of individually-name controls (ans1, ans2 etc), create a control
array of option buttons by placing one option control on the form and
setting its index property to 0. Change its name to Ans, then copy and
paste four additional copies of that control to create a control array named
ans(0), ans(1), ans(2) through ans(4). Delete ans(0) since there is no "0"
question.
Now, in the code above that sets the question you need to change each line
like:
ans1.Caption = qset(question).ans.choices(1)
.... to ...
ans(1).Caption = qset(question).ans.choices(1)
In your answergen routine you can now drop all the code for testing the
response and simply do a loop from 1 to 5 to test the selected option button
using this:
TheyGotItRightIf = ans(qset(x).correctAnswerNo) = True
In other words, they got a particular question right if the value of the
ans() control array option button is True (selected) for a given question
number (x).
--
Randy Birch
MS MVP Visual Basic
http://vbnet.mvps.org/
"Uncle Whiplash" <N/A> wrote in message
news:cm74j101rvv@enews2.newsguy.com...
: To be more specific with my question:
:
:
: I'm creating a bible trivia program, with a very simple gui. Here is the
code I am working on. Anyone got any tips to point me in the right
direction of better code? Now I'm trying to figure out how to randomly
call the questions, but not call them twice in a row.
:
: TIA
:
: Uncle
:
: Dim QNum
: Dim QCorrect
: Dim QIncorrect
: Dim NumCorrect
: Dim NumIncorrect
: Private Sub AnswerGen()
:
: If QNum = 1 Then
: If Ans3.Value = True Then
: NumCorrect = NumCorrect + 1
: Else
: NumIncorrect = NumIncorrect + 1
: End If
: End If
:
: If QNum = 2 Then
: If Ans1.Value = True Then
: NumCorrect = NumCorrect + 1
: Else
: NumIncorrect = NumIncorrect + 1
: End If
: End If
:
: If QNum = 3 Then
: If Ans1.Value = True Then
: NumCorrect = NumCorrect + 1
: Else
: NumIncorrect = NumIncorrect + 1
: End If
: End If
:
: If QNum = 4 Then
: If Ans4.Value = True Then
: NumCorrect = NumCorrect + 1
: Else
: NumIncorrect = NumIncorrect + 1
: End If
: End If
:
: If QNum = 5 Then
: If Ans4.Value = True Then
: NumCorrect = NumCorrect + 1
: Else
: NumIncorrect = NumIncorrect + 1
: End If
: End If
:
: Ans1.Value = False
: Ans2.Value = False
: Ans3.Value = False
: Ans4.Value = False
:
:
: TCorrect.Caption = NumCorrect
: TIncorrect.Caption = NumIncorrect
:
: QGen
:
: End Sub
:
: Private Sub cmdGo_Click()
: AnswerGen
: End Sub
:
: Private Sub Command1_Click()
: Form_Load
: TCorrect.Caption = "0"
: TIncorrect.Caption = "0"
: GamePercent.Caption = "00%"
: End Sub
:
: Private Sub Form_Load()
: QGen
: NumCorrect = 0
: NumIncorrect = 0
: End Sub
:
: Private Sub QGen()
:
: Randomize
: Dim A
: A = Int((5 - 1 + 1) * Rnd + 1)
: Question = A
: Select Case Question
:
: Case 1
:
: txtQuestion.Text = "For _____ so loved the world that he gave his only
begotten son that whosoever believeth on him should not perish but have
everlasting life."
: Ans1.Caption = "James"
: Ans2.Caption = "Peter"
: Ans3.Caption = "God"
: Ans4.Caption = "Jesus"
: QNum = 1
:
: Case 2
:
: txtQuestion.Text = "According to the Old Testament, who was the wisest
person to ever live?"
: Ans1.Caption = "Solomon"
: Ans2.Caption = "Methusela"
: Ans3.Caption = "Moses"
: Ans4.Caption = "David"
:
: QNum = 2
:
: Case 3
:
: txtQuestion.Text = "What was Saul's wife's name?"
: Ans1.Caption = "Ahinoam"
: Ans2.Caption = "Ruth"
: Ans3.Caption = "Sarah"
: Ans4.Caption = "Sarai"
:
: QNum = 3
:
: Case 4
: QNum = 4
: txtQuestion.Text = "Who wrote the book of Ruth?"
: Ans1.Caption = "Boaz"
: Ans2.Caption = "Ruth"
: Ans3.Caption = "Naomi"
: Ans4.Caption = "Samuel"
:
: QNum = 4
:
: Case 5
: QNum = 5
: txtQuestion.Text = "Who cursed a fig tree for not bearing fruit?"
: Ans1.Caption = "Peter"
: Ans2.Caption = "Paul"
: Ans3.Caption = "Hezekiah"
: Ans4.Caption = "Jesus"
:
: QNum = 5
:
: End Select
:
: End Sub
---
ū RIMEGate(tm)/RGXPost V1.14 at BBSWORLD * Info@bbsworld.com
---
* RIMEGate(tm)V10.2á˙* RelayNet(tm) NNTP Gateway * MoonDog BBS
* RgateImp.MoonDog.BBS at 11/3/04 6:06:10 AM
* Origin: MoonDog BBS, Brooklyn,NY, 718 692-2498, 1:278/230 (1:278/230)
|