94,88
Рейтинг
Plarium
Разработчик мобильных и браузерных игр

Создание игры «Крестики-нолики» при помощи TypeScript, React и Mocha

Блог компании PlariumПрограммированиеРазработка игрTypeScript
Tutorial
Автор оригинала: Josh Kuttler
Представляем вам перевод статьи Josh Kuttler, опубликованной на blog.bitsrc.io. Узнайте, как создать приложение «Крестики-нолики», используя React и TypeScript.



Простая игра в крестики-нолики создана по модульному принципу и загружена на сайт Bit. Вы можете изменять компоненты моей игры и тестировать ее онлайн на Bit PlayGround при помощи NPM, Yarn или Bit. Для этого перейдите к моей коллекции компонентов.

Когда создаешь игры типа «Крестики-нолики» по модульному принципу, трудно найти причину, по которой компоненты UI могут снова когда-либо использоваться. Поэтому я сосредоточился в основном на игровых утилитах.

Для программирования я выбрал язык TypeScript — скомпилировал код при помощи TypeScript на сайте Bit. Затем воспользовался фреймворком Mocha для тестирования.

Чтобы установить компоненты из моего проекта, сначала настройте bit.dev в качестве реестра области (скопируйте и вставьте на своем устройстве). Это следует сделать только один раз! При дальнейшем использовании сайта Bit проводить повторную настройку не понадобится.

npm config set '@bit:registry' https://node.bit.dev

Затем установите компонент при помощи менеджеров пакетов Yarn или NPM:

npm i @bit/joshk.tic-tac-toe-game.game
yarn add @bit/joshk.tic-tac-toe-game.game

Компонент «игра»


Компонент «игра» является основным компонентом моего приложения — он создан при помощи одного компонента Board и двух компонентов Prime React.

Я использовал компоненты Button и Input-text для экрана настройки — протестировать и посмотреть их код можно здесь.



Установите компоненты PrimeReact в свой проект:

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

После настройки параметров можно кликнуть на «Играть» и… играть!

Компонент Board


Компонент Board создает динамическую таблицу при помощи Props, устанавливает очередь для игроков и определяет победителя. Протестировать и посмотреть код можно здесь.



Компонент Square


Компонент Square — это обычная ячейка, которая получает значение с опциональным цветом и отправляет ивент компоненту Board при изменении значения. Протестировать и посмотреть код можно здесь.



Функция Empty cell


Функция Empty cell — это вспомогательная функция для функции Winner-calc, которая проверяет, есть ли пустые ячейки в таблице игры.

Bit позволяет увидеть документы компонента и результаты тестов:



Код функции
/**
 * @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 — это функция, которая вычисляет победителя по горизонтальной, вертикальной и диагональной плоскостям.

Bit позволяет увидеть документы компонента и результаты тестов:



Код функции
/**
 * @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


Проект доступен в моей коллекции на Bit и в моём репозитории GitHub.

Не стесняйтесь комментировать эту статью и подписывайтесь на мой Twitter.
Теги:разработка игрразработка приложенийигрыначинающимсвоими рукамикрестики-ноликикрестики ноликиtypescriptmochareactпрограммирование игрпрограммированиепрограммирование для начинающих
Хабы: Блог компании Plarium Программирование Разработка игр TypeScript
+6
4,3k 37
Комментарии 4

Похожие публикации

Middle Unity3D Developer
PLARIUMКраснодар
Copywriter
PLARIUMКраснодар
Game Monetization Designer
PLARIUMКраснодар
Sub Lead Graphic Developer
PLARIUMКраснодар
Project Manager
PLARIUMКраснодар

Лучшие публикации за сутки

Информация

Дата основания
2009
Местоположение
Израиль
Сайт
company.plarium.com
Численность
1 001–5 000 человек
Дата регистрации

Блог на Хабре