private int evaluationPlayer(LatrunculiApp latrunculi) { var evaluation = latrunculi.HistoryManager.Steps.TakeLast(depth + 1).Reverse().Select((step, index) => step.CapturedCount * (index + 1) * (index % 2 == 0 ? 1 : -1) ).Sum(); if (latrunculi.Debug && evaluation != 0) { string steps = string.Join(", ", latrunculi.HistoryManager.Steps.TakeLast(depth + 1).Select(step => step.Move)); Console.WriteLine($"{steps}: {evaluation}"); DebugPrintDesk?.Invoke(this, null); } return(depth % 2 == 0 ? evaluation : -evaluation); }
public CommandManager(LatrunculiApp app, HistoryPrinter historyPrinter, DeskPrinter deskPrinter) { this.app = app; this.historyPrinter = historyPrinter; this.deskPrinter = deskPrinter; this.playerTypes = new Dictionary <string, Func <IPlayer> >() { ["human"] = () => createHumanPlayer(), ["random"] = () => createRandomPlayer(), ["minimax2"] = () => createMiniMaxPlayer(2), ["minimax4"] = () => createMiniMaxPlayer(4), ["minimax3"] = () => createMiniMaxPlayer(3) }; this.helpPlayer = createMiniMaxPlayer(3); }
private (Move move, int evaluation, int bestMovesCount) minMaxRecursive(LatrunculiApp latrunculi, int depth, Move move, CancellationToken ct = default) { ct.ThrowIfCancellationRequested(); try { latrunculi.Rules.Move(latrunculi.HistoryManager.ActualPlayer, move); var indentation = this.depth - depth; var moves = string.Join(';', latrunculi.HistoryManager.Steps.TakeLast(this.depth - depth + 1) .Select(step => step.Move.ToString())); if (latrunculi.Debug) { deskLogger.WriteLine($"{latrunculi.HistoryManager.ActualPlayer} {moves}"); deskLogger.WriteLine(deskToString.GetDeskAsString(latrunculi)); } (Move move, int evaluation, int bestMovesCount)? evaluation = null; if (depth == 0 || latrunculi.IsEnded) { evaluation = (move, evaluationPlayer(latrunculi), 1); if (latrunculi.Debug && evaluation.Value.evaluation != 0) { logger.WriteLine($"{latrunculi.HistoryManager.ActualPlayer} {moves} ({evaluation})", indentation); } } else { //logger.WriteLine($"Start {app.HistoryManager.ActualPlayer} {moves}", indentation); var evaluations = latrunculi.Rules.GetAllValidMoves(latrunculi.HistoryManager.ActualPlayer) .ToArray() .Select(nextMove => minMaxRecursive(latrunculi, depth - 1, nextMove, ct)) .ToArray(); var maxEvaluation = evaluations.Max(move => move.evaluation); var maxCount = evaluations .Where(eval => eval.evaluation == maxEvaluation) .Sum(eval => eval.bestMovesCount); if (latrunculi.Debug && maxEvaluation != 0) { logger.WriteLine($"End {latrunculi.HistoryManager.ActualPlayer} {moves} ({maxEvaluation}, count: {maxCount})", indentation); } evaluation = (move, maxEvaluation, maxCount); } return(evaluation.Value); } finally { latrunculi.HistoryManager.Back(); } }
private Move getBestMove(LatrunculiApp latrunculi, ChessBoxState player, CancellationToken ct = default) { ct.ThrowIfCancellationRequested(); logger?.Dispose(); deskLogger?.Dispose(); logger = new FileLogger($"{latrunculi.HistoryManager.ActualRound} - {player} - minimax {depth}"); deskLogger = new FileLogger($"{latrunculi.HistoryManager.ActualRound} - {player} - minimax {depth} - desk"); var validMoves = latrunculi.Rules.GetAllValidMoves(player).ToArray(); IEnumerable <(Move move, int evaluation, int bestMovesCount)> moves = validMoves.Select(move => (minMaxRecursive(latrunculi, depth, move, ct))).ToArray(); if (latrunculi.Debug) { logger.WriteLine("############################# Result"); foreach (var moveInfo in moves) { logger.WriteLine($"{moveInfo.evaluation} {moveInfo.move}, count: {moveInfo.bestMovesCount}"); } } if (latrunculi.BestMovesDebug) { Console.WriteLine(); foreach (var moveInfo in moves) { Console.WriteLine($"{moveInfo.evaluation} {moveInfo.move}, count: {moveInfo.bestMovesCount}"); } Console.WriteLine($"--------------------------------"); } var maxEvaluation = moves.Max(move => move.evaluation); var maxMoves = moves.Where(move => move.evaluation == maxEvaluation).ToArray(); var maxBestCount = maxMoves.Max(move => move.bestMovesCount); var bestMoves = maxMoves.Where(move => move.bestMovesCount == maxBestCount).Select(move => move.move).ToArray(); var moveForwardDirection = player == ChessBoxState.Black ? -1 : 1; var bestForwardMoves = bestMoves.Where(move => move.To.Y - move.From.Y == moveForwardDirection).ToArray(); if (bestForwardMoves.Length == 0) { bestForwardMoves = bestMoves.Where(move => move.From.Y == move.To.Y).ToArray(); } if (bestForwardMoves.Length == 0) { bestForwardMoves = bestMoves; } logger.Dispose(); return(bestForwardMoves.Skip(random.Next(bestForwardMoves.Count()) - 1).First()); }
public string GetDeskAsString(LatrunculiApp latrunculi) { var desk = latrunculi.Desk; StringBuilder sb = new StringBuilder(2 * desk.Size.Width * desk.Size.Height); sb.Append(getLineSeparator(desk)); for (int y = desk.Size.Height - 1; y >= 0; y--) { string inner = string.Join(" | ", Enumerable.Range(0, desk.Size.Width) .Select(x => getCheckBox(latrunculi, new ChessBoxPosition(desk.Size, x, y))) ); sb.Append($"{y + 1} | {inner} |\n"); sb.Append(getLineSeparator(desk)); } sb.Append(getLetters(desk)); return(sb.ToString()); }
public GameContext(LatrunculiApp latrunculi) { Latrunculi = latrunculi; latrunculi.PropertyChanged += (_, e) => { switch (e.PropertyName) { case nameof(latrunculi.Desk): helpCts?.Cancel(); HelpMove = null; break; case nameof(latrunculi.ActualPlayer): turnCts?.Cancel(); helpCts?.Cancel(); TryTurn(); break; } ; }; latrunculi.HistoryManager.PropertyChanged += (_, e) => { if (e.PropertyName == nameof(latrunculi.HistoryManager.IsLastIndexSelected)) { if (latrunculi.HistoryManager.IsLastIndexSelected && !latrunculi.IsEnded) { TryTurn(); } else { turnCts?.Cancel(); helpCts?.Cancel(); } } }; turnWorker = createMoveWorker(handlePlayerTurn); helpWorker = createMoveWorker(handleHelped); ActualizeStatus(); TryTurn(); }
public Move Turn(LatrunculiApp latrunculi, ChessBoxState player, CancellationToken ct = default) { Console.Write("Váš tah (start cíl): "); string line = Console.ReadLine().Trim().ToLower(); if (commandManager.CheckCommand(line)) { return(null); } var moveMatch = Regex.Match(line, @"^(?<from>[a-zA-Z][1-9])\s*(?<to>[a-zA-Z][1-9])$"); if (moveMatch.Success) { ChessBoxPosition from = ChessBoxPosition.FromString(deskSize, moveMatch.Groups["from"].Value); ChessBoxPosition to = ChessBoxPosition.FromString(deskSize, moveMatch.Groups["to"].Value); return(new Move(from, to)); } else { throw new InvalidCastException("Je vyžadován tah ve formátu start cíl, např. E4 E5"); } }
private string getCheckBox(LatrunculiApp latrunculi, ChessBoxPosition position) { var lastChange = latrunculi.HistoryManager.LastStep?.Changes.Find(change => change.Position.Index == position.Index); var state = latrunculi.Desk.PlayingDesk[position.X, position.Y]; string symbol; switch (state) { case ChessBoxState.Black: symbol = "b"; break; case ChessBoxState.White: symbol = "w"; break; case ChessBoxState.Empty: default: symbol = " "; break; } if (lastChange != null) { if (lastChange.IsCaptured == true) { symbol = "X"; } else if (lastChange.NewState == ChessBoxState.Empty) { symbol = "_"; } else if (lastChange.NewState == state) { symbol = symbol.ToUpper(); } } return(symbol); }
public Move Turn(LatrunculiApp latrunculi, ChessBoxState player, CancellationToken ct = default) { return(getBestMove(latrunculi, player, ct)); }
public void Dispose() { app = null; }
public SaveGameManager(LatrunculiApp app) { this.app = app; }
static void Main(string[] args) { Console.WriteLine("========================================"); Console.WriteLine("Latrunculi - @author: František Pospíšil"); Console.WriteLine("========================================"); Console.WriteLine(); var latrunculi = new LatrunculiApp(); HistoryPrinter historyPrinter = new HistoryPrinter(latrunculi.HistoryManager); DeskPrinter deskPrinter = new DeskPrinter(latrunculi.Desk, latrunculi.HistoryManager); var commandManager = new CommandManager(latrunculi, historyPrinter, deskPrinter); latrunculi.WhitePlayer = commandManager.createPlayerByType(args.FirstOrDefault()) ?? commandManager.GetPlayerType(ChessBoxState.White); latrunculi.BlackPlayer = commandManager.createPlayerByType(args.Skip(1).FirstOrDefault()) ?? commandManager.GetPlayerType(ChessBoxState.Black); while (true) { try { while (true) { try { if (!latrunculi.IsEnded) { Console.WriteLine(); deskPrinter.PrintDesk(); string actualPlayer = latrunculi.HistoryManager.ActualPlayer == ChessBoxState.Black ? "černý" : "bílý"; Console.WriteLine(); WriteColoredMulti( TextSegment($"Tah "), TextSegment($"@{latrunculi.HistoryManager.ActualRound}", ConsoleColor.Yellow), TextSegment($", hraje "), TextSegment($"{actualPlayer} ", ConsoleColor.Yellow), TextSegment($"hráč ({latrunculi.ActualPlayer.ToString()}). ")); var move = latrunculi.Turn(); if (move != null) { WriteColoredMulti(TextSegment("Zahrán tah "), TextSegment($"{move}", ConsoleColor.Green), TextSegment(".")); } latrunculi.Rules.CheckEndOfGame(); } else { Console.Write("Zadejte příkaz: "); var line = Console.ReadLine(); commandManager.CheckCommand(line); } } catch (EndOfGameException e) { Console.WriteLine(); deskPrinter.PrintDesk(); WriteColoredLine(e.Message, ConsoleColor.Green); WriteColoredLine("Engine: " + (e.Winner == ChessBoxState.Black ? latrunculi.BlackPlayer : latrunculi.WhitePlayer).ToString(), ConsoleColor.Gray); break; } catch (AbortGameException) { return; } catch (Exception e) { WriteColoredLine(e.Message, ConsoleColor.Red); } } } catch (Exception) { return; } } }
public Move Turn(LatrunculiApp latrunculi, ChessBoxState player, CancellationToken ct = default) { var validMoves = latrunculi.Rules.GetAllValidMoves(player); return(validMoves.Skip(random.Next(validMoves.Count()) - 1).First()); }