Python Forum
Help with simplifying the tie function
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help with simplifying the tie function
#1
Hi so for my AI class intro we had to programme a game. I made tic tac toe in python. If you look at the check_for_tie function, it looks a little bit too long and janky. Is there a way to simplify it?

#creating tic tac toe


# 1 create a board
# 2 print the board
# 3 create a function that asks the users for input.
# 4 create a function that checks for a win.

# global variable
game = True

#create a board

board = [
    "-", "-", "-",
    "-", "-", "-",
    "-", "-", "-",
]

player_won = "none"

# create a function that prints the board
def print_board():
    print("|" + board[0] + "|" + board[1] + "|" + board[2] +  "|")
    print("|" + board[3] + "|" + board[4] + "|" + board[5] + "|")
    print("|" + board[6] + "|" + board[7] + "|" + board[8] + "|")


# create the functions that ask the two users for input. You wil have an x and an o


# we want it to ask for the position
def player_x():
    position = input("Choose your position from 1-9: ")
    position = int(position) - 1
    board[position] = "x"


# the function for player o
def player_o():
    position = input("Choose your position from 1-9: ")
    position = int(position) - 1
    board[position] = "o"

tie = False
# check for rows
def check_rows():
    global game
    row1 = board[0] == board[1] == board[2] != "-"
    row2 = board[3] == board[4] == board[5] != "-"
    row3 = board[6] == board[7] == board[8] != "-"
    if row1 or row2 or row3:
        game = False
    if row1:
        print("You have won, player: " + board[0])
    elif row2:
        print("You have won, player: " + board[3])
    elif row3:
        print("You have won, player: " + board[6])

# check for diagonals
def check_diagonals():
    global game
    diag1 = board[2] == board[4] == board[6] != "-"
    diag2 = board[0] == board[4] == board[8] != "-"
    if diag1 or diag2:
        game = False
    if diag1:
        return print("You have won, player: " + board[2])
    elif diag2:
        return print("You have won, player: " + board[0])

# check for columns
def check_columns():
    global game
    c1 = board[0] == board[3] == board[6] != "-"
    c2 = board[1] == board[4] == board[7] != "-"
    c3 = board[2] == board[5] == board[8] != "-"
    if c1 or c2 or c3:
        game = False
    if c1:
        return print("You have won, player: " + board[0])
    if c2:
        return print("You have won, player: " + board[1])
    if c3:
        return print("You have won, player: " + board[2])

# create a function where all the positions are filled in with x's or o's. So basically where everything doesn't equal "-".
def check_for_tie():
    global game
    b1 = board[0] and board[1] and board[2] and board[3] and board[4] and board[5] and board[6] and board[7] and board[8] != "-"
    if b1:
        game = False
        print("You have tied!")



# creating the check function
def check_for_winner():
    check_rows()
    check_diagonals()
    check_columns()

# creating the game loop


# this is the game loop that makes the code run
while game:
    print_board()
    player_x()
    check_for_winner()
    print_board()
    player_o()
    check_for_winner()
    check_for_tie()
Reply
#2
First off, this condition, is not doing what you think it is doing:
board[0] and board[1] and board[2] and board[3] and board[4] and board[5] and board[6] and board[7] and board[8] != "-"
for board[0]-> board[7] you are only checking if they are truthy values and only board[8] is checked if it's not equal "-" value, you would have to write it like this:
board[0] != "-" and board[1] != "-" and board[2] != "-" and board[3] != "-" and board[4] != "-" and board[5] != "-" and board[6] != "-" and board[7] != "-" and board[8] != "-"
or shorter version:
if all(x != '-' for x in board):
	game = False
	print("You have tied!")
Reply
#3
Why are you testing for a tie? The three outcomes after an entry are: Player Wins, Continue Play, Tie. If the last entry did not win the game the state of the board is Tie or Continue Play. How can we differentiate between the two?

One way is to verify that each position on the board is filled, but a simpler solution is to count the number of entries made since the start of the game. If entries < 9, the game is not over. If entries = 9 and nobody won, the game ended in a tie.

I would write this game starting with :
for i in range(9):
else:
    print('You have tied!')
Next I would have to decide who makes the next choice, X or O. Player X plays on even turns and Y plays on odd turns. Then I would notice that the player_x() and player_o() functions are identical except they use a different letter. I hate code, so I combine the two.

Why are there so many functions for finding a win? Do I care how the player won? Is a diagonal win better than a row or column? If there is no difference between the wins, why is there more than one win function? Do you think it makes the code easier to read? You have some nice tests to check for a win, why not combine them into one function?
def player_wins(mark):
    """Return True of player "mark" won"""
    # Check the rows
    if mark == board[0] == board[1] == board[2] or \
       mark == board[3] == board[4] == board[5] or \
       mark == board[6] == board[7] == board[8]:
        return True

    # Check the columns
    if mark == board[0] == board[3] == board[6] or \
       mark == board[1] == board[4] == board[7] or \
       mark == board[2] == board[5] == board[8]:
        return True

     # Check the columns
    if mark == board[0] == board[4] == board[8] or \
       mark == board[2] == board[4] == board[6]:
        return True

    return False
The test for a win is complicated by empty spots using the same marker ("-"). Are you required to use this marker, or could you use something different like this:
Output:
Place X: 1 |X|2|3| |4|5|6| |7|8|9|
Now each spot is different, simplifying the test for a win. Plus the numbers on the board help the player make a selection.

Tic-tac-toe is a simple game and it should be a simple program. Starting with your code I chopped it down to 30 lines, including a few comments. As with most programs, code reduction/optimization resulted mostly from removing what wasn't needed (do not need a test for a tie), replacing specific code with generic code (replace player_x() and player_o() with one function that does either) and doing things in the simplest way (test for win is the most complicated part of the program. Make as simple as possible. My win test got so short it no longer deserves its' own function).
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Simplifying a short code schniefen 4 2,615 Apr-18-2019, 10:50 PM
Last Post: schniefen
  Simplifying a rather short code schniefen 1 2,014 Apr-07-2019, 02:11 AM
Last Post: nilamo

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020