Skip to main content
added 1 character in body
Source Link
Barry
  • 18.4k
  • 1
  • 40
  • 92
def split(self):
    half = len(self.cards) // 2
    return Deck(self.cards[:half]), Deck(self.cards[half:])
def split(self):
    half = len(self.cards) / 2
    return Deck(self.cards[:half]), Deck(self.cards[half:])
def split(self):
    half = len(self.cards) // 2
    return Deck(self.cards[:half]), Deck(self.cards[half:])
Source Link
Barry
  • 18.4k
  • 1
  • 40
  • 92

!!NO GLOBAL VARIABLES!!

That merits being capitalized. And underlined. And lots of exclamation points. Nothing can kill your ability to write good, modular quite quite like global variables. You have several of them, and it took me several reads to understand what exactly is going on here.

Let's simplify. What do we need for WAR? We need a Deck:

class Deck(object):
    ...

We can start with the default deck, this will be all of our cards:

class Deck(object):
    def __init__(self, cards=None):
        if cards is not None:
            self.cards = cards
        else:
            self.cards = range(13) * 4

Never write multiple lines of code on one line (your line with the ;) It'll be hard to even see that the second line exists! I also don't understand your extend([15,15]) line. Why are there 15s?

So anyway, with this deck, we have:

full_deck = Deck() # all the cards

Which we probably want to be able to shuffle:

def shuffle(self):
    random.shuffle(self.cards)

Now we need to split this in half for our two players. Let's just add a split() method:

def split(self):
    half = len(self.cards) / 2
    return Deck(self.cards[:half]), Deck(self.cards[half:])

With which we can do:

deck.shuffle()
player, enemy = deck.split()

Note that we didn't need any global variables here! It's easy to see where this is coming from. We had a full deck of cards, we shuffled it, and split it in half.

NO RELIANCE ON INTERNAL MEMBERS

In Python, everything is public. But that doesn't mean that you should rely on this. You are relying very explicitly on the members and their types. There had better be a .deck that's a list. Much better to hide the implementation behind an interface that just has a few key operations.

Which operations? Well, we need the pop off the top card:

def pop(self):
    return self.cards.pop(0)

And we need to push cards onto it:

def push(self, vals):
    self.cards.extend(vals)

And we need to check for emptiness:

def empty(self):
    return not self.cards

And that's about it. Now our main loop just has to look like:

while True:
    if player.empty():
        # enemy won
    elif enemy.empty():
        # player won

    player_card = player.pop()
    enemy_card = enemy.pop()

    if player_card > enemy_card:
        player.push([player_card, enemy_card])
    elif enemy_card > player_card:
        enemy.push([player_card, enemy_card])
    else:
        repeat

Avoiding the globals and the internal memory structure would let you do later improvements to the Deck internals. Right now we're popping off the top and pushing onto the back, that's not very efficient for list, but it's much better for deque. Maybe we change to that? Then we'd just have to change pop(0) to be popleft(), but none of the callers of our code will have to know that.