Home > other >  How do I make this function like a tic tac toe board
How do I make this function like a tic tac toe board

Time:10-08

This tic-tac-toe board doesn't work like one. What can I adjust? Also, how do I determine a winner? Would it be easiest to start from scratch?

import random
score = 0
x_or_o =('x','o')
a = (random.choice(x_or_o))  
b = (random.choice(x_or_o))
c = (random.choice(x_or_o)) 
d = (random.choice(x_or_o)) 
e = (random.choice(x_or_o)) 
f = (random.choice(x_or_o)) 
g = (random.choice(x_or_o)) 
h = (random.choice(x_or_o)) 
i = (random.choice(x_or_o)) 
j = (random.choice(x_or_o)) 
def board():
    board = [["|", a,"|", b,"|", c,'|'],
            ["--------------------"],
            ["|", d,"|", e,"|", f,'|'],
            ["--------------------"],
            ["|", g,"|", h,"|", j,'|']]  
    for i in board:
       for z in i:
         print(z, end = "  ")
       print()    

board()

CodePudding user response:

This function will check if someone has won, and return either the winner if there is one, or returns False otherwise. It may not be the most efficient method, but it should work, and it could certainly be less efficient.

def check():
    winner = False

    checksets = [
        {a, b, c}, #top
        {d, e, f}, #middle
        {g, h, i}, #bottom
        {a, d, g}, #left
        {b, e, h}, #center
        {c, f, i}, #right
        {a, e, i}, #diag TL to BR
        {c, e, g}  #diag TR to BL
    ]

    for s in checksets:
        # sets can only have unique values, so if the length is 1, it means there is only one unique value in the set, meaning all 3 items are the same
        if len(s) == 1 & (next(iter(s)) == "x" or next(iter(s)) == "o"):
            winner = next(iter(s))
    return winner

Call this function after each variable declaration starting with the 3rd one. Ensure all the variables are set to something other than "x" or "o" at the beginning.

I want to note that this is my way to make your existing code check for a winner. If you want a better method, there are better ways. Perhaps you can look for a tutorial, or just think about using a loop to fill in the board list instead of using variables. Keep in mind you will need to use board[0][0], board[0][1], etc. instead of a, b, etc. when you check for a winner. And for that to work, you will want your board to only have the values, with no extra characters (like pipes and dashes). If you want those to show up when you display the board, add it into a function for printing the board.

CodePudding user response:

Another way instead of my other answer is to prepare a full set of possible winning combinations of positions and use these to check for a winner.

import numpy as np

row_idxs = np.array([
    (0, 0, 0),  # horizontals
    (1, 1, 1),
    (2, 2, 2),
    (0, 1, 2),  # verticals
    (0, 1, 2),
    (0, 1, 2),
    (0, 1, 2),  # diagonals
    (0, 1, 2),
])

col_idxs = np.array([
    (0, 1, 2),  # horizontals
    (0, 1, 2),
    (0, 1, 2),
    (0, 0, 0),  # verticals
    (1, 1, 1),
    (2, 2, 2),
    (0, 1, 2),  # diagonals
    (2, 1, 0)
])


def check_game_state(state):
    """Check the game state to see whether any player
    has won or if it is draw.
    Args:
        state (np.array):
            Game state
    returns:
        game_over, winner (bool, bool):
            If there is a winner, winner will be the winning 
            player. If the game is over, game_over will be True.
            If it's a draw, winner will be None.
    """

    game_over, winner = False, None

    # Check for a win state using already-defined
    # array indices
    lines = state[row_idxs, col_idxs]
    for player in players:
        if ((lines == player).sum(axis=1) == 3).any():
            game_over, winner = True, player
            break
    if winner is None and np.all(state > 0):
        game_over = True

    return game_over, winner


state = np.zeros((3, 3))
assert(check_game_state(state) == (False, None))
state[1, :] = 1
assert(check_game_state(state) == (True, 1))
state[:, 2] = 2
assert(check_game_state(state) == (True, 2))
state = np.array([
    [1, 2, 1],
    [2, 2, 1],
    [1, 1, 2]
])
assert(check_game_state(state) == (True, None))

CodePudding user response:

I wrote a tic-tac-toe game script before here using numpy if you would like to check it out.

In this version I use 0 to represent a position on the board that is not taken. 1 and 2 represent positions taken by each player.

This is how I implemented the checks of the game state.

import numpy as np

players = [1, 2]

def check_game_state(state):
    """Check the game state to see whether any player
    has won or if it is draw.
    Args:
        state (np.array):
            Game state
    returns:
        game_over, winner (bool, bool):
            If there is a winner, winner will be the winning 
            role. If the game is over, game_over will be True.
            If it's a draw, winner will be None.
    """

    game_over, winner = False, None
    for player in players:
        positions = (state == player)
        if any((
                np.any(positions.sum(axis=0) == 3),
                np.any(positions.sum(axis=1) == 3),
                (np.diagonal(positions).sum() == 3),
                (np.diagonal(np.fliplr(positions)).sum() == 3)
            )):
            game_over, winner = True, player
    if winner is None and np.all(state > 0):
        game_over = True

    return game_over, winner

state = np.zeros((3, 3))
assert(check_game_state(state) == (False, None))
state[1, :] = 1
assert(check_game_state(state) == (True, 1))
state[:, 2] = 2
assert(check_game_state(state) == (True, 2))
state = np.array([
    [1, 2, 1],
    [2, 2, 1],
    [1, 1, 2]
])
assert(check_game_state(state) == (True, None))

CodePudding user response:

As I said in my comment, I was tempted to play with it, and here's a version that simulates random moves and reports a winner. Some of the compares could be cleaned up (like better random functions and stuff...):

from random import randint
from time import sleep

# Tic-tac-toe simulator
# The grid:
#  0 | 1 | 2
# -----------
#  3 | 4 | 5
# -----------
#  6 | 7 | 8
# -----------

# create winning lines
winlines = tuple(
    map(
        set,
        (
            (0, 1, 2),  # across
            (3, 4, 5),
            (6, 7, 8),
            (0, 3, 6),  # down
            (1, 4, 7),
            (2, 5, 8),
            (0, 4, 8),  # diagonals
            (2, 4, 6),
        ),
    )
)

for trials in range(10):
    # clear the table
    available = list(range(9))  # 9 positions 0-8
    xPlacement = set()
    oPlacement = set()

    winner = None

    while len(available):
        index = randint(0, len(available) - 1)
        move = available[index]
        if index < len(available) - 1:
            available[index] = available.pop()
        else:
            available.pop()
        print("X takes ", move)
        xPlacement.add(move)
        if any(((xPlacement & winline) == winline) for winline in winlines):
            winner = "X"
            break
        if len(available) == 0:
            break

        index = randint(0, len(available) - 1)
        move = available[index]
        if index < len(available) - 1:
            available[index] = available.pop()
        else:
            available.pop()
        print("O takes ", move)
        oPlacement.add(move)
        if any(((oPlacement & winline) == winline) for winline in winlines):
            winner = "O"
            break

    print(
        " {} | {} | {}\n-----------\n {} | {} | {}\n-----------\n {} | {} | {}".format(
            *[
                "X" if pos in xPlacement else "O" if pos in oPlacement else " "
                for pos in range(9)
            ]
        )
    )
    if winner:
        print(f"{winner} wins!")
    else:
        print("It's a tie!")
    sleep(1)
  • Related