public IEnumerable<Movement> FindMoves(Board board) { List<Tuple<Block, FlagCombination>> allValidCombinations = new List<Tuple<Block, FlagCombination>>(); for (int i = 0; i < board.Width; i++) { for (int j = 0; j < board.Height; j++) { Block current = board.Grid[i, j]; if (current.State != BlockState.Value || current.Value == 0) continue; var neighbors = new NeighborList(board.Grid, current); if (board.isBlockSolved(current, neighbors)) continue; int flagCount = neighbors.GetFlagCount(); var unknown = neighbors.GetUnknownBlocks().ToList(); allValidCombinations.Add(new Tuple<Block, FlagCombination>(current, board.getValidCombinations(unknown, current.Value - flagCount))); } } yield break; }
/// <summary> /// This algorithm will loop through each unsolved value on the board. /// It will then lock one flag on the board, and check if the board is in a valid state. /// If the board is invalid, then that block should be cleared, and that move will be returned. /// </summary> /// <returns></returns> private Movement? getMoveLock1(Board board) { for (int i = 0; i < board.Width; i++) { for (int j = 0; j < board.Height; j++) { Block current = board.Grid[i, j]; if (current.State != BlockState.Value || current.Value == 0) continue; var neighbors = new NeighborList(board.Grid, current); var unknown = neighbors.Where(n => n.State == BlockState.Unknown).ToList(); var valid = board.getValidCombinations(unknown, 2); //clearAllGuesses(); foreach (var comb in valid) { foreach (var flag in comb) { // Loop through each potential flag in a combiantion. // If setting that block as a flag breaks the board, then it must not be a flag flag.SetRoundGuess(BlockState.Flag, roundGuesses); bool guessFailed = false; try { getMovesLock0(board).ToList(); } catch (InvalidBoardException ex) { guessFailed = true; } clearAllRoundGuesses(); if (guessFailed) { return new Movement(flag, MoveTypes.SetClear); } } } } } return null; }
public IEnumerable <Movement> FindMoves(Board board) { int flagsLeft = 0; List <Block> allUnknown = board.getUnknownBlocks(out flagsLeft); float overallFlagProb = (float)flagsLeft / allUnknown.Count; Block bestClearChance = null; float bestClearProbability = 0f; Block bestFlag = null; float bestFlagProbability = 0f; //Dictionary<Block, float> probs = new Dictionary<Block, float>(); for (int i = 0; i < board.Width; i++) { for (int j = 0; j < board.Height; j++) { Block current = board.Grid[i, j]; if (current.State != BlockState.Value || current.Value == 0) { continue; } var neighbors = new NeighborList(board.Grid, current); int flagCount = neighbors.GetFlagCount(); var unknown = neighbors.GetUnknownBlocks().ToList(); var combinations = board.getValidCombinations(unknown, current.Value - flagCount).ToList(); foreach (var un in unknown) { int count = combinations.Count(c => c.Any(b => b == un)); float flagProb = (float)count / combinations.Count; float clearProb = 1 - flagProb; //float existing; //if (probs.TryGetValue(un, out existing)) //{ // if (flagProb < existing) // probs[un] = flagProb; //} //else //{ // probs.Add(un, flagProb); //} if (clearProb > bestClearProbability) { bestClearChance = un; bestClearProbability = clearProb; } if (flagProb > bestFlagProbability) { bestFlag = un; bestFlagProbability = flagProb; } } } } float overallClearProb = 1 - overallFlagProb; float max = getHeighestProb(overallClearProb, overallFlagProb, bestFlagProbability, bestClearProbability); if (overallClearProb == max || overallFlagProb == max) { MoveTypes moveType = overallClearProb == max ? MoveTypes.SetClear : MoveTypes.SetFlag; Block random = getBestRandom(board, allUnknown); if (random != null) { yield return(new Movement(random, moveType, overallClearProb == max ? overallClearProb : overallFlagProb)); } } else if (bestClearProbability == max) { yield return(new Movement(bestClearChance, MoveTypes.SetClear, bestClearProbability)); } else { yield return(new Movement(bestFlag, MoveTypes.SetFlag, bestFlagProbability)); } yield break; }
/// <summary> /// If the given block has a value, then this checks if the neighboring flags/potential flags /// represents a valid block (ie if block is a 2 and there are 3 flags around it, then it is invalid). /// <para>If the given block does not have value, then assume it is a valid block.</para> /// </summary> /// <param name="block"></param> /// <param name="neighbors"></param> /// <returns></returns> private bool isValidGuess(Block block, NeighborList neighbors = null) { if (block.State == BlockState.Unknown || block.State == BlockState.Flag) return true; if (neighbors == null) neighbors = new NeighborList(Grid, block); int flags = neighbors.GetFlagCount(true); int unknown = neighbors.Count(n => n.State == BlockState.Unknown && n.Guess == GuessState.None); if (block.Value < flags || block.Value - flags > unknown) return false; return true; }
private bool isBoardSolved() { for (int i = 0; i < Grid.GetLength(0); i++) { for (int j = 0; j < Grid.GetLength(1); j++) { if (Grid[i, j].State != BlockState.Value) continue; var neighbors = new NeighborList(Grid, Grid[i, j]); int flagCount = neighbors.GetFlagCount(); var unknown = neighbors.GetUnknownBlocks().ToList(); if (Grid[i,j].Value - flagCount < unknown.Count) return false; } } return true; }
/// <summary> /// Gets a list of blocks that can be cleared if the given guess is performed. /// </summary> /// <param name="guess"></param> /// <returns></returns> private IEnumerable<Block> clearBlocksAroundGuess(Block guess) { List<Block> ret = new List<Block>(); var adjacentToGuess = new NeighborList(Grid, guess); var allBlocksToCheck = new List<Block>(); // Loop through each block around the guess foreach (var adj in adjacentToGuess) { allBlocksToCheck.AddRange(new NeighborList(Grid, adj)); } // Loop through each neighbor of an adjacent block to the guess // Basically, search each block around the guess, and get blocks that can cleared around the blocks next to guess foreach (var t in allBlocksToCheck.Distinct()) { if (t.State != BlockState.Value) continue; var neighbors = new NeighborList(Grid, t); int flags = neighbors.Count(n => n.State == BlockState.Flag || n.Guess == GuessState.Flag); int unknown = neighbors.Count(n => n.State == BlockState.Unknown); if (flags == t.Value && unknown != 0) { foreach (var clear in neighbors) if (clear.State == BlockState.Unknown && clear.Guess == GuessState.None) ret.Add(clear); } } return ret.Distinct(); }
/// <summary> /// Checks if the block and all neighboring blocks are in a valid state given /// the current board state plus any guesses that have been made this round. /// <para>The idea is the come up with some guess (of where a flag or value is). Whoever calls this will make the guess (using SetGuess).</para> /// <para>After making the guess, this function will check the game board around that block to see if it is in a valid state.</para> /// <para>If it is not in a valid state, then we can assume that guess is incorrect and the caller can gain some information about a potential move.</para> /// </summary> /// <param name="block">The block to check. All 2-order neighbors around the block will be also checked.</param> /// <param name="potentialvalues">When checking valid blocks, this algorithm marks necessary neighbors as values /// (if a block was solved by the guess) /// <para>Each block that was marked as a value will be added to this parameter.</para> /// </param> /// <returns>True if the block is valid.</returns> internal bool isValidBlock(Block block, List<Block> potentialvalues = null) { var n = new NeighborList(Grid, block); // If the given block is solved, then mark all unknown neighbors as values (using SetGuess) if (isBlockSolved(block, n, true)) { for (int i = 0; i < n.Count; i++) { if (n[i].State == BlockState.Unknown && n[i].Guess != GuessState.Flag) { if (potentialvalues != null) potentialvalues.Add(n[i]); n[i].SetGuess(GuessState.Value, tempGuesses); } } } // Now loop through each neighbor of the block, and perform what was done above. for (int i = 0; i < n.Count; i++) { var test = new NeighborList(Grid, n[i]); if (isBlockSolved(n[i], test, true)) { for (int j = 0; j < test.Count; j++) { if (test[j].State == BlockState.Unknown && test[j].Guess != GuessState.Flag) { if (potentialvalues != null) potentialvalues.Add(test[j]); test[j].SetGuess(GuessState.Value, tempGuesses); } } if (!isValidGuess(n[i], test)) return false; } } return isValidGuess(block, n) && new NeighborList(Grid,block,2).All(b=>isValidGuess(b)); }
internal bool isBlockSolved(Block block, NeighborList neighbors, bool useGuesses = false) { if (block.State != BlockState.Value) return false; if (neighbors == null) new NeighborList(Grid, block); return neighbors.GetFlagCount(useGuesses) == block.Value; }
/// <summary> /// This is the fastest step and is done at the start of ever pass. /// <para></para> /// </summary> /// <returns></returns> private IEnumerable<Movement> getMovesLock0(Board board) { foreach (Block current in board.nonZeroValues) { var neighbors = new NeighborList(board.Grid, current); var unknown = neighbors.GetUnknownBlocks().ToList(); if (unknown.Count == 0) // Already solved continue; int flagCount = neighbors.GetFlagCount(); // Check if all neighboring mines have been found if (flagCount == current.Value && unknown.Count != 0) { yield return new Movement(current, MoveTypes.DoubleClick); } // Check if rest of unknown neighbors should be flags else if (current.Value - flagCount == unknown.Count) { foreach (var n in neighbors) { if (n.State == BlockState.Unknown) { yield return new Movement(n, MoveTypes.SetFlag); } } } else if (unknown.Count != 0 && current.Value - flagCount > 0) { var combinationMoves = board.getCombinationMoves(unknown, current.Value - flagCount); foreach (var c in combinationMoves) yield return c; } } }
private bool isValidMacroGuess(Board board, IEnumerable<Block> unsolvedBlocks, IList<Block> comb) { foreach (Block b in unsolvedBlocks) { var neighbors = new NeighborList(board.Grid, b); int flags = neighbors.Count(i => i.State == BlockState.Flag || i.Guess == GuessState.Flag); if (flags != b.Value) return false; } return true; }
public IEnumerable<Movement> FindMoves(Board board) { int flagsLeft = 0; List<Block> allUnknown = board.getUnknownBlocks(out flagsLeft); float overallFlagProb = (float)flagsLeft / allUnknown.Count; Block bestClearChance = null; float bestClearProbability = 0f; Block bestFlag = null; float bestFlagProbability = 0f; //Dictionary<Block, float> probs = new Dictionary<Block, float>(); for (int i = 0; i < board.Width; i++) { for (int j = 0; j < board.Height; j++) { Block current = board.Grid[i, j]; if (current.State != BlockState.Value || current.Value == 0) continue; var neighbors = new NeighborList(board.Grid, current); int flagCount = neighbors.GetFlagCount(); var unknown = neighbors.GetUnknownBlocks().ToList(); var combinations = board.getValidCombinations(unknown, current.Value - flagCount).ToList(); foreach (var un in unknown) { int count = combinations.Count(c => c.Any(b => b == un)); float flagProb = (float)count / combinations.Count; float clearProb = 1 - flagProb; //float existing; //if (probs.TryGetValue(un, out existing)) //{ // if (flagProb < existing) // probs[un] = flagProb; //} //else //{ // probs.Add(un, flagProb); //} if (clearProb > bestClearProbability) { bestClearChance = un; bestClearProbability = clearProb; } if (flagProb > bestFlagProbability) { bestFlag = un; bestFlagProbability = flagProb; } } } } float overallClearProb = 1 - overallFlagProb; float max = getHeighestProb(overallClearProb, overallFlagProb, bestFlagProbability, bestClearProbability); if (overallClearProb == max || overallFlagProb == max) { MoveTypes moveType = overallClearProb == max ? MoveTypes.SetClear : MoveTypes.SetFlag; Block random = getBestRandom(board, allUnknown); if (random != null) yield return new Movement(random, moveType, overallClearProb == max ? overallClearProb : overallFlagProb); } else if (bestClearProbability == max) { yield return new Movement(bestClearChance, MoveTypes.SetClear, bestClearProbability); } else { yield return new Movement(bestFlag, MoveTypes.SetFlag, bestFlagProbability); } yield break; }
private Block getBestRandom(Board board, List<Block> allUnknown) { Block onlyUknownNeighbors = null; foreach (var un in allUnknown) { var neighbors = new NeighborList(board.Grid, un); if (neighbors.All(i => i.State == BlockState.Unknown)) { if (onlyUknownNeighbors == null) onlyUknownNeighbors = un; } // Sugest it if no neighbars are values and it is not surrounded by flags else if (!neighbors.Any(i => i.State == BlockState.Value) && !neighbors.All(i=>i.State == BlockState.Flag)) { // best choice because if not a flag, then it can open up non-guesses return un; } } return onlyUknownNeighbors; }