private double HeuristicEval(BoardStates player, OthelloGame game) { //Based of features of the board that humans have identified. //Hints of evaluation from any source I could find //idealy these could me optimized using a genetic algorithm, //but that is a different project const int searchableDepthOverride = 2; //override min-max in favor of complete evaluation const int endGame = 20; //<20 moves is endgame const int midGame = 40; // 20 moves in is midgame double value = 0; int empty = game.GetPieceCount(BoardStates.empty); if (game.GameComplete) { return(CompleteEval(player, game)); } else if (empty < searchableDepthOverride) { return(MinimaxAlphaBeta(game, searchableDepthOverride, int.MinValue, int.MaxValue, player)); } value += coinDiffWeight * Math.Pow((game.GetPieceCount(player) - game.GetPieceCount(~player) + empty - coinDiffOffset), coinDiffPower); value += cornerDiffWeight * Math.Pow((game.GetCornerCount(player) - game.GetCornerCount(~player) + empty - cornerDiffOffset), cornerDiffPower); value += nearCornerDiffWeight * Math.Pow((game.GetAdjCornerCount(player) - game.GetAdjCornerCount(~player) + empty - nearCornerDiffOffset), nearCornerDiffPower); value += avalibleMoveDiffWeight * Math.Pow((game.GetPossiblePlayList(player).Count() - game.GetPossiblePlayList(~player).Count() + empty - avalibleMoveDiffOffset), avalibleMoveDiffPower); value += nonTurnableCoinDiffWeight * Math.Pow((game.GetSafePeiceCountEstimation(player) - game.GetSafePeiceCountEstimation(~player) + empty - nonTurnableCoinDiffOffset), nonTurnableCoinDiffPower); value += ControlledCornerDiffWeight * Math.Pow((game.GetControlledCorners(player) - game.GetControlledCorners(~player) + empty - ControlledCornerDiffOffset), ControlledCornerDiffPower); return(value); }