// looks for immediate win or loss, and moves to win or prevent loss private Board Easy_Bot(Board b) { // see if there is an immediate win available for (int c = 0; c < 7; c++) { Board copy1 = (Board)b.Copy(); if (copy1.AddPiece(2, c) && copy1.Winner() == 2) { b.AddPiece(2, c); return(b); } } // see if there is an immediate threat needed to block for (int c = 0; c < 7; c++) { Board copy2 = (Board)b.Copy(); if (copy2.AddPiece(1, c) && copy2.Winner() == 1) { b.AddPiece(2, c); return(b); } } // otherwise, just pick a random move return(Random_Bot(b)); }
protected override int SelectNonWinningBlockingMove(Board b, int lastColumn, int color) { var m = WinInXMoves(b, color, 4); if (m >= 0) { return(m); } var nonLosers = new List <int>(); foreach (var column in PossibleMoves(b)) { var copy = b.Copy(); copy.DoMove(new Move(column, color)); var t = WinInXMoves(copy, -color, 3); if (t < 0) { nonLosers.Add(column); } } if (nonLosers.Count > 0) { return(nonLosers[RNG.Next(nonLosers.Count)]); } return(base.SelectNonWinningBlockingMove(b, lastColumn, color)); }
protected override int SelectNonWinningBlockingMove(Board b, int lastColumn, int color) { var nonLosers = new List <int>(); foreach (var column in PossibleMoves(b)) { var copy = b.Copy(); copy.DoMove(new Move(column, color)); var m = Win(copy, -color); if (m >= 0) { continue; } nonLosers.Add(column); var winner = true; foreach (var column2 in PossibleMoves(copy)) { var copy2 = copy.Copy(); m = Win(copy2, color); if (m < 0) { winner = false; break; } } if (winner) { return(column); } } if (nonLosers.Count > 0) { return(nonLosers[RNG.Next(nonLosers.Count)]); } return(base.SelectNonWinningBlockingMove(b, lastColumn, color)); }
int WinInXMoves(Board b, int color, int X) { var pm = PossibleMoves(b); foreach (var column in pm) { if (b.IsWinningMove(new Move(column, color))) { return(column); } } var oppWins = 0; foreach (var column in PossibleMoves(b)) { if (b.IsWinningMove(new Move(column, -color))) { pm = new List <int>() { column }; oppWins++; } } if (oppWins > 1) { return(-1); } foreach (var column in pm) { var copy = b.Copy(); copy.DoMove(new Move(column, color)); var winner = true; foreach (var column2 in PossibleMoves(copy)) { var copy2 = copy.Copy(); copy2.DoMove(new Move(column2, -color)); int m; if (X <= 1) { m = Win(copy2, color); } else { m = WinInXMoves(copy2, color, X - 1); } if (m < 0) { winner = false; break; } } if (winner) { return(column); } } return(-1); }
// helper for minimax alg, recursively determines move strength private int moveStrength(Board b, int move, int depth) { int currentPlayer = b.Turn; Board copy = (Board)b.Copy(); if (copy.AddPiece(copy.Turn, move)) { // if this move would spell an immediate win for either player int winner = copy.Winner(); if (winner != 0) { // return the id of the current player * 10, with depth added return((currentPlayer * 100) + depth); //return (currentPlayer * 10); } } // if the move is illegal, return -1 else { return(-1); } // base case: if depth has hit 0 (and no immediate win after this move established by previous step) if (depth == 0) { return(0); } // otherwise, begin searching further through moves else { bool tieAvailable = false; int strongestMoveStrength = 0; int bestBadMoveStrength = 0; for (int c = 0; c < 7; c++) { int nextMoveStrength = moveStrength(copy, c, depth - 1); // if the next move will ultimately result in a loss for currentPlayer, mark it as such if ((nextMoveStrength / 100) == copy.Turn && nextMoveStrength > strongestMoveStrength) { strongestMoveStrength = nextMoveStrength; } // if at least one of the next moves will continue towards a potential victory for currentPlayer else if (nextMoveStrength == 0) { tieAvailable = true; } else if (nextMoveStrength > bestBadMoveStrength) { bestBadMoveStrength = nextMoveStrength; } } if (strongestMoveStrength > 0) { return(strongestMoveStrength); } else if (tieAvailable) { return(0); } else { return(bestBadMoveStrength); } } }