Search code examples
pythontic-tac-toe

Tic-Tac-Toe Game


I've wrote a code for the Tic-Tac-Toe game.

Here's what the code does:

  1. Gets the name of Player 1.
  2. Gets the name of Player 2.
  3. Asks if the Player 1 wants X or O.
  4. If he chooses X then Player 2 gets O and vice versa.
  5. Prints the empty board.
  6. Asks both players to enter the row and column one by one and prints the updated board.
    • If a player doesn't repeat previous player's spot, everything works fine until the end without any problem.
    • If a player repeats previous player's spot, a message is displayed saying that the previous player has already taken this spot and makes him guess again.

Now, after this point, if I guess any index other than the one that the previous player has already taken, it overwrites the previous players spot.

Screenshot of the terminal when this occurs:

enter image description here

I'm certain that the problem is in the function enterguess(turncount), but haven't been able to spot it yet. Any idea where the problem is?

<----------------------------------------------[ Demo Without the colors ]-------------------------------------------->

Code:

import termcolor

board = [[" ", " ", " "], [" ", " ", " "], [" ", " ", " "]]
vb = termcolor.colored("|", "yellow", None, ['bold'])
s = termcolor.colored("\t+---+---+---+", "yellow", None, ['bold'])
players = {
        'player1' : '',
        'player2' : ''
}
sym = {
        'player1': '',
        'player2': ''
}

def rules ():
    print("\nWelcome to Tic Tac Toe...")

def printboard():
    #boardlist = [[" "," "," "],[" "," "," "],[" "," "," "]]
    for row in board:
        print s
        print "\t" + vb + " " + row[0] + " " + vb + " " + row[1] + " " + vb + " " + row[2] + " " + vb
    print s

def playerNames():
    p1 = termcolor.colored(raw_input("\nEnter name of Player 1: ").title(), 'red', None, ['underline'])
    p2 = termcolor.colored(raw_input("Enter name of Player 2: ").title(), 'blue', None, ['underline'])
    sym['player1'] = termcolor.colored(raw_input("\n" + p1 + ', you want X or O? - ').capitalize(), 'red', None, ['bold'])
    if sym['player1'] == 'X':
        sym['player2'] = termcolor.colored('O', 'blue', None, ['bold'])
    else:
        sym['player2'] = termcolor.colored('X', 'red', None, ['bold'])
    players['player1'] = p1
    players['player2'] = p2
    return {p1:termcolor.colored('X', 'red', None, ['bold']), p2: termcolor.colored('O', 'blue', None, ['bold'])}

def enterguess(turncount):
    def guess(name):
        return (int(input("\n" + players[name] + ", Enter row number: ")),
                int(input(players[name] + ", Enter column number: ")))

    if turncount % 2 == 0:
        (row, col) = guess('player1')

        try:
            if board[row - 1][col - 1] in [sym['player1'], sym['player2']]:
                print "\n" + players['player2'] + " already took that spot! Please guess again."
                enterguess(turncount)
        except:
            print "\nPlease enter the indexes between 1 and 3."
            enterguess(turncount)

    else:
        (row, col) = guess('player2')

        try:
            if board[row - 1][col - 1] in [sym['player1'], sym['player2']]:
                print "\n" + players['player1'] + " already took that spot! Please guess again."
                enterguess(turncount)
        except IndexError:
            print "\nPlease enter a number between 1 and 3."
            enterguess(turncount)

    return (row - 1, col - 1)


def changeboard(row, col, xo, c):
    if c % 2 == 0:
        board[row][col] = xo[players['player1']]
    else:
        board[row][col] = xo[players['player2']]

def checkWinner():
    for x in range(3):
        if board[x][0] == board[x][1] == board[x][2] and board[x][0] != " ":
            return [players[n] for n, s in sym.iteritems() if s == board[x][0]][0]

    for y in range(3):
        if board[0][y] == board[1][y] == board[2][y] and board[0][y] != " ":
            return [players[n] for n, s in sym.iteritems() if s == board[0][y]][0]

    xx = 0
    yy = 2
    while True:
        if board[xx][xx] == board[1][1] == board[2][yy] and board[xx][xx] != " ":
            return [players[n] for n, s in sym.iteritems() if s == board[xx][xx]][0]
        xx += 2
        yy -= 2
        if xx == 2:
            break


def main():
    rules()
    xo = playerNames()
    printboard()
    turncount = 0
    for turn in range(9):
        (r, c) = enterguess(turncount)
        print (r, c)
        changeboard(r, c, xo, turncount)
        turncount += 1
        winner = checkWinner()
        printboard()

        if winner:
            print("\nCongratulations " + winner + "! You are the winner.\n")
            break
        if turn == 8:
            print ("\n    Well! Its a tie.\n")

main()

Solution

  • The issue you have is that although you recall enterguess, you don't return it. So it simply keeps recalling enterguess until a valid input is given, then it just ignores all this and goes to the final return statement which still has the malformed guess.

    Add return statements:

    def enterguess(turncount):
        def guess(name):
            return (int(input("\n" + players[name] + ", Enter row number: ")),
                    int(input(players[name] + ", Enter column number: ")))
    
        if turncount % 2 == 0:
            (row, col) = guess('player1')
    
            try:
                if board[row - 1][col - 1] in [sym['player1'], sym['player2']]:
                    print "\n" + players['player2'] + " already took that spot! Please guess again."
                    return enterguess(turncount)
            except:
                print "\nPlease enter the indexes between 1 and 3."
                return enterguess(turncount)
    
        else:
            (row, col) = guess('player2')
    
            try:
                if board[row - 1][col - 1] in [sym['player1'], sym['player2']]:
                    print "\n" + players['player1'] + " already took that spot! Please guess again."
                    return enterguess(turncount)
            except IndexError:
                print "\nPlease enter a number between 1 and 3."
                return nterguess(turncount)
    
        return (row - 1, col - 1)