public bool DoesPlayer1HaveZugzwang(Board board) { //find threats, label even or odd var boardSearch = new BoardSearch(4); var groups = boardSearch.FindGroups(1, board, 1); var hasOddThreat = groups.Select(g => g.Coords.Any(t => t.Row % 2 != 0)).Any(); return(hasOddThreat); }
public int Run(Board board, int numToWin, int playerNumber = 2) { PLAYERNUM = playerNumber; var search = new BoardSearch(numToWin); var legalMoves = search.FindAllLegalMoves(board); var yourThreats = search.FindGroups(PLAYERNUM, board, 1); var oppThreats = search.FindGroups(1, board, 1); int?columnToPlay = 0; //can you win? columnToPlay = MatchThreatsWithLegal(yourThreats, legalMoves); if (columnToPlay.HasValue) { return(columnToPlay.Value); } //should you block? columnToPlay = MatchThreatsWithLegal(oppThreats, legalMoves); if (columnToPlay.HasValue) { return(columnToPlay.Value); } //are there hidden forks for player 1? //look for threats with 2 blanks var forkThreats = search.FindGroups(1, board, 2); //do any threats share a blank? var forkPositions = new List <Position>(); for (var i = 0; i < forkThreats.Count; i++) { var ft = forkThreats[i]; var blanks = ft.Coords.Where(c => c.Mark == 0); for (var j = 0; j < forkThreats.Count; j++) { if (j == i) { continue; } var jft = forkThreats[j]; var jBlanks = jft.Coords.Where(c => c.Mark == 0); var shared = jBlanks.Intersect <Position>(blanks, new PositionEqualityComparer()); forkPositions.AddRange(shared); } } //are any blanks legal moves? columnToPlay = MatchPositionsThreatsWithLegal(forkPositions, legalMoves); if (columnToPlay.HasValue) { return(columnToPlay.Value); } //should we remove a legal move if it will harm us? //can player1 score after this move? //take all legal moves and transpose one row up - do any fulfill player 1 threats? var toRemove = new List <Position>(); foreach (var legalMove in legalMoves) { var transposedMove = new Position(legalMove.Row + 1, legalMove.Col, 0); foreach (var threat in oppThreats) { var blank = threat.Coords.Single(t => t.Mark == 0); if (blank.Equals(transposedMove)) { toRemove.Add(legalMove); } } } toRemove.ForEach(r => legalMoves.Remove(r)); //claimeven var claimevens = search.FindPossibleClaimEvens(board); foreach (var claimEven in claimevens) { foreach (var move in legalMoves) { if (claimEven == move.Col) { return(claimEven); } } } var moveIndex = random.Next(0, legalMoves.Count()); return(legalMoves[moveIndex].Col); }