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); }
public int Coherence() { var directions = new Direction[] { Direction.Up, Direction.Left, Direction.Right, Direction.Down }; var game = new Game(this); int ret = int.MinValue; foreach (var direction in directions) { ret = Math.Max((int)game.Update(direction).MergedCount, ret); for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { game.AddCellTrivial(i, j, _numbers[i, j]); } } } return(ret); }
public void TestMoveRightTrivial() { var game = new Game(); game.SetNumber(1, 0, 2); game.Update(Direction.Right); Assert.AreEqual<uint>(2, game.GetNumber(1, 3)); Assert.AreEqual<uint>(0, game.GetNumber(1, 1)); Assert.AreEqual<uint>(0, game.GetNumber(1, 2)); }
public void TestMoveRightRight() { var game = new Game(); game.SetNumber(1, 3, 4); game.Update(Direction.Right); Assert.AreEqual<uint>(4, game.GetNumber(1, 3)); Assert.AreEqual<uint>(0, game.GetNumber(1, 2)); Assert.AreEqual<uint>(0, game.GetNumber(1, 1)); foreach (var trans in game.Transformations) Assert.AreEqual(Coordinate.Nowhere, trans.Destination); }
public void TestMoveRightMulti() { var game = new Game(); game.SetNumber(1, 0, 2); game.SetNumber(1, 1, 2); game.SetNumber(1, 2, 4); game.Update(Direction.Right); Assert.AreEqual<uint>(0, game.GetNumber(1, 0)); Assert.AreEqual<uint>(0, game.GetNumber(1, 1)); Assert.AreEqual<uint>(4, game.GetNumber(1, 2)); Assert.AreEqual<uint>(4, game.GetNumber(1, 3)); var info = game.Transformations[1, 0]; Assert.AreEqual(new Coordinate(1, 2), info.Destination); Assert.AreEqual<uint>(2, info.PreviousNumber); info = game.Transformations[1, 2]; Assert.AreEqual(true, info.WasNew); game.Update(Direction.Right); Assert.AreEqual<uint>(0, game.GetNumber(1, 0)); Assert.AreEqual<uint>(0, game.GetNumber(1, 1)); Assert.AreEqual<uint>(0, game.GetNumber(1, 2)); Assert.AreEqual<uint>(8, game.GetNumber(1, 3)); }
public void TestMoveDownMulti() { var game = new Game(); game.SetNumber(1, 0, 4); game.SetNumber(2, 0, 2); game.SetNumber(3, 0, 2); game.Update(Direction.Down); Assert.AreEqual<uint>(0, game.GetNumber(1, 0)); Assert.AreEqual<uint>(4, game.GetNumber(2, 0)); Assert.AreEqual<uint>(4, game.GetNumber(3, 0)); var info = game.Transformations[1, 0]; Assert.AreEqual(new Coordinate(2, 0), info.Destination); Assert.AreEqual<uint>(4, info.PreviousNumber); info = game.Transformations[3, 0]; Assert.AreEqual(true, info.WasNew); game.Update(Direction.Down); Assert.AreEqual<uint>(0, game.GetNumber(1, 0)); Assert.AreEqual<uint>(0, game.GetNumber(2, 0)); Assert.AreEqual<uint>(8, game.GetNumber(3, 0)); info = game.Transformations[2, 0]; Assert.AreEqual(new Coordinate(3, 0), info.Destination); Assert.AreEqual<uint>(4, info.PreviousNumber); info = game.Transformations[3, 0]; Assert.AreEqual(true, info.WasNew); }
public void TestMoveDownBottom() { var game = new Game(); game.SetNumber(3, 0, 4); game.Update(Direction.Down); Assert.AreEqual<uint>(4, game.GetNumber(3, 0)); Assert.AreEqual<uint>(0, game.GetNumber(1, 0)); Assert.AreEqual<uint>(0, game.GetNumber(2, 0)); foreach (var trans in game.Transformations) Assert.AreEqual(Coordinate.Nowhere, trans.Destination); }
public int Coherence() { var directions = new Direction[] { Direction.Up, Direction.Left, Direction.Right, Direction.Down }; var game = new Game(this); int ret = int.MinValue; foreach (var direction in directions) { ret = Math.Max((int)game.Update(direction).MergedCount, ret); for (int i = 0; i < 4; ++i) for (int j = 0; j < 4; ++j) game.AddCellTrivial(i, j, _numbers[i, j]); } return ret; }
//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 }; } }