using JoshHeaps.Net.Services.Interfaces;
using Microsoft.Extensions.Options;
namespace JoshHeaps.Net.Services.Implementations;
/// The available chess engine implementations.
public enum ChessEngineKind
{
Stockfish,
Custom,
/// The custom engine with the reinforcement-learned piece-square evaluation.
CustomLearned
}
/// Configuration selecting which to use.
public sealed class ChessEngineOptions
{
public const string SectionName = "ChessEngine";
public ChessEngineKind Engine { get; set; } = ChessEngineKind.Stockfish;
///
/// Absolute path to the learned-weights file. Leave null to default to
/// {ContentRoot}/chess-data/learned-weights.txt (fine for local dev). In
/// production set this to a stable, service-writable location OUTSIDE the deploy
/// directory (e.g. /var/lib/joshheaps/chess-data/learned-weights.txt) so the
/// trained weights survive deploys and avoid deploy-user vs service-user permission
/// clashes. Override via the ChessEngine__WeightsPath environment variable.
///
public string? WeightsPath { get; set; }
///
/// When true (and outside Development), a background service continuously plays the learned
/// engine against Stockfish to train it. Set to false to stop auto-training without a
/// redeploy. Override via the ChessEngine__AutoTrain environment variable.
///
public bool AutoTrain { get; set; } = true;
///
/// How many auto-training games run concurrently (when is on). This is
/// the starting value; it can be changed at runtime from the website. Override the default via
/// the ChessEngine__AutoTrainGameCount environment variable.
///
public int AutoTrainGameCount { get; set; } = 2;
}
/// Creates the configured per game.
public sealed class ChessEngineFactory(
IOptions options,
ILearnedWeightsStore weightsStore) : IChessEngineFactory
{
private readonly ChessEngineKind _kind = options.Value.Engine;
public IChessEngine Create(int skill) => Create(skill, _kind);
public IChessEngine Create(int skill, ChessEngineKind kind) => kind switch
{
ChessEngineKind.Custom => new CustomChessEngine(skill),
ChessEngineKind.CustomLearned => new CustomChessEngine(skill, EngineVariant.Learned, weightsStore.WeightsFilePath),
ChessEngineKind.Stockfish => new Stockfish(skill),
_ => throw new InvalidOperationException($"Unknown chess engine '{kind}'.")
};
}