简单的Python纸牌游戏

1 投票
1 回答
12917 浏览
提问于 2025-04-16 15:25

我刚接触Python,对这个程序完全没有头绪。

我想做一个迷你纸牌游戏,具体功能如下:

  1. 游戏有六个玩家。
  2. 每局开始时,每个玩家会发到四张牌。
  3. 每个玩家会把手中的所有对子放下。如果一对牌的点数都小于10(而A算作大于10),那么这个玩家得1分;如果一对牌的点数都是10或更高,玩家得2分。如果手中有两对牌,都会放下,玩家会根据每对的类型得到相应的分数(1分或2分)。
  4. 在放下对子后,这一局就结束了。(玩家实际上不需要输入什么或做决定。我之前就说了,这个游戏挺无聊的。)所有牌会被放回牌堆,洗牌后开始新的一局。
  5. 每局结束后,玩家会根据总分从高到低排列。如果有两个玩家得分相同,编号较小的玩家会排在前面。
  6. 经过六局后,游戏结束。得分列表中的第一个玩家(按照上面的定义)获胜。

输出应该是这样的:

Hand 1 deal:
Player 1's hand: 5D 5H KD AS
Player 2's hand: 7D 8D 9C JS
Player 3's hand: 3D 3H 6S 7C
Player 4's hand: 4C 6D 8S TH
Player 5's hand: 4H 5C 7S QC
Player 6's hand: 5S 6H 9H KH

Dropping pairs:
Player 1 dropped 1 pair.
Player 2 dropped no pairs.
Player 3 dropped 1 pair.
Player 4 dropped no pairs.
Player 5 dropped no pairs.
Player 6 dropped no pairs.

Score:
Player 1: 1
Player 3: 1
Player 2: 0
Player 4: 0
Player 5: 0
Player 6: 0

我为这个游戏准备的模块包括:

CARDS.py

import string
import random

suits = ['S', 'C', 'D', 'H']
longsuits = ['spades', 'clubs', 'diamonds', 'hearts']

ranks = ['2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A']
longranks = ['two', 'three', 'four', 'five', 'six', 'seven', 'eight',
        'nine', 'ten', 'jack', 'queen', 'king', 'ace']

ranklist = string.join(ranks, "")

ranklookup = {}
for i in range(len(ranks)):
    ranklookup[ranks[i]] = i

suitlookup = {}
for i in range(len(suits)):
    suitlookup[suits[i]] = i

class Card:
    """
    Class to hold information about a single playing card.  The card's rank
    and suit are stored.

    The constructor takes two arguments, the rank and suit of the card.  The
    rank and suit must be values from the ranks and suits list.

    >>> c1 = Card('8', 'C')
    >>> c2 = Card('K', 'H')
    >>> print c1
    8C
    >>> print c2
    KH
    """

    def __init__(self, rank, suit):
        self.__rank = ranklookup[rank]
        self.__suit = suitlookup[suit]

    def __cmp__(self, other):
        """
        Compare two card objects.

        >>> c1 = Card('8', 'C')
        >>> c2 = Card('K', 'H')
        >>> c1<c2
        True
        >>> c1>c2
        False
        >>> c1==c2
        False
        """
        if self.__rank == other.__rank:
            return cmp(self.__suit, other.__suit)
        else:
            return cmp(self.__rank, other.__rank)

    def __str__(self):
        """
        Return a two-character string representing the card.

        >>> c1 = Card('8', 'C')
        >>> str(c1)
        '8C'
        """
        return self.shortname()
    def __repr__(self):
        """
        Return a the Python code required to construt the card.

        >>> c1 = Card('8', 'C')
        >>> print repr(c1) .split(".",1)[1]
        Card('8', 'C')
        """
        return "%s.Card('%s', '%s')" % (self.__module__, ranks[self.__rank], suits[self.__suit])

    def suit(self):
        """
        Return a character representing the card's suit.  This will be one of the
        characters from suits.

        >>> c1 = Card('8', 'C')
        >>> c1.suit()
        'C'
        """
        return suits[self.__suit]

    def rank(self):
        """
        Return a character with the card's rank.  This will be one of the
        characters from ranks.

        >>> c1 = Card('8', 'C')
        >>> c1.rank()
        '8'
        """
        return ranks[self.__rank]

    def shortname(self):
        """
        Output a short two-character description of the card.

        >>> c1 = Card('8', 'C')
        >>> c1.shortname()
        '8C'
        """
        return ranks[self.__rank] + suits[self.__suit]

    def longname(self):
        """
        Return a long English description of the card.

        >>> c1 = Card('8', 'C')
        >>> c1.longname()
        'eight of clubs'
        """
        return longranks[self.__rank] + " of " + longsuits[self.__suit]



testhand = [ Card('9', 'H'), Card('6', 'C'), Card('7', 'S'), Card('6', 'D'), Card('A', 'H') ]

def deck():
    """
    Return an *unshuffled* deck of cards (list of card objects).

    >>> d = deck()
    >>> print hand_string(d)
    2S 3S 4S 5S 6S 7S 8S 9S TS JS QS KS AS 2C 3C 4C 5C 6C 7C 8C 9C TC JC QC KC AC 2D 3D 4D 5D 6D 7D 8D 9D TD JD QD KD AD 2H 3H 4H 5H 6H 7H 8H 9H TH JH QH KH AH
    >>> print len(d)
    52
    """
    d = []
    for suit in range(len(suits)):
        for rank in range(len(ranks)):
            c = Card(ranks[rank], suits[suit])
            d.append(c)

    return d


def small_deck():
    """
    Return a small *unshuffled* deck of cards (list of card objects).  This is
    smaller than a regular deck and can be used for testing.

    >>> d = small_deck()
    >>> print hand_string(d)
    9S TS JS QS KS AS 9C TC JC QC KC AC 9D TD JD QD KD AD 9H TH JH QH KH AH
    >>> print len(d)
    24
    """
    d = []
    for suit in range(len(suits)):
        for rank in [7,8,9,10,11,12]:
            c = Card(ranks[rank], suits[suit])
            d.append(c)

    return d



def start_pair(hand):

    """
        Return index of first card in first pair of the hand.
        The index is for the order the hand has after sorting.
        If there are no pairs, return -1.

        Side effect:  The hand is sorted.
    """
    hand.sort()
    start = -1
    for i in range(len(hand)-1, 0, -1):
        if hand[i].rank() == hand[i-1].rank():
            start = i -1
    return start





def drop_pair(hand):
    """
    Remove a pair from the hand (list of card objects) if possible.  Return
    the new hand and the number of pairs dropped (0 or 1).  A "pair" is two
    cards with the same rank.

    If there is more than one pair, only the first is removed.

    The hand MUST be sorted by rank before this function is called.  This
    can be done with:
        hand.sort()

    >>> testhand.sort()
    >>> print hand_string(testhand)
    6C 6D 7S 9H AH
    >>> newhand, pts = drop_pair(testhand)
    >>> print hand_string(newhand)
    7S 9H AH
    >>> print pts
    1
    """
    newhand = hand[:]
    for i in range(len(newhand)-1):
        if newhand[i].rank() == newhand[i+1].rank():
            del(newhand[i+1])
            del(newhand[i])
            return newhand, 1
    return newhand, 0



def hand_string(hand):
    """
    Create a string that represents the cards in the player's hand.

    >>> hand_string(testhand)
    '6C 6D 7S 9H AH'
    >>> hand_string([])
    ''
    """

    return " ".join( [c.shortname() for c in hand] )


def _test():
    import doctest
    doctest.testmod()

if __name__ == "__main__":
    _test()

模块结束。

还有

pointsort.py

'''
    Module to sort players by points and player numbers.  See definition for
    function sortPlayers() for details of sort order.
'''

def playerToSort(p):
    ''' Represent player number such that lower-numbered players sort before higher-numbered '''
    return -p

def playerFromSort(p):
    ''' Extract original player number from playerToSort() representation '''
    return -p

def sortPlayers(playerNum, points):
    ''' Sort players by total points, then by player number within total points.
        Player numbers are sorted such that low-numbered players are highest.

        Returns list of tuples (playerNumber, points), sorted in *increasing* order
        by the two criteria.
    '''
    keys = []
    for n in playerNum:
        keys.append(playerToSort(n))

    order = []
    for i in range(len(points)):
        order.append((points[i], keys[i]))

    order.sort()
    result = []
    for i in range(len(order)):
        result.append((playerFromSort(order[i][1]), order[i][0]))

    return result

if __name__ == "__main__":
    points = [3, 4, 1, 2, 0, 3]
    number = [2, 1, 3, 4, 0, 5]
    order = sortPlayers(number, points)
    # Note that the following prints results in the WRONG order for A4 
    for i in range(len(order)):
        print "Player " + str(order[i][0]) + " had " + str(order[i][1]) + " points."



i was really hoping if someone could help me with the loops that this program needs, especially the point loop system. 
this what i have so far, 

import cards
import random

new = cards.small_deck()

print cards.hand_string(new)
print len(new)


player1 = []
player2 = []
player3 = []
player4 = []
player5 = []
player6 = []
#shuffle the cards
random.shuffle(new)
num = input('How many cards to deal to each player? ')
while num > 0:
        player1.append(new.pop(0))
        player2.append(new.pop(0))
        player3.append(new.pop(0))
        player4.append(new.pop(0))
        player5.append(new.pop(0))
        player6.append(new.pop(0))
        num = num - 1
#prints out 8 cards for each person

print 'the cards remaining in the deck are: '
print len(new)

#sorts player1 cards and removes the pairs
player1.sort()
print "sorted hand for player 1:"
print cards.hand_string(player1)
newplayer1 = []
player1points = 0

newplayer1, player1points = cards.drop_pair(player1)
print cards.hand_string(newplayer1)

#sorts player2 cards
player2.sort()
print "sorted hand for player 2:"
print cards.hand_string(player2)
newplayer2 = []
player2points = 0

newplayer2, player1points = cards.drop_pair(player2)
print cards.hand_string(newplayer2)



#sorts player3 cards
player3.sort()
print "sorted hand for player 3:"
print cards.hand_string(player3)
newplayer3 = []
player3points = 0

newplayer3, player1points = cards.drop_pair(player3)
print cards.hand_string(newplayer3)   


#sorts player4 cards
player4.sort()
print "sorted hand for player 4:"
print cards.hand_string(player4)
newplayer4 = []
player4points = 0

newplayer4, player1points = cards.drop_pair(player4)
print cards.hand_string(newplayer4)


#sorts player5 cards
player5.sort()
print "sorted hand for player 5:"
print cards.hand_string(player5)
newplayer5 = []
player5points = 0

newplayer5, player1points = cards.drop_pair(player5)
print cards.hand_string(newplayer5)

#sorts player6 cards
player6.sort()
print "sorted hand for player 6:"
print cards.hand_string(player6)
newplayer6 = []
player6points = 0

newplayer6, player1points = cards.drop_pair(player6)
print cards.hand_string(newplayer6)

我在循环方面遇到了很大的困难,任何帮助我都非常感激,谢谢!

1 个回答

1

看起来你根本没有用到 pointsort.py,这没关系,因为我发现你想要的输出并不需要它。

# main.py
import cards
import random

deck = cards.small_deck()

class Player(object):
    def __init__(self, number):
        self.number = number
        self.points = 0
        self.hand = []

    def __str__(self):
        return "Player %d" % self.number

players = [Player(num + 1) for num in xrange(6)]  # create six numbered players
rounds = 6
hand_size = 4

for round_num in xrange(rounds):
    #shuffle the cards
    random.shuffle(deck)
    print "Hand %d deal:" % (round_num + 1)
    # deal cards
    for _ in xrange(hand_size):
        for player in players:
            # draw from the back instead of the front: possibly slightly more efficient
            player.hand.append(deck.pop())

    # sort player cards
    for player in players:
        player.hand.sort()
        print "%s's hand: %s" % (player, cards.hand_string(player.hand))
    print

    print "Dropping pairs:"
    for player in players:
        #removes the pairs
        new_hand, dropped_cards, pairs = cards.drop_pairs(player.hand)
        deck.extend(player.hand)  # realistically we can dump the hand now anyway.
        player.hand = []

        player.points += pairs

        how_many = pairs
        plural = "s"
        if pairs == 0:
            how_many = "no"
        elif pairs == 1:
            plural = ""
        print "%s dropped %s pair%s" % (player, how_many, plural)
    print

    print "Score:"
    for player in players:
        print "%s: %d" % (player, player.points)
    print

我还把 drop_pair 改成了 drop_pairs,并且让它能找到所有的配对,而不仅仅是一个。如果找到三张相同的牌,就值 2 分,四张相同的牌值 3 分。

# in cards.py
def drop_pairs(hand):
    new_hand = hand[:]
    dropped_cards = []
    pairs = 0
    for card1, card2 in zip(hand, hand[1:]):  # look at every two-in-a-row cards
        if card1.rank() == card2.rank():
            try:
                new_hand.remove(card1)
            except ValueError:
                pass
            else:
                dropped_cards.append(card1)
            try:
                new_hand.remove(card2)
            except ValueError:
                pass
            else:
                dropped_cards.append(card2)
            pairs += 1
    return new_hand, dropped_cards, pairs

我没有仔细看你所有的代码,光是“帮忙处理循环”这样的指导我也帮不了太多,但我注意到了一些事情:

  • 在 Python 中,你可以直接遍历一个列表,而不是从 0 遍历到列表的长度减 1,然后一个个检查索引。例如:

    # this will work, but it's not recommended
    for suit in range(len(suits)):
        for rank in range(len(ranks)):
            c = Card(ranks[rank], suits[suit])
            d.append(c)
    
    # this is much cleaner
    for suit in suits:
        for rank in ranks:
            d.append(Card(rank, suit))
    
  • 不过,有时候你确实需要遍历一系列连续的数字,或者你只是想让某段代码运行特定的次数,这时候你可以使用 range(在 Python 2 中还有一个更高效的选项叫 xrange,适合大范围的情况)。

    # don't do this
    while num > 0:
        do_something()
        num = num - 1
    
    # Do this instead!
    for i in xrange(num):
        do_something()
    

另外,如果你不需要当前数字的 'i' 变量,可以用 '_' 这个名字,它经常被重新赋值,是个放垃圾数据的好地方。

  • 你还可以嵌套列表。如果你不确定会有多少个列表,这个方法非常有用。比如说,如果你有六个玩家:

    # no no no
    player1 = []
    player2 = []
    player3 = []
    player4 = []
    player5 = []
    player6 = []
    
    # better...
    players = [[], [], [], [], [], []]
    
    # yes!
    players = []
    for _ in xrange(6):
        players.append([])
    
    # There's also a shortcut called List Comprehensions, which allows us
    # to be even more concise with our list definitions.
    players = [[] for _ in xrange(6)]
    

后面这两个例子的好处在于,你可以通过改变数字 6 来轻松调整游戏中的玩家数量,甚至可以用一个变量来代替。这样也减少了代码的重复:你处理每个玩家牌的逻辑要复制粘贴 6 次,只是中间的数字不同。这种方式不太灵活:如果你想增加或减少玩家,就得在代码中添加或删除那么多重复的代码块。相反:

    # no! bad!
    player1 = []
    player2 = []
    player3 = []
    player4 = []
    player5 = []
    player6 = []

    player1.do_stuff()
    player2.do_stuff()
    player3.do_stuff()
    player4.do_stuff()
    player5.do_stuff()
    player6.do_stuff()

    # much easier!
    for player in players:
        player.do_stuff()

撰写回答