AV's Blog

Tic-tac-toe Game Using NumPy

August 07, 2017

NumPy is a Python module that allows for vectorized operations on arrays of data. For example, to add, say 1 to each of the elements of a list, say a list containing elements 1, 2, 3 (numbers or integers), you cannot simply write:

>>>numbers = [1, 2, 3]
>>>numbers + 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "int") to list
>>>

(Concatenation is possible if you are adding another list. Also, if you want to add an element, you can use the function append or insert.)

One way to create a list out of this list where each element is incremented by one is by using a for loop or using a list comprehension.

Using a for loop

>>>numbers = [1, 2, 3]
>>>numbers2 = []
>>>for number in numbers:
...    numbers2.append(number + 1)
...
>>>print(numbers2)
[2, 3, 4]

Using a list comprehension

>>>numbers = [1, 2, 3]
>>>numbers3 = [x + 1 for x in numbers]
>>>print(numbers3)
[2, 3, 4]

But using the NumPy module, one can simply use the addition operation. But you need to first convert the list to a NumPy object.

>>>import numpy as np
>>>numbers = np.array([1, 2, 3])
>>>numbers + 1
array([2, 3, 4])

One game I was able to apply NumPy to is the game of tic-tac-toe. I modified this code which was an assignment for the EdX course, “Using Python for Research” taught by JP Onnela (I also highly recommend it). Here is the whole code. Among the NumPy operations I was able to use and really learn were:

  • numpy.where()
  • numpy.any()
  • numpy.all()

This game allows one to be able to choose whether you want to play the game (play against the computer only), play first or second and play again. It doesn’t include AI (computer randomly chooses its position in the board). So you will always win!

"""
Tic-tac-toe game using NumPy
"""


import numpy as np
import random
import matplotlib.pyplot as plt


def print_header():
    print("-------------------------------")
    print("         TIC TAC TOE")
    print("-------------------------------\n")


def create_board():
    return np.zeros((3,3))


def place(board, player, position):
    if board[position[0], position[1]] == 0:
        board[position[0], position[1]] = player
    else:
        print("Cannot place in that position.")
    return board


def possibilities(board):
    empty = np.where(board == 0)
    first = empty[0].tolist()
    second = empty[1].tolist()
    return [x for x in zip(first, second)]


def random_place(board, player):
    empty = possibilities(board)
    return place(board, player, random.choice(empty))


def row_win(board, player):
    return np.any((np.all(board == player, axis=1)))


def col_win(board, player):
    return np.any((np.all(board==player, axis=0)))


def diag_win(board, player):
    diag1 = np.array([board[0,0], board[1,1], board[2,2]])
    diag2 = np.array([board[0,2], board[1,1], board[2,0]])
    return np.all(diag1 == player) or np.all(diag2 == player)


def evaluate(board, players):
    winner = 0
    for player in players:
        if row_win(board, player):
            winner = player
        elif col_win(board, player):
            winner = player
        elif diag_win(board, player):
            winner = player
    if np.all(board != 0) and winner == 0:
        winner = -1
    return winner


def game_loop():

    start = input("Do you want to play a game? (y/n) ")
    print(start)
    if start.lower() in ["y", "yes"]:
        repeat = True
        while repeat == True:
            play_game()
            loop = input("Do you want to play again? (y/n) ")
            if loop.lower() in ["y", "yes"]:
                repeat = True
            else:
                repeat = False
                print("Goodbye!")
    else:
        print("I'm sorry, I didn't understand.")
        game_loop()


def play_game():
    """
    Game proper.
    """
    board = create_board()
    print("Here is the board.")
    print(board)
    print()
    print("To place your position, indicate the row number and the column number.")
    print("For example, to place your position in the middle, type in 2,2 (without spaces).")
    print("If you want to place in the top left corner, type in 1,1 (without spaces")
    order = int(input("Do you want to go first or second? (1/2) "))

    if order == 1:
        player1 = 1
        player2 = 2
        players = [player1, player2]
    else:
        player1 = 2
        player2 = 1
        players = [player2, player1]
    print("You are player {}:".format(order))
    winner = 0
    while winner == 0:
        for player in players:
            if player == order:
                position = input("What position do you want to place? ")
                print("You want to place at {} position.".format(position))
                position = int(position[0])-1, int(position[2])-1
                place(board, player1, position) # will break if position is not 0 (empty)
                print(board)
            else:
                print("My move:")
                random_place(board, player)
                print(board)
            winner = evaluate(board, players)
            if winner > 0:
                if winner == order:
                    print("You win!!!")
                else:
                    print("I win!!!")
                break
            elif winner == -1:
                print("It's a draw!")
                break
            print()
    return winner

def main():
    """
    Main program for playing tictactoe.
    """
    print_header()
    game_loop()


if __name__ == '__main__':
    main()