15,946,718 members
See more:
For my cards game I have a lot of code like that:
```If sHandCards IsNot Nothing Then

If sHandCards.ToString.Contains("7") Then Return "7"
If sHandCards.ToString.Contains("8") Then Return "8"
If sHandCards.ToString.Contains("9") Then Return "9"
If sHandCards.ToString.Contains("K") Then Return "K"

If TrumpCardID = 4 Then
If sHandCards.ToString.Contains("O") Then Return "O"
End If

If sHandCards.ToString.Contains("A") Then Return "A"
If sHandCards.ToString.Contains("10") Then Return "10"

End If

If sNonTrumpCards IsNot Nothing Then

If sNonTrumpCards.ToString.Contains("7") Then Return "7"
If sNonTrumpCards.ToString.Contains("8") Then Return "8"
If sNonTrumpCards.ToString.Contains("9") Then Return "9"

If sNonTrumpCards.ToString.Contains("K") Then Return "K"

If TrumpCardID = 4 Then
If sNonTrumpCards.ToString.Contains("O") Then Return "O"
End If

If sNonTrumpCards.ToString.Contains("10") Then Return "10"
If sNonTrumpCards.ToString.Contains("A") Then Return "A"

If sNonTrumpCards.ToString.Contains("U") Then Return "U"
If sNonTrumpCards.ToString.Contains("O") Then Return "O"

End If
```

Could the code get shorter using a variable / array for strings (7,8,9,U,O ...) and then make a loop?

What I have tried:

I plan to use a variable and a loop instead of many separate strings but do not know how the array and the loop should look like.
Posted
Updated 26-Dec-22 4:16am

## Solution 2

As OriginalGriff pointed out, it's much easier to use objects to represent The deck, cards, etc. If you think about it, it is no different from the actual objects in real life.

A card has a suit and value. A deck has a number of cards. A dealer gives cards to players. Each of these is an object. So you should create classes for each of these objects to hold their values (properties). Action like shuffling, dealing, etc are methods for specific objects.

I'll build the Cards, Deck, Hand (Player), and Dealer + include a sorter.

Let us break it down:

1. Card Suits
VB
```Public Enum Suit
Clubs
Diamonds
Hearts
End Enum```

2. Card Kinds (values)
VB
```Public Enum Kind
Two
Three
Four
Five
Six
Seven
Eight
Nine
Ten
Jack
Queen
King
Ace
End Enum```

Note: Card values are sorted based on kinds: Value Cards, Picture Cards, and Ace (highest value card). I have not included wilds, I will leave that up to you.

3. Cards - Suit + Kind + custom ordering
VB.NET
```Public Class Card
Implements IComparable(Of Card)

Public Kind As Kind
Public Suit As Suit

Public Sub New()
End Sub

Public Sub New(kind As Kind, suit As Suit)
Me.Kind = kind
Me.Suit = suit
End Sub

Public Function CompareTo(other As Card) As Integer _
Implements IComparable(Of Card).CompareTo
Return If(other Is Nothing, 1, If(Suit <> other.Suit, Suit.CompareTo(other.Suit), Kind.CompareTo(other.Kind)))
End Function

Public Overrides Function ToString() As String
Return \$"{Kind} of {Suit}"
End Function

End Class```

4. Card Deck
VB.NET
```Public Class CardDeck
Public Sub New()
Cards = [Enum].GetValues(GetType(Suit)) _
.Cast(Of Suit)() _
.SelectMany(Function(__) [Enum].GetValues(GetType(Kind)) _
.Cast(Of Kind)(),
Function(suit, kind) New With {suit, kind}) _
.Select(Function(card) New Card(card.kind, card.suit)) _
.ToList()
End Sub

Public Property Cards As List(Of Card)

Public ReadOnly Property Count As Integer
Get
Return Cards.Count
End Get
End Property

Public Function DrawCardAt(index As Integer) As Card
If index < 0 OrElse index >= Count Then
Throw New ArgumentOutOfRangeException(NameOf(index))
End If
Dim card As Card = Cards(index)
Cards.RemoveAt(index)
Return card
End Function

Public Function DrawTopCard() As Card
Return DrawCardAt(0)
End Function

Public Function DrawBottomCard() As Card
Return DrawCardAt(Count - 1)
End Function

Public Function DrawRandomCard() As Card
Dim random As Random = New Random()
Dim index As Integer = random.[Next](Count)
Return DrawCardAt(index)
End Function

If Cards.Contains(card) Then
Throw New InvalidOperationException(\$"Deck already contains card {card}.")
End If
Cards.Insert(0, card)
End Sub

If Not Cards.Contains(card) Then
Return
End If

Throw New InvalidOperationException(\$"Deck already contains card {card}.")
End Sub

Public Sub Shuffle()
Cards = Cards.OrderBy(Function(x) Guid.NewGuid()).ToList()
End Sub

Public Sub Sort()
Cards.Sort()
End Sub

Public Sub Sort(comparer As IComparer(Of Card))
Cards.Sort(comparer)
End Sub
End Class```

5. Hand (Player)
VB.NET
```Public Class Hand
Public Sub New(name As String)
Me.Name = name
Me.Cards = New List(Of Card)
End Sub

Public Property Cards As List(Of Card)
Public Property Name As String

If Cards.Contains(card) Then
Throw New InvalidOperationException(\$"Hand already contains card {card}.")
End If
End Sub

Public Sub RemoveCard(card As Card)
If Not Cards.Contains(card) Then
Throw New InvalidOperationException(\$"Hand does not contain card {card}.")
End If
End Sub
End Class```

6. Dealer
VB.NET
```Public Class Dealer
Public Sub New(deck As CardDeck)
Me.Deck = deck
End Sub

Public ReadOnly Property Deck As CardDeck

Public Sub DealCard(hand As Hand)
End Sub
End Class```

7. For the card sorting, I have supported a number of different orders:
7a. Sorting Types
VB
```Public Enum CardSortType
KindOnly
SuitOnly
SuitThenKind
KindThenSuit
End Enum```

b. The sorter
VB.NET
```Public Class CardSorter
Implements IComparer(Of Card)

Public Sub New(Optional sortBy As CardSortType = CardSortType.SuitThenKind)
Me.SortBy = sortBy
End Sub

Property SortBy As CardSortType

Public Function Compare(x As Card, y As Card) As Integer Implements IComparer(Of Card).Compare
Select Case Me.SortBy
Case CardSortType.KindOnly
Return x.Kind.CompareTo(y.Kind)
Case CardSortType.SuitOnly
Return x.Suit.CompareTo(y.Suit)
Case CardSortType.SuitThenKind
If x.Suit <> y.Suit Then
Return x.Suit.CompareTo(y.Suit)
End If
Return x.Kind.CompareTo(y.Kind)
Case CardSortType.KindThenSuit
If x.Kind <> y.Kind Then
Return x.Kind.CompareTo(y.Kind)
End If
Return x.Suit.CompareTo(y.Suit)
Case Else
Throw New NotImplementedException(\$"CardOrderMethod {SortBy} is not implemented.")
End Select
End Function
End Class```

Below I have included examples of shuffling, sorting, and using the dealer to deal hands.
VB
```Module Program

Private cardDeck As CardDeck

Sub Main(args As String())

cardDeck = New CardDeck()
DumpDeck("Created Deck")

Shuffle()
TestSortBy()

Shuffle()
TestSortBy(CardSortType.SuitThenKind)

Shuffle()
TestSortBy(CardSortType.KindThenSuit)

Shuffle()
TestSortBy(CardSortType.SuitOnly)

Shuffle()
TestSortBy(CardSortType.KindOnly)

'Sample of shuffling and dealing cards for a player

Shuffle()

Dim myHand = New Hand("Player 1")
Dim theDealer = New Dealer(cardDeck)

For i As Integer = 0 To 5
theDealer.DealCard(myHand)
Next

DumpHand(myHand)

End Sub

Private Sub DumpHand(hand As Hand)
Console.WriteLine(\$"--- Player: {hand.Name} ---")

For Each card As Card In hand.Cards
Console.WriteLine(card)
Next

Console.WriteLine()
End Sub

Private Sub Shuffle()
CardDeck.Shuffle()
DumpDeck("Shuffled Deck")
End Sub

Private Sub TestSortBy(ByVal Optional sortType As CardSortType? = Nothing)
If sortType Is Nothing Then
CardDeck.Sort()
Else
CardDeck.Sort(New CardSorter With {
.SortBy = CType(sortType, CardSortType)
})
End If

DumpDeck(\$"Sorted By: {(If(sortType IsNot Nothing, sortType.ToString(), "default"))}")
End Sub

Private Sub DumpDeck(title As String)
Console.WriteLine(\$"--- {title} ---")

For Each card As Card In CardDeck.Cards
Console.WriteLine(card)
Next

Console.WriteLine()
End Sub
End Module```

SAmple output of the Dealer dealing cards:
```--- Player: Player 1 ---
Five of Clubs
Nine of Clubs
Ace of Diamonds
Eight of Clubs
Six of Clubs```

I've created a card object-orientated framework for you. Now you can build your game around it.

UPDATE
As Dave was pointing out in the comments below, you missed the point of the code above. I gave you a bare framework that you can build upon eliminating the use of strings and optimiszing your code.

Let me give you an example. Say you want to check if a card is in your hand. You could write a custom method for the hand class, or ue an extension method. Here I will use the latter:
VB
```Public Module HandExtensions
<Extension>
Public Function HasCard(hand As Hand, kind As Kind, suit As Suit) As Boolean
Return hand.Cards.Any(Function(card) card.Kind = kind And card.Suit = suit)
End Function
End Module```

Now, to check if a hand has a card, the code is simple and clean:
VB
```If myHand.HasCard(Kind.Eight, Suit.Clubs) Then
'do something...
End If```

Update #2

Evaluating the hand. Here is a mock of evaluating a poker hand (without the testing). Note, by using an enum, the value of each enum is incremental, so the highest hand has the highest enum value:
VB
```Public Enum HandRules
HighCard
OnePair
TwoPair
ThreeOfAKind
Straight
Flush
FullHouse
FourOfAKind
StraightFlush
RoyalFlush
End Enum

Public Module GenericPokerEvaluator

Public Function Evaluate(hand As Hand) As HandRules

Dim result As HandRules = HandRules.HighCard

'do testing here

Return result

End Function

End Module```

Then, to check the results, you simply:
VB
`Dim result = GenericPokerEvaluator.Evaluate(myHand)`

UPDATE #3

Looking at your code above and your comments, if you are looking for an optimized version of finding the Lowest Card in the Hand, using the code above, we could write the following extension method:
VB
```Public Module HandExtensions
<Extension>
Public Function GetLowestCard(hand As Hand) As Card
Return hand.Cards _
.OrderBy(Function(card) card.Kind) _
.ThenBy(Function(card) card.Suit) _
.FirstOrDefault()
End Function

<Extension>
Public Function GetLowestCard(hand As Hand, suit As Suit) As Card
Return hand.Cards _
.Where(Function(card) card.Suit = suit) _
.OrderBy(Function(card) card.Kind) _
.FirstOrDefault()
End Function
End Module```

Now to check, here is the code:
VB
```Dim lowestCard = myHand.GetLowestCard(Suit.Hearts)
Console.WriteLine(\$"The lowest Card of Hearts is: {If(lowestCard Is Nothing, "no hearts", lowestCard)}")```

and sample output:
```--- Player: Player 1 ---
Queen of Clubs
Ten of Hearts
Seven of Clubs
Six of Clubs
Ace of Hearts

The lowest Card of Hearts is: Ten of Hearts```

That is a lot cleaner and far less code ... no strings required!

v5
Jo_vb.net 26-Dec-22 11:09am
Thanks for your work - this looks like a variant for my already existing classes.

deck class
shuffle method
4 cardpanels with playingCards

After shuffling the cards are distributed to the 4 cardpanels.
1 panel is controlled by the user, the pc controls 3 panels and plays against the user.

In my original question I asked for a better version of that:

If sHandCards IsNot Nothing Then

If sHandCards.ToString.Contains("7") Then Return "7"
If sHandCards.ToString.Contains("8") Then Return "8"
If sHandCards.ToString.Contains("9") Then Return "9"
If sHandCards.ToString.Contains("K") Then Return "K"

If TrumpCardID = 4 Then
If sHandCards.ToString.Contains("O") Then Return "O"
End If

If sHandCards.ToString.Contains("A") Then Return "A"
If sHandCards.ToString.Contains("10") Then Return "10"

End If

In this case the lowest card of a cardPanel should be given as return.

I do not understand how your approach should be helpful for that issue.
And I do do not want to re-write the complete project because of this issue.
Dave Kreskowiak 26-Dec-22 11:25am
You're not understanding what's going on. You "optimize" the code by NOT USING STRINGS! Every time you use a string you are allocating more memory and fragmenting it when the strings are freed. Every time you use .ToString(), you are allocating memory and them doing character comparisons. This is the SLOWEST way to go about handling cards.

Unfortunately for you, getting rid of the strings also means completely rewriting your classes to avoid using them. You simply have no choice.
Jo_vb.net 26-Dec-22 11:37am
I would re-write bigger parts of this fun project if that would have advantage for important code parts.

One is how the lowest (or the highest) card of a cardsPanel (with all the cards one player has in his hands) could be given as return without using my string method.

Other points are how such a framework would be helpful for creating game rules.
Graeme_Grant 26-Dec-22 11:46am
See my update above. Also, as for the cards, I overload the `ToString()` to return the card values.
Jo_vb.net 27-Dec-22 3:55am

I give your Hand class and the Extensions module a chance and combine them with my existing classes.

## Solution 1

Do yourself a favour, and don't use strings at all.

Create a Card class, which has a Value and a Suit and then a Deck class which contains a List of Card objects. Populate the Deck with all 52 possible cards, and then write a Shuffle method that randomizes them.

Then create a Hand class, which has a collection of Card objects and add a Hand for each player. Deal into the hands, and work from that.

It'll almost certainly become a whole lot simpler to simulate any card game than the version you have at the moment - and a whole load more readable!

Jo_vb.net 26-Dec-22 9:13am
I have a deck class and playingCard class.

Each player has a cardsPanel with the cards (playingCards) of only himself (handCards).

I get the strings like that:

' GetTrumpList
With CardsPanel.Children
If .Count > 0 Then
For n = 0 To .Count - 1
If .Item(n).CardType = TrumpCardID Then
sTrumpList = sTrumpList & " " & .Item(n).CardShortName & " " & .Item(n).CardSymbol & Environment.NewLine
End If
Next
End If
End With

So how to get same results shorter and without using strings?

P.S.:

Public Class PlayingCard
Inherits ToggleButton

Public Property CardSymbol As String
Public Property CardShortName As String
Public Property IsCallAce As Boolean
Public Property IsPlayedTwice As Boolean
Public Property IsHighestCardInColor As Boolean
Public Property IsPlayableThrowMeAwayCard As Boolean ' Abspatzen
Public Property IsPlayableSchmearCard As Boolean ' Schmieren

Public Property IsUsefulAsFirstCardInTrick As Boolean ' Trumpf-As/10er = False !!!
Public Property IsHighestPlayableTrumpCard As Boolean
Public Property IsLowestPlayableTrumpCard As Boolean

Private Shared CardOwnerProperty As DependencyProperty = DependencyProperty.Register("CardOwner", GetType(CardOwner), GetType(PlayingCard), New PropertyMetadata(CardOwner.North))

Private Shared CardTypeProperty As DependencyProperty = DependencyProperty.Register("CardType", GetType(CardType), GetType(PlayingCard), New PropertyMetadata(CardType.Acorn))

Private Shared CardValueProperty As DependencyProperty = DependencyProperty.Register("CardValue", GetType(CardValue), GetType(PlayingCard), New PropertyMetadata(CardValue.Seven, AddressOf UpdateTemplate))

Private Shared CardTemplatesProperty As DependencyProperty = DependencyProperty.Register("CardTemplates", GetType(CardTemplateCollection), GetType(PlayingCard), New PropertyMetadata(New CardTemplateCollection(), AddressOf UpdateTemplate))