-1

For my tic-tac-toe program, I decided to create a function that checks whether a player's input is available or not. I defined a function named checkOverride() that checks for the input of a player. If the input has already been chosen and has either an "X" or an "O" the function would return True. Else it would return False. However, when testing the program I attempted to make the function return True, but the value the function returned was None. Why is this?

def main():
    # Welcome the players
    print("Welcome players to Tic-Tac-Toe!")

    # Variables for creating game board
    top     = "1|2|3"
    middle  = "4|5|6"
    bottom  = "7|8|9"
    divider = "-+-+-"

    # Display game board
    Board = createGameBoard(top, middle, bottom, divider)
    print(Board)

    playerOneWin = False
    playerTwoWin = False

    while playerOneWin == False and playerTwoWin == False:
        # Get input from player One
        playerOneInput = input("x's turn to choose a square (1-9): ")

        # Check for override
        override = checkOverride(Board, playerOneInput)

        if override == True:
            print(f"{playerOneInput} has already been filled. Please choose another square.")
            continue
        
        elif override == False:
            Board = playerOneMove(Board, playerOneInput)
            print(Board)

        # Get input from player Two
        playerTwoInput = input("o's' turn to choose a square(1-9): ")

        # Check for override
        override = checkOverride(Board, playerTwoInput)

        if override == True:
            print(f"{playerTwoInput} has already been filled. Please choose another square.")
            continue

        elif override == False:
            Board = playerTwoMove(Board, playerTwoInput)
            print(Board)
        

def createGameBoard(top, middle, bottom, divider):
    ''' 
    Create a Tic-Tac-Toe game board.
    '''
    Board = f"{top}\n{divider}\n{middle}\n{divider}\n{bottom}"
    return Board


def playerOneMove(Board, playerOneInput):
    '''
    Take player one's input and display it onto the board.
    '''
    # Identify where player one's move and replace number with 'X'
    if playerOneInput in Board:
        Board = Board.replace(playerOneInput, 'X')
    
    return Board
    

def playerTwoMove(Board, playerTwoInput):
    '''
    Take player two's input and display it onto the board.
    '''
    # Identify where player one's move and replace number with 'X'
    if playerTwoInput in Board:
        Board = Board.replace(playerTwoInput, "O")

    return Board


def checkOverride(Board, playerOneInput="", playerTwoInput=""):
    '''
    Look at the input of player one or player two and see if their input is already taken.
    '''

    if playerOneInput:
        if playerOneInput in Board:
            square = Board.index(playerOneInput)
            if Board[square] == "X" or Board[square] == "O":    
                return True
            else:
                return False
    
    elif playerTwoInput:
        if playerTwoInput in Board:
            square = Board.index(playerTwoInput)
            if Board[square] == "X" or Board[square] == "O":
                return True
            else:
                return False
  • 1
    What does your function return if `playerOneInput` is truthy but not `in Board`? [How to debug small programs.](//ericlippert.com/2014/03/05/how-to-debug-small-programs/) | [What is a debugger and how can it help me diagnose problems?](//stackoverflow.com/q/25385173/843953) Step through your code and see what path it takes for it to return `None`. Is there a change you can make to your function to force it to return `False` if none of the `if` conditions are met? – Pranav Hosangadi Apr 27 '21 at 19:56
  • 1
    Please provide a [mcve]. The code that you have posted can't be run as is, and we can only guess as to what input you fed the function for it to return `None`. Also -- please fix the indentation. – John Coleman Apr 27 '21 at 19:58
  • Probably because the playerTwoInput/playerOneInput wasn't True, so it didn't have anything to return. So It returned None. – Tkinter Lover Apr 27 '21 at 19:59
  • 1
    run it through a debugger. Post the inputs and the value of `Board`. Most of it doesn't make sense as it is – njzk2 Apr 27 '21 at 20:01
  • 1
    You don't have a return statement on all your paths of execution. Either missing else clauses, or missing final return at end of function. Or both. – RufusVS Apr 27 '21 at 20:02
  • Note that `if x: return True else: return False` can be reduced to `return x`. (Here `x` stands for an complicated boolean expression) – Code-Apprentice Apr 27 '21 at 20:36

2 Answers2

1

Generally functions return None if they end without reaching a return with a value.

In your function this can happen in two ways:

  1. Both playerOneInput and playerTwoInput are falsy. When that happens, code execution will end below both if blocks, where there is no more code to execute, and None will be returned, because there is nothing to return. (To understand what "truthy" and "falsy" means, this SO answer explains is pretty well. )
  2. The same thing happens if one of playerOneInput and playerTwoInput is truthy, but when testing whether it is in Board, this evaluates to False. There is no else: present to catch execution, it ends up having nothing to return, and thus it returns None.

To fix 2, you might want to change

    if playerOneInput:
        if playerOneInput in Board:

to

    if playerOneInput and playerOneInput in Board:

if you need both to be True and you don't want to handle it differently when the player input is truthy, but not in the board.

To fix 1, you need to figure out whether you want to test the input in the beginning, and raise an error when neither playerOneInput or playerTwoInput (or maybe even Board) is usable, or if you want to handle it in an else: at the end of the function.

Also, you may want to just take the input of just one player, and then call the function twice.

beruic
  • 5,517
  • 3
  • 35
  • 59
0

The only way that the function returned None is if either both playerOneInput and playerTwoInput are equal to "", False, or None (since they would've failed the conditionals) or that both playerOneInput and playerTwoInput are not found in the Board (if this is the case, then we can't help since you haven't provided us with the code for the Board so that we can see where the problem is).

Therefore, the reason why the function returns None is because you are running it without parameters, making it default to the value "" for playerOneInput and playerTwoInput.

  • I edited it so that you can see the rest of my code for the program. – Kendrick Jude Mausisa Apr 27 '21 at 20:30
  • @KendrickJudeMausisa for future reference: we _don't_ want all of your code. We want a [MRE] that _replicates_ your problem in _as little code as possible_. This is _not the same as_ all of your code, and while we know that it's extra work, it's work that _any programmer_ would to do as part of their job anyway if Stack Overflow didn't exist. A [mre] allows us to quickly see the code in a context that breaks it, but without having to hunt for the relevant parts in a wall of code. – Pranav Hosangadi Apr 27 '21 at 20:42
  • @PranavHosangadi I understand. I'm very new to this. Thank you for your help! – Kendrick Jude Mausisa Apr 27 '21 at 20:47