1

I am fairly new to intermediate programming, yet have played around with code for a while. At the moment I am making a simple card game. This issue is I am not sure where to use my functions or when to make them class methods.

For example, here is a simple function that deals out 5 cards to each player (from a predefined list) and then turns a card from the top of the pack (actually all just random selections). The cards are returned as a list of items (3 lists). I have also made a class called "Player".

p1_hand = []
p2_hand = []
flip_card = []

def deal_deck():
    count = 0
    for i in range(0, 10, 1):
        count += 1
        if count % 2 == 0:
            card = random.choice(deck)
            p2_hand.append(card)
            deck.remove(card)
        else:
            card = random.choice(deck)
            p1_hand.append(card)
            deck.remove(card)
        if count == 10:
            flip_card.append(random.choice(deck))
    return p2_hand, p1_hand, flip_card

In this example, it's just a deal, so I wonder why it would need to be a class method of "Player"? Possibly the class "Player" does not do much at all except keep score, keep track of who is dealing and what the score is?

To put it simply I am having trouble understanding the class as an object that interacts and preforms actions, I have made other classes and they have ended up working like a mini database rather than using much complexity in the methods at all.

2
  • 1
    My intuition is to make a classes called Game, Dealer, Deck, Card, Player, and Hand. The Dealer class would have a Deck data member. Deck would have a shuffle method. The Player class would have a Hand data member. deal_deck would become a Dealer class method and would transfer Card objects from the Dealer's Deck to each Player's Hand and then to the Flipped_Card member of the Game object. Commented Apr 4, 2021 at 23:29
  • 1
    This is likely subjective; but to me, dealing is something a Deck instance does, possibly by telling a Player (or better, Hand) instance to draw a card from itself. If you have a weird kind of dealing, I'd put it in Game. Specifically here, if this is something that happens at the start of a game, I wold have Game.__init__ initialise a Deck instance, then tell it to deal, then tell it to reveal the top card. I would not have dealing as a Player class method: as you note, deaing is not really related to abstract "playerness", and especially not the turning over the top card. Commented Apr 4, 2021 at 23:29

2 Answers 2

3

There is an art to designing classes and objects. The fundamental purpose of using classes is information hiding. The rest of your program should not have to know how a deck of cards is implemented, which allows you to change the implementation without redesigning the whole program. Thus, you create a Deck class that has all of the data stored internally, and only exposes to the outside world the things you want to DO with a deck, like shuffle and deal_card. A Player class might include a hand and a score, and functions to add another card, and the Game object (maybe) could coordinate dealing cards into the hand and triggering the plays.

The code you have is mixing all of this. It has to know how a deck is implemented, and how a hand is implemented, and how a card is flipped.

By the way, for the sake of realism, it would be better for you to shuffle the deck and deal cards off the top, instead of using random.choice.

Sign up to request clarification or add additional context in comments.

1 Comment

yes thank you, I have since found "shuffle" to be a far better function to use in my code.
2

I originally down-voted this as too broad, but changed my mind as I wrote up my notes for you. Classes are a programming tool whose implementation doesn't receive much treatment at the level you're asking. There are many examples of good card-game classes available on the Internet ... and many bad ones. The research isn't easy for you.

Use a class to represent a unit of your system (a card game, in this case) that is cohesive (a set of data and capabilities with a readily understood boundary) and interacts with other units, or with the main program.

In this case, you have a good start: you've identified card, player, and hand as entities in your game system. You may want to treat the deck as a hand instance (just another list of cards), or you may want to give it special treatment due to different functions within the game.

The classes and functions I've seen as useful include:

Deck
    The impartial source of cards
data
    a list of cards
methods
    reset -- shuffle all 52 cards into a list
    deal(n) -- return a list of n cards

Hand
    cards held by a single player
data
    a list of cards
methods
    reset -- whatever is needed to return the hand to a game-start state
    draw(n) -- acquire n cards
    play(n) -- play n cards to the game area
    
Card
    A single card, containing all information needed to identify it to the game
data
    suit
    rank
methods
    none

Player
    Game information about each player
data
    hand -- see Hand class above
    game-role -- depending on the game, this could be "dealer", "idle", "active", ...
    ... other, depending on the game: points, money, etc.
methods
    ... very dependent on the game being played

Game
    the overall monitor for the game
data
    roster -- list of players
    deck -- see Deck class above
    ... other, depending on the game: round, player to play next, etc.

Some of these overlap a bit, such as "Deck.deal" and "Hand.draw". One of the design decisions you face is to choose which entity will drive an interaction between two objects.

As for implementation, I do suggest that you make your basic operations a lot simpler. For the desk, initialize by generating all 52 cards with a nested list comprehension. shuffle the deck, and then use list slicing to deal the cards. For instance, to deal 5 cards to each player:

def deal(n):
    take = deck[:n]
    deck = deck[n:]
    return take

# elsewhere, to drive the initial dealing ...
for player in roster:
    player.hand = deck.deal(5)

Simply reduce the interactions to match the way you talk about the game: "deal each player five cards" should look just like that in the code. Bury the mechanics within each class.

3 Comments

What style of coding is this? Do you have any suggested reading or topics/links that would help me simplify my code like this?
This is object-oriented design -- a "style" for which you should already have materials, given that you're working with classes. Much of the simplification is merely learning the language, rather than a "style". Mostly, it's working with straightforward modular design: decide what simple task each function or block will do -- then do it directly and return to the calling program.
Thanks very helpful, I am just getting into this side of it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.