runSelfPlaySession method

Future<void> runSelfPlaySession(
  1. int numGames
)

Implementation

Future<void> runSelfPlaySession(int numGames) async {
  final random = math.Random();

  for (int g = 0; g < numGames; g++) {
    final game = Game(variant: Variant.standard());
    List<int> history = [0];
    List<GameStep> gameSteps = [];

    while (!game.gameOver && history.length < 100) {
      final legalMoves = game.generateLegalMoves();
      if (legalMoves.isEmpty) break;

      // 1. Prediction & Masking
      final state = model.represent(history);
      final pred = model.predict(state);
      final logits = pred['policy']!.data;

      double maxLogit = -double.infinity;
      for (var m in legalMoves) {
        int idx = encodeMove(m, game);
        if (logits[idx] > maxLogit) maxLogit = logits[idx];
      }

      // 2. Softmax for Target Policy
      double sumExp = 0;
      List<double> probs = List.filled(4098, 0.0);
      for (var m in legalMoves) {
        int idx = encodeMove(m, game);
        double p = math.exp((logits[idx] - maxLogit).clamp(-10, 10));
        probs[idx] = p;
        sumExp += p;
      }
      for (int j = 0; j < probs.length; j++) {
        if (probs[j] > 0) probs[j] /= (sumExp + 1e-10);
      }

      // 3. Move Selection
      double r = random.nextDouble();
      double cumulative = 0;
      Move chosenMove = legalMoves.first;
      for (var m in legalMoves) {
        int idx = encodeMove(m, game);
        cumulative += probs[idx];
        if (r <= cumulative) {
          chosenMove = m;
          break;
        }
      }

      gameSteps.add(GameStep(List.from(history), List.from(probs)));

      // 4. Update Game
      game.makeMove(chosenMove);
      history.add(encodeMove(chosenMove, game));
      if (history.length > 16) history.removeAt(0);
    }

    // 5. Calculate Result
    double outcome = 0.0;
    final result = game.result;
    if (result is WonGame) {
      outcome = (result.winner == Bishop.white) ? 1.0 : -1.0;
    }

    for (var step in gameSteps) {
      step.targetValue = outcome;
      if (replayBuffer.length >= maxBufferSize) replayBuffer.removeAt(0);
      replayBuffer.add(step);
    }
  }
}