user3295015
user3295015

Reputation: 131

Python tic tac toe game

I am unsure if all of the code will be necessary or not so i will post it:

# Tic-Tac-Toe
# Plays the game of tic-tac-toe against a human opponent

# global constants
X = "X"
O = "O"
EMPTY = " "
TIE = "TIE"
NUM_SQUARES = 9


def display_instruct():
    """Display game instructions."""  
    print(
    """
    Welcome to the greatest intellectual challenge of all time: Tic-Tac-Toe.  
    This will be a showdown between your human brain and my silicon processor.  

    You will make your move known by entering a number, 0 - 8.  The number 
    will correspond to the board position as illustrated:

                    0 | 1 | 2
                    ---------
                    3 | 4 | 5
                    ---------
                    6 | 7 | 8

    Prepare yourself, human.  The ultimate battle is about to begin. \n
    """
    )


def ask_yes_no(question):
    """Ask a yes or no question."""
    response = None
    while response not in ("y", "n"):
        response = input(question).lower()
    return response


def ask_number(question, low, high):
    """Ask for a number within a range."""
    response = None
    while response not in range(low, high):
        response = int(input(question))
    return response


def pieces():
    """Determine if player or computer goes first."""
    go_first = ask_yes_no("Do you require the first move? (y/n): ")
    if go_first == "y":
        print("\nThen take the first move.  You will need it.")
        human = X
        computer = O
    else:
        print("\nYour bravery will be your undoing... I will go first.")
        computer = X
        human = O
    return computer, human


def new_board():
    """Create new game board."""
    board = []
    for square in range(NUM_SQUARES):
        board.append(EMPTY)
    return board



def display_board(board):
    """Display game board on screen."""
    print("\n\t", board[0], "|", board[1], "|", board[2])
    print("\t","---------")
    print("\t",board[3], "|", board[4], "|", board[5])
    print("\t","---------")
    print("\t",board[6], "|", board[7], "|", board[8])

def legal_moves(board):
    """Create list of legal moves."""
    moves = []
    for square in range(NUM_SQUARES):
        if board[square] == EMPTY:
            moves.append(square)
    return moves


def winner(board):
    """Determine the game winner."""
    WAYS_TO_WIN = ((0, 1, 2),
                   (3, 4, 5),
                   (6, 7, 8),
                   (0, 3, 6),
                   (1, 4, 7),
                   (2, 5, 8),
                   (0, 4, 8),
                   (2, 4, 6))

    for row in WAYS_TO_WIN:
        if board[row[0]] == board[row[1]] == board[row[2]] != EMPTY:
            winner = board[row[0]]
            return winner

    if EMPTY not in board:
        return TIE

    return None


def human_move(board, human):
    """Get human move."""  
    legal = legal_moves(board)
    move = None
    while move not in legal:
        move = ask_number("Where will you move? (0 - 8):", 0, NUM_SQUARES)
        if move not in legal:
            print("\nThat square is already occupied, foolish human.  Choose another.\n")
    print("Fine...")
    return move


def computer_move(board, computer, human):
    """Make computer move."""
    # make a copy to work with since function will be changing list
    board = board[:]
    # the best positions to have, in order
    BEST_MOVES = (4, 0, 2, 6, 8, 1, 3, 5, 7)

    print("I shall take square number,", end="")

    # if computer can win, take that move
    for move in legal_moves(board):
        board[move] = computer
        if winner(board) == computer:
            print(move)
            return move
        # done checking this move, undo it
        board[move] = EMPTY

    # if human can win, block that move
    for move in legal_moves(board):
        board[move] = human
        if winner(board) == human:
            print(move)
            return move
        # done checkin this move, undo it
        board[move] = EMPTY

    # since no one can win on next move, pick best open square
    for move in BEST_MOVES:
        if move in legal_moves(board):
            print(move)
            return move


def next_turn(turn):
    """Switch turns."""
    if turn == X:
        return O
    else:
        return X


def congrat_winner(the_winner, computer, human):
    """Congratulate the winner."""
    if the_winner != TIE:
        print(the_winner, "won!\n")
    else:
        print("It's a tie!\n")

    if the_winner == computer:
        print("As I predicted, human, I am triumphant once more.  \n" \
              "Proof that computers are superior to humans in all regards.")

    elif the_winner == human:
        print("No, no!  It cannot be!  Somehow you tricked me, human. \n" \
              "But never again!  I, the computer, so swear it!")

    elif the_winner == TIE:
        print("You were most lucky, human, and somehow managed to tie me.  \n" \
              "Celebrate today... for this is the best you will ever achieve.")


def main():
    display_instruct()
    computer, human = pieces()
    turn = X
    board = new_board()
    display_board(board)

    while not winner(board):
        if turn == human:
            move = human_move(board, human)
            board[move] = human
        else:
            move = computer_move(board, computer, human)
            board[move] = computer
        display_board(board)
        turn = next_turn(turn)

    the_winner = winner(board)
    congrat_winner(the_winner, computer, human)


# start the program
main()
input("\n\nPress the enter key to quit.")

This is an example in a book i am reading and i am not fully understanding, i think understand all of it up until:

for row in WAYS_TO_WIN:
            if board[row[0]] == board[row[1]] == board[row[2]] != EMPTY:
                winner = board[row[0]]
                return winner

Can somebody please explain what this function does and more specifically what the condition if board[row[0]] == board[row[1]] == board[row[2]] != EMPTY: is testing?

Upvotes: 2

Views: 23407

Answers (5)

vamshi mannem
vamshi mannem

Reputation: 125

  1. List item

    def tic_tac_toe(): board = [1, 2, 3, 4, 5, 6, 7, 8, 9] end = False win_commbinations = ((0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), (0, 4, 8), (2, 4, 6))

    def draw(): print(board[0], board[1], board[2]) print(board[3], board[4], board[5]) print(board[6], board[7], board[8]) print()

    def p1(): n = choose_number() if board[n] == "X" or board[n] == "O": print("\nYou can't go there. Try again") p1() else: board[n] = "X"

    def p2(): n = choose_number() if board[n] == "X" or board[n] == "O": print("\nYou can't go there. Try again") p2() else: board[n] = "O"

    def choose_number(): while True: while True: a = input() try: a = int(a) a -= 1 if a in range(0, 9): return a else: print("\nThat's not on the board. Try again") continue except ValueError: print("\nThat's not a number. Try again") continue

    def check_board(): count = 0 for a in win_commbinations: if board[a[0]] == board[a[1]] == board[a[2]] == "X": print("Player 1 Wins!\n") print("Congratulations!\n") return True

        if board[a[0]] == board[a[1]] == board[a[2]] == "O":
            print("Player 2 Wins!\n")
            print("Congratulations!\n")
            return True
    for a in range(9):
        if board[a] == "X" or board[a] == "O":
            count += 1
        if count == 9:
            print("The game ends in a Tie\n")
            return True
    

    while not end: draw() end = check_board() if end == True: break print("Player 1 choose where to place a cross") p1() print() draw() end = check_board() if end == True: break print("Player 2 choose where to place a nought") p2() print()

    if input("Play again (y/n)\n") == "y": print() tic_tac_toe()

Upvotes: 0

Ashwani Jha
Ashwani Jha

Reputation: 390

I would put it simply. Row is a variable that is assigned to each tuple in the tuple WAYS_TO_WIN. In the first iteration, row = (0,1,2) it checks if value at 0==1==2.

In the second iteration, row = (3,4,5) it checks if value at 3==4==5.

Row goes to each inner tuple of the outer tuple ways_to_win till row = (2,4,6) is reached. That's what the program is doing.

Upvotes: 0

Scormer
Scormer

Reputation: 62

I am new to Python. The script below for tic tac toe game is from one of my exercises. It uses a different approach.

For the data structure, I used integer value 0 for blank cells, +1 for computer placed cells and -1 for user placed cells.

The main benefit is I can use the lineValue, i.e., the sum of all three cells' values in a line, to track the status of each line. All 8 line values are stored in the list lineValues. This can make the decision much easier. For example, When it's my (computer's) turn, if there is a line with lineValue==2, I know I am going to win. Otherwise, if there are line(s) with lineValue ==-2, I have to block the intersection (if any) of these lines.

The key for making decision is the function findMostValuableCell. What it does is to find out which cell is most valuable for the next move (i.e., which cell appears in most number of lines for a specific lineValue). There is no try-out test (what-if test) in this script. It uses quite a few list comprehensions.

Hope it can help.

ttt = [0 for i in range(9)]
lines = [[0, 1, 2],[3, 4, 5],[6, 7, 8],[0, 3, 6],[1, 4, 7],[2, 5, 8],[0, 4, 8],[2, 4, 6]]
lineValues = [0 for i in range(8)]
userChar = {1: "O", -1: "X", 0: "_"}
turn = -1 # defalut to user move first

#*****************************************************
def main():
    global userChar, turn
    if input("Do you want me to start first? (Y/N)").lower()=="y":
        userChar = {1:"X",-1:"O",0:"_"}
        turn = 1
    display()
    while not hasWinner():
        if 0 in ttt:
            nextMove(turn)
            turn *= -1
            display()
        else:
            print("It's a tie!")
            break
#*****************************************************
def hasWinner():
    if max(lineValues) == 3:
        print("********  I win!!  ********")
        return True
    elif min(lineValues) == -3:
        print("********  You win  ********")
        return True
#*****************************************************
def nextMove(turn):
    if turn== -1: #User's turn
        print("It's your turn now (" + userChar[-1]+"):")
        while not isUserMoveSuccessful(input("Please choose your cell number:")):
            print("Your choice is not valid!")
    else: #Computer's turn
        print("It's my turn now...")
        for lineValue in [2,-2,-1,1,0]:
            cell = findMostValuableCell(lineValue)
            if cell>=0: #found a cell for placement
                markCell(cell, turn)
                print ("I chose cell", str(cell),"." )
                return
#*****************************************************
def isUserMoveSuccessful(userInput):
    s = list(userInput)[0]
    if '012345678'.find(s)>=0 and ttt[int(s)]==0:
        markCell(int(s), turn)
        return True
#*****************************************************
def findMostValuableCell(lineValue):
    if set(ttt)=={0}:
        return 1
    allLines = [i for i in range(8) if lineValues[i]==lineValue]
    allCells =[j for line in allLines for j in lines[line] if ttt[j]==0]
    cellFrequency = dict((c, allCells.count(c)) for c in set(allCells))
    if len(cellFrequency)>0: # get the cell with highest frequency.
        return max(cellFrequency, key=cellFrequency.get)
    else:
        return -1
#*****************************************************
def markCell(cell, trun):
    global lineValues, ttt
    ttt[cell]=turn
    lineValues = [sum(cellValue) for line in lines for cellValue in [[ttt[j] for j in line]]]
#*****************************************************
def display():
    print(' _ _ _\n'+''.join('|'+userChar[ttt[i]]+('|\n' if i%3==2 else '') for i in range(9)))
#*****************************************************
main()

Upvotes: 1

mackworth
mackworth

Reputation: 5953

It's just checking the current board to see if any winning combination of cells (as listed in the row array) have (a) the same value and (b) that value is not EMPTY.

Note: in Python, if a == b == c != d, checks that a ==b AND b == c AND c != d

So if cells 0, 1, and 2, all have X, then on the first pass through the loop, it will return X from the winner routine.

Upvotes: 2

Isaac
Isaac

Reputation: 16382

The best way to see what is going on is to put some print statements in this code when you run it.

Judging by the way things are names, you can tell that you're looking to see if someone has won the game. You know from the rules of TicTacToe that if X or O have three in a row, column, or diagonal, that player wins. You see in the board[x] == board[y] == board[z] that we're probably testing for three in a row here. So what is x, y z? Well, look at WAYS_TO_WIN. In that array are rows indicating the indices that are in a row, column, or diagonal. Thus, we're testing to see if a row, column, or diagonal contains the same character, and that character is NOT EMPTY (which is the " " [space] character).

Upvotes: 1

Related Questions