Top

Selenium for Games: Automating Tic Tac Toe

selenium game

Selenium for Games: Automating Tic Tac Toe

For this week’s live session, I was inspired by Sudharsan Selvaraj’s demo of him using Selenium to play a virtual piano. I, too, wanted to use Selenium to do something fun, so this recipe demonstrates how to automate playing tic-tac-toe online!

What’s great about this recipe is it goes beyond just using Selenium to test, but exercises design skills.

 

 

Recipe to Play Tic-Tac-Toe

Ingredients

  • Selenium WebDriver
  • Tic Tac Toe Game

Instructions

  1. Create construct to represent game spaces
  2. Create construct to represent game board and play behavior
  3. Create construct to represent the game itself
  4. Create class to execute game play
— Angie Jones

 

Live Stream Video

 

 

Ingredients

 

1 Selenium WebDriver

 

Add the Selenium WebDriver dependency to your project. I am using maven so I add this dependency to my pom.xml file.

 

2 Tic Tac Toe Game

 

We’ll use this online Tic Tac Toe game.

 

 

Instructions

 

1 Create construct to represent game spaces

 

I created an enum to hold the spaces on the tic tac toe game. The enum will also hold the locators for the each of the spaces. This will allow us to easily references board spaces as we need them.

 

2 Create construct to represent game board and play behavior

 

Now we need a class that represents the game board. This class will keep track of the current game in play, holding the state of each of the board spaces, and allowing the player to make a move.

Since we’ll need to interact with the website, this class will need the ChromeDriver from Selenium.

 

Next, I want a structure to represent the status of each of the spaces on the board, so let’s create a Map which holds each space and a boolean value indicating whether it is occupied.

 

Next, we need to populate the map with each of the spaces from our Space enum and set occupancy to false for all of them since the game has not begun and the board is empty.

 

Now for the fun part! We need a method that allows the user to make a play. In this method, we’ll have the player provide the Space they’d like to put their marker on, and we also need to update our internal Map.

Also, because we are playing against a computer, it makes it’s play right after ours, so I’ve added a little wait here to allow for their move. Don’t worry, this isn’t test code that will be running on multiple environments as part of a CI build. A little sleep here is ok 🤪

The play method updates our internal Map with our move, but doesn’t account for the computer’s move. So let’s make a method to check the browser and update our Map to accurately reflect the status of the board.

But first, we need a locator to get all of the empty spaces on the board.

Next, we use Selenium to get all of these empty spaces, store them into a List, then loop through our internal Map to update all of the spaces that do not appear in the empty-space Selenium list to be marked as occupied.

Ok, one more method for this class. It would be nice to provide a list of the unoccupied spaces so that our player knows what’s available to choose from. This method will call into the one we just made, updateSpaceOccupancy(), then filter through our internal Map of spaces and get all of the unoccupied ones.

 

3 Create construct to represent the game itself

 

Now, let’s make a class to represent the actual game itself. The first thing this class needs to do is setup up the ChromeDriver and launch the game. We can also create an instance of the board.

We want to enable the user to determine when the game is over. This app displays a restart overlay once the game ends, so we can create a method that let’s us know this, and another method to restart the game should the player want to. When restarting, it’s important to reinstatiate the board so that all spaces are marked as empty again.

Next, we need to determine if the player has won or lost. So, I’ve created three methods. One to get the scores from the website, another to allow the user to provide a winning score (in case they want to play until one of the players reaches a certain score), and finally one to print the results.

Finally for this class, we’ll add a method to end the game – which closes the browser and kills the thread.

 

4 Create class to execute game play

 

Now to play the game! I’ve created another class to execute the game as the player. First thing we’ll do here is instantiate a new game and get a handle to the game board.

Next, we determine how many rounds of the game we want to play before determining a winner. In this example, we indicate that whoever gets to 5 wins first is the ultimate winner. We want to continue playing until we get to this point, so we’ll use a while loop to represent each round.

Inside of the loop, we need another while loop to represent each play within a single round.

Inside of this inner loop, we want to make a play on the board. So we need to get the empty spaces. It would be nice to have an algorithm for choosing the most strategic spot to choose, however, for now, we’re just going to randomly choose one of the open spaces.

Then after each round, we have to make sure to clear the board by clicking the reset. This needs to be inside of the outer loop but outside of the inner loop.

Finally, we end the game! This needs to be outside of both loops.

 

Voila! Now we have a solution to automate playing tic-tac-toe.

See Code on Github

Angie Jones
2 Comments
  • Maha Lakshmi

    how to find the best move in this game ?

    December 28, 2021 at 3:00 am Reply
  • zemiak

    to avoid Enum and Map
    get list of empty squares from webpage
    (where elements are of RemoteWebElement type)

    use random element
    and do .click()

    October 30, 2022 at 12:18 pm Reply

Post a Comment