private static List <List <int> > GetPossibleSetsFromIndices2(List <int> list) { var results = new List <List <int> >(); for (int t1 = 0; t1 < list.Count; t1++) { for (int t2 = t1; t2 < list.Count; t2++) { if (t2 == t1) { continue; } for (int t3 = t2; t3 < list.Count; t3++) { if (t3 == t2 || t3 == t1) { continue; } var result = new List <int> { list[t1], list[t2], list[t3] }; if (U.is_chi(result) || U.is_pon(result)) { results.Add(result); } } } } return(results); }
public override bool is_condition_met(List <List <int> > hand, params object[] args) { int honors = 0; int terminals = 0; int chi = 0; foreach (var group in hand) { if (U.is_chi(group)) { chi++; } if (U.are_tiles_in_indices(group, C.TERMINAL_INDICES)) { terminals++; } if (U.are_tiles_in_indices(group, C.HONOR_INDICES)) { honors++; } } //honroutou if (chi == 0) { return(false); } return(terminals + honors == 5 && terminals != 0 && honors != 0); }
// Replaced the original "get possible sets" block by this, seems more efficient and compact // Also: binary count browsing is cool // Input: sorted array of indices private static List <List <int> > GetPossibleSetsFromIndices(List <int> list) { var array = list.ToArray(); int count = (int)Math.Pow(2, array.Length); //We know we'll iterate on 2^n possibilities int min = (int)Math.Pow(2, 3) - 1; //start at b'...000000111' since it's the first result of length >= 3 int max = count - (int)Math.Pow(2, array.Length - 3); //end at b'11100000...' since it's the last result of length <= 3 (12% faster) var results = new List <List <int> >(); if (list.Count < 3) { return(results); } int lastTile = -1; int currentTile; int nbTile; bool ok; for (int i = min; i <= max; i++) { var result = new List <int>(); string str = Convert.ToString(i, 2).PadLeft(array.Length, '0'); //we take i and convert it to a n bit integer, each value of i representing a possibility nbTile = 0; ok = true; for (int j = 0; j < str.Length; j++) { if (str[j] == '1') { if (nbTile == 3) { ok = false; break; // result is too large so let's stop here (might be the only useful optim here...) } currentTile = array[j]; if (currentTile - lastTile > 1 && lastTile >= 0) { ok = false; break; // there is no way a group containing 'x,x+2' is a set } result.Add(currentTile); lastTile = currentTile; nbTile++; } } if (ok && (U.is_chi(result) || U.is_pon(result))) { results.Add(result); } } return(results); }
// // Find and return all valid set combinations in given suit // :param tiles_34: // :param first_index: // :param second_index: // :param hand_not_completed: in that mode we can return just possible shi or pon sets // :return: list of valid combinations // List <List <List <int> > > find_valid_combinations(int[] tiles_34, int first_index, int second_index, bool hand_not_completed = false) { int count_of_sets; var indices = new List <int>(); foreach (var x in Enumerable.Range(first_index, second_index + 1 - first_index)) { if (tiles_34[x] > 0) { indices.AddRange(Enumerable.Repeat(x, tiles_34[x]).ToList()); } } var count_of_needed_combinations = Convert.ToInt32(indices.Count / 3); if (indices.Count == 0 || count_of_needed_combinations == 0) { return(new List <List <List <int> > > { new List <List <int> >() }); } // indices are already sorted var validMelds = GetPossibleSetsFromIndices(indices); if (validMelds.Count == 0) { return(new List <List <List <int> > > { new List <List <int> >() }); } // simple case, we have count of sets == count of tiles if (count_of_needed_combinations == validMelds.Count) { var toCheck = validMelds.Select(x => x.ToList() as IEnumerable <int>).Aggregate((z, y) => z.Concat(y)); if (toCheck.SequenceEqual(indices)) { return(new List <List <List <int> > >() { validMelds }); } } // filter and remove not possible pon sets IEnumerable <List <int> > identicalSets; foreach (var item in validMelds.ToArray().ToList()) { if (U.is_pon(item)) { count_of_sets = 1; var count_of_tiles = 0; while (count_of_sets > count_of_tiles) { count_of_tiles = (from x in indices where x == item[0] select x).ToList().Count / 3; identicalSets = (from x in validMelds where x[0] == item[0] && x[1] == item[1] && x[2] == item[2] select x); count_of_sets = identicalSets.Count(); if (count_of_sets > count_of_tiles) { validMelds.Remove(identicalSets.First()); } } } } // filter and remove not possible chi sets foreach (var item in validMelds.ToArray().ToList()) { if (U.is_chi(item)) { count_of_sets = 5; // TODO calculate real count of possible sets var count_of_possible_sets = 4; while (count_of_sets > count_of_possible_sets) { identicalSets = (from x in validMelds where x[0] == item[0] && x[1] == item[1] && x[2] == item[2] select x); count_of_sets = identicalSets.Count(); if (count_of_sets > count_of_possible_sets) { validMelds.Remove(identicalSets.First()); } } } } // lit of chi\pon sets for not completed hand if (hand_not_completed) { return(new List <List <List <int> > >() { validMelds }); } // hard case - we can build a lot of sets from our tiles // for example we have 123456 tiles and we can build sets: // [1, 2, 3] [4, 5, 6] [2, 3, 4] [3, 4, 5] // and only two of them valid in the same time [1, 2, 3] [4, 5, 6] int maxIndex = indices.Max() + 1; var indexCount = new int[maxIndex]; foreach (var index in indices) { indexCount[index]++; } var possibleHands = GetPossibleHandsFromSets(validMelds, indexCount, count_of_needed_combinations); return(possibleHands); }