public void InvalidIndexesAreInvalid(int someBadIndex) { var player1 = new Player(1); var board = new LocalBoard(); Assert.False(board.Move(player1, someBadIndex).IsValid); }
public void ValidIndexesAreValid(int someGoodIndex) { var player1 = new Player(1); var board = new LocalBoard(); Assert.True(board.Move(player1, someGoodIndex).IsValid); }
/// <summary> /// play of the bot /// </summary> public override void play() { // init array of scores for different possibilities int[] lScores = { 0, 0, 0, 0, 0, 0, 0 }; int[] lScoresByThread = { 0, 0, 0, 0, 0, 0, 0 }; // copy the board Board board = new Board(LocalBoard); AsyncCheckBestThread[] threads = { null, null, null, null, null, null, null }; Console.Write("bot is thinking"); // check each possibility string scoreprintA = "|"; for (int y = 0; y < 7; y++) { // create copy for use in task board = new Board(LocalBoard); // check reseted board asynchronously threads[y] = new AsyncCheckBestThread(this, board, y, nDifficulty, nPlayerNo); } // wait until all tasks are done for (int y = 0; y < 7; y++) { // thread is active while (threads[y].isThreadActive()) { // pause execution a bit Thread.Sleep(10); } // get the result after lScores[y] = threads[y].getResult(); // for debugging scoreprintA = scoreprintA + lScores[y] + "|"; } int maxValue = lScores.Max(); int maxIndex = lScores.ToList().IndexOf(maxValue); best_column = maxIndex; // check the best possibility. if valid, do it, otherwise change column // TODO multiple same values -> choose random one to make things more intersting while (LocalBoard.getFirstEmpty(best_column) == -1) { best_column += 1; if (best_column == 7) { best_column = 0; } } // play the game Program.play(nPlayerNo, best_column); }
/// <summary> /// Evaluation function /// </summary> /// <param name="whiteTurn">Players turn /// <param name="minOrMax">Minimizing or maximizing operation /// <returns>The number that correspond to the score of the function</returns> public float Eval(bool whiteTurn, int minOrMax) { // Retrieve board informations Tuple <int, int> cornersScore = CornersScore(); int whiteMobility = LocalBoard.GetNextPossibleMoves(true).Capacity; int blackMobility = LocalBoard.GetNextPossibleMoves(false).Capacity; // Assign variables if ((minOrMax == 1) ^ whiteTurn) { maxPlayerScore = LocalBoard.BlackScore; minPlayerScore = LocalBoard.WhiteScore; maxPlayerCorners = cornersScore.Item2; minPlayerCorners = cornersScore.Item1; maxPlayerMobility = blackMobility; minPlayerMobility = whiteMobility; } else { maxPlayerScore = LocalBoard.WhiteScore; minPlayerScore = LocalBoard.BlackScore; maxPlayerCorners = cornersScore.Item1; minPlayerCorners = cornersScore.Item2; maxPlayerMobility = whiteMobility; minPlayerMobility = blackMobility; } // Parity Score float scoreParity = 0f; if (maxPlayerScore + minPlayerScore != 0) { scoreParity = (100f * (maxPlayerScore - minPlayerScore)) / (maxPlayerScore + minPlayerScore); } // Mobility Score float scoreMobility = 0f; if (maxPlayerMobility + minPlayerMobility != 0) { scoreMobility = (100f * (maxPlayerMobility - minPlayerMobility)) / (maxPlayerMobility + minPlayerMobility); } // Corners Score float scoreCorners = 0f; if (maxPlayerCorners + minPlayerCorners != 0) { scoreCorners = (100f * (maxPlayerCorners - minPlayerCorners)) / (maxPlayerCorners + minPlayerCorners); } // Result return(WEIGHT_SCORE * scoreParity + WEIGHT_MOBILITY * scoreMobility + WEIGHT_CORNERS * scoreCorners); }
/// <summary> /// user input for the column he wants to play in his turn /// </summary> /// <param name="player">current player</param> /// <returns>column number of the column he wants to play</returns> public int readColumn(int player) { int column = -1; while (column == -1) { LocalBoard.drawBoard(); print("it is your turn, player " + player + "! \nwhere do you want to play?"); string s = Console.ReadLine(); if (s.Equals("m")) { Console.Clear(); Program.menu(); column = -1; Console.ReadLine(); } if (s.Equals("")) { print("you have to enter a Number between 0 and 6 and not nothing!"); print("press Enter to acknowledge"); column = -1; Console.ReadLine(); } else { if (Int32.TryParse(s, out column)) { if (column > 6 || column < 0) { print("you have to enter a Number between 0 and 6!"); print("press Enter to acknowledge"); column = -1; Console.ReadLine(); } else if (LocalBoard.getFirstEmpty(column) == -1) { print("can't play here, column full"); print("press Enter to acknowledge"); column = -1; Console.ReadLine(); } } else { print("you have to enter a Number and not some nonsense!"); print("press Enter to acknowledge"); column = -1; Console.ReadLine(); } } } return(column); }
public void PlayerCanNotMoveOnAnOccupiedSpace() { var player1 = new Player(1); var player2 = new Player(2); var board = new LocalBoard(); var move1Result = board.Move(player1, 1); var move2Results = board.Move(player2, 1); Assert.True(move1Result.IsValid); Assert.False(move2Results.IsValid); }
/// <summary> /// Applies the board state to this node and return the new node /// </summary> /// <param name="move">The move to apply to the board</param> /// <returns>The new node if this board state</returns> public IANode Apply(Tuple <int, int> move, bool whiteTurn) { Board board = LocalBoard.DeepCopyBoard(); bool isPlayable = board.IsPlayable(move.Item1, move.Item2, whiteTurn); IANode node = null; if (isPlayable) { board.PlayMove(move.Item1, move.Item2, whiteTurn); node = new IANode(board, move, board.GetNextPossibleMoves(!whiteTurn)); } return(node); }
/// <summary> /// Compute the number of corners taken /// </summary> /// <returns>How many corners by each player are taken</returns> private Tuple <int, int> CornersScore() { int whiteCorners = 0; int blackCorners = 0; int[,] grid = LocalBoard.GetBoard(); if (grid[0, 0] == 0) { whiteCorners++; } else if (grid[0, 0] == 1) { blackCorners++; } if (grid[0, grid.GetLength(1) - 1] == 0) { whiteCorners++; } else if (grid[0, grid.GetLength(1) - 1] == 1) { blackCorners++; } if (grid[grid.GetLength(0) - 1, 0] == 0) { whiteCorners++; } else if (grid[grid.GetLength(0) - 1, 0] == 1) { blackCorners++; } if (grid[grid.GetLength(0) - 1, grid.GetLength(1) - 1] == 0) { whiteCorners++; } else if (grid[grid.GetLength(0) - 1, grid.GetLength(1) - 1] == 1) { blackCorners++; } return(new Tuple <int, int>(whiteCorners, blackCorners)); }
/// <summary> /// checks the best solution for a play by the bot /// </summary> /// <param name="board">board to play on</param> /// <param name="column">column to play</param> /// <param name="depth">how many more iterations should be done</param> /// <param name="currPlayer">player whose turn it is</param> /// <returns></returns> private int checkBest(Board board, int column, int depth, int currPlayer) { // init score for node int score = 0; // no move is pretty bad // store different things at beginning of testing node Board preBoard = new Board(board); int prePlayer = currPlayer; Board virtBoard = new Board(board); // depth not reached, otherwise return default score; do not play if (depth == 0) { return(score); } // if no valid play, return default score; do not play if (board.getFirstEmpty(column) == -1) { return(score); } // valid -> play virtBoard = playLocal(prePlayer, column, virtBoard); // check for win or loose if (virtBoard.checkwin(nPlayerNo, false)) { //Program.drawBoard(board); score = winWeight * depth; printScore(score, depth); if (bAccurateLog) { print("found possible win for " + nPlayerNo); } //print("BOTWIN"); return(score); } else if (virtBoard.checkwin(nOpponentNo, false)) { //Program.drawBoard(board); score = looseWeight * depth; printScore(score, depth); // make sure to enter here if loss imminent best_column = column; if (bAccurateLog) { print("found possible win for " + nOpponentNo); } //print("BOTLOOSE"); return(score); } int nply; // swap playerNo if (currPlayer == nOpponentNo) { nply = nPlayerNo; } else { nply = nOpponentNo; } int playerFac = 0; if (currPlayer == nOpponentNo) { playerFac = -1; } else { playerFac = 1; } for (int i = 3; i > 1; i--) { if (LocalBoard.checkForCountDown(currPlayer, i)) { //Program.drawBoard(board); // the deeper in the win is the less acceptable is a win score = aSCORES_NOT_WIN[i] * depth * currPlayer; printScore(score, depth); //print("BOTWIN"); i = 1; } if (LocalBoard.checkForCountDiagonal(currPlayer, i)) { //Program.drawBoard(board); // the deeper in the win is the less acceptable is a win score = aSCORES_NOT_WIN[i] * depth * currPlayer; printScore(score, depth); //print("BOTWIN"); i = 1; } if (LocalBoard.checkForCountSideways(currPlayer, i)) { //Program.drawBoard(board); // the deeper in the win is the less acceptable is a win score = aSCORES_NOT_WIN[i] * depth * currPlayer; printScore(score, depth); //print("BOTWIN"); i = 1; } } int[] scores = { 0, 0, 0, 0, 0, 0, 0 }; int lDeeperScore = 0; // play the other variants for (int i = 0; i < 7; i++) { // check the score of the different plays // TODO if depth > threshold, run in async in different thread to speed up the process scores[i] = checkBest(virtBoard, i, depth - 1, nply) * depth; } if (nply == nOpponentNo) { lDeeperScore = scores.Min() * depth; } if (nply == nPlayerNo) { lDeeperScore = scores.Max() * depth; } score = lDeeperScore + score; // log if (bAccurateLog) { print(indent(depth) + "CB: p= " + currPlayer + "; x= " + column + "; d= " + depth + "; score= " + score + "; deep= " + lDeeperScore); } // Program.print("p "+ currPlayer,false,true); // Program.print(depth + ": " + scores[0] + "|" + scores[1] + "|" + scores[2] + "|" + scores[3] + "|" + scores[4] + "|" + scores[5] + "|" + scores[6] + "|", false, true); // reset board board = new Board(preBoard); currPlayer = prePlayer; printScore(score, depth); // return score of node return(score); }