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}'.") }; }