2-player Tic-Tac-Toe game Below is my Python 3.7 code for a Tic-Tac-Toe game I made as a programming challenge. I want to know if I could make this code less janky, more readable or improve it in any way.

# Defining Main Game Functions, variables, etc.
board = [0,1,2,
         3,4,5,
         6,7,8]
win_con = [[0,1,2],[3,4,5],[6,7,8],
            [0,3,6],[1,4,7],[2,5,8],
            [0,4,8],[2,4,6]] # possible 3-in-a-rows
def show():
    print(board[0],'|',board[1],'|',board[2])
    print('----------')
    print(board[3],'|',board[4],'|',board[5])
    print('----------')
    print(board[6],'|',board[7],'|',board[8])
def x_move(i):
    if board[i] == 'X' or board[i] == 'O':
        return print('Already taken!')
    else:
        del board[i]
        board.insert(i,'X')
def o_move(i):
    if board[i] == 'X' or board[i] == 'O':
        return print('Already taken!')
    else:
        del board[i]
        board.insert(i,'O')    
# Main Game Loop
while True:
    turn_num = 1
    board = [0,1,2,3,4,5,6,7,8]
    print('Welcome to Tic-Tac-Toe!')
    print('AI not implemented yet.')
    while True:
        for list in win_con: # check if someone's won
            xnum = 0
            onum = 0
            for num in list:
                if board[num] == 'X':
                    xnum += 1
                elif board[num] == 'O':
                    onum += 1
                else:
                    pass
            if xnum == 3 or onum == 3:
                break
        if xnum == 3 or onum == 3: # break out of all loops
            break
        if turn_num &gt; 9: # check if board is full
            break
        show()
        if turn_num % 2 == 1:
            print('X\'s turn.')
        else:
            print('O\'s turn.')
        move = int(input('Choose a space. '))
        if turn_num % 2 == 1:
            x_move(move)
        else:
            o_move(move)
        turn_num += 1
    if xnum == 3: # After game is over
        print('X Won!')
    elif onum == 3:
        print('O Won!')
    else:
        print('Draw!')
    play_again = input('Play again? Y or N ')
    if play_again == 'Y' or play_again == 'y':
        continue
    else:
        break
You probably forgot to test for this, but there's a bug in your program.

def x_move(i):
    if board[i] == 'X' or board[i] == 'O':
        return print('Already taken!')
    else:
        del board[i]
        board.insert(i,'X')
def o_move(i):
    if board[i] == 'X' or board[i] == 'O':
        return print('Already taken!')
    else:
        del board[i]
        board.insert(i,'O')


For starters, you should move this into a single function which takes the player as argument. This way a single function can be used for both players and this will save you from having to fix the bug twice. Code duplication is bad.

An obvious, not necessarily pretty, solution:

def any_move(i, player_character):
    if not isinstance(board[i], int):
        return print('Already taken!')
    else:
        del board[i]
        board.insert(i, player_character)


This checks whether the value picked on the board is an integer. If it's not, it has already been taken by either X, O or whatever player characters you're using at that moment.

But the real problem is this will skip a turn on invalid input. If I pick 4 with X in one turn and pick the same tile with O a turn later, O will be missing out a turn. I imagine there should be a loop in there checking whether valid input has been inserted yet. If not, stay in the loop. If valid input is inserted, make the actual move.

I'm talking about valid input here, not just whether the input is 0 - 8. Your program will crash if I enter something invalid, like b or 11. The first is not an integer and the second is out of range. It crashes on no input (just hit enter) as well. You should at least capture those exceptions.