Months_not_minutes
Months_not_minutes

Reputation: 35

Python question about functions classes and class methods

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.

Upvotes: 1

Views: 97

Answers (2)

Prune
Prune

Reputation: 77837

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.

Upvotes: 2

Tim Roberts
Tim Roberts

Reputation: 54698

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.

Upvotes: 3

Related Questions