Results 1 to 14 of 14

Thread: [RESOLVED]DiceRoller Function

  1. #1

    Thread Starter
    New Member
    Join Date
    Oct 2010
    Posts
    6

    [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

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    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.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  3. #3

  4. #4

    Thread Starter
    New Member
    Join Date
    Oct 2010
    Posts
    6

    Re: DiceRoller Function

    Quote Originally Posted by stateofidleness View Post
    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.

  5. #5
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    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.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  6. #6

    Thread Starter
    New Member
    Join Date
    Oct 2010
    Posts
    6

    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
    Quote Originally Posted by jmcilhinney View Post
    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.

  7. #7
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    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.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  8. #8

    Thread Starter
    New Member
    Join Date
    Oct 2010
    Posts
    6

    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.

  9. #9
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    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:
    1. Private Function CreateDieCollection(ByVal diceCount As Integer) As DieCollection
    2.     Dim dice As New DieCollection
    3.  
    4.     For count = 1 To diceCount
    5.         dice.Add(New Die(6))
    6.     Next
    7.  
    8.     Return dice
    9. End Function
    or you might encapsulate that functionality into the DieCollection class itself:
    vb.net Code:
    1. Public Sub New()
    2. End Sub
    3.  
    4. Public Sub New(ByVal diceCount As Integer, ByVal sideCount As Integer)
    5.     For count = 1 To diceCount
    6.         Me.Add(New Die(sideCount))
    7.     Next
    8. End Sub
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  10. #10

    Thread Starter
    New Member
    Join Date
    Oct 2010
    Posts
    6

    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:
    1. Dim dice As New DieCollection
    2.         Dim rolls As Integer() = dice.RollAll()
    3.         For Each roll As Integer In rolls
    4.             If roll < THN Then                                  'if a roll is less than the to-hit number, the roll misses and is ignored
    5.                 'should I put somethere here or will it act as expected?
    6.             ElseIf roll >= THN Then                             'if a roll hits, it is counted and will be used in a later part of the program
    7.                 Hits = Hits + 1                                     'see variables module
    8.             End If
    9.         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:
    1. Public Class DieCollection
    2.         Inherits System.Collections.ObjectModel.Collection(Of Die)
    3.  
    4.         Public Sub New(ByVal RollCount As Integer)
    5.             Dim count As Integer
    6.             For count = 1 To RollCount
    7.                 Me.Add(New Die(6))
    8.             Next
    9.         End Sub
    10.  
    11.         Public Function RollAll() As Integer()
    12.             Dim values(Me.Count - 1) As Integer
    13.  
    14.             For index As Integer = 0 To values.GetUpperBound(0)
    15.                 values(index) = Me.Items(index).Roll()
    16.             Next
    17.  
    18.             Return values
    19.         End Function
    20.  
    21.     End Class

    So I am rather confused. How do I specify an argument for RollCount when RollCount is a variable?

    Thanks for your patience.

  11. #11
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    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:
    Code:
    New Die(6)
    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?
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  12. #12

    Thread Starter
    New Member
    Join Date
    Oct 2010
    Posts
    6

    Re: [RESOLVED]DiceRoller Function

    All figured out. Thanks for all your help Jmc.

  13. #13
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    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
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  14. #14
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    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.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width