Home > Net >  Created an endless loop, but can't tell why it is endless
Created an endless loop, but can't tell why it is endless

Time:04-27

So I am creating a card game in python using classes. I got it all set up to the point where it should work. But when I ran it it just simply never stops running. I am not really sure how to make this code minimal and reproduceable, because I do not know where the issue is at. Here is the code i have written.

It has to be in the play_uno() class object.

""" UNO Simulator """
import random

class card():
    def __init__(self, value, color, wild):
        '''
        An UNO deck consists of 108 cards, of which there are 76 Number cards,
        24 Action cards and 8 Wild cards. UNO cards have four color "suits",
        which are red, yellow, blue and green.
        '''
        self.card_nums = ['0','1','2','3','4','5','6','7','8','9']
        self.card_colors = ['red','blue','green','yellow']
        self.spec_cards = ['draw2','reverse','skip']
        self.wild_cards = ['wild','wild_draw_4']
        if wild == False:
            self.value = self.card_nums[value]
            self.color = self.card_colors[color]
        elif wild == 'special':
            self.value = self.spec_cards[value]
            self.color = self.card_colors[color]
        elif wild == True:
            self.value = self.wild_cards[value]
            self.color = None

class generate_deck():
    def __init__(self):
        self.number_cards = self.get_num_cards()
        self.special_cards = self.get_special_cards()
        self.wild_cards = self.get_wild_cards()
        self.cards = self.number_cards   self.special_cards   self.wild_cards
        random.shuffle(self.cards)

    def get_num_cards(self):
        # only one zero per color
        with_zeroes = [card(i,j,False) for i in range(10) for j in range(4)]
        no_zeroes = [card(i,j,False) for i in range(1,10) for j in range(4)]
        return no_zeroes   with_zeroes

    def get_wild_cards(self):
        wild_draw4s = [card(i,None,True) for i in range(2) for x in range(2)]
        wilds = [card(i,None,True) for i in range(2) for x in range(2)]
        return wilds   wild_draw4s

    def get_special_cards(self):
        return [card(i,j,'special') for i in range(3) for j in range(4) for x in range(2)]

class player():
    def __init__(self, name):
        self.wins = 0
        self.name = name
        self.cheater = False
        self.cards = ''
        self.turn = 0
        self.uno = 0

class play_uno():
    def __init__(self, num_players = 3, num_cheaters = 0, cards_per_player = 5):
        # get started
        self.rules = 'default'
        self.status = 'ongoing'
        self.deck = generate_deck().cards
        self.played_cards = []
        self.dro = 0
        self.direction = 0
        self.top_card = self.deck.pop() # random card as first card to play on
        self.tot_turns = 0

        # generate players, make cheaters later
        self.players = [player('player'   str(i)) for i in range(num_players   num_cheaters)]

        # give each player 7 cards to start
        for _player_ in self.players:
            _player_.cards = [self.draw_card() for i in range(cards_per_player)]

        # start playing turns in order
        # do not know how to reverse yet
        """
        Right now it is endless for some reason.
        """
        while self.status == 'ongoing':
            for _player in self.players:
                self.turn(_player)

    def draw_card(self):
         # draws random card from deck instead of card on top
         if len(self.deck) == 0:
             self.re_shuffle()
             self.dro  = 1
         return self.deck.pop()

    def re_shuffle(self):
         self.deck = self.played_cards
         random.shuffle(self.deck)
         self.played_cards = []
         return self.deck, self.played_cards

    def play_card(self, player_cards, _card):
        self.top_card = _card
        return player_cards.remove(_card), self.played_cards.append(_card), self.top_card

    def game_over(self, winner):
        winner.wins  = 1
        self.game_status = 'over'

    def turn(self, _player):
        played = False
        # check if someone played wild card last turn
        if self.top_card.value in card(1,2,None).wild_cards:
            self.top_card.color = random.choice(card.card_colors)
            if self.top_card.value == 'wild_draw_4':
                _player.cards  = [self.draw_card() for i in range(4)]
                self.tot_turns  = 1
                return _player
        # check for special cards
        elif self.top_card.value in card(1,2,None).spec_cards:
            if self.top_card.value == 'draw2':
                _player.cards  = [self.draw_card() for i in range(4)]
                self.tot_turns  = 1
                return _player
            # for now we are treating reverse cards like skips
            elif self.top_card.value == 'reverse' or self.top_card.value == 'skip':
                played = True
                self.tot_turns  = 1
                return _player
        # If its a normal card, or regular wild
        if played == False:
            for _card in _player.cards:
                if _card.color == self.top_card.color:
                    self.play_card(_player.cards, _card)
                    played = True
                    break
                elif _card.value == self.top_card.value:
                    self.play_card(_player.cards, _card)
                    played = True
                    break
        # if the player cannot play at all
        # rn they just move on if they have to draw,
        # cant play the card they just drew.
        if played == False:
            _player.cards  = [self.draw_card()]
            played = True
            self.tot_turns  = 1
        # check if the player won or not
        if len(_player.cards) == 0:
            self.game_over(_player)
        elif len(_player.cards) == 1:
            _player.uno  = 1
        return _player.cards

CodePudding user response:

I did not run the code, but I think you should test a player's number of cards before drawing again. Like this:

if len(_player.cards) == 0:
    self.game_over(_player)
elif len(_player.cards) == 1:
    _player.uno  = 1

if played == False:
    _player.cards  = [self.draw_card()]
    played = True
    self.tot_turns  = 1

Or are the rules of this game different? I sincerely don't remember them anymore.

CodePudding user response:

The while loop at the end of play_uno's __init__ checks for status, which never changes.

The loop calls turn on each of players every iteration. You must change status somewhere or you must put an if ...: break in the while loop (e.g. if not _player.cards).

EDIT: It appears that you meant self.status instead of self.game_status, in game_over. Try changing game_status to status there.

CodePudding user response:

In the function turn in the play_uno class you are checking for certain wild/special cards. If the value is reverse, for example, the function hits a return _player line which ends the execution of the function and the player is unable to play another card.

Move the return statements to the end of the function if you want to ensure the rest of the code is run.

  • Related