public void TestMixed() { var game = new Game(); game.SetNumber(3, 1, 2); game.SetNumber(3, 2, 2); game.SetNumber(3, 3, 4); var res = game.Update(Direction.Up); Assert.AreEqual<uint>(2, game.GetNumber(0, 1)); Assert.AreEqual<uint>(2, game.GetNumber(0, 2)); Assert.AreEqual<uint>(4, game.GetNumber(0, 3)); Assert.AreEqual(new Coordinate(0, 1), game.Transformations[3, 1].Destination); Assert.AreEqual(new Coordinate(0, 2), game.Transformations[3, 2].Destination); Assert.AreEqual(new Coordinate(0, 3), game.Transformations[3, 3].Destination); Assert.AreEqual(-1, game.Smoothness()); Assert.AreEqual(1, game.Coherence()); Assert.AreEqual<uint>(0, res.MergedCount); res = game.Update(Direction.Right); Assert.AreEqual<uint>(0, game.GetNumber(0, 1)); Assert.AreEqual<uint>(4, game.GetNumber(0, 2)); Assert.AreEqual<uint>(4, game.GetNumber(0, 3)); Assert.AreEqual<uint>(1, res.MergedCount); Assert.AreEqual(new Coordinate(0, 2), game.Transformations[0, 1].Destination); Assert.AreEqual(true, game.Transformations[0, 2].WasNew); Assert.AreEqual(1, game.Coherence()); res = game.Update(Direction.Left); Assert.AreEqual<uint>(8, game.GetNumber(0, 0)); Assert.AreEqual<uint>(0, game.GetNumber(0, 2)); Assert.AreEqual<uint>(0, game.GetNumber(0, 3)); Assert.AreEqual(new Coordinate(0, 0), game.Transformations[0, 2].Destination); Assert.AreEqual(true, game.Transformations[0, 0].WasNew); Assert.AreEqual<uint>(1, res.MergedCount); }
//static Dictionary<Game, SearchResultInfo> _games = new Dictionary<Game, SearchResultInfo>(); public static unsafe SearchResultInfo Search(uint depth, bool isMax, Game theGame, int alpha, int beta) { Game.Logger($"-----------------Start searching depth = {depth} alpha = {alpha}------------------"); theGame.LogGrid(); if (isMax) { if (depth == 0) { Game.Logger($"Depth = 0, score : {Evaluate(theGame, depth)}"); return new SearchResultInfo { Score = Evaluate(theGame, depth) }; } var newGame = new Game(theGame); Direction? bestMove = null; foreach (var direction in Directions) { Game.Logger($"Searching {direction}"); //var game = new Game(theGame); var res = newGame.Update(direction); if (res.HasMoved) { if (res.HasWon) return new SearchResultInfo { Score = int.MaxValue, MoveDirection = direction }; else { Game.Logger("Searching down by max."); var result = Search(depth - 1, false, newGame, alpha, beta); if (result.Score > alpha) { bestMove = direction; alpha = result.Score; if (alpha >= beta) break; } } } newGame.Reset(theGame); } Game.Logger($"result = {alpha} {bestMove}"); return new SearchResultInfo { Score = alpha, MoveDirection = bestMove }; } else { var bitmap = theGame.GetBitmap(); var ptr = stackalloc int[48]; var cellScores = new StaticList(ptr); var emptyCells = new StaticList(ptr + 16); int lowestScore = int.MaxValue; for (int i = 0; i < 16; ++i) { ushort mask = (ushort)(1 << i); if((bitmap & mask) == 0) { var x = i / 4; var y = i % 4; theGame.AddCellTrivial(x, y, 1); var score = theGame.Smoothness() - theGame.Dispersion(); Game.Logger($"Add cell at {x}, {y} gets score {score}, Smooth = {theGame.Smoothness()}, Monotonic = {theGame.Monotonicity()} Dispersion = {theGame.Dispersion()}"); theGame.LogGrid(); cellScores.Add(score); lowestScore = Math.Min(score, lowestScore); theGame.RemoveCellTrivial(x, y); emptyCells.Add(i); } } var lowestCells = new StaticList(ptr + 32); for (int i = 0; i < emptyCells.Count; ++i) { if (cellScores[i] == lowestScore) lowestCells.Add(emptyCells[i]); } for(int i = 0; i < lowestCells.Count; ++i) { var cell = lowestCells[i]; Game.Logger($"Add cell at {cell}, score is {lowestScore}"); var x = cell / 4; var y = cell % 4; theGame.AddCellTrivial(x, y, 1); Game.Logger("Searching down by min."); var result = Search(depth, true, theGame, alpha, beta); theGame.RemoveCellTrivial(x, y); if (result.Score < beta) { beta = result.Score; Game.Logger($"Beta updated {beta}"); if (alpha >= beta) { Game.Logger("Cutoff"); break; } } } return new SearchResultInfo { Score = beta, MoveDirection = null }; } }
public void TestSmoothness() { var game = new Game(); game.AddCellTrivial(0, 0, 1); game.AddCellTrivial(0, 1, 1); game.AddCellTrivial(0, 2, 2); Assert.AreEqual(-1, game.Smoothness()); //game.AddCellTrivial(1, 0, 2); //Assert.AreEqual(-1, game.Smoothness()); //game.AddCellTrivial(1, 1, 3); //Assert.AreEqual(-4, game.Smoothness()); }
static int Evaluate(Game game, uint depth) { var emptyCount = game.EmptyNumberCount(); var smoothness = game.Smoothness(); var monotonicity = game.Monotonicity(); var maxNumber = game.MaxNumber(); //if (emptyCount == 0) // return smoothness + monotonicity * 3 + maxNumber * 10 + emptyCount * 50; return smoothness + monotonicity * 10 + maxNumber * 10 + emptyCount * 25; /*+ game.Coherence() * 2*///- (int)depth; }