|
-
Oct 3rd, 2010, 10:38 PM
#1
Thread Starter
New Member
[RESOLVED]DiceRoller Function
Hey all,
I have a function as such:
Code:
Function THRoller(ByVal Swings As Integer) As Integer
Dim Hits, Misses As Integer 'variables for attack results
Do Until RollCount = 0 'RollCount taken from initiative winners AttacksBox
THRollVal = CInt(Int((6 * Rnd()) + 1))
If THRollVal >= THN Then 'if the roll is greater or equal to the to hit number, it hits
Hits = Hits + 1
RollCount = RollCount - 1
ElseIf THRollVal < THN Then 'if the roll is less than the to hit number, it misses
Misses = Misses + 1
RollCount = RollCount - 1
End If
Loop
MsgBox("Rollcount is " & RollCount & "and hits equal " & Hits) 'why do you keep showing me one number???
End Function
I'm sending the function a user determined value from another section. My problem is, it only seems to be generating one number, and listing each roll as a hit. How can I get a new roll(repeating values are fine) for each loop iteration?
My apologies if the answer is obvious. I've only been programming for a week or so. Any other tips for cleaner/faster practices would be appreciated as well.
Last edited by Reichvier; Oct 16th, 2010 at 02:26 PM.
Reason: Clarity/detail
-
Oct 3rd, 2010, 11:12 PM
#2
Re: DiceRoller Function
You're passing in 'Swings' and never using it and you're using 'RollCount' that isn't declared in that code. I'm guessing that you should be referring to Swings rather than RollCount in your method.
Also, what's the point of the ElseIf here:
Code:
If THRollVal >= THN Then 'if the roll is greater or equal to the to hit number, it hits
Hits = Hits + 1
RollCount = RollCount - 1
ElseIf THRollVal < THN Then 'if the roll is less than the to hit number, it misses
Misses = Misses + 1
RollCount = RollCount - 1
End If
If the first condition is False then the second MUST be True, so there's no point even testing it. It should just be If...Else. You know for a fact that RollCount is going to be decremented either way so why put it in both blocks? Just do it once after the End If.
I'm very tired of seeing rank beginners using code like this:
Code:
THRollVal = CInt(Int((6 * Rnd()) + 1))
to generate random numbers. It's not your fault. It's the fault of those teaching you, whether they be school teachers, book authors or those who post examples on the web. Everyone who wants to generate random numbers in VB.NET should be using the Random class. You create one Random object and then, every time you need a random number, you call its Next method. For an example of how that can be encapsulated into rolling dice, follow the CodeBank link in my signature and check out my thread on Dice.
-
Oct 3rd, 2010, 11:46 PM
#3
Re: DiceRoller Function
also, from a fundamental standpoint, don't functions return a value?
-
Oct 4th, 2010, 09:50 PM
#4
Thread Starter
New Member
Re: DiceRoller Function
 Originally Posted by stateofidleness
also, from a fundamental standpoint, don't functions return a value?
I'm hoping so, as the only thing I need from the function is the number of hits.
jmcilhinney:
I found your post on rolling dice. I'm trying to make sense of it, but I have no experience with classes. I would simply copy and paste it, but the example code:
Code:
Dim dice As New DieCollection
'Add two six-sided dice.
dice.Add(New Die(6))
dice.Add(New Die(6))
'Roll all the dice.
Dim rolls As Integer() = dice.RollAll()
'Display the values rolled.
For Each roll As Integer In rolls
MessageBox.Show(roll.ToString(), "You rolled a ...")
Next
isn't exactly what I need. Is there a way I can add a number of dice equal to the Swings variable in my first post? I don't know how many dice will need to be rolled each combat, so it needs to be dynamic.
If the solution is simply a loop, how do I remove the dice at the end of the calculation? Is that done by garbage collection somehow?
Thanks again.
-
Oct 4th, 2010, 10:09 PM
#5
Re: DiceRoller Function
In a real-world app, something like my code is the way to go. You may or may not use my classes, depending on whether this is a learning exercise and, if so, whether your instructor would accept it. I pointed you to my code for an example of using the Random class.
If you want to use my code then yes, you would use a For loop to add the appropriate number of dice to the collection. There's no specific cleanup required when you're done.
-
Oct 6th, 2010, 05:45 PM
#6
Thread Starter
New Member
Re: DiceRoller Function
Ok, so I have my calculation block as such :
Code:
If YourAverageIniBox.Text > TheirAverageIniBox.Text Then 'if Your initiative is greater than Their initiative, set the x and y to-hit values
THGx = YAWS 'see variable module
THGy = TAWS 'see variable module
ToHit(THGx, THGy) = THN
IniWinTeam = 0 'sets Yours as initiative winner
RollCount = YourAttacksBox.Text 'sets the RollCount variable for DiceRoller for Your number of attacks
Dim dice As New DieCollection
Dim remover As Integer
Dim rolls As Integer() = dice.RollAll() 'Roll all the dice.
Do Until RollCount = 0
dice.Add(New Die(6))
remover = remover + 1
Loop
For Each roll As Integer In rolls
If roll < THN Then 'if a roll is less than the to-hit number, the roll misses and is ignored
'should I put something here or will it act as expected and ignore the result?
ElseIf roll >= THN Then 'if a roll hits, it is counted and will be used in a later part of the program
Hits = Hits + 1
End If
Next
Do While RollCount = 0 And remover > 0
dice.Remove() 'the compiler doesn't like this. it asks for an argument, but I don't know what to send it.
remover = remover - 1 'I was hoping to remove one die in the collection per loop here, but instead it curls up and cries.
Loop
What I aim to do(in case comments aren't clear) is to roll a number of six sided dice equal to the RollCount variable. Action needs to be taken for each roll result, not the total of all rolls. Each roll that is greater than or equal to the to-hit number hits, and will be used later to roll wounds.
In jmcilhinney's codebank post on dice, located here, he says
 Originally Posted by jmcilhinney
Obviously for a game you would assign your DieCollection to a member variable and then call it's RollAll method each time a player had to roll the dice. You would not create a new DieCollection and Die objects each time you wanted to roll.
Honestly, I don't have any clue how to do that, so I tried the loop method at the bottom of the block. Unfortunately, I don't know what argument to send it, so it throws exceptions at run time. Any ideas?
Thanks again.
-
Oct 6th, 2010, 06:12 PM
#7
Re: DiceRoller Function
A local variable is one declared inside a method. A member variable is one declared outside a method. You are doing the opposite of my recommendation, i.e. you are creating a new DieCollection every time you want to use one. Declare a member variable of type DieCollection and create a single DieCollection. Use that member variable and that object every time you want a DieCollection. Also, add dice to the DieCollection once only.
Look at your code:
Code:
Dim dice As New DieCollection
Dim remover As Integer
Dim rolls As Integer() = dice.RollAll() 'Roll all the dice.
Do Until RollCount = 0
dice.Add(New Die(6))
remover = remover + 1
Loop
You create the DieCollection, roll all the dice it contains, then you add dice to it. Wouldn;t it be better to add the dice to the collection first? Otherwise, there's no dice to role when you call RollAll.
-
Oct 6th, 2010, 06:36 PM
#8
Thread Starter
New Member
Re: DiceRoller Function
Ah, the problem is that I must be able to alter the amount of dice being rolled each time the calculate button is hit.
Every time the calculate button(the function of which is to simply take values from text boxes and do math) is pressed, the calculations will be performed, depending on who wins the Initiative comparison(values of 0, 1, and 3 as "Your" win, "Their" win, or tie). Then a number of troops will make attacks(RollCount) Which will miss(and be ignored) or hit(Hits). Hits will then be rolled as Wounds, which I'll work on after Hits work.
Last edited by Reichvier; Oct 6th, 2010 at 06:46 PM.
-
Oct 6th, 2010, 06:49 PM
#9
Re: DiceRoller Function
If the number of dice to be rolled will change each time then it makes sense to use a different DieCollection each time. There's no need to worry about removing dice though. Once you've used a DieCollection you can simply discard it. You might declare a method to create a DieCollection with a specific number of dice:
vb.net Code:
Private Function CreateDieCollection(ByVal diceCount As Integer) As DieCollection Dim dice As New DieCollection For count = 1 To diceCount dice.Add(New Die(6)) Next Return dice End Function
or you might encapsulate that functionality into the DieCollection class itself:
vb.net Code:
Public Sub New() End Sub Public Sub New(ByVal diceCount As Integer, ByVal sideCount As Integer) For count = 1 To diceCount Me.Add(New Die(sideCount)) Next End Sub
-
Oct 9th, 2010, 01:27 PM
#10
Thread Starter
New Member
Re: DiceRoller Function
Thanks for all your help so far Jmc.
I've run into an error thats stonewalled me, since it won't allow the program to compile. I have the following block(Hits is declared in a different module that holds all my Public variables):
VB Code:
Dim dice As New DieCollection
Dim rolls As Integer() = dice.RollAll()
For Each roll As Integer In rolls
If roll < THN Then 'if a roll is less than the to-hit number, the roll misses and is ignored
'should I put somethere here or will it act as expected?
ElseIf roll >= THN Then 'if a roll hits, it is counted and will be used in a later part of the program
Hits = Hits + 1 'see variables module
End If
Next
The compiler puts squiggles under the word "dice," and shows the error "Error 1 Argument not specified for parameter 'RollCount' of 'Public Sub New(RollCount As Integer)'.
The only thing it could be referencing is this(I removed the sidecount portion of the DieCollection addition, as this game only rolls six sided dice):
VB Code:
Public Class DieCollection
Inherits System.Collections.ObjectModel.Collection(Of Die)
Public Sub New(ByVal RollCount As Integer)
Dim count As Integer
For count = 1 To RollCount
Me.Add(New Die(6))
Next
End Sub
Public Function RollAll() As Integer()
Dim values(Me.Count - 1) As Integer
For index As Integer = 0 To values.GetUpperBound(0)
values(index) = Me.Items(index).Roll()
Next
Return values
End Function
End Class
So I am rather confused. How do I specify an argument for RollCount when RollCount is a variable?
Thanks for your patience.
-
Oct 9th, 2010, 08:01 PM
#11
Re: DiceRoller Function
RollCount isn't a variable. RollCount is a parameter. How do you usually pass parameter values to a constructor? Here's a clue. This is the Die constructor:
Code:
Public Sub New(ByVal faceCount As Integer)
and this is how you're invoking it in your own code:Now, if this is your DieCollection constructor:
Code:
Public Sub New(ByVal RollCount As Integer)
how do you suppose you're going to invoke it?
-
Oct 16th, 2010, 02:28 PM
#12
Thread Starter
New Member
Re: [RESOLVED]DiceRoller Function
All figured out. Thanks for all your help Jmc.
-
Oct 16th, 2010, 03:19 PM
#13
Re: [RESOLVED]DiceRoller Function
Some old code I found (maybe based on JMC's link?)
Code:
Public Class Form1
'requires a Button and two picture boxes
Dim foo As New Dice
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
'foo = New Dice
If foo.Count <> 2 Then
Dim d1 As New Die(PictureBox1)
Dim d2 As New Die(PictureBox2)
foo.AddDie(d1) 'add die to dice collection
foo.AddDie(d2)
End If
'roll the dice
Dim stpw As New Stopwatch
Dim rollAround As Integer = 500 'how long the dice roll around
stpw.Reset()
stpw.Start()
Do
foo.RollAll()
Me.Refresh()
Loop While stpw.ElapsedMilliseconds < rollAround
End Sub
Private Sub _Paint(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs)
' Create string to draw.
If DirectCast(sender, PictureBox).Tag.ToString <> "" Then
Dim drawString As String = DirectCast(sender, PictureBox).Tag.ToString
' Create font and brush.
Dim drawFont As New Font("Arial", 24)
Dim drawBrush As New SolidBrush(Color.Black)
' Create point for upper-left corner of drawing.
Dim drawRect As Rectangle = e.ClipRectangle
' Draw string to screen.
e.Graphics.DrawString(drawString, drawFont, drawBrush, drawRect)
End If
End Sub
Public Class Dice
Public Shared _rnd As Random 'only need one random
Private _lDie As List(Of Die) 'store n die
Public Sub New() 'set up
If _rnd Is Nothing Then
_rnd = New Random
End If
Me._lDie = New List(Of Die)
End Sub
Public Sub AddDie(ByVal aDie As Die)
'add a die to list
Me._lDie.Add(aDie)
End Sub
Public Sub RollAll()
'roll all the dies
For Each d As Die In Me._lDie
'randomly change the die value
If _rnd.Next(0, 2) = 1 OrElse d.Roll = -1 Then
d.Roll = _rnd.Next(1, 7)
d.Display()
End If
Next
End Sub
ReadOnly Property Count As Integer
Get
Return Me._lDie.Count
End Get
End Property
End Class
Public Class Die
Private _vDie As Integer = -1 'indicates the die has never been rolled
Private _disp As PictureBox
Private _newV As Integer
Public Sub New(ByVal display As PictureBox)
Me._disp = display
End Sub
Property Roll() As Integer
Get
Return Me._vDie
End Get
Set(ByVal value As Integer)
Me._vDie = value
End Set
End Property
Public Sub Display()
Me._disp.Tag = Me.Roll
Me._disp.Invalidate()
End Sub
End Class
Private Sub Form1_Shown(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Shown
'set up picture boxes
For Each c As Control In Me.Controls
If TypeOf c Is PictureBox Then
Dim pb As PictureBox = DirectCast(c, PictureBox)
pb.Image = New Bitmap(pb.Width, pb.Height)
pb.BackColor = Color.White
pb.Tag = ""
AddHandler pb.Paint, AddressOf _Paint
End If
Next
End Sub
End Class
-
Oct 16th, 2010, 04:04 PM
#14
Re: [RESOLVED]DiceRoller Function
For a broader understanding of pseudo random numbers take the advice in the the first part of the first post here http://social.msdn.microsoft.com/For...8-97c21017998f.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|