/// <summary> /// Execute Alpha - Beta Negemax search to find the next best cell. /// </summary> /// <returns> /// The best cell and its score. /// </returns> /// <param name='board'> /// The Game Board. /// </param> /// <param name='cell'> /// The last taken <see cref="Yavalath.cell"/>. /// </param> /// <param name='height'> /// The Height to which the search should be run until. /// </param> /// <param name='achievable'> /// The Achievable Cell. /// </param> /// <param name='hope'> /// Hope. /// </param> /// <param name='player'> /// Player. /// </param> public static SearchResult ABNegamax(Board board, Cell cell, int height, SearchResult achievable, SearchResult hope, int player) { var emptyCells = board.EmptyCells (); if (height == 0 || emptyCells.Length == 0) { return new SearchResult { Score = Evaluation (board, cell, player), Cell = cell, Count = 1 }; } else { SearchResult temp; var score = Evaluation (board, cell, player); achievable.Count += 1; foreach (var _cell in emptyCells) { _cell.Player = player; temp = -ABNegamax (board, _cell, height-1, -hope, -achievable, -player); temp.Score += score; _cell.Player = 0; if (temp.Score >= hope.Score) { return temp; } achievable.Count = temp.Count = achievable.Count + temp.Count; achievable = temp.Score >= achievable.Score ? temp : achievable; } return achievable; } }
/// <summary> /// Initializes a new instance of the <see cref="Yavalath.Game"/> class. /// </summary> /// <param name='player1'> /// Player1. /// </param> /// <param name='player2'> /// Player2. /// </param> public Game(Player player1, Player player2) { GameBoard = new Board(); Players = new Dictionary<Player, int>(){ {player1, -1}, {player2, 1} }; CurrentPlayer = player1; }
// public static SearchResult Negamax (Board board, Cell cell, int player, int height, // int oldscore = 0, Pattern[] patterns = null) public override string GetNextMove(Board board, int playerSymbol) { Score -= board.Latest.Score; var s = Algorithms.ABNegamax(board, board.Latest.Cell, SearchDepth, new Algorithms.SearchResult {Score = -1.0/0, Count = 0}, new Algorithms.SearchResult {Score = 1.0/0}, playerSymbol); Score = s.Score; Console.WriteLine("Position: {0}; Evaluation count: {1}", s.Cell.Position, s.Count); return s.Cell.Position; }
/// <summary> /// Evaluate the score for a specific <see cref="Yavalath.Cell"/>. /// </summary> /// <param name='gameBoard'> /// Game board. /// </param> /// <param name='cell'> /// Cell. /// </param> /// <param name='playerSymbol'> /// Player symbol. /// </param> /// <param name='patterns'> /// Patterns. /// </param> public static double Evaluation(Board gameBoard, Cell cell, int playerSymbol, Pattern[] patterns = null) { if(patterns == null) patterns = Patterns(playerSymbol); var patterns2 = Patterns (-playerSymbol); var t = cell.Player; cell.Player = 0; var lines = GetLines(gameBoard, cell); var preScore = GetScore(lines, patterns) + GetScore(lines, patterns2); cell.Player = t; lines = GetLines(gameBoard, cell); var postScore = GetScore(lines, patterns) + 2*GetScore(lines, patterns2); return postScore - preScore; }
/// <summary> /// Gets the correcponding row and diagonals for a <see cref="Yavalath.Cell"/>. /// </summary> /// <returns> /// The player values for each cell. /// </returns> /// <param name='gameBoard'> /// The Game board. /// </param> /// <param name='cell'> /// The Cell. /// </param> private static int[][] GetLines(Board gameBoard, Cell cell) { Func<Cell, int> getPlayer = c => c.Player; var t = gameBoard.UpDiagonal (cell).Select (getPlayer).ToArray (); return new int[][]{ gameBoard.UpDiagonal (cell).Select (getPlayer).ToArray (), gameBoard.DownDiagonal (cell).Select (getPlayer).ToArray (), gameBoard.Row (cell).Select (getPlayer).ToArray () }; }
public abstract string GetNextMove(Board board = null, int playerSymbol = 0);
public override string GetNextMove(Board board, int playerSymbol) { Console.Write("Take your move: [CellCoords] or \"TakeOver\""); var input = Console.ReadLine(); return input; }