Forcetrails: Build Tic Tac Toe in LWC OSS

Build Tic Tac Toe in LWC OSS

Hello Folks! It's always fun to build any game (even if it's not something unique and new) with the technology that you are starting off with or already know. The agenda is to have some fun and to improve your coding skills or maybe to get comfortable with the Tech. 

Okay, so in this post, we will build a not-so-difficult, Tic-Tac-Toe game using Lightning Web Component OSS. I am sure most of you must have played this game in your childhood, and you may know what it is, if not, then check out this wiki - Tic-tac-toe.


Features/Requirements

Before we jump into the design and code let us fix the bare minimum requirements. This is the initial and crucial thing for any project that you need to take and consider the most important and limited number features to be implemented first. Later we can scale it as needed.

  1. This will be a Two-Player Game.
  2. Users can enter their names, one gets X, and the other get O.
  3. There will be a 10-second timer for each player to make a move, if one fails to do the move other wins.
  4. After a player makes a move turn will be changed so the other player can play.
  5. We need to visualize the timer so users can see how much time they have.
  6. We also need a START/RESTART.

High-Level Design

UI Design

We will draw nine clickable boxes which can be changed to X's or O's on click based on the current player. Like this:

Game UI

Player input form to enter the player names.

Player form UI

Pop-up modal to display the messages to users.

popup modal display


Component Composition

We will follow the single responsibility principle from the SOLID principles of Object-Oriented Programming to create the component composition.

  1. "Box" component: As shown in the UI design image we need to draw nine boxes that are clickable and stateful, so we can store the states of the boxes, like empty, X, O.
  2. "PlayerForm" component: This component will show the form to enter player names.
  3. "Popup" Component: This component will display the messages/alerts on a popup screen.
  4. "ProgressBar" Component Displays the timer for each move. 
  5. "Styles" component: Shared CSS styles for all components.
  6. "Board" component: This is the parent component of all other components.
    1. This component is responsible to handle the click events from the box components.
    2. This will show the game status. It will check the winner on each move and announce the winner.
    3. Changes the turn of the player.
    4. Starts/Stops the timer for each move.
    5. Shows the player form and collects the player names.
    6. Handles the core logic of the game.

Low-Level Design

Logic to check the winner

So let's talk about how do we decide the winner. Every time a player makes a move we need to check if that player is won. The player wins if they have filled the 3 boxes with their X/O char in:

  • In any row
  • In any column
  • In the diagonal
  • In the reverse diagonal
  • Game ties if all boxes are filled and none of the above conditions is satisfied.

So the logic is simple after the player makes a move we check all those rows, cols, and diagonals if any of them are occupied by the current user. As the last move decides the winner we don't need to check only the current row, current column, and current diagonal (if the current move is made on any of the diagonals).

If we take a look at the time complexity, it is linear and we need to make 4N comparisons in the worst case (move is made on the center box). So time complexity is O(n). Space complexity is O(n2) because we need to create 9 boxes.

But there is a better way we can do this in O(1), how? Let's see. If we maintain the count of boxes in each row, cols and two of the diagonal. As we only have two players we will increase that count by +1 for player A and decrease it by -1 for player B.

So if the count is +3 for any particular row/col/diagonal it means that player A has won. If it's -3 means that player B has won. You can see this code in the checkWin function from the board component i.e board.js.

Logic to check tie

As we know that game is tied when all boxes are filled, and none of the players won, we will maintain a count of boxes occupied, when it is equal to 9 and no player wins, we flag it as a Tie.

Draw the boxes

Boxes are just simple divs with fixed spacing and dimentions. The values X/O determine the background color. It fires an event to the parent component when it is clicked by the player to make a move. Check the code here.

Timer

The timer is created with setInterval method from JS. The timer is started when the game is started. The player has 10 seconds to make a move, if not done then the other player wins. The timer resets after every move and when the game is restarted.

Every tick of the timer the progress bar is updated to visualize the remaining time of the user to make move. The progress bar is shown in the reverse way to reduce the value on each tick.

See the startTimer and stopTimer methods here.


Try it yourself/See full code

Thank you for reading, please do let me know your feedback in the comments. You can check out all code in the below give GitHub repo.

  1. Go to the git repo: rahulgawale/lwc-tic-tac-toe
  2. Clone the repo using the command: git clone https://github.com/rahulgawale/lwc-tic-tac-toe
  3. Move to the root directory of the project using the command: cd lwc-tic-tac-toe
  4. Run cmd to install all dependencies : npm install
  5. Start the project using cmd: npm run watch

No comments :
Post a Comment

Hi there, comments on this site are moderated, you might need to wait until your comment is published. Spam and promotions will be deleted. Sorry for the inconvenience but we have moderated the comments for the safety of this website users. If you have any concern, or if you are not able to comment for some reason, reach email us at rahul@forcetrails.com