/// <summary> /// find next move by direct score /// </summary> /// <param name="x">current board</param> /// <returns>next move</returns> static public int DirectScoreMove(Board x) { double maxScore = 0; int maxi = -1; for (int k = 0; k < 4; k++) { if (BoardControl.ExecuteMove(x, k) == x) { continue; } if (PreScore.DirectScore(BoardControl.ExecuteMove(x, k)) > maxScore) { maxScore = PreScore.DirectScore(BoardControl.ExecuteMove(x, k)); maxi = k; } } if (maxi == -1) { return(new Random(DateTime.Now.Millisecond).Next() % 4); } else { return(maxi); } }
/// <summary> /// play game for monte carlo method /// </summary> /// <param name="Str">play strategy</param> /// <param name="board">current board</param> /// <param name="nmove">monte carlo steps</param> /// <param name="move">pre-pointed next step</param> /// <returns>score by monte carlo</returns> public static double MontePlay(Strategy Str, Board board, int nmove, int move = -1) { bool first = true; while (true) { UInt64 newboard; if (first && (move != -1)) { if (BoardControl.ExecuteMove(board, move) == board) { return(0); } first = false; } else { for (move = 0; move < 4; move++) { if (BoardControl.ExecuteMove(board, move) != board) { break; } } if (move == 4) { break; } move = Str(board); if (move < 0) { break; } } newboard = BoardControl.ExecuteMove(board, move); if (newboard == board) { continue; } UInt64 tile = BoardControl.RandomTile(); board = BoardControl.InsertTileRand(newboard, tile); nmove--; if (nmove <= 0) { return(PreScore.DirectScore(board)); } } return(0); }
/// <summary> /// play game by pointed strategy /// </summary> /// <param name="Str">play strategy</param> public static void Play(Strategy Str) { Board board = BoardControl.InitBoard(); int moveno = 0; int scorepenalty = 0; while (true) { int move; Board newboard; for (move = 0; move < 4; move++) { if (BoardControl.ExecuteMove(board, move) != board) { break; } } if (move == 4) { break; } BoardControl.Print(board); System.Console.WriteLine("Move:" + (++moveno).ToString() + ", score:" + (BoardControl.Score(board) - scorepenalty).ToString() + '\n'); move = Str(board); if (move < 0) { break; } newboard = BoardControl.ExecuteMove(board, move); if (newboard == board) { System.Console.WriteLine("Illegal move!\n"); moveno--; continue; } Board tile = BoardControl.RandomTile(); if (tile == 2) { scorepenalty += 4; } board = BoardControl.InsertTileRand(newboard, tile); } BoardControl.Print(board); System.Console.WriteLine("\nGame over.\nScore:" + (BoardControl.Score(board) - scorepenalty).ToString() + ".\n"); }
/// <summary> /// score while next process is move /// </summary> /// <param name="x">current board</param> /// <param name="prob">current board probability</param> /// <param name="para">parameters of search</param> /// <returns>score</returns> static double ScoreNextMove(UInt64 x, float prob, Param para) { double best = 0.0f; UInt64 newboard; para.depth++; for (int d = 0; d < 4; ++d) { newboard = BoardControl.ExecuteMove(x, d); if (x != newboard) { best = Math.Max(best, ScoreNextInsert(newboard, prob, para)); } } para.depth--; return(best); }
/// <summary> /// score while next process is insert /// </summary> /// <param name="x">current board</param> /// <param name="prob">current board probability</param> /// <param name="para">parameters of search</param> /// <returns>score</returns> static double ScoreNextInsert(UInt64 x, float prob, Param para) { if (para.depth < DictionaryLimit) { if (para.scoreTable.ContainsKey(x)) { return(para.scoreTable[x]); } } if (prob < ProbTresh || para.depth >= para.depthLimit) { return(HeurScore(x)); } int num = BoardControl.CountEmpty(x); prob /= num; double res = 0.0f; UInt64 tmp = x; UInt64 tile = 1; while (tile != 0) { if ((tmp & 0xf) == 0) { res += ScoreNextMove(x | tile, prob * 0.9f, para) * 0.9f; res += ScoreNextMove(x | (tile << 1), prob * 0.1f, para) * 0.1f; } tmp >>= 4; tile <<= 4; } res = res / num; if (para.depth < DictionaryLimit) { para.scoreTable[x] = res; } return(res); }
/// <summary> /// score board while pointed the next move /// </summary> /// <param name="x">current board</param> /// <param name="d">pre-pointed next move</param> /// <returns>score</returns> public static double ScoreFirstMove(Board x, int d) { double res; Param para = new Param(); para.scoreTable = new Dictionary <ulong, double>(); para.depthLimit = Math.Max(3, BoardControl.CountDistinctTiles(x) - 2); UInt64 newboard = BoardControl.ExecuteMove(x, d); if (x == newboard) { res = 0; } else { res = ScoreNextInsert(newboard, 1.0f, para) + 1e-6; } return(res); }
/// <summary> /// find next move by monte carlo method /// </summary> /// <param name="x">current board</param> /// <returns>next move</returns> static public int MonteCarloMove(Board x) { int iterN = 2000; double[] score = new double[4] { 0, 0, 0, 0 }; double maxScore = 0; int maxi = 0; Parallel.For(0, 4, (i, loopState) => { if (BoardControl.ExecuteMove(x, i) != x) { for (int j = 0; j < iterN; j++) { score[i] = score[i] + PlayGame.MontePlay(DirectScoreMove, x, 10, i); } } }); for (int k = 0; k < 4; k++) { if (score[k] > maxScore) { maxScore = score[k]; maxi = k; } } if (BoardControl.ExecuteMove(x, maxi) == x) { return(new Random(DateTime.Now.Millisecond).Next() % 4); } Console.WriteLine("Predict average score:" + (maxScore / iterN).ToString()); Console.WriteLine(); return(maxi); }
static void Main(string[] args) { BoardControl.Initialize(); PreScore.Initialize(); PlayGame.Play(AI.SearchMove); }
/// <summary> /// calculate direct score by rules /// </summary> /// <param name="x">current board</param> /// <returns>direct score</returns> public static double DirectScore(Board x) { return(BoardControl.ScoreHelper(x, scoreTable) + BoardControl.ScoreHelper(BoardControl.Transpose(x), scoreTable)); }