Это одна из тривиальных реализаций простой игры, которую новичок может использовать для проверки своего уровня понимания языка программирования. На самом деле меня попросили реализовать это на JavaScript в интервью. Сначала я ожидал, что мне зададут вопросы о технологиях (Node.js и React.js) в отношении должности, потому что я провел первоначальную оценку алгоритма на платформе удаленной работы, но меня встретил интервьюер, который отвел меня на online IDE и попросил, чтобы я реализовал Tic Tac Toe с парой скелетных функций. Между тем, мы потратили 10 минут из 30 минут на сеанс на технические вопросы, переход от увеличения к Google Meet, проблемы со звуком и потраченное время не были компенсированы. Интервьюер опередил меня на 6 часов в часовом поясе. Я не масштабировался. Раздражающий. Фух!

Хотя крестики-нолики могут быть банальными, но я не уверен, что 30 минут достаточно, вероятно, час будет хорошо. После этой неприятной встречи я решил реализовать Tic Tac Toe, не обращаясь за помощью в Google (в интервью мне была предоставлена ​​возможность поиска в Google).

Единственная часть, которую я получил от Google для этой реализации, это то, как читать ввод из командной строки в Node.js, с которым я был не очень знаком, но реализация этого помогла мне понять, как заставить объект readline принимать входные данные от команды. строка в Node.js

Крестики-нолики

По данным Википедии (см. Изображение в заголовке). Крестики-нолики, крестики и нолики или крестики и крестики - это игра в карандаш и бумагу для двух игроков, X и O, которые по очереди отмечают пробелы в сетке 3 × 3. Игрок, которому удастся разместить три своих метки в горизонтальном, вертикальном или диагональном ряду, становится победителем.

Реализация

Итак, первая часть Tic Tac Toe - это представление игры. И используется массив. Одномерный массив. Мы также можем использовать 2D или двумерный массив 3x3 (это изменит реализацию) и упростить вычисление победителя (если вы новичок, попробуйте). И массив инициализирован пустыми строками, чтобы иметь пустую доску. Мы дадим игрокам возможность сменить стартового игрока. Доска известна игрокам как 1–9.

let player = ‘X’;
let ticktacktoe = [
  ’ ', ’ ', ‘ ',
  ’ ’, ’ ’, ‘ ’,
  ’ ’, ’ ’, ‘ ’
];

И при каждой игре нам нужно распечатать доску, показывающую состояние игры. Итак, мы кодируем printboard(). Прокрутите массив (игровую доску) с помощью цикла for. Мы также можем использовать map(). Мы использовали оператор модуля, чтобы вызвать печать новой строки.

const printBoard = () => {
    let line = “”;
    for (let i = 1; i < 10; i++) {
        line += ticktacktoe[i-1] + ‘ | ‘;
        if (i % 3 === 0) {
          console.log(line);
          console.log(‘____________’)
          line = “”;
     }
   }
}

Мы должны дать игрокам возможность установить первого игрока . defaultPlayer() функция проверяет, должны ли игроки продолжать с X. Сначала мы объявляем объект readline rl для чтения из стандартного ввода. Он полагается на объект global process. Если мы получаем «Да», мы вызываем setPlayer(), который вызывает changePlayer().. Если нет, мы printBoard() playTickTacToe() и начинаем игру.

const rl = readline.createInterface({
   input: process.stdin,
   output: process.stdout
});
const defaultPlayer = () => { 
    rl.question(“Default player is X, Do you want to change it, y or n “, function (defaultOrChoose) {
     let choice = defaultOrChoose.toLowerCase();
     if (choice == ‘y’) {
       setPlayer();
     } else if (choice === ’n’) {
       console.log(`Starting player is X`);
       printBoard();
       playTickTacToe();
     } else {
       defaultPlayer();
     }
  });
}
const setPlayer = () => {
    rl.question(“Default player is X, Do you want to change it, enter O? “, function (whichPlayer) {
    changePlayer(whichPlayer);
  });
}
const changePlayer = (playerChange) => {
     let mov = playerChange.toUpperCase();
     if (mov === ‘O’ || mov === ‘X’) {
        console.log(`Starting player is ${mov}`)
        player = mov;
        printBoard();
        playTickTacToe();
      } else {
        setPlayer();
     }
}

Следующим шагом будет кодирование пьесы. playTickTacToe() инициализирует флаг continuePlay, чтобы проверить, есть ли оставшиеся игровые слоты, и попросить игрока сделать ход.

const playTickTacToe = () => {
  let continePlay = false;
  for (i = 0; i < ticktacktoe.length; i++) { 
     if (ticktacktoe[i] === ‘ ‘) {
     continePlay = true;
     }
  }
  if (continePlay === true) {
     rl.question(“Play Game ? “, function (movve) {
     gameplayer(movve)
  });
 }
};

playTickTacToe() callsgameplayer(movve), который является движком, игровой логикой. Игроки играют с 1 по 9. 1–3 = первый ряд, 4–6 = второй ряд и 7–9 = третий ряд. Внутренние индексы представительства в наших советах директоров от 0 до 8. Итак, сначала мы выравниваем движение in let moveToCheck, анализируя строку, которую мы получаем из командной строки. Затем мы переходим к обходу или итерации по массиву (игровому полю). Когда мы находим индекс, соответствующий ходу игрока, мы проверяем, является ли это пустым слотом moveToCheck == i && ticktacktoe[i] === ‘ ‘. Если это так, мы устанавливаем слот на плеер. Иначе мы ничего не делаем и просим игрока сделать еще один ход. Если ход допустим, мы устанавливаем ход игрока. Повторить!

const gameplayer = (move) => {
   let moveToCheck = parseInt(move) — 1;
   let i;
   for (i = 0; i < ticktacktoe.length; i++) {
       if (moveToCheck == i && ticktacktoe[i] === ‘ ‘) {
          ticktacktoe[i] = player;
          if (player === ‘X’) {
             player = ‘O’;
          } else if (player === ‘O’) {
             player = ‘X’
          }
       }else{
         playTickTacToe();
       }
   }
   console.log(‘\n’);
   printBoard();
   const winner = calculateWinner();
   if (winner != ‘ ‘) {
      console.log(`Winner is ${winner}`)
      process.exit(0);
   }
   playTickTacToe();
}

Затем мы приступаем к печати доски. И вычислите победителя. Мы опишем calculateWinner() дальше. Это делается на каждом шагу. Мы можем по-разному подсчитывать победителя, по крайней мере, до 3 ходов. Это оптимизация. Для учащегося в центре внимания должна быть грубая сила. Сначала получите рабочее решение. В Принципах разработки программного обеспечения это называется преждевременной оптимизацией. Известный компьютерный ученый Дональд Кнут отметил это в одном из своих сочинений.

«Преждевременная оптимизация - это корень всего зла (или, по крайней мере, большей его части) в программировании» - Дональд Кнут

Функция calculateWinner() проверяет, выпала ли одна из 8 возможных выигрышных ситуаций. Возможности выигрыша от индексов массива:

По горизонтали = ›0,1,2; 3,4,5; 6,7,8

Вертикально = ›0,3,6; 1,4,7; 2,5,8

По диагонали = ›0,4,8; 2,4,6

 const calculateWinner = () => {
// We can improve this to make it less verbose by declaring the 
// slots as const like const zero = ticktacktoe[0];
// and replace all occurances
if (ticktacktoe[0] == ticktacktoe[1] && ticktacktoe[0] == ticktacktoe[2]) {
       return ticktacktoe[0];
   } else if (ticktacktoe[3] == ticktacktoe[4] && ticktacktoe[3] == ticktacktoe[5]) {
       return ticktacktoe[3];
   } else if (ticktacktoe[6] == ticktacktoe[7] && ticktacktoe[6] == ticktacktoe[8]) {
       return ticktacktoe[6];
   } else if (ticktacktoe[0] == ticktacktoe[3] && ticktacktoe[0] == ticktacktoe[6]) {
       return ticktacktoe[0];
   } else if (ticktacktoe[1] == ticktacktoe[4] && ticktacktoe[1] == ticktacktoe[7]) {
       return ticktacktoe[1];
   } else if (ticktacktoe[2] == ticktacktoe[5] && ticktacktoe[2] == ticktacktoe[8]) {
       return winner = ticktacktoe[2];
   } else if (ticktacktoe[0] == ticktacktoe[4] && ticktacktoe[0] == ticktacktoe[8]) {
       return ticktacktoe[0];
   }else if (ticktacktoe[2] == ticktacktoe[4] && ticktacktoe[2] == ticktacktoe[6]) {
       return ticktacktoe[2];
   }
  return ‘ ‘;
}

На этом мы подошли к концу простого упражнения. Все, что мы делаем, это вызываем наши printboard() и defaultPlayer(), чтобы начать игру. Установив Node.js, вы можете запустить его в командной строке как node ticktacktoe.js, и мы играем. Вот полная версия игры на github gist.

Тот интервьюер / компания, которая думала, что я не смогу реализовать крестики-нолики, упустила грамотного программиста.

Примечание на простом английском

Вы знали, что у нас четыре публикации и канал на YouTube? Вы можете найти все это на нашей домашней странице plainenglish.io - проявите немного любви, подписавшись на наши публикации и подписавшись на наш канал YouTube!