0

While coding a simple command-line tictactoe game to learn Python (here's a link to the entire script on repl.it), I was not happy with my game_over function, since a lot of code is repeated:

Edit: fixed the code by putting the [deck_is_full] if last instead of first

Edit 2: changed the code back to original for clarity

def game_over(deck):
    if deck_is_full(deck):
        return deck_is_full(deck)
    if three_in_line(deck, "X"):
        return three_in_line(deck, "X")
    if three_in_line(deck, "O"):
        return three_in_line(deck, "O")
    return False

Is there a pythonic, repetition-free way to code that? I have found this answer on SO, but it doesn't get rid of the repetition, just gets it into a one-liner.

2 Answers 2

5
def game_over(deck):
    return deck_is_full(deck) or three_in_line(deck, "X") or three_in_line(deck, "O")

Edit: Had a look at your whole code and see that three_in_line returns true strings or the default None. So if you do need False here instead of None, then add it explicitly:

def game_over(deck):
    return deck_is_full(deck) or three_in_line(deck, "X") or three_in_line(deck, "O") or False

Edit 2: Hmm, just a note: If your functions had side effects, my version wouldn't be equivalent to yours, as I only call them once, not twice like you (when they return a true value). But as expected, and as they in my opinion should, they don't have side effects.

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

12 Comments

The prople who just copied your post and reposted downvoted this, propped you back up..
note that contrary to what you wrote on a deleted answer, any() does short circuit on the first False condition
@Chris_Rands any does, but the tuple/list-building doesn't.
@Chris_Rands Just removing parentheses wouldn't make it a generator expression. It would make it three separate arguments being passed to any.
@khelwood yes, i got that wrong, would actually require an awkard construct like any(func() for func in (lambda: deck_is_full(deck), lambda: three_in_line(deck, "X"), lambda: three_in_line(deck, "O")))
|
0

Since python 3.8 you can use the walrus operator to assign a variable in the if clause

def game_over(deck):
    if not (result:=deck_is_full(deck)):
        if not (result:=three_in_line(deck, "X")):
            if not (result:=three_in_line(deck, "O")):
                return False
    return result

5 Comments

Interesting, I didn't know about the walrus operator. By the way, you have fixed an error in my original code (edited since), which if a player won while filling the last remaining space, would declare the game a draw (because the deck becomes full) instead of a victory.
@ArnaudBouffard What do you mean this fixed that? This is equivalent to your original and I even just tested it, it did report a draw in that case.
@superbrain original function checked deck_is_full then three_in_line(deck, "X") then three_in_line(deck, "X"), thus reporting a draw instead of a victory in this case: [O O X] [O X X] [O X O]. Fixed by checking deck_is_full last.
@ArnaudBouffard Yes, but this code checks deck_is_full first.
and reports a draw in that case, you are right @superbrain, I got mixed up

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.