TicTacToe

TicTacToe is a HackaGames game, a simple two-player game where each player tries to align trees of their pieces.

It comes with two modes: classic and ultimate.

Try the game:

HackaGames comes with a command to start and try the game with an interactive interface in a shell.

hacka-tictactoe-play

However, it is also possible to edit and execute a short script launching a game with the interactive shell-interface, and a very simple opponent.

from hackagames.tictactoe import TictactoeMaster
from hackagames.tictactoe.shell import PlayerShell
from hackagames.tictactoe.firstBot import Bot

gameMaster= TictactoeMaster("Clasic")
gameMaster.launchLocal( [PlayerShell(), Bot()], 1 )

In ticTacToe, the players can perform one and only one action at its turn, and the game stops automatically with a winner or when no more pieces can be set on the tabletop.

The actions consist of positioning a player's piece on the grid of the form: coordinateLetter-coordinateNumber. There are 3 times 3 actions in classic mode: A-1, A-2, A-3, B-1, B-2, B-3, C-1, C-2 and C-3.

Example of grid at some point:

x: A B C
1  x    
2    o  
3  o   x

The letter at the up-left corner informs about the player pieces ('x' or 'o'). The first player aligning 3 of its pieces win the game.

Initialize a Bot

If you are implementing your first bot, please follow the first bot tutorial on Py421 game.

The wakeUp method informs about the mode of the game, the perception of the status of the grid and the possibilities of actions. The hackagames Tictactoe package includes a very useful Grid class to manipulate the game state.

A minimal random Bot can be implemented in a few lines:

import random, hacka
from hackagames.tictactoe.grid import Grid

class MyBot() :
    def __init__(self):
        self.grid= Grid()
        self.playerId= 0
        self.possibilities= [0]
        self.results= []

    # Player interface :
    def wakeUp(self, playerId, numberOfPlayers, gamePod ):
        assert( gamePod.label() in ['TicTacToe-Classic', 'TicTacToe-Ultimate'] )
        self.playerId= playerId
        # Initialize the grid Classic or Ultimate
        self.grid= Grid( gamePod.label().split('-')[1] )
        self.possibilities= [1]

    def perceive(self, gameState):
        # Update the grid:
        self.grid.update( gameState.children()[:-1] )
        self.possibilities= gameState.children()[-1].integers()

    def decide(self):
        # Get all actions
        actions= self.grid.possibleActions( self.possibilities )
        # Select one 
        return hacka.Pod( random.choice( actions ) )

    def sleep(self, result):
        self.results.append(result)

And can be tested by replacing the PlayerShell or the opponent bot in the launch script. To notice that, the number of games can be increased mainly when 2 bots are competing:

gameMaster= TictactoeMaster("classic")
gameMaster.launchLocal( [MyBot(), Bot()], 1000 )

At this point, the results comparing the 2 Bot would be very close. The 2 bots have the same behavior (selecting a random action). To notice that, in case of wrong actions, the game will ask the player for a second call.

Customize your Bot:

The Grid object provides an abstract of the game tableboard easily updatable at perception step. It is based on two main methods: at(abs, ord), returning a cell value (for instance grid.at('A', 2)\(\rightarrow\)0 if the cell is empty) and at_set(abs, ord, aValue) to set a specific value on a specific cell. For debug purpose, it is also possible to visualize the grid: str(self.grid), typically into the shell : print(grid).

From that point you can create your own evaluation of the grid and search for promising actions. You can also import the tictactoe.engine class for a more complete toolbox (test actions, etc.)

The source code is provided on github.com.

Ultimate TicTacToe

The ultimate mode is a hierarchical 2-levels TicTacToe. It is possible to activate the mode with a command parameter:

hacka-tictactoe-play ultimate

The grid is composed of \(9\) times \(9\) cells, so potentially \(9\) times \(9\) actions for the players: A-1, A-2, ... , A-9, B-1, ... , I-9. In practice, most of the time, only a sub-number of actions are available. The particularity in Ultimate (the hierarchical TicTacToe) is that, the piece position taken by a player in the local grid indicates the next grid to play for the next player turn.

Example of grid at some point:

x: A B C   D E F   G H I
1  x     |       |      
2        |       |      
3    o   |       |      
  -------|-------|-------
4        |       |      
5        |       |      
6        |   o   |      
  -------|-------|-------
7        |       |      
8        |   x   |      
9        |       |      
actions: DEF-789

The line actions: DEF-789 informs on the possible positions to play on (any free position between D and F and 7 and 9, so : D-7, D-8, D-9, E-7, E-9, F-7, F-8 or F-9). At the beginning of the game, it is possible to play in a corner grid, a side grid or the center grid. That for the action line indicates: actions: A:C-1:3, A:C-4:6, D:F-4:6

The players have to win \(3\) aligned classic grids to win a Ultimate TicTacToe.

At launch script, it requires to create the Tictactoe master on ultimate mode.

from hackagames.tictactoe import TictactoeMaster
from hackagames.tictactoe.shell import PlayerShell
from hackagames.tictactoe.firstBot import Bot

gameMaster= TictactoeMaster("ultimate")
gameMaster.launchLocal( [MyBot(), Bot()], 1 )