makeMove method

bool makeMove(
  1. Move move, [
  2. bool generateMeta = true
])

Make a move and modify the game state. Returns true if the move was valid and made successfully. generateMeta determines whether to generate the BishopState.moveMeta field. Set this to false for more efficient calculations.

Implementation

bool makeMove(Move move, [bool generateMeta = true]) {
  BishopState state = this.state;
  Square fromSq =
      move.from >= Bishop.boardStart ? state.board[move.from] : Bishop.empty;

  if (variant.hasActionsForEvent(ActionEvent.beforeMove)) {
    state = state.executeActions(
      trigger: ActionTrigger(
        event: ActionEvent.beforeMove,
        variant: variant,
        state: state,
        move: move,
        piece: move.dropPiece ?? fromSq,
      ),
      zobrist: zobrist,
    );
  }

  if (state.invalidMove) return false;

  BishopState? newState;
  if (move is GatingMove) {
    newState = makeGatingMove(state, move);
  } else if (move is StandardMove || move is DropMove) {
    newState = makeStandardMove(state, move);
  } else if (move is PassMove) {
    newState = makePassMove(state, move);
  } else {
    newState = variant.makeCustomMove(
      MoveProcessorParams(state: state, move: move, zobrist: zobrist),
    );
  }
  if (newState == null) return false;

  if (variant.hasActionsForEvent(ActionEvent.afterMove)) {
    newState = newState.executeActions(
      trigger: ActionTrigger(
        event: ActionEvent.afterMove,
        variant: variant,
        state: newState,
        move: move,
        piece: move.promoPiece ?? move.dropPiece ?? fromSq,
      ),
      zobrist: zobrist,
    );
  }

  final moveMeta = generateMeta
      ? MoveMeta(
          algebraic: toAlgebraic(move),
          formatted: toSan(move),
        )
      : null;
  history.add(newState);
  // todo: move this to before history.add (above) when move generation
  // becomes part of state (i.e. not dependent on current state)
  // probably after dart 3 cos records
  // basically this sucks because methods depend on the state of the game
  // instead of applying to specific states
  if (generateMeta) {
    history.last = newState.copyWith(
      meta: StateMeta(
        variant: variant,
        moveMeta: moveMeta,
        checks: [
          getKingAttackers(Bishop.white),
          getKingAttackers(Bishop.black),
        ],
      ),
    );
  }
  if (newState.invalidMove) return false;

  // kind of messy doing it like this, but inCheck depends on the current state
  // maybe that's a case for refactoring some methods into State?
  bool countChecks =
      variant.gameEndConditions[newState.turn.opponent].checkLimit != null;
  if (variant.forbidChecks || countChecks) {
    bool isInCheck = inCheck;
    if (isInCheck) {
      if (countChecks) {
        history.last = newState.copyWith(
          checks: List.from(newState.checks)..[newState.turn.opponent] += 1,
        );
      }
      if (variant.forbidChecks) {
        return false;
      }
    }
  }

  zobrist.incrementHash(newState.hash);
  return true;
}