private static void MCRollout(Node leaf) { Con4Board board = leaf.state; int player = leaf.playerToMove; int value = 0; BoardState bs = leaf.bs; while (true) { //BoardState bs = board.EvaluateBoard(); //checkEqualityOfEval(board, bs); if (bs != BoardState.ongoing) { value = BoardStateToValue(bs); break; } else { List <int> possMoves = board.GetPossibleMoves(); board = board.SimulateMove(player, possMoves[rnd.Next(possMoves.Count)]); simulations++; bs = Evaluate.EvaluateBoard(board); evaluations++; player *= -1; } } Backpropagate(leaf, value); }
public override bool Equals(object obj) { /*Con4Board other = obj as Con4Board; * if (other == null) * return false; */ if (obj.GetType() != GetType()) { return(false); } Con4Board other = obj as Con4Board; /*for (int x = 0; x < WIDTH; x++) * for (int y = 0; y < HEIGHT; y++) * if (other.grid[x, y] != grid[x, y]) * return false;*/ // Iteration order to find differences early for (int y = HEIGHT - 1; y >= 0; y--) { for (int x = 0; x < WIDTH; x++) { if (other.grid[x, y] != grid[x, y]) { return(false); } } } return(true); }
public static BoardState EvaluateBoard(Con4Board board) { BoardState bs; bs = CheckRows(board); if (bs != BoardState.ongoing) { return(bs); } bs = CheckColumns(board); if (bs != BoardState.ongoing) { return(bs); } bs = CheckDiagonals(board); if (bs != BoardState.ongoing) { return(bs); } if (IsDraw(board)) { return(BoardState.draw); } return(BoardState.ongoing); }
private static void HandleLeafNode(Node leaf) { if (leaf.totalVisits == 0) { MCRollout(leaf); } else { // EXPAND Con4Board board = leaf.state; //BoardState bs = board.EvaluateBoard(); //checkEqualityOfEval(board, bs); //BoardState bs = Evaluate.EvaluateBoard(board); BoardState bs = leaf.bs; //evaluations++; if (bs != BoardState.ongoing) // Terminal node, do not expand, just backprop { Backpropagate(leaf, BoardStateToValue(bs)); } else // Not terminal, expand { List <int> possMoves = board.GetPossibleMoves(); foreach (int move in possMoves) { leaf.children.Add(new Node(leaf, board.SimulateMove(leaf.playerToMove, move), leaf.playerToMove * -1, move)); simulations++; } Node firstChild = leaf.children[0]; MCRollout(firstChild); } } }
public Con4Board SimulateMove(int player, int move) { simulations++; Con4Board deepCopy = new Con4Board(grid); deepCopy.PlayMove(player, move); return(deepCopy); }
/*public Node(Node parent, Con4Board state, int playerToMove) { * this.parent = parent; * this.state = state; * this.playerToMove = playerToMove; * this.bs = Evaluate.EvaluateBoard(state); * }*/ public Node(Node parent, Con4Board state, int playerToMove, int previousMove) { this.parent = parent; this.state = state; this.playerToMove = playerToMove; this.previousMove = previousMove; this.bs = Evaluate.EvaluateBoard(state); }
private static BoardState CheckDiagonals(Con4Board board) { List <int> seq; BoardState bs; // Positive line slopes for (int i = 0; i < 4; i++) { seq = GenerateDiagonalSequence(board, i, boardHeight - 1, true); bs = CheckSequence(seq); if (bs != BoardState.ongoing) { return(bs); } } seq = GenerateDiagonalSequence(board, 0, boardHeight - 2, true); bs = CheckSequence(seq); if (bs != BoardState.ongoing) { return(bs); } seq = GenerateDiagonalSequence(board, 0, boardHeight - 3, true); bs = CheckSequence(seq); if (bs != BoardState.ongoing) { return(bs); } // Negative line slopes for (int i = 0; i < 4; i++) { seq = GenerateDiagonalSequence(board, i, 0, false); bs = CheckSequence(seq); if (bs != BoardState.ongoing) { return(bs); } } seq = GenerateDiagonalSequence(board, 0, 1, false); bs = CheckSequence(seq); if (bs != BoardState.ongoing) { return(bs); } seq = GenerateDiagonalSequence(board, 0, 2, false); bs = CheckSequence(seq); if (bs != BoardState.ongoing) { return(bs); } return(BoardState.ongoing); }
private static bool IsDraw(Con4Board board) { for (int x = 0; x < boardWidth; x++) { if (board.grid[x, 0] == 0) { return(false); } } return(true); }
private static List <int> GenerateDiagonalSequence(Con4Board board, int x, int y, bool positiveSlope) { List <int> seq = new List <int>(); while (LegalPos(x, y)) { seq.Add(board.grid[x, y]); x++; y += positiveSlope ? -1 : 1; } return(seq); }
private static void checkEqualityOfEval(Con4Board board, BoardState bs) { BoardState localBs = Evaluate.EvaluateBoard(board); if (bs != localBs) { Albot.Connect4.Connect4Board albotBoard = new Albot.Connect4.Connect4Board(board.grid); albotBoard.PrintBoard("Board which gave error:"); Console.WriteLine("Albot implementation evaluates to: " + bs.ToString() + "\n" + "Local implementation evaluates to: " + localBs.ToString()); throw new Exception("LOCAL EVALUATION NOT SAME AS ALBOTS!"); } }
private static BoardState CheckRows(Con4Board board) { for (int y = 0; y < boardHeight; y++) { List <int> seq = new List <int>(boardWidth); for (int x = 0; x < boardWidth; x++) { seq.Add(board.grid[x, y]); } BoardState bs = CheckSequence(seq); if (bs != BoardState.ongoing) { return(bs); } } return(BoardState.ongoing); }
private static int DecideMove(Connect4Board board) { Con4Board con4Board = new Con4Board(board); return(MCTS.FindMove(con4Board, 9000)); }
public static int FindMove(Con4Board board, long searchTimeMs) { simulations = 0; evaluations = 0; if (root == null) { // New tree root = new Node(null, board, 1, -1); List <int> possMoves = board.GetPossibleMoves(); foreach (int move in possMoves) { root.children.Add(new Node(root, board.SimulateMove(root.playerToMove, move), root.playerToMove * -1, move)); simulations++; } } else { // Continue from last tree // Set root to child which matches opponents move foreach (Node node in root.children) { if (node.state.Equals(board)) { root = node; root.parent = null; // Let GC remove rest of tree Console.WriteLine("Found root, continuing where we left off!"); break; } } } stopwatch.Restart(); while (stopwatch.ElapsedMilliseconds < searchTimeMs) { //stopwatch.Restart(); for (int i = 0; i < 100; i++) { MCTSIteration(); } //stopwatch.Stop(); //Console.WriteLine(stopwatch.ElapsedMilliseconds); //searchTimeMs -= stopwatch.ElapsedMilliseconds; } List <Node> children = root.children; int bestMove = children[0].previousMove; double bestValue = children[0].totalValue; Node nextRoot = children[0]; // To continue on same tree next move Console.Write("Move values {m, v}: "); Console.Write("{" + children[0].previousMove + ", " + children[0].totalValue + "} "); for (int i = 1; i < children.Count; i++) { Node child = children[i]; double totVal = child.totalValue; Console.Write("{" + child.previousMove + ", " + totVal + "}"); if (totVal > bestValue) { bestValue = totVal; bestMove = child.previousMove; nextRoot = child; } } Console.WriteLine(" => Playing move: " + bestMove); Console.WriteLine("Simulations: " + simulations + ", Evaluations: " + evaluations); root = nextRoot; return(bestMove); }