private static IEnumerable <IEnumerable <TileKinds> > FindValidCombinations(Tiles34 tiles34, int firstIndex, int secondIndex, bool handNotCompleted = false) { //Tiles34[0,1,1,1,2,...]=>TileKinds[1,2,3,4,4,...] var indices = new TileKinds(); for (var x = firstIndex; x <= secondIndex; x++) { if (tiles34[x] > 0) { var l = indices.ToList(); l.AddRange(Enumerable.Repeat(new TileKind(x), tiles34[x])); indices = new TileKinds(l); } } if (indices.Count == 0) { return(new List <IEnumerable <TileKinds> >()); } //TileKindsのnP3全順列を列挙 //[1,2,3,4,4]=>[[1,2,3],[1,2,4],[1,3,2],[1,3,4],[1,4,2],[1,4,3],[1,4,4],...] var t = indices.Permutations(3); var allPossibleCombinations = t.Select(x => new TileKinds(x)); //刻子、順子の形をしている順列を抜きだす var validCombinations = new List <TileKinds>(); foreach (var combination in allPossibleCombinations) { if (combination.IsChi || combination.IsPon) { validCombinations.Add(combination); } } if (validCombinations.Count == 0) { return(new List <IEnumerable <TileKinds> >()); } var countOfNeededCombinations = indices.Count / 3; //有り得る順列のセットが一通りしかないとき if (countOfNeededCombinations == validCombinations.Count && indices.Equals(validCombinations.Aggregate( (x, y) => new TileKinds(Enumerable.Concat(x, y))))) { return new List <IEnumerable <TileKinds> > { validCombinations } } ; var validCombinationsCopy = new List <TileKinds>(validCombinations); foreach (var item in validCombinations) { if (!item.IsPon) { continue; } var countOfSets = 1; var countOfTiles = 0; while (countOfSets > countOfTiles) { countOfTiles = indices.Count(x => item[0].Equals(x)) / 3; countOfSets = validCombinationsCopy.Count(x => item[0].Equals(x[0]) && item[1].Equals(x[1]) && item[2].Equals(x[2])); if (countOfSets > countOfTiles) { validCombinationsCopy.Remove(item); } } } validCombinations = validCombinationsCopy; validCombinationsCopy = new List <TileKinds>(validCombinations); foreach (var item in validCombinations) { if (!item.IsChi) { continue; } var countOfSets = 5; var countOfPossibleSets = 4; while (countOfSets > countOfPossibleSets) { countOfSets = validCombinationsCopy.Count(x => item[0].Equals(x[0]) && item[1].Equals(x[1]) && item[2].Equals(x[2])); if (countOfSets > countOfPossibleSets) { validCombinationsCopy.Remove(item); } } } validCombinations = validCombinationsCopy; if (handNotCompleted) { return new List <IEnumerable <TileKinds> >() { validCombinations } } ; var possibleCombinations = new TileKinds(Enumerable.Range(0, validCombinations.Count)) .Permutations(countOfNeededCombinations); var combinationsResults = new List <IEnumerable <TileKinds> >(); foreach (var combination in possibleCombinations) { var result = new List <TileKind>(); foreach (var item in combination) { result.AddRange(validCombinations[item.Value]); } result.Sort((x, y) => x.CompareTo(y)); if (!indices.Equals(new TileKinds(result))) { continue; } var results = new List <TileKinds>(); foreach (var item in combination) { results.Add(validCombinations[item.Value]); } results.Sort((x, y) => x[0].CompareTo(y[0])); if (!combinationsResults.Contains_(results)) { combinationsResults.Add(results); } } return(combinationsResults); }