public static Tuple <bool, char> ComputeGameResult(char[,] board, char emptyChar) { var boardLines = BoardUtils.GetAllBoardLinesCoordinates(board.GetLength(0)); foreach (var line in boardLines) { char c = board[line.First().Item1, line.First().Item2]; if (c == emptyChar) { continue; } bool win = true; foreach (var coord in line) { if (c != board[coord.Item1, coord.Item2]) { win = false; break; } } if (win) { return(new Tuple <bool, char>(true, c)); } } if (BoardUtils.IsDraw(board, emptyChar)) { return(new Tuple <bool, char>(true, emptyChar)); } return(new Tuple <bool, char>(false, emptyChar)); }
protected Tuple <int, int> findWinningMove(char[,] board, char symbol) { List <List <Tuple <int, int> > > boardLines = BoardUtils.GetAllBoardLinesCoordinates(boardSize); foreach (var line in boardLines) { int currentLineScore = 0; int movesToWin = 0; Tuple <int, int> winCoords = null; foreach (var coord in line) { if (board[coord.Item1, coord.Item2] == symbol) { currentLineScore++; } else if (board[coord.Item1, coord.Item2] == Engine.EMPTY_CHAR) { movesToWin++; winCoords = coord; } } if (currentLineScore == boardSize - 1 && movesToWin == 1) { return(winCoords); } } return(null); }
public bool IsGameOver() { var gameResult = BoardUtils.ComputeGameResult(board, EMPTY_CHAR); if (gameResult.Item1 && gameResult.Item2 != EMPTY_CHAR) { Winner = getWinnerFromSymbol(gameResult.Item2); } return(gameResult.Item1); }
private int minimaxScoreWithCache(char[,] board, char currentSymbol) { Tuple <bool, char> result = BoardUtils.ComputeGameResult(board, Engine.EMPTY_CHAR); if (result.Item1) { // win if (result.Item2 == Symbol) { return(10); } // loose else if (result.Item2 != Engine.EMPTY_CHAR) { return(-10); } // draw else { return(0); } } List <int> scores = new List <int>(); foreach (var move in BoardUtils.GetAllLegalMoves(board, Engine.EMPTY_CHAR)) { char[,] workingBoard = (char[, ])board.Clone(); workingBoard[move.Item1, move.Item2] = currentSymbol; string key = GetCustomHash(workingBoard); if (!cache.ContainsKey(key)) { IPlayer opponent = PlayerManager.GetInstance().GetOpponent(currentSymbol); int score = minimaxScoreWithCache(workingBoard, opponent.Symbol); cache.Add(key, score); } scores.Add(cache[key]); } // if current player is our IA, we try to maximize the score, // else minimize it if (currentSymbol == Symbol) { return(scores.Max()); } else { return(scores.Min()); } }
internal override Tuple <int, int> AskNextMove(char[,] board) { Tuple <int, int> bestMove = null; int bestScore = int.MinValue; foreach (var move in BoardUtils.GetAllLegalMoves(board, Engine.EMPTY_CHAR)) { char[,] workingBoard = (char[, ])board.Clone(); workingBoard[move.Item1, move.Item2] = Symbol; IPlayer opponent = PlayerManager.GetInstance().GetOpponent(Symbol); int currentScore = minimaxScoreWithCache(workingBoard, opponent.Symbol); if (currentScore > bestScore) { bestScore = currentScore; bestMove = new Tuple <int, int>(move.Item1, move.Item2); } } return(bestMove); }