DEV Community

Josh Kuttler
Josh Kuttler

Posted on • Originally published at blog.bitsrc.io

1

Build a Tic Tac Toe App with TypeScript, React and Mocha

Learn how to compose a tic-tac-toe app with React and TypeScript components.

A simple Tic-Tac-Toe game built with modularity in mind and shared on Bit. After sharing, my game’s components can be tweaked and tested on Bit’s live PlayGround. Go to my components collection on Bit to test or consume the entire game or just some of its components, using NPM, Yarn or Bit.

GitHub logo JoshK2 / tic-tac-toe-game-using-bit

Simple Tic Tac Toe game built with react-typescript components

Modular Tic Tac Toe Game built with TypeScript and tested with Mocha components

A simple Tic Tac Toe game build with TypeScript components and test with Mocha tester then shared them to bit for testing in the live PlayGround and see the result of tests runnig in bit.
Allow users to consume the entire game or just a part of the game components using NPM and Yarn or using bit to consume and modify the component directly inside the project.

The game has multiple options to modify the game rules, like the dynamic dimension of the table, and the number of matching value to win the game.

Try the game in live PlayGround in the project collection

Tutorial

See the full tutorial- build your own modular application with React TypeScript components.

Build a Tic Tac Toe App with TypeScript, React and Mocha.

Import and use the entire game component in

When building a game like Tic-Tac-Toe “with modularity in mind”, it's hard to think of a reason for the UI components to be reused ever again, so I kept my focus primarily on the game’s utility functions.

I chose TypeScript as my coding language of choice — compiled by Bit’s TypeScript compiler and used Mocha for testing.

To install components from my project, first configure bit.dev as a scoped registry (copy and paste to your terminal) — this is done only once! later uses of bit do not require you to configure again.

npm config set '@bit:registry' [https://node.bit.dev](https://node.bit.dev)

and then install the component using Yarn or NPM:

npm i [@bit/joshk](http://twitter.com/bit/joshk).tic-tac-toe-game.game
yarn add [@bit/joshk](http://twitter.com/bit/joshk).tic-tac-toe-game.game

Game Component

The ‘game’ component is my app’s main component — composed using one component from ‘Board’ and two components from ‘Prime React’.

I used the button and the input-text for the configuration screen — test and see the code here.

Install PrimeReact components in your project:

yarn add @bit/primefaces.primereact.inputtext
yarn add @bit/primefaces.primereact.button

After setting the parameters, you can click ‘Play’ and… Play!

Board Component

The board component creates a dynamic table by props, manage player turn and check for the winner. Test and see the code here.

Square Component

The square component is a simple cell that receives value with optional color and sends an event to the board component when the value changes. Test and see the code here.

Empty cell function

‘Empty cell function’ Is a helper function to winner-calc function that checks if there are any empty cells in the game’s table.

Bit lets you see the docs for the component and the results of the tests:

The code of the function:

/**
* @description
* check if 2d array have an empty cell
* @param {{Array.<string[]>}} matrix 2d array
* @param {number} rowsNum number of rows
* @param {number} colsNum number of columns
* @returns {boolean} return true if empty cell was found, and false if not.
* @example
* import haveEmptyCell from '@bit/joshk.tic-tac-toe-game.utils.have-empty-cell';
*
* const matrix = [
* ['X', 'O', 'X'],
* ['O', 'X', 'O'],
* ['O', 'X', 'O']
* ];
* const result = haveEmptyCell(matrix, 3, 3);
*
* export default result
* @example
* import haveEmptyCell from '@bit/joshk.tic-tac-toe-game.utils.have-empty-cell';
*
* const matrix = [
* ['X', 'O', 'X'],
* ['O', '', 'O'],
* ['O', 'X', 'O']
* ];
* const result = haveEmptyCell(matrix, 3, 3);
*
* export default result
* @example
* import haveEmptyCell from '@bit/joshk.tic-tac-toe-game.utils.have-empty-cell';
*
* const matrix = [
* ['X', 'O', 'X'],
* ['O', , 'O'],
* ['O', 'X', 'O']
* ];
* const result = haveEmptyCell(matrix, 3, 3);
*
* export default result
* @example
* import haveEmptyCell from '@bit/joshk.tic-tac-toe-game.utils.have-empty-cell';
*
* const matrix = [
* ['X', 'O', 'X'],
* ['O', null, 'O'],
* ['O', 'X', 'O']
* ];
* const result = haveEmptyCell(matrix, 3, 3);
*
* export default result
*/
function haveEmptyCell(matrix: Array<Array<string>>, rowsNum: number, colsNum: number): boolean {
let empty: boolean = false;
for (let x = 0; x < rowsNum; x++) {
for (let y = 0; y < colsNum; y++) {
const element: any = matrix[x][y];
if (!element) {
empty = true;
break;
}
}
if (empty)
break;
}
return empty;
}
export default haveEmptyCell

Winner Calculation

Winner calculation is a function that checks for the winner in horizontal, vertical and diagonal cases.

Bit let you see the docs for the component and the results of the tests:

The code for the function:

/**
* @description
* check winner horizontal, vertical and diagonal
* @param {Array.<string[]>} matrix 2d array with X and O
* @param {number} rowsNum number of rows
* @param {number} colsNum number of columns
* @param {number} numToWin the number of matching to win
* @param {number} lastRow the row number of the square player click
* @param {number} lastCol the column number of the square player click
* @returns {string} return the winner, X or O or '' if no one win.
* @example
* import winnerCalc from '@bit/joshk.tic-tac-toe-game.utils.winner-calc';
*
* const matrix = [
* ['O', 'O', 'X'],
* ['O', 'X', ''],
* ['X', '', '']
* ];
* const result = winnerCalc(matrix, 3, 3, 3, 0, 2);
*
* export default result
*/
import haveEmptyCell from '../HaveEmptyCell'
function winnerCalc(matrix: Array<Array<string>>, rowsNum: number, colsNum: number, numToWin: number, lastRow: number, lastCol: number): string {
let winner: string = '';
let match: number = 0;
const lastValue: string = matrix[lastRow][lastCol];
//check Horizontal
for (let c = 0; c < colsNum; c++) {
let currentValue = matrix[lastRow][c];
if (currentValue === lastValue)
match++;
else match = 0;
if (match === numToWin) {
winner = lastValue;
break;
}
}
if (winner !== '')
return winner;
match = 0;
//check Vertical
for (let r = 0; r < rowsNum; r++) {
let currentValue = matrix[r][lastCol];
if (currentValue === lastValue)
match++;
else match = 0;
if (match === numToWin) {
winner = lastValue;
break;
}
}
if (winner !== '')
return winner;
//check diagonal top-left to bottom-right - include middle
match = 0;
for (let r = 0; r <= rowsNum - numToWin; r++)
{
let rowPosition = r;
for (let column = 0; column < colsNum && rowPosition < rowsNum; column++)
{
const currentValue = matrix[rowPosition][column];
if (currentValue === lastValue)
match++;
else match = 0;
if (match === numToWin)
{
winner = lastValue;
break;
}
rowPosition++;
}
if (winner !== '') break;
}
if (winner !== '')
return winner;
//check diagonal top-left to bottom-right - after middle
match = 0;
for (let c = 1; c <= colsNum - numToWin; c++)
{
let columnPosition = c;
for (let row = 0; row < rowsNum && columnPosition < colsNum; row++)
{
let currentValue = matrix[row][columnPosition];
if (currentValue === lastValue)
match++;
else match = 0;
if (match === numToWin)
{
winner = lastValue;
break;
}
columnPosition++;
}
if (winner !== '') break;
}
if (winner !== '')
return winner;
//check diagonal bottom-left to top-right - include middle
match = 0;
for (let r = rowsNum - 1; r >= rowsNum - numToWin - 1; r--)
{
let rowPosition = r;
for (let column = 0; column < colsNum && rowPosition < rowsNum && rowPosition >= 0; column++)
{
let currentValue = matrix[rowPosition][column];
if (currentValue === lastValue)
match++;
else match = 0;
if (match === numToWin)
{
winner = lastValue;
break;
}
rowPosition--;
}
if (winner !== '') break;
}
if (winner !== '')
return winner;
//check diagonal bottom-left to top-right - after middle
match = 0;
for (let c = 1; c < colsNum; c++)
{
let columnPosition = c;
for (let row = rowsNum - 1; row < rowsNum && row >= 0 && columnPosition < colsNum && columnPosition >= 1; row--)
{
console.log(`[${row}][${columnPosition}]`);
let currentValue = matrix[row][columnPosition];
if (currentValue === lastValue)
match++;
else match = 0;
if (match === numToWin)
{
winner = lastValue;
break;
}
columnPosition++;
}
if (winner !== '') break;
}
if (winner !== '')
return winner;
if(haveEmptyCell(matrix, rowsNum, colsNum) === false) {
winner = '-1';
}
return winner;
}
export default winnerCalc
view raw winner-calc.ts hosted with ❤ by GitHub

The project is available in my bit collection and in my GitHub repository:

GitHub logo JoshK2 / tic-tac-toe-game-using-bit

Simple Tic Tac Toe game built with react-typescript components

Modular Tic Tac Toe Game built with TypeScript and tested with Mocha components

A simple Tic Tac Toe game build with TypeScript components and test with Mocha tester then shared them to bit for testing in the live PlayGround and see the result of tests runnig in bit.
Allow users to consume the entire game or just a part of the game components using NPM and Yarn or using bit to consume and modify the component directly inside the project.

The game has multiple options to modify the game rules, like the dynamic dimension of the table, and the number of matching value to win the game.

Try the game in live PlayGround in the project collection

Tutorial

See the full tutorial- build your own modular application with React TypeScript components.

Build a Tic Tac Toe App with TypeScript, React and Mocha.


Import and use the entire game component in





Feel free to comment below and follow me on Twitter 😃

AWS Q Developer image

Your AI Code Assistant

Generate and update README files, create data-flow diagrams, and keep your project fully documented. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

Top comments (0)

SurveyJS custom survey software

Simplify data collection in your JS app with a fully integrated form management platform. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more. Integrates with any backend system, giving you full control over your data and no user limits.

Learn more