private static bool RemoveFromCollection(PermutationsCollection target, BitArray mustBeOn, BitArray mustBeOff, int inputIx, int targetIx, CancellationToken cancellationToken) { var coll = target[targetIx]; var count = coll.RemoveAll(permutation => CanPermutationBeRemoved(permutation, mustBeOn, mustBeOff, inputIx, targetIx, cancellationToken)); return(count > 0); }
private static ProcessStepResult Step(PermutationsCollection rows, PermutationsCollection cols, CancellationToken cancellationToken) { try { var firstPass = RemovePermutations(cols, rows, cancellationToken); if (firstPass == ProcessStepResult.Unsolvable || firstPass == ProcessStepResult.Cancelled) { return(firstPass); } if (cancellationToken.IsCancellationRequested) { return(ProcessStepResult.Cancelled); } var secondPass = RemovePermutations(rows, cols, cancellationToken); if (secondPass == ProcessStepResult.Unsolvable || secondPass == ProcessStepResult.Cancelled) { return(secondPass); } bool keepGoing = firstPass == ProcessStepResult.KeepGoing || secondPass == ProcessStepResult.KeepGoing; return(keepGoing ? ProcessStepResult.KeepGoing : ProcessStepResult.Finished); } catch (OperationCanceledException) { return(ProcessStepResult.Cancelled); } }
/// <summary> /// Go through all permutations within <paramref name="input"/> and see which fields are commonly on or commonly off between all of them. /// Then, remove any mismatches from <paramref name="target"/>, bringing the total permutation count down, hopefully to 1. /// /// If we end up with no permutations in the target, the Nonogram is unsolvable. /// </summary> /// <param name="input">The collection that we're using to try to determine which permutations to remove from <paramref name="target"/>.</param> /// <param name="target">The collection that we're trying to remove permutations from.</param> /// <param name="cancellationToken">A cancellationToken to support canceling this method</param> /// <returns> /// Whether we successuly removed permutations from <paramref name="target"/>. /// * <see cref="ProcessStepResult.KeepGoing"/> means that permutations were removed, and that we should loop once more. /// * <see cref="ProcessStepResult.Finished"/> means that no further permutations were removed. We're possibly done with <paramref name="target"/> for good. /// * <see cref="ProcessStepResult.Unsolvable"/> means that there are no further permutations left in at least one element of <paramref name="target"/> - the Nonogram is unsolvable. /// * <see cref="ProcessStepResult.Cancelled"/> means that the <paramref name="cancellationToken"/> was cancelled, likely due to a timeout or user cancellation /// </returns> private static ProcessStepResult RemovePermutations(PermutationsCollection input, PermutationsCollection target, CancellationToken cancellationToken) { bool keepGoing = false; for (int inputIx = 0; inputIx < input.Count; inputIx++) { DetermineMustBeOnOff(input[inputIx], target.Count, cancellationToken, out var mustBeOn, out var mustBeOff); for (int targetIx = 0; targetIx < target.Count; targetIx++) { cancellationToken.ThrowIfCancellationRequested(); if (RemoveFromCollection(target, mustBeOn, mustBeOff, inputIx, targetIx, cancellationToken)) { keepGoing = true; } if (target[targetIx].Count == 0) { return(ProcessStepResult.Unsolvable); } } } return(keepGoing ? ProcessStepResult.KeepGoing : ProcessStepResult.Finished); }
/// <summary> /// Create Row and Column Permutations. /// </summary> /// <returns>FALSE if we hit the timeout, TRUE if everything went well.</returns> internal bool PopulatePermutations() { var rowPermutations = new PermutationsCollection(Nonogram.RowHints.Count); var colPermutations = new PermutationsCollection(Nonogram.ColumnHints.Count); var colLength = Nonogram.ColumnHints.Count; var rowLength = Nonogram.RowHints.Count; bool result = true; Stopwatch.Restart(); if (UseMultipleCores) { var po = new ParallelOptions { CancellationToken = CancellationToken, MaxDegreeOfParallelism = Environment.ProcessorCount }; void AddAndCheckTimeout(BitArray ba, PermutationsCollection collection, int index) { collection[index].Add(ba); if (WillHitTimeout || CancellationToken.IsCancellationRequested) { CancelToken(); } } try { Parallel.For(0, rowLength, po, ix => { PermutationGenerator.GeneratePermutationsForHintData(Nonogram.RowHints[ix], colLength, ba => AddAndCheckTimeout(ba, rowPermutations, ix)); }); Parallel.For(0, colLength, po, ix => { PermutationGenerator.GeneratePermutationsForHintData(Nonogram.ColumnHints[ix], rowLength, ba => AddAndCheckTimeout(ba, colPermutations, ix)); }); result = true; } catch (OperationCanceledException) { result = false; } } else { for (int ix = 0; ix < rowLength; ix++) { PermutationGenerator.GeneratePermutationsForHintData(Nonogram.RowHints[ix], colLength, rowPermutations[ix].Add); if (WillHitTimeout || CancellationToken.IsCancellationRequested) { CancelToken(); result = false; break; } } if (result) { for (int ix = 0; ix < colLength; ix++) { PermutationGenerator.GeneratePermutationsForHintData(Nonogram.ColumnHints[ix], rowLength, colPermutations[ix].Add); if (WillHitTimeout || CancellationToken.IsCancellationRequested) { CancelToken(); result = false; break; } } } } Stopwatch.Stop(); UpdateElapsed(); RowPermutations = rowPermutations; ColumnPermutations = colPermutations; InitialRowPermutationsCount = rowPermutations.GetTotalPermutationCount(); InitialColumnPermutationsCount = colPermutations.GetTotalPermutationCount(); return(result); }