Хочу продолжить тему создания игр, которая была открыта статьей об игре «Змейка» на JavaScript. В ней рассматривался прием «игрового цикла» при создании динамических игр. В этой статье хочу рассказать о пошаговой игре «Реверси». Игровой процесс ведётся с «компьютерным» противником.

Возможно, правила игры, реализованные мной несколько отличаются от «официальных», но лишь самую малость.

Итак, в начале игры в центр доски выставляются 4 фишки как показано на рисунке:

Первый ход делает человек (белыми). Далее игроки ходят по очереди.

Игрок должен поставить свою фишку так, чтобы между двумя его фишками на доске находился непрерывный ряд фишек второго игрока. Ряд может быть вертикальным, горизонтальным или диагональным.

Когда будут заполнены все клетки поля подсчитывается количество белых и черных фишек. Выигрывает тот, чьих больше.

Готовая игра находится тут.

Основной принцип

Заключается в том, как захватывать фишки врага. Нам нужно определять какие фишки попадают под захват и находятся между двумя своими фишками. Для этого есть функция reversi.captureAvailableSpots с четырьмя входящими параметрами:

  • x — координата клика по оси x;
  • y — координата клика по оси y;
  • enemi — определяет чей сейчас ход (1 или 0);
  • do_capture — захватывать ли найденные фишки (true или false).

Функция проверяет наличие возможности захвата фишек в восьми направлениях от места клика, то есть по всем возможным диагоналям и прямым. Используется как для захвата фишек так и для определения наилучшего хода для компьютера.

reversi.captureAvailableSpots = function(x, y, enemi, do_capture) {
    /*** Диагональ по убыванию [НАЧАЛО] ***/
    var white_found = false;
    var black       = [];
    var total_enemi = [];
    for( var i = x, j = y; i >= 0, j >= 0; i--, j-- ) {
      if( reversi.board[i] != undefined && reversi.board[i][j] != undefined && i != x && j != y ) {
        // Если встретилась пустая клетка - вываливаемся сразу
        if ( reversi.board[i][j] == 0 ) break;
        // Если встретилась клетка врага - собираем её координаты
        if ( reversi.board[i][j] == enemi ) {
          black.push({
            x:i,
            y:j
          });
        }
        // Если встретилась своя клетка - запоминаем это
        if ( reversi.board[i][j] == -enemi ) {
          white_found = true;
          total_enemi = total_enemi.concat( black );
          break;
        }
      }
    }
    // Если была найдена своя клетка и если собранные клетки врага - красим их в свой цвет
    if ( white_found && black.length && do_capture ) {
        reversi.captureSpot(black, enemi);
    }
    /*** Диагональ по убыванию [КОНЕЦ] ***/
    /*** Диагональ по возрастанию [НАЧАЛО] ***/
    white_found = false;
    black = [];
    for( i = x, j = y; i <= reversi.board_size, j <= reversi.board_size; i++, j++ ) {
      if( reversi.board[i] != undefined && reversi.board[i][j] != undefined && i != x && j != y ) {
        // Если встретилась пустая клетка - вываливаемся сразу
        if ( reversi.board[i][j] == 0 ) break;
        // Если встретилась клетка врага - собираем её координаты
        if ( reversi.board[i][j] == enemi ) {
          black.push({
            x:i,
            y:j
          });
        }
        // Если встретилась своя клетка - запоминаем это
        if ( reversi.board[i][j] == -enemi ) {
          white_found = true;
          total_enemi = total_enemi.concat( black );
          break;
        }
      }
    }
    // Если была найдена своя клетка и если собранные клетки врага - красим их в свой цвет
    if ( white_found && black.length && do_capture ) {
        reversi.captureSpot(black, enemi);
    }
    /*** Диагональ по возрастанию [КОНЕЦ] ***/
    /*** Диагональ 3 [НАЧАЛО] ***/
    white_found = false;
    black = [];
    for( i = x, j = y; i <= reversi.board_size, j >= 0; i++, j-- ) {
      if( reversi.board[i] != undefined && reversi.board[i][j] != undefined && i != x && j != y ) {
        // Если встретилась пустая клетка - вываливаемся сразу
        if ( reversi.board[i][j] == 0 ) break;
        // Если встретилась клетка врага - собираем её координаты
        if ( reversi.board[i][j] == enemi ) {
          black.push({
            x:i,
            y:j
          });
        }
        // Если встретилась своя клетка - запоминаем это
        if ( reversi.board[i][j] == -enemi ) {
          white_found = true;
          total_enemi = total_enemi.concat( black );
          break;
        }
      }
    }
    // Если была найдена своя клетка и если собранные клетки врага - красим их в свой цвет
    if ( white_found && black.length && do_capture ) {
      reversi.captureSpot(black, enemi);
    }
    /*** Диагональ 3 [КОНЕЦ] ***/
    /*** Диагональ 4 [НАЧАЛО] ***/
    white_found = false;
    black = [];
    for( i = x, j = y; i >= 0, j <= reversi.board_size; i--, j++ ) {
      if( reversi.board[i] != undefined && reversi.board[i][j] != undefined && i != x && j != y ) {
        // Если встретилась пустая клетка - вываливаемся сразу
        if ( reversi.board[i][j] == 0 ) break;
        // Если встретилась клетка врага - собираем её координаты
        if ( reversi.board[i][j] == enemi ) {
          black.push({
            x:i,
            y:j
          });
        }
        // Если встретилась своя клетка - запоминаем это
        if ( reversi.board[i][j] == -enemi ) {
          white_found = true;
          total_enemi = total_enemi.concat( black );
          break;
        }
      }
    }
    // Если была найдена своя клетка и если собранные клетки врага - красим их в свой цвет
    if ( white_found && black.length && do_capture ) {
      reversi.captureSpot(black, enemi);
    }
    /*** Диагональ 4 [КОНЕЦ] ***/
    /*** Вверх [НАЧАЛО] ***/
    white_found = false;
    black = [];
    j = y;
    for( i = x; i >= 0; i-- ) {
      if( reversi.board[i] != undefined && reversi.board[i][j] != undefined && i != x ) {
        // Если встретилась пустая клетка - вываливаемся сразу
        if ( reversi.board[i][j] == 0 ) break;
        // Если встретилась клетка врага - собираем её координаты
        if ( reversi.board[i][j] == enemi ) {
          black.push({
            x:i,
            y:j
          });
        }
        // Если встретилась своя клетка - запоминаем это
        if ( reversi.board[i][j] == -enemi ) {
          white_found = true;
          total_enemi = total_enemi.concat( black );
          break;
        }
      }
    }
    // Если была найдена своя клетка и если собранные клетки врага - красим их в свой цвет
    if ( white_found && black.length && do_capture ) {
      reversi.captureSpot(black, enemi);
    }
    /*** Вверх [КОНЕЦ] ***/
    /*** Вниз [НАЧАЛО] ***/
    white_found = false;
    black = [];
    j = y;
    for( i = x; i <= reversi.board_size; i++ ) {
      if( reversi.board[i] != undefined && reversi.board[i][j] != undefined && i != x ) {
        // Если встретилась пустая клетка - вываливаемся сразу
        if ( reversi.board[i][j] == 0 ) break;
        // Если встретилась клетка врага - собираем её координаты
        if ( reversi.board[i][j] == enemi ) {
          black.push({
            x:i,
            y:j
          });
        }
        // Если встретилась своя клетка - запоминаем это
        if ( reversi.board[i][j] == -enemi ) {
          white_found = true;
          total_enemi = total_enemi.concat( black );
          break;
        }
      }
    }
    // Если была найдена своя клетка и если собранные клетки врага - красим их в свой цвет
    if ( white_found && black.length && do_capture ) {
      reversi.captureSpot(black, enemi);
    }
    /*** Вниз [КОНЕЦ] ***/
    /*** Вправо [НАЧАЛО] ***/
    white_found = false;
    black = [];
    i = x;
    for( j = y; j <= reversi.board_size; j++ ) {
      if( reversi.board[i] != undefined && reversi.board[i][j] != undefined && j != y ) {
        // Если встретилась пустая клетка - вываливаемся сразу
        if ( reversi.board[i][j] == 0 ) break;
        // Если встретилась клетка врага - собираем её координаты
        if ( reversi.board[i][j] == enemi ) {
          black.push({
            x:i,
            y:j
          });
        }
        // Если встретилась своя клетка - запоминаем это
        if ( reversi.board[i][j] == -enemi ) {
          white_found = true;
          total_enemi = total_enemi.concat( black );
          break;
        }
      }
    }
    // Если была найдена своя клетка и если собранные клетки врага - красим их в свой цвет
    if ( white_found && black.length && do_capture ) {
      reversi.captureSpot(black, enemi);
    }
    /*** Вправо [КОНЕЦ] ***/
    /*** Влево [НАЧАЛО] ***/
    white_found = false;
    black = [];
    i = x;
    for( j = y; j >= 0; j-- ) {
      if( reversi.board[i] != undefined && reversi.board[i][j] != undefined && j != y ) {
        // Если встретилась пустая клетка - вываливаемся сразу
        if ( reversi.board[i][j] == 0 ) break;
        // Если встретилась клетка врага - собираем её координаты
        if ( reversi.board[i][j] == enemi ) {
          black.push({
            x:i,
            y:j
          });
        }
        // Если встретилась своя клетка - запоминаем это
        if ( reversi.board[i][j] == -enemi ) {
          white_found = true;
          total_enemi = total_enemi.concat( black );
          break;
        }
      }
    }
    // Если была найдена своя клетка и если собранные клетки врага - красим их в свой цвет
    if ( white_found && black.length && do_capture ) {
      reversi.captureSpot(black, enemi);
    }
    /*** Влево [КОНЕЦ] ***/
    // Возвращаем массив с найдеными клетками врага
    return total_enemi;
}