utility.cpp 5.26 KB
#include "utility.h"

// stl
#include "numeric"
#include "iostream"

namespace othello { namespace utility
{
  ////////////////////
  //
  //
  // Interface Utility
  // Functions
  //
  //
  ////////////////////

  BitPieces occupiedPositions(const BitBoard& board)
  {
    return othello::BitPieces(board[0] | board[1]);
  }

  bool occupied(const BitPieces& pieces, const BitPos& board_pos)
  {
    return pieces.test(board_pos.value()); //.test checks without giving it access to modify
  }

  bool occupied(const BitBoard& board, const BitPos& board_pos)
  {
    //return occupiedPositions(board).test(board_pos.value());

    const auto isOccupied = occupiedPositions(board);
    return occupied(isOccupied, board_pos);
  }

  BitPos nextPosition(const BitPos& board_pos, const MoveDirection& dir)
  {
      switch(dir) {
      case othello::MoveDirection::N:
          if(board_pos.value() < 56)
              return othello::BitPos(board_pos.value() + 8);
          break;
      case othello::MoveDirection::NE:
          if((board_pos.value() < 56) and (board_pos.value() % 8 != 0))
              return othello::BitPos(board_pos.value() + 7);
          break;
      case othello::MoveDirection::E:
          if(board_pos.value() % 8 != 0)
              return othello::BitPos(board_pos.value() - 1);
          break;
      case othello::MoveDirection::SE:
          if((board_pos.value() > 7) and (board_pos.value() % 8 != 7))
              return othello::BitPos(board_pos.value() - 9);
          break;
      case othello::MoveDirection::S:
          if(board_pos.value() > 7)
              return othello::BitPos(board_pos.value() - 8);
          break;
      case othello::MoveDirection::SW:
          if((board_pos.value() > 7) and (board_pos.value() % 8 != 7))
              return othello::BitPos(board_pos.value() - 7);
          break;
      case othello::MoveDirection::W:
          if(board_pos.value() % 8 != 7)
              return othello::BitPos(board_pos.value() + 1);
          break;
      case othello::MoveDirection::NW:
          if((board_pos.value() < 56) and (board_pos.value() % 8 != 7))
              return othello::BitPos(board_pos.value() + 9);
          break;
      }
    return BitPos::invalid();
  }

  BitPosSet findBorder(const BitBoard &board)
  {
      BitPieces occupied_positions = occupiedPositions(board);
      BitPosSet border_pieces;
        for (size_t i = 0; i < detail::computeBoardSize(); ++i){
            if (occupied_positions.test(i)){
                for (int j=0; j < 8; ++j){
                    BitPos neighbor = nextPosition(BitPos {i}, static_cast <MoveDirection>(j));
                    if (neighbor.isValid() && !occupied(board, neighbor)){
                        border_pieces.insert(neighbor);
                    }
                }
            }
        }
      return border_pieces; //not as efficient as it goes through the whole board for every move instead of simply updating
  }

  BitPos findBracketingPiece(const BitBoard& board,
                             const BitPos& board_pos,
                             const PlayerId& player_id,
                             const MoveDirection& dir)
  {
    BitPos next_position = nextPosition(board_pos, dir);

    const BitPieces& current_player_pieces = board.at(size_t(player_id));
    const BitPieces& opponent_player_pieces = board.at(size_t(opponent(player_id)));

    if (not next_position.isValid() or not opponent_player_pieces.test(next_position.value())){
        return BitPos::invalid();
    }
    next_position = nextPosition(board_pos, dir);

    while (next_position.isValid()){
        if (current_player_pieces.test(next_position.value()))
            return next_position;
        if (not opponent_player_pieces.test(next_position.value()))
            return BitPos::invalid(); // Must be an empty position

        next_position = nextPosition(board_pos, dir);

    }

    return BitPos::invalid();
  }

  BitPosSet legalMoves(const BitBoard& board, const PlayerId& player_id)
  {
      BitPosSet legal_moves;
        for (size_t i = 0; i < detail::computeBoardSize(); ++i){
            if(isLegalMove(board, player_id, BitPos(i))){
                legal_moves.insert(BitPos(i));
                    }
                }
  }

  bool isLegalMove(const BitBoard& board, const PlayerId& player_id,
                   const BitPos& board_pos)
  {
    for (size_t i = 0; i < 8; ++i){
        auto dir = static_cast<MoveDirection>(i);
        BitPos bracketing_pieces = findBracketingPiece(board, board_pos, player_id, dir);
        if (bracketing_pieces.isValid())
          return true;
    }
    return false;
  }


  void placeAndFlip(BitBoard& board, const PlayerId& player_id,
                    const BitPos& board_pos)
  {
    if(isLegalMove(board, player_id, board_pos)){
      board.at(size_t(player_id)).set(board_pos.value());
      for (size_t i = 0; i < 8; ++i){
        auto dir = static_cast<MoveDirection>(i);
        BitPos captured_piece = nextPosition(board_pos, dir);
        board.at(size_t(opponent(player_id))).flip(captured_piece.value());
            captured_piece = nextPosition(captured_piece, dir);
      }
    }
  }

  PlayerId opponent(const PlayerId& player_id){
      if (player_id == PlayerId::One){
         return PlayerId::Two;
      }
      return PlayerId::One;
  }
}
}   // namespace othello::utility