public void NewGame_NoOneCanWin(int degreeOfParallelism, ParallelismMode parallelismMode) { TicTacToeState startState = Utils.GetEmptyTicTacToeState(); var engine = GetSearchEngine(degreeOfParallelism, parallelismMode); var evaluation = engine.Search(startState, 10); Assert.AreEqual(0, evaluation.Evaluation); var lastMove = (IDeterministicState)evaluation.StateSequence.Last(); Assert.AreEqual(0, lastMove.Evaluate(0, new List <IState>()), "Should have found a wining state"); Assert.IsTrue(evaluation.FullTreeSearchedOrPruned); Assert.IsFalse(evaluation.AllChildrenAreDeadEnds); if (degreeOfParallelism == 1) { //Check that the our optimizations are working Assert.IsTrue(evaluation.Leaves < 63000, "Too many leaves in search."); Assert.IsTrue(evaluation.InternalNodes < 84000, "Too many internal nodes in search."); } // Too few leaves or internal nodes means that something went wrong Assert.IsTrue(evaluation.Leaves > 500, "Too few leaves in search."); Assert.IsTrue(evaluation.InternalNodes > 500, "Too few internal nodes in search."); }
public void Search_SearchDepthIsRight(int depth, ParallelismMode parallelismMode) { var engine = TestUtils.GetBasicSearchEngine(parallelismMode, 8); var result = engine.Search(new IncreasingNumberState(8, Player.Max), depth); Assert.AreEqual(depth, result.SearchDepth, "Got wring depth"); }
public void Search_IsSearchCompletedTrue(int degreeOfParallelism, ParallelismMode parallelismMode) { var tree = new UnaryDeterministicTree(); var engine = TestUtils.GetBasicSearchEngine(parallelismMode, degreeOfParallelism); var result = engine.Search(tree.State3, 5); Assert.IsTrue(result.IsSearchCompleted, "Search should have been completed"); }
public static SearchEngine GetBasicSearchEngine( ParallelismMode parallelismMode = ParallelismMode.FirstLevelOnly, int maxDegreeOfParallelism = 1, int parallelismLevel = 1) => new SearchEngine(CacheMode.NewCache, CacheKeyType.StateOnly) { SkipEvaluationForFirstNodeSingleNeighbor = false, ParallelismMode = parallelismMode, MaxLevelOfParallelism = parallelismLevel, MaxDegreeOfParallelism = maxDegreeOfParallelism };
public void Search_CheckPreventLoopPrunerWorks(int degreeOfParallelism, ParallelismMode parallelismMode) { var searchEngine = new SearchEngine(CacheMode.NewCache, CacheKeyType.StateOnly) { PreventLoops = true, MaxDegreeOfParallelism = degreeOfParallelism, ParallelismMode = parallelismMode, SkipEvaluationForFirstNodeSingleNeighbor = false }; searchEngine.Search(new ThrowExceptionAtDepthThreeState(0, Player.Max), 5); }
private void BenchmarkWithDegreeOfParallelism(int degreeOfParallelism, ParallelismMode parallelismMode) { Console.WriteLine("Running with degreeOfParallelism: " + degreeOfParallelism + ", Mode: " + parallelismMode); var engine = Connect4TestUtils.GetSearchEngine(degreeOfParallelism, parallelismMode); var startState = new StartState(new Connect4State(Connect4TestUtils.GetEmptyBoard(), Player.Max)); var results = engine.Search(startState, 7); Console.WriteLine("Time: " + results.SearchTime); Console.WriteLine("Leaves: " + results.Leaves); Console.WriteLine("InternalNodes: " + results.InternalNodes); }
public void Search_DontStopWithUnstableState(int degreeOfParallelism, ParallelismMode parallelismMode) { var searchEngine = new SearchEngine(CacheMode.NewCache, CacheKeyType.StateOnly) { IsUnstableState = (s, d, l) => s.Evaluate(d, l) < 10, MaxDegreeOfParallelism = degreeOfParallelism, ParallelismMode = parallelismMode, SkipEvaluationForFirstNodeSingleNeighbor = false, }; var result = searchEngine.Search(new IncreasingNumberState(0, Player.Max), 1); Assert.AreEqual(10, result.Evaluation, "Engine seems to have stopped before reaching a stable state"); }
private void Benchmark(Player[,] startBoard, int searchDepth, ParallelismMode parallelismMode = ParallelismMode.FirstLevelOnly, int degreeOfParallelism = 1, int levelOfParallelism = 1) { Console.WriteLine(GetTestMessage(parallelismMode, degreeOfParallelism, levelOfParallelism)); var engine = Connect4TestUtils.GetSearchEngine(degreeOfParallelism, parallelismMode, levelOfParallelism); var startState = new Connect4State(startBoard, Player.Max); var results = engine.Search(startState, searchDepth); Console.WriteLine("Time: " + results.SearchTime); Console.WriteLine("Leaves: " + results.Leaves); Console.WriteLine("InternalNodes: " + results.InternalNodes); }
public static SearchEngine GetSearchEngine(int degreeOfParallelism, ParallelismMode parallelismMode, CacheMode cacheMode = CacheMode.NewCache) { var searchEngine = cacheMode == CacheMode.NoCache ? new SearchEngine() : new SearchEngine(cacheMode, CacheKeyType.StateOnly); searchEngine.MaxDegreeOfParallelism = degreeOfParallelism; searchEngine.DieEarly = true; searchEngine.MinScore = -1; searchEngine.MaxScore = 1; searchEngine.ParallelismMode = parallelismMode; searchEngine.SkipEvaluationForFirstNodeSingleNeighbor = false; searchEngine.StateDefinesDepth = true; return(searchEngine); }
private string GetTestMessage(ParallelismMode parallelismMode, int degreeOfParallelism, int levelOfParallelism) { var stringBuilder = new StringBuilder("Running Mode " + parallelismMode); if (parallelismMode == ParallelismMode.TotalParallelism) { stringBuilder.Append($" {nameof(degreeOfParallelism)} == {degreeOfParallelism}"); } if (parallelismMode == ParallelismMode.ParallelismByLevel) { stringBuilder.Append($" {nameof(levelOfParallelism)} == {levelOfParallelism}"); } return(stringBuilder.ToString()); }
public void MinCanWinInFiveTurns_MinWins(ParallelismMode parallelismMode, bool dieEarly) { var board = TestUtils.GetEmptyBoard(7); board[2, 4] = CheckerPiece.MinKing; board[5, 3] = CheckerPiece.MaxKing; var startState = board.ToState(Player.Min); var engine = TestUtils.GetCheckersSearchEngine(4, parallelismMode, 1, dieEarly); var searchResult = engine.Search(startState, 5); Assert.AreEqual(CheckerPiece.MinKing, searchResult.NextMove.GetBoard()[3, 3], "Min should have set a trap by moving to [3, 3] " + Environment.NewLine + searchResult.NextMove); Assert.AreEqual(CheckersState.MIN_WIN, searchResult.Evaluation, "Min should have won!"); }
public void NewGame_CheckCancellationToken(int degreeOfParallelism, ParallelismMode parallelismMode) { var startState = new Connect4State(Connect4TestUtils.GetEmptyBoard(), Player.Max); var engine = Connect4TestUtils.GetSearchEngine(degreeOfParallelism, parallelismMode); var cancellationSource = new CancellationTokenSource(); var searchTask = engine.SearchAsync(startState, 20, cancellationSource.Token); Thread.Sleep(500); cancellationSource.Cancel(); Thread.Sleep(500); Assert.IsTrue(searchTask.IsCompleted, "Search should have complated by now"); var t = searchTask.Result; // Check that we can get a result even if the search was terminated }
public static SearchEngine GetSearchEngine(int maxDegreeOfParallelism, ParallelismMode parallelismMode, int levelOfParallelism = 1, CacheMode cacheMode = CacheMode.NewCache) { var engine = cacheMode == CacheMode.NoCache ? new SearchEngine() : new SearchEngine(cacheMode, CacheKeyType.StateOnly); engine.MaxDegreeOfParallelism = maxDegreeOfParallelism; engine.MaxLevelOfParallelism = levelOfParallelism; engine.DieEarly = true; engine.MinScore = BoardEvaluator.MinEvaluation; engine.MaxScore = BoardEvaluator.MaxEvaluation; engine.ParallelismMode = parallelismMode; engine.SkipEvaluationForFirstNodeSingleNeighbor = false; engine.StateDefinesDepth = true; return(engine); }
public void MaxCanWinInThreeTurns_MaxWins(ParallelismMode parallelismMode, bool dieEarly) { var board = TestUtils.GetEmptyBoard(5); board[0, 0] = CheckerPiece.MaxChecker; board[1, 3] = CheckerPiece.MaxChecker; board[3, 3] = CheckerPiece.MinChecker; var startState = board.ToState(Player.Max); var engine = TestUtils.GetCheckersSearchEngine(4, parallelismMode, 1, dieEarly); var searchResult = engine.Search(startState, 3); Assert.AreEqual(CheckerPiece.MaxChecker, searchResult.NextMove.GetBoard()[2, 2], "Max should have set a trap by moving to [2, 2] " + Environment.NewLine + searchResult.NextMove); Assert.AreEqual(CheckersState.MAX_WIN, searchResult.Evaluation, "Max should have won!"); }
public void Search_RowOfMixedTurns_FindBest(int degreeOfParallelism, ParallelismMode parallelismMode) { var tree = new DeterministicTree2(); A.CallTo(() => tree.ChildState1.Turn).Returns(Player.Max); tree.EndState1.SetEvaluationTo(5); tree.EndState2.SetEvaluationTo(6); tree.EndState3.SetEvaluationTo(4); tree.EndState4.SetEvaluationTo(7); var engine = TestUtils.GetBasicSearchEngine(parallelismMode, degreeOfParallelism); var result = engine.Search(tree.RootState, 5); Assert.AreEqual(tree.EndState2, result.StateSequence.Last()); Assert.AreEqual(6, result.Evaluation); }
private void BenchmarkWithDegreeOfParallelism(int degreeOfParallelism, ParallelismMode parallelismMode) { Console.WriteLine("Running with degreeOfParallelism: " + degreeOfParallelism + ", Mode: " + parallelismMode); var engine = TicTacToeBassicTests.GetSearchEngine(degreeOfParallelism, parallelismMode); var startState = new TicTacToeState(new[, ] { { Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty }, }, Player.Max); var results = engine.Search(startState, 10); Console.WriteLine("Time: " + results.SearchTime); Console.WriteLine("Leaves: " + results.Leaves); Console.WriteLine("InternalNodes: " + results.InternalNodes); }
public void CancelSearch_ReturnBestResultSoFar(int degreeOfParallelism, ParallelismMode parallelismMode) { var tree = new EndlessTree(); tree.ChildState1.SetEvaluationTo(1); tree.ChildState2.SetEvaluationTo(3); var cancellationSource = new CancellationTokenSource(20); var engine = TestUtils.GetBasicSearchEngine(parallelismMode, degreeOfParallelism); var result = engine.SearchAsync(tree.RootState, int.MaxValue, cancellationSource.Token).Result; Assert.AreEqual(3, result.Evaluation, "Didn't get a good enough state"); if (parallelismMode == ParallelismMode.NonParallelism) { A.CallTo(() => tree.ChildState2.GetNeighbors()).MustNotHaveHappened(); } }
private void RunThreadSaftyTest(int degreeOfParallelism, ParallelismMode parallelismMode, Action <SearchEngine> searchMethod) { var engine = TicTacToeBassicTests.GetSearchEngine(degreeOfParallelism, parallelismMode); var tasks = new Task[TEST_RUNS]; for (int i = 0; i < TEST_RUNS; i++) { tasks[i] = Task.Run(() => searchMethod(engine)); } var allTaskFinished = true; foreach (var task in tasks) { allTaskFinished = allTaskFinished && task.Wait(TimeSpan.FromSeconds(30)); } Assert.IsTrue(allTaskFinished, "Not all tasks finished"); }
public void Search_PrunerTest(int maxDegreeOfParallelism, ParallelismMode parallelismMode) { var tree = new DeterministicTree(); var pruner = A.Fake <IPruner>(); A.CallTo(() => pruner.ShouldPrune(A <IState> ._, A <int> ._, A <List <IState> > ._)) .ReturnsLazily((IState s, int d, List <IState> l) => s.Equals(tree.ChildState2)); var engine = TestUtils.GetBasicSearchEngine(parallelismMode, maxDegreeOfParallelism); engine.AddPruner(pruner); tree.EndState1.SetEvaluationTo(1); tree.EndState2.SetEvaluationTo(2); tree.EndState3.SetEvaluationTo(2); tree.ChildState2.SetEvaluationTo(-2); var result = engine.Search(tree.RootState, 4); Assert.AreEqual(1, result.Evaluation, $"We should have pruned away {nameof(tree.ChildState2)}"); }
public void Search_DieEarllyOptionWorks(int degreeOfParallelism, ParallelismMode parallelismMode) { var tree = new DeterministicTree3(); tree.EndState1.SetEvaluationTo(10); tree.EndState2.SetEvaluationTo(15); tree.EndState3.SetEvaluationTo(0); var searchEngine = new SearchEngine(CacheMode.NewCache, CacheKeyType.StateOnly) { DieEarly = true, MaxScore = 5, MinScore = 5, MaxDegreeOfParallelism = degreeOfParallelism, ParallelismMode = parallelismMode, SkipEvaluationForFirstNodeSingleNeighbor = false, }; var evaluation = searchEngine.Search(tree.RootState, 2); Assert.AreEqual(tree.EndState1, evaluation.StateSequence.Last(), "Should have ended with" + nameof(tree.EndState1)); }
public void NewGame_NoOneCanWin(int degreeOfParallelism, ParallelismMode parallelismMode) { var startState = new Connect4State(Connect4TestUtils.GetEmptyBoard(), Player.Max); var engine = Connect4TestUtils.GetSearchEngine(degreeOfParallelism, parallelismMode); var evaluation = engine.Search(startState, 7); Assert.IsFalse(BoardEvaluator.IsWin(((Connect4State)evaluation.StateSequence.Last()).Board, Player.Max)); Assert.IsFalse(evaluation.FullTreeSearchedOrPruned); Assert.IsFalse(evaluation.AllChildrenAreDeadEnds); if (degreeOfParallelism == 1) { //Check that the our optimizations are working Assert.IsTrue(evaluation.Leaves < 26000, "Too many leaves in search. Leaves = " + evaluation.Leaves); Assert.IsTrue(evaluation.InternalNodes < 10000, "Too many intarnal nodes in search. Nodes = " + evaluation.InternalNodes); } // Too few leaves or internal nodes means that something went wrong Assert.IsTrue(evaluation.Leaves > 1000, "Too few leaves in search. Leaves = " + evaluation.Leaves); Assert.IsTrue(evaluation.InternalNodes > 1000, "Too few intarnal nodes in search. Nodes = " + evaluation.InternalNodes); }
public void TwoStepsAwayFromMaxWinning__MinsTurn_DontLetMinMax(int degreeOfParallelism, ParallelismMode parallelismMode) { var startState = new Connect4State(new[, ] { { Player.Empty, Player.Max, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Max, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Max, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, }, Player.Min); var engine = Connect4TestUtils.GetSearchEngine(degreeOfParallelism, parallelismMode); var newState = (Connect4State)engine.Search(startState, 2).NextMove; Assert.AreEqual(Player.Min, newState.Board[3, 1], "Min didn't block Max's win"); }
public void MaxCanWinNextMoveOrInThree_MaxWinsNextMove(int degreeOfParallelism, ParallelismMode parallelismMode) { var startState = new Connect4State(new[, ] { { Player.Empty, Player.Empty, Player.Max, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Max, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Max, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, }, Player.Max); var engine = new SearchEngine(CacheMode.NewCache, CacheKeyType.StateOnly) { FavorShortPaths = true, MaxDegreeOfParallelism = degreeOfParallelism, ParallelismMode = parallelismMode, SkipEvaluationForFirstNodeSingleNeighbor = false, StateDefinesDepth = true }; var evaluation = engine.Search(startState, 5); Assert.IsTrue(evaluation.StateSequence.Count == 1, "Max should have won in one move"); Assert.AreEqual(Player.Max, ((Connect4State)evaluation.NextMove).Board[3, 2], "Max didn't win"); }
public void Search_TaskCanceld_DontContinueSearching(int degreeOfParallelism, ParallelismMode parallelismMode) { var tree = new UnaryDeterministicTree(); var cancellationSource = new CancellationTokenSource(); A.CallTo(() => tree.RootState.GetNeighbors()).ReturnsLazily(() => { cancellationSource.Cancel(); return(new List <IDeterministicState> { tree.State2 }); }); tree.RootState.SetEvaluationTo(1); tree.State2.SetEvaluationTo(2); tree.EndState.SetEvaluationTo(2); var searchEngine = TestUtils.GetBasicSearchEngine(parallelismMode, degreeOfParallelism); var result = searchEngine.Search(tree.RootState, 5, cancellationSource.Token); Assert.AreEqual(1, result.Evaluation); Assert.AreEqual(0, result.StateSequence.Count, "We shouldn't have gotten to past " + nameof(tree.RootState)); Assert.IsFalse(result.IsSearchCompleted, "The search shouldn't have been completed"); }
public void MaxCanWinInFourMovesOrTwo_MinBlocksNearWin(int degreeOfParallelism, ParallelismMode parallelismMode) { var startState = new Connect4State(new[, ] { { Player.Empty, Player.Empty, Player.Max, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Max, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Max, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, }, Player.Min); var engine = new SearchEngine(CacheMode.NewCache, CacheKeyType.StateOnly) { FavorShortPaths = true, MaxDegreeOfParallelism = degreeOfParallelism, ParallelismMode = parallelismMode, SkipEvaluationForFirstNodeSingleNeighbor = false }; var evaluation = engine.Search(startState, 5); Assert.IsTrue(evaluation.StateSequence.Count > 2, "Min should have blocked the near win"); Assert.AreEqual(Player.Min, ((Connect4State)evaluation.NextMove).Board[3, 2], "Min didn't block Max's win"); }
public void Search_WinMovesTwoAndThreeStepsAway_FindTheNearerOne(int degreeOfParallelism, ParallelismMode parallelismMode, bool dieEarly) { var tree = new UnevenDeterministicTree(); tree.EndState1.SetEvaluationTo(15); tree.EndState2.SetEvaluationTo(11); tree.EndState3.SetEvaluationTo(18); var engine = new SearchEngine(CacheMode.NewCache, CacheKeyType.StateOnly) { MaxDegreeOfParallelism = degreeOfParallelism, FavorShortPaths = true, DieEarly = dieEarly, MaxScore = 10, ParallelismMode = parallelismMode, SkipEvaluationForFirstNodeSingleNeighbor = false, }; var result = engine.Search(tree.RootState, 5); Assert.AreEqual(tree.EndState1, result.StateSequence.Last(), nameof(tree.EndState1) + " should have been good enough"); }
public void Search_CheckThatRecordPassThroughStatesIsWorking(int degreeOfParallelism, ParallelismMode parallelismMode) { var tree = new DeterministicTree(); A.CallTo(() => tree.EndState1.Evaluate(A <int> ._, A <List <IState> > .That.IsEmpty())) .Throws(new Exception("passedStats list should have been empty")); A.CallTo(() => tree.EndState1.Evaluate(A <int> ._, A <List <IState> > ._)) .Invokes((int i, List <IState> l) => { Assert.AreEqual(1, l.Count, "passThroughStates should only have one node (state1)"); Assert.IsTrue(l.Contains(tree.ChildState1), "passThroughStates should contain state1"); }); var searchEngine = TestUtils.GetBasicSearchEngine(parallelismMode, degreeOfParallelism); searchEngine.Search(tree.ChildState1, 5); }
public void FiveStepsAwayFromMaxWinning_MaxTurn_MaxWin(int degreeOfParallelism, ParallelismMode parallelismMode, CacheMode cacheMode) { var startState = Connect4TestUtils.GetMaxFiveMovesAwayFromWinningState(); var engine = Connect4TestUtils.GetSearchEngine(degreeOfParallelism, parallelismMode, 1, CacheMode.ReuseCache); var evaluation = engine.Search(startState, 5); Assert.AreEqual(BoardEvaluator.MaxEvaluation, evaluation.Evaluation); Assert.IsTrue(BoardEvaluator.IsWin(((Connect4State)evaluation.StateSequence.Last()).Board, Player.Max), "Should have found a wining state"); Assert.IsTrue(evaluation.AllChildrenAreDeadEnds, "All children should be dead ends"); }
public void Search_MaxHasTwoTurnsInARow_FindBestMove(int degreeOfParallelism, ParallelismMode parallelismMode) { var tree = new DeterministicTree(); A.CallTo(() => tree.ChildState2.Turn).Returns(Player.Max); tree.EndState2.SetEvaluationTo(2); tree.EndState3.SetEvaluationTo(3); var engine = TestUtils.GetBasicSearchEngine(parallelismMode, degreeOfParallelism); var result = engine.Search(tree.ChildState2, 5); Assert.AreEqual(tree.EndState3, result.NextMove, "Actually found " + result.NextMove); }
public void ThreeStepsAwayFromMaxWinning_MaxTurn_MaxWin(int degreeOfParallelism, ParallelismMode parallelismMode) { var startState = new Connect4State(new[, ] { { Player.Empty, Player.Empty, Player.Empty, Player.Max, Player.Max, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, { Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty, Player.Empty }, }, Player.Max); var engine = Connect4TestUtils.GetSearchEngine(degreeOfParallelism, parallelismMode); var evaluation = engine.Search(startState, 3); Assert.IsTrue(BoardEvaluator.IsWin(((Connect4State)evaluation.StateSequence.Last()).Board, Player.Max), "Should have found a wining state"); }