private static IEnumerable <int?[]> generateCombinations(bool isCol, int rowCol, int[] clue, IEnumerable <UniquenessConstraint> furtherRestrictions, int gridWidth, int gridHeight, int minValue, int maxValue) { var combinations = new List <int?[]>(); var affectedCenterCells = Enumerable.Range(0, isCol ? gridHeight : gridWidth).Select(ix => isCol ? rowCol + gridWidth * ix : ix + gridWidth * rowCol).ToArray(); bool combinationAcceptable(int?[] combination) { if (furtherRestrictions == null) { return(true); } foreach (var uniq in furtherRestrictions) { for (var i = 0; i < uniq.AffectedCells.Length; i++) { if (combination[uniq.AffectedCells[i]] != null) { for (var j = i + 1; j < uniq.AffectedCells.Length; j++) { if (combination[uniq.AffectedCells[j]] == combination[uniq.AffectedCells[i]]) { return(false); } } } } } return(true); } switch (clue.Length) { case 0: return(Enumerable.Empty <int?[]>()); case 1: { for (var i1 = 0; i1 < affectedCenterCells.Length; i1++) { var comb = new int?[gridWidth * gridHeight]; var neigh1 = PuzzleUtil.Orthogonal(affectedCenterCells[i1], gridWidth, gridHeight).ToArray(); foreach (var numbers in PuzzleUtil.Combinations(minValue, maxValue, neigh1.Length, allowDuplicates: true).Where(c => c.Sum() == clue[0])) { for (var i = 0; i < neigh1.Length; i++) { comb[neigh1[i]] = numbers[i]; } if (combinationAcceptable(comb)) { combinations.Add((int?[])comb.Clone()); } } } break; } case 2: { for (var i1 = 0; i1 < affectedCenterCells.Length; i1++) { var comb = new int?[gridWidth * gridHeight]; var neigh1 = PuzzleUtil.Orthogonal(affectedCenterCells[i1], gridWidth, gridHeight).ToArray(); foreach (var numbers in PuzzleUtil.Combinations(minValue, maxValue, neigh1.Length, allowDuplicates: true).Where(c => c.Sum() == clue[0])) { for (var i = 0; i < neigh1.Length; i++) { comb[neigh1[i]] = numbers[i]; } if (!combinationAcceptable(comb)) { continue; } for (var i2 = i1 + 1; i2 < affectedCenterCells.Length; i2++) { var neigh2 = PuzzleUtil.Orthogonal(affectedCenterCells[i2], gridWidth, gridHeight).ToArray(); foreach (var numbers2 in PuzzleUtil.Combinations(minValue, maxValue, neigh2.Length, allowDuplicates: true).Where(c => c.Sum() == clue[1])) { var comb2 = (int?[])comb.Clone(); for (var i = 0; i < neigh2.Length; i++) { if (comb2[neigh2[i]] != null && comb2[neigh2[i]] != numbers2[i]) { goto busted2; } comb2[neigh2[i]] = numbers2[i]; } if (combinationAcceptable(comb2)) { combinations.Add(comb2); } } busted2 :; } } } break; } default: throw new NotImplementedException("NeighborSumConstraint currently only supports up to 2 numbers per clue."); } return(combinations); }
private bool isUnique(int[] rowSums, int[] rowVoltorbs, int[] colSums, int[] colVoltorbs, int[] givenCells) { var puzzle = new Puzzle(25, 0, 3); for (var i = 0; i < 5; i++) { puzzle.AddConstraint(new CombinationsConstraint(Enumerable.Range(0, 5).Select(j => j + 5 * i), PuzzleUtil.Combinations(0, 3, 5, true).Where(c => c.Sum() == rowSums[i] && c.Count(v => v == 0) == rowVoltorbs[i]))); puzzle.AddConstraint(new CombinationsConstraint(Enumerable.Range(0, 5).Select(j => i + 5 * j), PuzzleUtil.Combinations(0, 3, 5, true).Where(c => c.Sum() == colSums[i] && c.Count(v => v == 0) == colVoltorbs[i]))); } for (var gcIx = 0; gcIx < givenCells.Length; gcIx++) { puzzle.AddConstraint(new GivenConstraint(givenCells[gcIx], 0)); } bool[] voltorbs = null; foreach (var solution in puzzle.Solve()) { if (voltorbs == null) { voltorbs = solution.Select(v => v == 0).ToArray(); } else { for (var i = 0; i < solution.Length; i++) { if ((solution[i] == 0) != voltorbs[i]) { return(false); } } } } return(true); }