giovedì 3 novembre 2011

[VB.NET] Generatore Random Slot

Descrizione :
Un mio generatore avanzato di numeri interi casuali, con un funzionamento stile "Slot-Machine".

+ Articolo :

Anzitutto un'immagine del generatore in funzione, per rendere rapidamente l'idea di cosa andiamo a costruire e di come dovrà girare :


Il progetto è di tipo Windows Forms, e le Classi essenziali alla compilazione sono le seguenti :
- Casella.vb : Controllo UserControl ( Controllo Utente ).
- Ruota.vb : Controllo UserControl ( Controllo Utente ).
- ModuloPublics.vb : Modulo.
- FormMain.vb : Form ( Form di avvio ).

1. Casella.vb :
E' l'elemento base. Ogni Ruota può contenere N Oggetti Casella.
Nel presente progetto ho limitato N in modo opportuno :
- N minimo = 2 ( per ovvi motivi ).
- N massimo = 10 ( da 0 a 9 ).

La struttura di Casella è semplice :
- lbl_valore : Label.

--> Codice per Casella.vb :

Public Class Casella

    'Dimensioni Fisse
    Private m_w As Integer = 170
    Private m_h As Integer = 170

    Private m_valore As Integer

    Public Property valore() As Integer
        Get
            Return m_valore
        End Get
        Set(ByVal value As Integer)
            m_valore = value
            Me.lbl_valore.Text = m_valore
        End Set
    End Property

    Protected Overrides Sub SetBoundsCore(ByVal x As Integer, ByVal y As Integer, ByVal width As Integer, ByVal height As Integer, ByVal specified As System.Windows.Forms.BoundsSpecified)

        MyBase.SetBoundsCore(x, y, m_w, m_h, specified)

    End Sub

End Class

2. Ruota.vb :
La Ruota è la Classe centrale del progetto. Provvede a caricare le caselle, a farle girare e a generare i valori casuali. Così come per Casella.vb, le dimensioni di Ruota non possono essere decise a casaccio, perciò per semplicità anche in questo caso sono bloccate.


- lbl_numruota : Label.
- pnl_ruota : Panel.
- tmr_ruota : Timer ( Interval = 20 ).

--> Codice per Ruota.vb :
Public Class Ruota

    'Membri Interni N.A.
    Private m_w As Integer = 200 'Dimensioni Fisse
    Private m_h As Integer = 200 'Dimensioni Fisse
    Private m_tmrTicks As Integer = 0
    Private m_speedMin As Integer = 80
    Private m_speedMax As Integer = 120
    Private m_speed As Integer = 0
    Private m_scarto As Integer = 0

    'Membri Interni Property
    Private m_numCaselleRuota As Integer = 10
    Private m_inGiocoRuota As Boolean = False
    Private m_esitoRuota As Integer = 0
    Private m_numRuota As Integer = 0
    Private m_velocitàRuota As Integer = 20

    Public Property NumCaselleRuota() As Integer
        Get
            Return m_numCaselleRuota
        End Get
        Set(ByVal value As Integer)
            If value < 2 Then
                m_numCaselleRuota = 2
            Else
                m_numCaselleRuota = value
            End If
            Me.ResetRuota()
        End Set
    End Property

    Public ReadOnly Property InGiocoRuota() As Boolean
        Get
            Return m_inGiocoRuota
        End Get
    End Property

    Public ReadOnly Property EsitoRuota() As Integer
        Get
            Return m_esitoRuota
        End Get
    End Property

    Public Property NumRuota() As Integer
        Get
            Return m_numRuota
        End Get
        Set(ByVal value As Integer)
            m_numRuota = value
            Me.lbl_numruota.Text = m_numRuota
        End Set
    End Property

    Public Property VelocitàRuota() As Integer
        Get
            Return m_velocitàRuota
        End Get
        Set(ByVal value As Integer)
            If value <= 0 Then
                m_velocitàRuota = 20
            Else
                m_velocitàRuota = value
            End If
            Me.tmr_ruota.Interval = m_velocitàRuota
        End Set
    End Property

    Protected Overrides Sub SetBoundsCore(ByVal x As Integer, ByVal y As Integer, ByVal width As Integer, ByVal height As Integer, ByVal specified As System.Windows.Forms.BoundsSpecified)

        MyBase.SetBoundsCore(x, y, m_w, m_h, specified)

    End Sub

    Private Sub ResetRuota()

        Me.pnl_ruota.BackColor = Color.Black
        Me.pnl_ruota.Controls.Clear()
        For i As Integer = 1 To m_numCaselleRuota
            Dim C As New Casella
            C.valore = i - 1
            Me.pnl_ruota.Controls.Add(C)
            C.Left = 10
            C.Top = (1 - i) * C.Height
        Next

    End Sub

    Public Sub Start()

        'Normalizzazione valori per SeedX Random
        Dim nr As Integer = m_numRuota * 99
        Dim ttcks As Integer = Convert.ToInt32(m_tmrTicks.ToString.PadRight(3, "9"))
        Dim er As Integer = m_esitoRuota * 99
        Dim mox As Integer = Cursor.Position.X
        Dim moy As Integer = Cursor.Position.Y

        Dim sxs As Integer = nr + er + ttcks + mox + moy

        m_speed = RandomizzaIntero(m_speedMin, m_speedMax, sxs)
        m_inGiocoRuota = True

        Me.pnl_ruota.BackColor = Color.Black
        Me.tmr_ruota.Enabled = True

    End Sub

    Private Sub tmr_ruota_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmr_ruota.Tick

        If m_tmrTicks = 999 Then
            m_tmrTicks = 1
        Else
            m_tmrTicks += 1
        End If
        Dim sxt As Integer = Convert.ToInt32(m_tmrTicks.ToString.PadRight(3, "9"))

        For Each C As Casella In Me.pnl_ruota.Controls
            C.Top = C.Top + m_speed
        Next
        For Each C As Casella In Me.pnl_ruota.Controls
            If C.Top > C.Height Then
                C.Top = C.Top - m_numCaselleRuota * C.Height
                Try
                    'Aggiungere qui un suono per slot casella
                    'My.Computer.Audio.Play(suonoSlot, AudioPlayMode.Background)
                Catch ex As Exception
                End Try
            End If
        Next

        If m_inGiocoRuota = True Then
            m_speed -= RandomizzaIntero(0, 1, sxt)
        Else
            m_scarto -= 1
            If m_scarto = 0 Then
                Me.tmr_ruota.Enabled = False
            End If
        End If

        If m_speed <= 0 And m_inGiocoRuota = True Then
            m_scarto = Integer.MaxValue
            m_inGiocoRuota = False
            Me.pnl_ruota.BackColor = Color.LimeGreen
            For Each C As Casella In Me.pnl_ruota.Controls
                If Math.Abs(C.Top) < m_scarto Then m_scarto = Math.Abs(C.Top)
            Next
            For Each C As Casella In Me.pnl_ruota.Controls
                If Math.Abs(C.Top) = m_scarto Then
                    m_esitoRuota = C.valore
                    If C.Top > 0 Then
                        m_speed = -1
                    ElseIf C.Top < 0 Then
                        m_speed = 1
                    Else 'C.Top = 0 
                        m_speed = 0
                    End If
                    Exit For
                End If
            Next
        End If

    End Sub

End Class

NOTA : Per rendere il tutto più "realistico" ho pensato alla possibilità di associare un suono ad ogni "[I]giro di slot[/I]". Il punto esatto in cui farlo è nel metodo [B]Private Sub tmr_ruota_Tick()[/B] di Ruota.vb, in corrispondenza del blocco Try/Catch, in cui ho commentato la riga di esecuzione del file suono :
                Try

                    'Aggiungere qui un suono per slot casella

                    'My.Computer.Audio.Play(suonoSlot, AudioPlayMode.Background)

                Catch ex As Exception

                End Try

3. ModuloPublics.vb :
Contiene dichiarazioni di utilità generale a livello di Progetto.

--> Codice per ModuloPublics.vb :
Module ModuloPublics

    Public percorso As String = Application.StartupPath & "\"
    Public suonoSlot As String = percorso & "slot.wav"
    Public reportFile As String = percorso & "GnrtrRndmSlt_Report.txt"

    Public ruote As New List(Of Ruota)

    Public msg As System.Text.StringBuilder
    Public esitoReport As System.Text.StringBuilder

    Public Function RandomizzaIntero(ByVal Min As Integer, ByVal Max As Integer, ByVal seedX As Integer) As Integer

        If seedX < 0 Then seedX = -seedX
        Dim gen As New System.Random(System.DateTime.Now.Millisecond + seedX)
        Return gen.Next(Min, Max + 1)

    End Function

    Public Sub CreaAccodaReport(ByVal esito As String)

        My.Computer.FileSystem.WriteAllText(reportFile, esito & Environment.NewLine, True)

    End Sub

End Module

4. FormMain.vb :

- num_numcaselle : NumericUpDown.
- cmb_velocitàruota : ComboBox ( 2 Items a Design : {Normale, Veloce} ).
- cmd_start : Button.
- tmr_check : Timer ( Interval = 500 ).

--> Codice per FormMain :
'**************************************************
'GENERATORE RANDOM SLOT - MarcoGG - 2011 **********
'VB 2010 FW 4.0 ***********************************
'**************************************************

Public Class FormMain

    Private Sub FormMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        cmb_velocitàruota.Text = cmb_velocitàruota.Items(0)

        For Each R As Control In Me.Controls
            If TypeOf R Is Ruota Then ruote.Add(R)
        Next

        'Ordinamento Ruote per righe e colonne, da sinistra a destra e dall'alto in basso
        ruote = ruote.OrderBy(Function(R) R.Top).ThenBy(Function(R) R.Left).ToList
        'Assegnazione 
        For Each R As Ruota In ruote
            R.NumCaselleRuota = num_numcaselle.Value
            R.NumRuota = ruote.IndexOf(R) + 1
        Next

    End Sub

    Private Sub cmd_start_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_start.Click

        msg = New System.Text.StringBuilder
        esitoReport = New System.Text.StringBuilder

        For Each R As Ruota In ruote
            R.Start()
        Next

        cmd_start.Enabled = False
        num_numcaselle.Enabled = False
        cmb_velocitàruota.Enabled = False

        tmr_check.Enabled = True

    End Sub

    Private Sub tmr_check_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmr_check.Tick

        For Each R As Ruota In ruote
            If R.InGiocoRuota = True Then Exit Sub
        Next

        tmr_check.Enabled = False

        For Each R As Ruota In ruote
            msg.Append("RUOTA " & R.NumRuota & " : " & R.EsitoRuota & Environment.NewLine)
            esitoReport.Append(R.EsitoRuota.ToString)
        Next

        MessageBox.Show(msg.ToString, "OK", MessageBoxButtons.OK, MessageBoxIcon.Information)
        CreaAccodaReport(esitoReport.ToString)

        cmd_start.Enabled = True
        num_numcaselle.Enabled = True
        cmb_velocitàruota.Enabled = True

    End Sub

    Private Sub cmb_velocitàruota_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmb_velocitàruota.SelectedIndexChanged

        '0.Normale - Risultato in circa 9 sec.
        '1.Veloce - Risultato in circa 4 sec.

        Dim V As Integer = 20 - cmb_velocitàruota.SelectedIndex * 10
        For Each R As Ruota In ruote
            R.VelocitàRuota = V
        Next

    End Sub

    Private Sub num_numcaselle_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles num_numcaselle.ValueChanged

        For Each R As Ruota In ruote
            R.NumCaselleRuota = num_numcaselle.Value
        Next

    End Sub

End Class


--> Alcune Note di Utilizzo :

I ) Una volta create le classi, basta eseguire una compilazione per trovare [B]Ruota[/B] tra i controlli WinForms utilizzabili. A questo punto si possono aggiungere tutte le ruote che si desiderano alla propria FormMain ( personalmente ho fatto un test con 16 Ruote senza problemi ).
Non è assolutamente necessario aggiungere Ruote da codice. Basta usare il Designer.
A tutto il resto pensa il MIO codice.

II ) Quando FormMain è pronta... START ! :D

III ) Quando tutte le Ruote avranno fornito il loro esito, apparirà una MessageBox di riepilogo.
Come ultima "chicca", verrà creato e aggiornato ad ogni Start, un semplice report txt : "GnrtrRndmSlt_Report.txt".

IV ) Possibili applicazioni ? L'unico limite è la fantasia ! :-)

+ Fine Articolo.

Un Click su "Mi Piace" è il modo migliore per ringraziare l'autore di questo articolo.



0 commenti:

Posta un commento

 
Design by Free WordPress Themes Modificato da MarcoGG