5
\$\begingroup\$

Is there any way I could make my Tic-Tac-Toe board more aesthetically pleasing?

Is there anything else I can improve besides the look of the board?

from AskUser import ask_user as As
from random import randint
Choice = 0
Player1 = None
Player2 = None

#Introduction
def intro():
    global Choice
    while True:
        Choice = As("Press 1 for Multiplayer\nPress 2 for Single player: ", int)
        if Choice != (1 or 2):
            print("Invalid Input")
            continue
        else:
            break
    return Choice

#Players
def choosenplayer():
        # Defines whos going first
    if Choice == 1:
        def whofirst():
            global q
            q = randint(1, 2)
            if q == 1:
                print(f"Player 1 ({Player1}) is going first")
            else:
                print(f"Player 2 ({Player2}) is going first")
        # Defines the player
        while True:
            global Player2
            global Player1
            Player = As("Press 1 if you want to be 'X'\nPress 2 if you want to be 'O': ", int)
            if Player == 1:
                Player1 = "X"
                Player2 = "O"
                break
            elif Player == 2:
                Player1 = "O"
                Player2 = "X"
                break
            else:
                print("Invalid Input")
                continue
        print(f"Player 1 is {Player1}, Player 2 is {Player2}")
        whofirst()
        return Player1 and Player2

board = list (range(0,9))
#Initialise The Tic Tac Toe Board
def t_Board():
    print(f"| {board[0]} | {board[1]} | {board[2]} |\n_____________")
    print(f"| {board[3]} | {board[4]} | {board[5]} |\n_____________")
    print(f"| {board[6]} | {board[7]} | {board[8]} |")

#Stops the game if theres a win
def stops_board():
    if (board[0] == board[1] == board[2]) or (board[3] == board[4] == board[5]) or (
    board[6] == board[7] == board[8]) or (board[0] == board[3] == board[6]) or (
    board[1] == board[4] == board[7]) or (board[2] == board[5] == board[8]) or (
    board[0] == board[4] == board[8]) or (board[2] == board[4] == board[6]):
        return True

#Ask for X User input
x_data = []
def xuser_input():
    def over_ride():
        global x
        while True:
            x = As("Player X, Please enter a number to place: ",int)
            if board[x] == "X" or board[x] == "O":
                print("You can't place here, it is already used")
                continue
            else:
                break
    while True:
        over_ride()
        if (x > 10) or (x < 0):
            print("Input must be Bigger than 0 and Smaller than 9")
            continue
        try:
            board[x] = "X"
            x_data.append(x)
        except (IndexError):
            print("Invalid input")
            continue
        t_Board()
        break
#Ask for Y User input
O_data = []
def yuser_input():
    def over_rideo():
        global O
        while True:
            O = As("Player O, Please enter a number to place: ",int)
            if board[O] == "X" or board[O] == "O":
                print("You can't place here, it is already used")
                continue
            else:
                break
    while True:
        over_rideo()
        if (O > 10) or (O < 0):
            print("Input must be Bigger than 0 and Smaller than 9")
            continue
        try:
            board[O] = "O"
            O_data.append(O)
        except (IndexError):
            print("Invalid input")
            continue
        t_Board()
        break

print("Welcome to TicTacToe simulator")
intro()
choosenplayer()
t_Board()
if ((q == 1) and (Player1 == "X")) or ((q == 2) and (Player2 =="X")):
    for i in range(5):
        xuser_input()
        if stops_board():
            print(f"Congrats X, You are the winner")
            break
        if i == 4:
            print("This is a tie")
            break
        yuser_input()
        if stops_board():
            print(f"Congrats Y, You are the winner")
            break


elif ((q == 1) and (Player1 == "O")) or ((q == 2) and (Player2 == "O")):
    for i in range(5):
        yuser_input()
        if stops_board():
            print(f"Congrats O, You are the winner")
            break
        if i == 4:
            print("This is a tie")
            break
        xuser_input()
        if stops_board():
            print(f"Congrats X, You are the winner")
            break

This is the As function

def ask_user(message, type_= str, valid=lambda x: True, invalid_message="Invalid"):
    while True:
        try:
            user_input = type_(input(message))
        except (ValueError, TypeError):
            print("Invalid input")
            continue
        if valid(user_input):
            return user_input
        else:
            print(invalid_message)

This code is fully functional, but only for local multiplayer. No AI is in place as of yet.

\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to Code Review! I changed the title so that it describes what the code does per site goals: "State what your code does in your title, not your main concerns about it.". Feel free to edit and give it a different title if there is something more appropriate. \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ May 22 at 23:34
  • \$\begingroup\$ An immediate bug I see is if Choice != (1 or 2): \$\endgroup\$ – Linny May 23 at 7:03
  • \$\begingroup\$ you were right it wasn't working when i type 2 \$\endgroup\$ – ShreddedPumpkin May 24 at 13:18
1
\$\begingroup\$

Check out the pyinputplus module. It's good for when you are asking for specific user input, such as when you want the user to answer with 'yes' or 'no', or in your case, 'X' or 'O'.

So in that case you would do something like this:

from pyinputplus import *

inputChoice(('X', 'O'))

Which will return:

Please select one of: X, O

Alternatively, as a second argument for inputChoice(), you can enter a string for the prompt:

from pyinputplus import *

inputChoice(('X', 'O'), 'Please enter your letter: X or O)

Which will return:

Please enter your letter: X or O

The input will act as a while loop until one of the provided choices are input(typecase is not taken into account by default, though I think this can be changed within the function's arguments). If an invalid choice is input, the code will return (assuming your input was 'x')

'x' is not a valid choice.

pyinputplus and its various functions are great when requiring specific user input, as it keeps you from having to have a bunch of if/elif/else statements under a while loop. It saves a lot of time.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ i know that it is a good module but i still need to assign player 1 as "X" or "Y' and same for player 2, so i think i still need the if else statement. Unless its for the single player mode where i just need it to be 1 letter \$\endgroup\$ – ShreddedPumpkin May 24 at 13:05
  • \$\begingroup\$ In that case, have the pyinputplus inputChoice command assign the letter to player 1, and use and if/else statements to assign the other letter to player 2. \$\endgroup\$ – Joel V May 25 at 14:34
  • \$\begingroup\$ @JoelV Don't do from ... import *. \$\endgroup\$ – userff May 27 at 14:15
1
\$\begingroup\$

Your first question "can the board be made more aesthetically pleasing" is subjective, but I would prefer, for only ASCII characters, something like:

 X | O | 2 
---+---+---
 3 | X | 5  
---+---+---
 6 | 7 | O 

But you could make it even more fancier by using Unicode Box-drawing characters, you can copy and paste these from the Wikipedia page 'Box-drawing character':

 X │ O │ 2 
───┼───┼───
 3 │ X │ 5  
───┼───┼───
 6 │ 7 │ O 

Some other remarks:

  • The function ask_user could be just as good in the main file and renaming it in the import statement to As does not make its use clearer.
  • You could use a main guard clause to indicate, amongst others, where the main part of the code begins, see for example this StackOverflow Question and links therein.
  • Think of more descriptive function names, for instance t_Board would be better called print_board.
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.