public void AlwaysAdvanceToEndNoPiecePlacing() { var state = new SimulationState(SimulationHelpers.GetRandomPieces(), 0); state.Fidelity = SimulationFidelity.NoPiecePlacing; var runner = new SimulationRunner(state, new PlayerDecisionMaker(AlwaysAdvanceMoveMaker.Instance, null), new PlayerDecisionMaker(AlwaysAdvanceMoveMaker.Instance, null)); //The game definitely ends within 200 steps for (var i = 0; i < 200 && !state.GameHasEnded; i++) { runner.PerformNextStep(); Assert.InRange(state.PlayerPosition[0], 0, SimulationState.EndLocation); Assert.InRange(state.PlayerPosition[1], 0, SimulationState.EndLocation); } //Both players should be at the end Assert.Equal(SimulationState.EndLocation, state.PlayerPosition[0]); Assert.Equal(SimulationState.EndLocation, state.PlayerPosition[1]); //Game should have ended Assert.True(state.GameHasEnded); //Players should have one button for each place they moved Assert.Equal(SimulationState.EndLocation + SimulationState.PlayerStartingButtons, state.PlayerButtonAmount[0]); Assert.Equal(SimulationState.EndLocation + SimulationState.PlayerStartingButtons, state.PlayerButtonAmount[1]); //non-starting player should have won by collecting all of the leather patches (https://boardgamegeek.com/thread/1703957/how-break-stalemate) Assert.Equal(1, state.WinningPlayer); //Check the ending points are correct Assert.Equal(SimulationState.EndLocation - BoardState.Width * BoardState.Height * 2 + SimulationState.PlayerStartingButtons, state.CalculatePlayerEndGameWorth(0)); Assert.Equal(SimulationState.EndLocation - BoardState.Width * BoardState.Height * 2 + SimulationState.PlayerStartingButtons + 2 * SimulationState.LeatherPatches.Length, state.CalculatePlayerEndGameWorth(1)); }
/// <summary> /// Returns the amount of wins the challenger got (from 100) /// </summary> private static int CalculateChallengerWinsFrom100(IMoveDecisionMaker best, IMoveDecisionMaker challenger) { int challengerWins = 0; Parallel.For(0, 200, (i) => { var state = new SimulationState(SimulationHelpers.GetRandomPieces(i / 2), 0); state.ActivePlayer = i % 2; state.Fidelity = SimulationFidelity.NoPiecePlacing; //TODO: May need a cheaper placement engine var runner = new SimulationRunner(state, new PlayerDecisionMaker(best, null), new PlayerDecisionMaker(challenger, null)); while (!state.GameHasEnded) { runner.PerformNextStep(); } if (state.WinningPlayer == 1) { Interlocked.Increment(ref challengerWins); } }); return(challengerWins); }
public void Run() { Evaluate(); var req = new TrainRequest(); for (var g = 0; g < 1000; g++) { var timer = Stopwatch.StartNew(); //Parallel.For(0, 8, (i) => for (var i = 0; i < 8; i++) { Console.WriteLine("Starting game " + i); var p0Samples = new List <TrainSample>(); var p1Samples = new List <TrainSample>(); var state = new SimulationState(SimulationHelpers.GetRandomPieces(), 0); state.Fidelity = SimulationFidelity.NoPiecePlacing; while (!state.GameHasEnded) { var sampleSet = state.ActivePlayer == 0 ? p0Samples : p1Samples; var sample = _ai.MakeMoveWithResult(state); sampleSet.Add(sample); } //Set the winner on the samples from the winner var winningSamples = state.WinningPlayer == 0 ? p0Samples : p1Samples; for (var j = 0; j < winningSamples.Count; j++) { winningSamples[j].IsWin = true; } //TODO: AddRange is terrible performance lock (req) { req.Samples.AddRange(p0Samples); req.Samples.AddRange(p1Samples); } } //); timer.Stop(); Console.WriteLine("Took " + timer.ElapsedMilliseconds); //if (req.Samples.Count >= 256) { Console.WriteLine("Training " + req.Samples.Count); _client.Train(req); req.Samples.Clear(); Evaluate(); } } Console.WriteLine("Hi"); Console.ReadLine(); }
private static void RunMoveMakerForPerformance() { var sw = Stopwatch.StartNew(); #if PERF_PARALLEL Parallel.For(0, 10, (run) => //5900 #else for (var run = 0; run < 4; run++) //13000 #endif { //var a = new PlayerDecisionMaker(new MoveOnlyMonteCarloTreeSearchMoveMaker(10000), PlacementMaker.FirstPossibleInstance); //var b = new PlayerDecisionMaker(new MoveOnlyMonteCarloTreeSearchMoveMaker(5000), PlacementMaker.FirstPossibleInstance); var mctsA = new MonteCarloTreeSearchMoveMaker(5000, TuneableUtilityMoveMaker.Tuning1, new TightBoardEvaluator(true), 2); var a = new PlayerDecisionMaker(mctsA, new PlacementMaker(mctsA.PlacementStrategy)); var mctsB = new MonteCarloTreeSearchMoveMaker(5000, TuneableUtilityMoveMaker.Tuning1, new TightBoardEvaluator(true), 2); var b = new PlayerDecisionMaker(mctsB, new PlacementMaker(mctsB.PlacementStrategy)); var state = new SimulationState(SimulationHelpers.GetRandomPieces(run / 2), 0); var runner = new SimulationRunner(state, run % 2 == 0 ? a : b, run % 2 == 1 ? a : b); while (!state.GameHasEnded) { runner.PerformNextStep(); } Console.WriteLine(state.WinningPlayer); }
public void BuyFirstPossibleMoveMakerNoPiecePlacing() { var state = new SimulationState(SimulationHelpers.GetRandomPieces(3), 0); state.Fidelity = SimulationFidelity.NoPiecePlacing; var runner = new SimulationRunner(state, new PlayerDecisionMaker(BuyFirstPossibleMoveMaker.Instance, null), new PlayerDecisionMaker(BuyFirstPossibleMoveMaker.Instance, null)); while (!state.GameHasEnded) { runner.PerformNextStep(); } //Check someone bought something Assert.True(state.Pieces.Count < PieceDefinition.AllPieceDefinitions.Length); }
internal (SimulationState state, int gameId) CreateSimulation(int?randomSeed, int mctsIterations) { lock (this) { var id = ++_nextSim; var state = new SimulationState(SimulationHelpers.GetRandomPieces(randomSeed), 0); state.Fidelity = SimulationFidelity.NoPiecePlacing; var opp = new MoveOnlyMonteCarloTreeSearchMoveMaker(mctsIterations); _simulations[id] = state; _opponents[id] = opp; return(state, id); } }
private void TestStrategy(IPlacementStrategy strategy, int expectPiecesPlaced) { var pieces = new PieceCollection(); pieces.Populate(SimulationHelpers.GetRandomPieces(1)); int placed = 0; var board = new BoardState(); for (var i = 0; i < pieces.Count; i++) { if (strategy.TryPlacePiece(board, PieceDefinition.AllPieceDefinitions[pieces[i]], in pieces, i + 1, out var bitmap, out var x, out var y)) { placed++; board.Place(bitmap, x, y); }
public void BuyFirstPossibleMoveMakerPlacing() { var state = new SimulationState(SimulationHelpers.GetRandomPieces(1), 0); var runner = new SimulationRunner(state, new PlayerDecisionMaker(BuyFirstPossibleMoveMaker.Instance, PlacementMaker.FirstPossibleInstance), new PlayerDecisionMaker(BuyFirstPossibleMoveMaker.Instance, PlacementMaker.FirstPossibleInstance)); while (!state.GameHasEnded) { runner.PerformNextStep(); } //Check someone bought something Assert.True(state.Pieces.Count < PieceDefinition.AllPieceDefinitions.Length); Assert.Equal(11, state.PlayerButtonIncome[0]); Assert.Equal(37, state.PlayerButtonAmount[0]); }
static void TestPlacementOnly() { var stopwatch = Stopwatch.StartNew(); var strategies = new IPlacementStrategy[] { //FirstPossiblePlacementStrategy.Instance, //SimpleClosestToWallAndCornerStrategy.Instance, //ClosestToCornerLeastHolesTieBreakerPlacementStrategy.Instance, //NextToPieceEdgeLeastHolesTieBreakerPlacementStrategy.Instance, //TightPlacementStrategy.InstanceDoubler, //TightPlacementStrategy.InstanceIncrement, ExhaustiveMostFuturePlacementsPlacementStrategy.Instance1_1, ExhaustiveMostFuturePlacementsPlacementStrategy.Instance1_6, new BestEvaluatorStrategy(TuneablePattern2x2BoardEvaluator.HandTuned), new BestEvaluatorStrategy(TuneablePattern2x2BoardEvaluator.Tuning1), }; //foreach (var strategy in strategies) Parallel.ForEach(strategies, (strategy) => { //var rand = new Random(0); int totalPlaced = 0; for (var i = 0; i < 100; i++) { var pieces = new PieceCollection(); pieces.Populate(SimulationHelpers.GetRandomPieces(i)); int index = 0; int placed = 0; var board = new BoardState(); while (true) { var piece = pieces[index]; pieces.RemoveAt(index); index = index % pieces.Count; if (strategy.TryPlacePiece(board, PieceDefinition.AllPieceDefinitions[piece], in pieces, index, out var bitmap, out var x, out var y)) { placed++; board.Place(bitmap, x, y); //Advance to a random one in the next 6 pieces (TODO: Would be good to bias this towards 1-3 as these are more likely) //index = (index + rand.Next(0, 6)) % pieces.Count; }
public void GetRandomPiecesPlaces0AtEnd() { for (var i = 0; i < 1000; i++) { var pieces = SimulationHelpers.GetRandomPieces(i); //0 at end Assert.Equal(0, pieces[pieces.Count - 1]); //Array contains all pieces pieces = pieces.OrderBy(p => p).ToList(); for (var j = 0; j < pieces.Count; j++) { Assert.Equal(j, pieces[j]); } } }
public void AdvanceToEndPlacingSinglePatches() { var state = new SimulationState(SimulationHelpers.GetRandomPieces(), 0); state.Fidelity = SimulationFidelity.FullSimulation; var runner = new SimulationRunner(state, new PlayerDecisionMaker(AlwaysAdvanceMoveMaker.Instance, PlacementMaker.FirstPossibleInstance), new PlayerDecisionMaker(AlwaysAdvanceMoveMaker.Instance, PlacementMaker.FirstPossibleInstance)); while (!state.GameHasEnded) { runner.PerformNextStep(); } //Both players should be at the end Assert.Equal(SimulationState.EndLocation, state.PlayerPosition[0]); Assert.Equal(SimulationState.EndLocation, state.PlayerPosition[1]); //Game should have ended Assert.True(state.GameHasEnded); //Players should have one button for each place they moved Assert.Equal(SimulationState.EndLocation + SimulationState.PlayerStartingButtons, state.PlayerButtonAmount[0]); Assert.Equal(SimulationState.EndLocation + SimulationState.PlayerStartingButtons, state.PlayerButtonAmount[1]); //non-starting player should have won by collecting all of the leather patches (https://boardgamegeek.com/thread/1703957/how-break-stalemate) Assert.Equal(1, state.WinningPlayer); //Check the ending points are correct Assert.Equal(SimulationState.EndLocation - BoardState.Width * BoardState.Height * 2 + SimulationState.PlayerStartingButtons, state.CalculatePlayerEndGameWorth(0)); Assert.Equal(SimulationState.EndLocation - BoardState.Width * BoardState.Height * 2 + SimulationState.PlayerStartingButtons + 2 * SimulationState.LeatherPatches.Length, state.CalculatePlayerEndGameWorth(1)); //Check the pieces are on their board int sum = 0; for (var x = 0; x < BoardState.Width; x++) { for (var y = 0; y < BoardState.Height; y++) { if (state.PlayerBoardState[1][x, y]) { sum++; } } } Assert.Equal(SimulationState.LeatherPatches.Length, sum); }
private void Evaluate() { Console.WriteLine($"Evaluating vs " + _opp.Name); var players = new IMoveDecisionMaker[] { _ai, _opp }; //Play X games (even amount), each player gets to start on each of the boards once for (var game = 0; game < 4; game++) { var state = new SimulationState(SimulationHelpers.GetRandomPieces(game / 2), 0); state.Fidelity = SimulationFidelity.NoPiecePlacing; state.ActivePlayer = game % 2; while (!state.GameHasEnded) { players[state.ActivePlayer].MakeMove(state); } Console.WriteLine($"Game {game}. Winner {state.WinningPlayer}. Scores: {state.CalculatePlayerEndGameWorth(0)} / {state.CalculatePlayerEndGameWorth(1)}"); } }
static void TestFullAi() { var aiToTest = new Func <PlayerDecisionMaker>[] { //() => new PlayerDecisionMaker(new GreedyCardValueUtilityMoveMaker(-1), PlacementMaker.TightDoublerInstance), //() => new PlayerDecisionMaker(new GreedyCardValueUtilityMoveMaker(0), PlacementMaker.TightDoublerInstance), //() => new PlayerDecisionMaker(new GreedyCardValueUtilityMoveMaker(1), PlacementMaker.TightDoublerInstance), //() => new PlayerDecisionMaker(new GreedyCardValueUtilityMoveMaker(2), PlacementMaker.TightDoublerInstance), // //() => new PlayerDecisionMaker(new GreedyCardValueUtilityMoveMaker(-1), PlacementMaker.ExhaustiveMostFuturePlacementsInstance1_6), //() => new PlayerDecisionMaker(new GreedyCardValueUtilityMoveMaker(0), PlacementMaker.ExhaustiveMostFuturePlacementsInstance1_6), //() => new PlayerDecisionMaker(new GreedyCardValueUtilityMoveMaker(1), PlacementMaker.ExhaustiveMostFuturePlacementsInstance1_6), //() => new PlayerDecisionMaker(new GreedyCardValueUtilityMoveMaker(2), PlacementMaker.ExhaustiveMostFuturePlacementsInstance1_6), //() => new PlayerDecisionMaker(new QuickRandomSearchMoveMaker(6, 1000), PlacementMaker.ExhaustiveMostFuturePlacementsInstance1_6), //() => new PlayerDecisionMaker(new QuickRandomSearchMoveMaker(10, 2000), PlacementMaker.ExhaustiveMostFuturePlacementsInstance1_6), //() => new PlayerDecisionMaker(new QuickRandomSearchMoveMaker(20, 5000), PlacementMaker.ExhaustiveMostFuturePlacementsInstance1_6), //() => new PlayerDecisionMaker(new QuickRandomSearchMoveMaker(30, 10000), PlacementMaker.ExhaustiveMostFuturePlacementsInstance1_6), //() => new PlayerDecisionMaker(new MoveOnlyMonteCarloTreeSearchMoveMaker(1000, TuneableUtilityMoveMaker.Tuning1), PlacementMaker.ExhaustiveMostFuturePlacementsInstance1_6), () => new PlayerDecisionMaker(new MoveOnlyMonteCarloTreeSearchMoveMaker(10000, TuneableUtilityMoveMaker.Tuning1), PlacementMaker.ExhaustiveMostFuturePlacementsInstance1_6), () => new PlayerDecisionMaker(new MoveOnlyMonteCarloTreeSearchMoveMaker(10000, TuneableUtilityMoveMaker.Tuning1), new PlacementMaker(new BestEvaluatorStrategy(TuneablePattern2x2BoardEvaluator.Tuning1))), () => { var p = new PreplacerStrategy(new EvaluatorTreeSearchPreplacer(TuneablePattern2x2BoardEvaluator.Tuning1, 4, 4, true)); var m = new MoveOnlyMonteCarloTreeSearchWithPreplacerMoveMaker(10000, TuneableUtilityMoveMaker.Tuning1, p); return(new PlayerDecisionMaker(m, new PlacementMaker(p))); }, () => new PlayerDecisionMaker(new AlphaBetaMoveMaker(15, TuneableByBoardPositionUtilityCalculator.Tuning1), PlacementMaker.ExhaustiveMostFuturePlacementsInstance1_6), () => new PlayerDecisionMaker(new AlphaBetaMoveMaker(15, TuneableByBoardPositionUtilityCalculator.Tuning1), new PlacementMaker(new BestEvaluatorStrategy(TuneablePattern2x2BoardEvaluator.Tuning1))), // //() => //{ // var p = new PreplacerStrategy(new EvaluatorTreeSearchPreplacer(new Pattern2x2BoardEvaluator(), 4, 4, true)); // var m = new MoveOnlyMinimaxWithAlphaBetaPruningWithPreplacerMoveMaker(13, TuneableByBoardPositionUtilityCalculator.Tuning1, p); // return new PlayerDecisionMaker(m, new PlacementMaker(p)); //}, () => { var p = new PreplacerStrategy(new EvaluatorTreeSearchPreplacer(TuneablePattern2x2BoardEvaluator.Tuning1, 4, 4, true)); var m = new MoveOnlyAlphaBetaWithPreplacerMoveMaker(15, TuneableByBoardPositionUtilityCalculator.Tuning1, p); return(new PlayerDecisionMaker(m, new PlacementMaker(p))); }, }; const int TotalRuns = 500; const bool enableConsoleLogging = false; //TODO: Play each AI against each other AI 100 times and print a table of results var totalWins = new int[aiToTest.Length, aiToTest.Length]; var totalTimeTaken = new long[aiToTest.Length]; Console.WriteLine($"Running {aiToTest.Length * (aiToTest.Length - 1) / 2} * {TotalRuns} Games"); int gameNumber = 0; for (var a = 0; a < aiToTest.Length; a++) { for (var b = a; b < aiToTest.Length; b++) { if (a == b) { continue; } long aiATime = 0; long aiBTime = 0; var aiA = aiToTest[a]; var aiB = aiToTest[b]; Console.WriteLine($"{++gameNumber} {aiA().Name} vs {aiB().Name}"); Parallel.For(0, TotalRuns, new ParallelOptions { MaxDegreeOfParallelism = 6 }, (run) => //for (var run = 0; run < TotalRuns; run++) { var state = new SimulationState(SimulationHelpers.GetRandomPieces(run / 2), 0); ConsoleLogger logger = null; if (enableConsoleLogging) { state.Logger = logger = new ConsoleLogger(state); } //state.Fidelity = SimulationFidelity.NoPiecePlacing; //Let each Ai have half of the goes first and half second var runner = new SimulationRunner(state, run % 2 == 0 ? aiA() : aiB(), run % 2 == 1 ? aiA() : aiB()); while (!state.GameHasEnded) { runner.PerformNextStep(); if (logger != null) { logger.PrintBoards(true); } } var aWin = run % 2 == state.WinningPlayer; lock (totalWins) { if (aWin) { totalWins[a, b]++; } else { totalWins[b, a]++; } } Interlocked.Add(ref aiATime, runner.Stopwatches[run % 2].ElapsedMilliseconds); Interlocked.Add(ref aiBTime, runner.Stopwatches[(run + 1) % 2].ElapsedMilliseconds); //Console.WriteLine(aWin); } ); Console.WriteLine(totalWins[a, b]); totalTimeTaken[a] += aiATime; totalTimeTaken[b] += aiBTime; } } //Calculate the total points for each var total = Enumerable.Range(0, aiToTest.Length).Select(ai => Enumerable.Range(0, aiToTest.Length).Sum(opponent => totalWins[ai, opponent])).ToArray(); //Dump a CSV with the results var filename = "result_" + DateTimeOffset.Now.Ticks + ".csv"; var res = new List <string>(); res.Add("," + string.Join(", ", aiToTest.Select(ai => ai().Name)) + ",Win%,Rank,Total Time"); for (var a = 0; a < aiToTest.Length; a++) { var line = aiToTest[a]().Name; for (var b = 0; b < aiToTest.Length; b++) { if (a == b) { line += ","; } else { line += "," + totalWins[a, b]; } } //Win%, rank, time line += "," + (total[a] / (float)(aiToTest.Length - 1) * 100 / TotalRuns).ToString("0.0"); line += "," + (aiToTest.Length - total.Count(c => c < total[a])); line += "," + totalTimeTaken[a]; res.Add(line); } Console.WriteLine("Saving results as " + filename); File.WriteAllLines(filename, res); Process.Start(filename); }