How to add enum to a list - vb.net

I have a class named Card with a property of CardNumbers
Private _number As CardNumbers
Public Property Number() As CardNumbers
Get
Return _number
End Get
Set(ByVal value As CardNumbers)
_number = value
End Set
End Property
I have this enum of cards numbers that was used as the property of Card.
Enum CardNumbers
Ace = 1
Two = 2
Three = 3
Four = 4
Five = 5
Six = 6
Seven = 7
Eight = 8
Nine = 9
Ten = 10
Jack = 11
Queen = 12
King = 13
End Enum
Now, I have a loop to insert CardNumbers into a Dim Cards As New List(Of Card), but I do not know how to add each of the CardNumbers into the List. Been researching awhile. Can anyone help? Thanks.
UPDATE:
I have now this code to add create an instance of the class Card and then add to the list of Card called Cards:
Dim c As New Card()
For Each n As CardNumber.CardNumbers In [Enum].GetValues(GetType(CardNumber.CardNumbers))
c.Number = n
Cards.Add(c)
Next
But then, I get a NullReferenceException error.

Some classes that can be used for cards and decks.
Public Enum aRank
Two = 2
Three = 3
Four = 4
Five = 5
Six = 6
Seven = 7
Eight = 8
Nine = 9
Ten = 10
Jack = 11
Queen = 12
King = 13
Ace = 14
End Enum
Public Enum aSuit
Clubs
Diamonds
Hearts
Spades
End Enum
Class Card
Private _rank As aRank
Private _suit As aSuit
Public ReadOnly Property Rank As aRank
Get
Return Me._rank
End Get
End Property
Public ReadOnly Property Suit As aSuit
Get
Return Me._suit
End Get
End Property
Public Sub New(rank As aRank, suit As aSuit)
Me._rank = rank
Me._suit = suit
End Sub
End Class
Class DeckOfCards
Private _deck As List(Of Card)
Private Shared _prng As New Random
Public Sub New()
Me.Shuffle()
End Sub
Public Sub Shuffle()
Me._deck = New List(Of Card)
For Each r As aRank In [Enum].GetValues(GetType(aRank))
For Each s As aSuit In [Enum].GetValues(GetType(aSuit))
Me._deck.Add(New Card(r, s))
Next
Next
End Sub
Public Function GetCard() As Card
If Me.CardsRemaining > 0 Then
Dim idx As Integer = DeckOfCards._prng.Next(Me._deck.Count)
Dim rvcard As Card = Me._deck(idx)
Me._deck.RemoveAt(idx)
Return rvcard
Else
'''TODO
'code for no more cards error
Return Nothing
End If
End Function
Public ReadOnly Property CardsRemaining As Integer
Get
Return Me._deck.Count
End Get
End Property
End Class

Say you have this line:
Dim n As CardNumbers = 1
Then this will get you "Ace":
Dim s As String = [Enum].GetName(GetType(CardNumbers), n)

You can create a list of 13 cards by doing it like this:
Dim list As New List(Of Card)((From item In [Enum].GetValues(GetType(CardNumbers)) Select New Card With {.Number = CType(item, CardNumbers)}))
With that being said, you might also want to look at my answer in this SO post:
Vb conceptual understanding of creating objects within a class

Related

VB.net - Sorting only one column in datagridview

I'm populating a DataGridView from an Excel file, and trying to sort only ONE column of my choice, other columns should remain as-is. How can it be achieved? Should the component be changed to something else, in case it is not possible in DataGridView?
I Created a List of my custom class, and this class will handle the sorting based on my preference (Randomization in this case)
Public Class Mylist
Implements IComparable(Of Mylist)
Private p_name As String
Private r_id As Integer
Public Property Pname() As String 'This will hold the contents of DGV that I want sorted
Get
Return p_name
End Get
Set(value As String)
p_name = value
End Set
End Property
Public Property Rid() As Integer 'This will be the basis of sort
Get
Return r_id
End Get
Set(value As Integer)
r_id = value
End Set
End Property
Private Function IComparable_CompareTo(other As Mylist) As Integer Implements IComparable(Of Mylist).CompareTo
If other Is Nothing Then
Return 1
Else
Return Me.Rid.CompareTo(other.Rid)
End If
End Function
End Class
Then a Button which will sort the contents:
Dim selcol = xlView.CurrentCell.ColumnIndex
Dim rand = New Random()
Dim x As Integer = 0
Dim plist As New List(Of Mylist)
Do While x < xlView.Rows.Count
plist.Add(New Mylist() With {
.Pname = xlView.Rows(x).Cells(selcol).Value,
.Rid = rand.Next()
})
x += 1
Loop
plist.Sort()
x = 0
Do While x < xlView.Rows.Count
xlView.Rows(x).Cells(selcol).Value = plist.ElementAt(x).Pname
x += 1
Loop
xlView.Update()
plist.Clear()
I'm open to any changes to code, as long as it achieves the same result.
Here is the simpler version. Pass the column index will do like Call SortSingleColum(0)
Private Sub SortSingleColumn(x As Integer)
Dim DataCollection As New List(Of String)
For i = 0 To dgvImport.RowCount - 2
DataCollection.Add(dgvImport.Item(x, i).Value)
Next
Dim t As Integer = 0
For Each item As String In DataCollection.OrderBy(Function(z) z.ToString)
dgvImport.Item(x, t).Value = item
t = t + 1
Next
End Sub

Properties not being assigned, unable to return values from Private as they are all zero (0)

Not all properties are being assigned correctly. Yet two properties are working. Now, I am aware of the Public ReadOnly auto correction, but I prefer the old get/set method because it helps me to understand more thoroughly. I have in a separate file, another class BusinessLogic:
Public Class BusinessLogic
Private _totalPiecesOfAllUsers As Integer
Private _totalCountOfUsers As Integer
Private _totalEarningsOfAllUsers As Decimal
Private _totalAverageOfAllUsers As Decimal
Private _name As String
Private _pieces As String
Private _individualEarning As Decimal
Public Property TotalPiecesOfAllUsers() As Integer
Get
Return _totalPiecesOfAllUsers
End Get
Set
_totalPiecesOfAllUsers += _pieces
End Set
End Property
Public Property TotalCountOfUsers() As Integer
Get
Return _totalCountOfUsers
End Get
Set
_totalCountOfUsers = value
End Set
End Property
Public Property TotalEarningsOfAllUsers() As Decimal
Get
Return _totalEarningsOfAllUsers
End Get
Set(ByVal value As Decimal)
_totalEarningsOfAllUsers = value
End Set
End Property
Public Property TotalAverageOfAllUsers() As Decimal
Get
Return _totalAverageOfAllUsers
End Get
Set(ByVal value As Decimal)
_totalAverageOfAllUsers = value
End Set
End Property
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Public Property Pieces() As Integer
Get
Return _pieces
End Get
Set(ByVal value As Integer)
_pieces = value
End Set
End Property
Public Property IndividualEarning() As Decimal
Get
Return _individualEarning
End Get
Set(ByVal value As Decimal)
_individualEarning = value
End Set
End Property
End Class
And then my Form1
Private Sub CalcPayToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles CalcPayToolStripMenuItem.Click
Try
' Create Object
Dim blog As New BusinessLogic
If tbName.Text <> String.Empty And tbPieces.Text <> String.Empty Then
' Get Transactions Per User
blog.Name = tbName.Text
blog.Pieces = Integer.Parse(tbPieces.Text)
blog.IndividualEarning = CalculatePieces(blog.Pieces)
' Counter Per User
blog.TotalCountOfUsers += 1
' Get Total of all users
blog.TotalPiecesOfAllUsers += blog.Pieces
blog.TotalEarningsOfAllUsers += blog.IndividualEarning
blog.TotalAverageOfAllUsers += (blog.TotalEarningsOfAllUsers / blog.TotalCountOfUsers)
Else
' SHow error if field is empty
MsgBox("Name and/or Piece count required")
End If
' Assign asmount earned txtbox the calculated value
lblAmountEarned.Text = FormatCurrency(blog.IndividualEarning)
Catch exc As Exception
' Show error if triggered
MsgBox("Error processing data, values may be empty or incorrect.")
End Try
End Sub
Public Function CalculatePieces(ByVal p As Decimal) As Decimal
' For piece claculation
Dim earningsByPiece As Decimal = 0D
' If pieces fall within range 1-199
If p >= 1 And p <= 199 Then
earningsByPiece = p * 0.5
' If pieces fall within range 200-399
ElseIf p >= 200 And p <= 399 Then
earningsByPiece = p * 0.55
' If pieces fall within range 100-599
ElseIf p >= 400 And p <= 599 Then
earningsByPiece = p * 0.6
' If pieces fall out of 600 range
ElseIf p >= 600 Then
earningsByPiece = p * 0.65
End If
Return earningsByPiece
End Function
Somehow it returns the IndividualEarning, but when I set a break in the BusinessLogic, none of the vraiables are holding anything.
You have started on the wrong foot. Reworking this code, I would start with a class called User. I added a custom constructor so you can add a new user in a single line of code. Then I added back the default constructor.
Public Class User
Public Property Name() As String
Public Property Pieces() As Integer
Public Property IndividualEarning() As Decimal
Public Sub New()
End Sub
Public Sub New(nme As String, pcs As Integer, earnings As Decimal)
Name = nme
Pieces = pcs
IndividualEarning = earnings
End Sub
End Class
Then I created a business logic class to hold the rest of the information. The properties are Shared so they are the same whenever the class is referenced. There is no need to create an instance when you are accessing shared members. Just refer to them with the class name.
Public Class BL
Public Shared Property TotalPiecesOfAllUsers() As Integer
Public Shared Property TotalCountOfUsers() As Integer
Public Shared Property TotalEarningsOfAllUsers() As Decimal
Public Shared Property TotalAverageOfAllUsers() As Decimal
End Class
Then in the Form I created a List(Of User) to hold your User objects.
Now, when you create a User, even though the u will fall out of scope, the user is safely tucked away in the list with the .Add method.
Every time you adjust the contents of the list you call CalculateTotalsAndAverage to keep your BL class up to date.
Dim lst As New List(Of User)
Private Sub CalcPayToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles CalcPayToolStripMenuItem.Click
'Validate input
If tbName.Text = "" Then
MessageBox.Show("Please enter a name")
Exit Sub
End If
Dim pcs As Integer
If Not Integer.TryParse(tbPieces.Text, pcs) Then
MessageBox.Show("Please enter a valid number of pieces")
Exit Sub
End If
Dim u As New User
u.Name = tbName.Text
u.Pieces = pcs
u.IndividualEarning = CalculatePieces(pcs)
lst.Add(u)
CalculateTotalsAndAverage()
lblAmountEarned.Text = FormatCurrency(u.IndividualEarning)
End Sub
Public Function CalculatePieces(ByVal p As Integer) As Decimal
Dim earnings As Decimal = 0D
Select Case p
Case 1 To 199
earnings = p * 0.5D
Case 200 To 399
earnings = p * 0.55D
Case 400 To 599
earnings = p * 0.6D
Case Else
earnings = p * 0.65D
End Select
Return earnings
End Function
Private Sub CalculateTotalsAndAverage()
BL.TotalAverageOfAllUsers = lst.Average(Function(u) u.IndividualEarning)
BL.TotalPiecesOfAllUsers = lst.Sum(Function(u) u.Pieces)
BL.TotalCountOfUsers = lst.Count
BL.TotalEarningsOfAllUsers = lst.Sum(Function(u) u.IndividualEarning)
Debug.Print($"Average {BL.TotalAverageOfAllUsers} Total Pieces {BL.TotalPiecesOfAllUsers} Total Earnings {BL.TotalEarningsOfAllUsers}")
End Sub

Why does this implementation of move corresponding work?

Since three is read only and depends on a non property (four). Three should be undefined.
How does props, which does not set four, set three to the correct value?
public sub main
Dim x1 = New one, x2 = New two
x1.one = 3
MoveCorresponding(x1, x2)
end sub
Public Sub MoveCorresponding(a As Object, b As Object, Optional ignoreList As List(Of String) = Nothing)
Dim oType As Type = b.GetType
Dim iType = a.GetType
Dim props = iType.GetProperties()
For Each pInf As PropertyInfo In props
Dim parName = pInf.Name
If pInf.CanWrite Then
Try
Dim val = pInf.GetValue(a, Nothing)
pInf.SetValue(b, val)
Catch ex As Exception
MsgBox(ex.Message)
End Try
End If
Next
End Sub
End Class
Class one
Public Property one As String = "1"
Dim four As Integer = 1
Public ReadOnly Property three As Integer
Get
Return four * 10
End Get
End Property
End Class
You set four on the same line that you declare it:
Dim four As Integer = 1 '<-- see? it's set to "1".
The property three is simply computed from four:
Return four * 10
Am I not understanding your question?

Vb conceptual understanding of creating objects within a class

I was wondering if you could help me understand how to create a Card object (with a value and suit) and use 52 of those cards to make an object called deck.
I have created my card class how do I initialize every card inside the deck class? Should I do it one by one? How do I link all those cards to one deck.
Thanks
As it happen I did read your previous question earlier today.
First, create a suit enum.
Public Enum Suit As Integer
Hearts = 1
Diamonds = 2
Clovers = 3
Spades = 4
End Enum
Then create the card class. Notice that the properties are read only as a card never changes its value. (Maybe not true if you're a magician)
Public Class Card
Public Sub New(suit As Suit, value As Integer)
Me.m_suit = suit
Me.m_value = value
End Sub
Public ReadOnly Property Suit() As Suit
Get
Return Me.m_suit
End Get
End Property
Public ReadOnly Property Value() As Integer
Get
Return Me.m_value
End Get
End Property
Private m_suit As Suit
Private m_value As Integer
End Class
Finally, create the deck class and populate 52 cards.
Public Class Deck
Public Sub New()
Dim cards = New Card(52 - 1) {}
Dim num As Integer = 0
For s As Integer = 1 To 4
For v As Integer = 1 To 13
cards(num) = New Card(CType(s, Suit), v)
num += 1
Next
Next
Me.m_cards = New Collections.ObjectModel.ReadOnlyCollection(Of Card)(cards)
End Sub
Public ReadOnly Property Cards() As Collections.ObjectModel.ReadOnlyCollection(Of Card)
Get
Return Me.m_cards
End Get
End Property
Private ReadOnly m_cards As Collections.ObjectModel.ReadOnlyCollection(Of Card)
End Class
You need two Enumerations and two Classes:
Enumerations
CardFaceValue - with values ranging from Ace-10 (inclusive), Jack, Queen, King.
CardFaceType - with values Hearts, Spades, Clubs, Diamonds
Classes
Deck - Has one property to contain the collection of all cards
Cards - of Type Array of Cards, sized 52.
Card - Has two properties
CardFaceValue
CardFaceType
In the constructor of the Deck class run a loop within a loop. The outer loop will run for 4 times for each of the CardFaceType enumeration, and the inner loop will run for 13 times for cards 1-10, J, Q, K.
With these loops iterate through the enumeration values and add cards to your Deck.
This is just a quick draft of what I envision
You'll need the card class first.
Public Class Card
Private cSuit As String
Private cValue As Integer
Public Property suit() As String
Get
Return cSuit
End Get
Set(ByVal value As String)
cSuit = value
End Set
End Property
Public Property value() As Integer
Get
Return cValue
End Get
Set(ByVal value As Integer)
value = cValue
End Set
End Property
Public Sub New(ByVal TheSuit As String, ByVal TheValue As Integer)
cSuit = TheSuit
cValue = TheValue
End Sub
Then you can make a new object for each card and add it to the deck collection.
Dim Deck As New List(Of Card)
Dim Suit As String = "Spade"
Dim Value As Integer = 11
Dim AceOfSpades As New Card(Suit, Value)
Deck.Add(AceOfSpades)

vb Class Random number

I am trying to make a poker game of sorts. I'm trying to learn vb classes. Here is my class code
Friend Class CalcCards
Dim random As New Random()
Private mH11 As Integer = 0
Private mH12 As Integer = 0
Public ReadOnly Property H11() As Integer
Get
H11 = mH11
End Get
End Property
Public ReadOnly Property H12() As Integer
Get
H12 = mH12
End Get
End Property
Public Sub Calc()
Dim count As Integer = 52
Dim intArr(51) As Integer
Dim intshuffle(51) As Integer
For i = 0 To 51
intArr(i) = i
Next
mH11 = intArr(Random.Next(0, 51))
mH12 = intArr(Random.Next(0, 51))
End Sub
This would be the form code.
picH11.Image = ImageList1.Images(calc.H11)
picH12.Image = ImageList1.Images(calc.H12)
My question is why does calc() always return 0 for H11 and H12? Can i not make an instance of random in a class?
You never called the Calc() method.