Ejemplo n.º 1
0
        public override bool is_condition_met(List <List <int> > hand, params object[] args)
        {
            int honor = 0;
            int sou   = 0;
            int pin   = 0;
            int man   = 0;

            foreach (var group in hand)
            {
                if (C.HONOR_INDICES.Contains(group[0]))
                {
                    honor++;
                }

                if (U.is_sou(group[0]))
                {
                    sou++;
                }
                else if (U.is_man(group[0]))
                {
                    man++;
                }
                else if (U.is_pin(group[0]))
                {
                    pin++;
                }
            }

            return(honor > 0 &&
                   ((sou > 0 && pin + man == 0) ||
                    (man > 0 && pin + sou == 0) ||
                    (pin > 0 && sou + man == 0)
                   ));
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 4
0
        public override bool is_condition_met(List <List <int> > hand, params object[] args)
        {
            int sou   = 0;
            int pin   = 0;
            int man   = 0;
            int honor = 0;

            if (U.is_sou(hand[0][0]))
            {
                sou++;
            }
            else if (U.is_pin(hand[0][0]))
            {
                pin++;
            }
            else if (U.is_man(hand[0][0]))
            {
                man++;
            }
            else
            {
                honor++;
            }
            bool allowOtherSets = (bool)args[0];
            bool onlyOneSuit    = sou + pin + man + honor == 1;

            if (!onlyOneSuit || honor > 0)
            {
                return(false);
            }

            if (!allowOtherSets && pin == 0)
            {
                //if we are not allowing other sets than pins
                return(false);
            }
            var indicesCount = new int[9];

            foreach (var set in hand)
            {
                foreach (var tile in set)
                {
                    indicesCount[U.simplify(tile)]++;
                }
            }
            foreach (var count in indicesCount)
            {
                if (count != 2)
                {
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 5
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);
        }
Ejemplo n.º 6
0
 public void rename(List <List <int> > hand)
 {
     if (U.is_sou(hand[0][0]))
     {
         this.name = "Daichikurin";
     }
     else if (U.is_pin(hand[0][0]))
     {
         this.name = "Daisharin";
     }
     else if (U.is_man(hand[0][0]))
     {
         this.name = "Daisuurin";
     }
 }
Ejemplo n.º 7
0
        public override bool is_condition_met(List <List <int> > hand, params object[] args)
        {
            var chis = hand.Where(x => Utils.is_chi(x));

            if (chis.Count() < 3)
            {
                return(false);
            }
            var sou = new List <List <int> >();
            var pin = new List <List <int> >();
            var man = new List <List <int> >();

            foreach (var chi in chis)
            {
                if (U.is_sou(chi[0]))
                {
                    sou.Add(chi);
                }
                else if (U.is_man(chi[0]))
                {
                    man.Add(chi);
                }
                else if (U.is_pin(chi[0]))
                {
                    pin.Add(chi);
                }
            }
            var suits = new List <List <List <int> > >
            {
                sou, man, pin
            };

            var one = new List <int> {
                0, 1, 2
            };
            var two = new List <int> {
                3, 4, 5
            };
            var three = new List <int> {
                6, 7, 8
            };
            var comp = new GroupComparer <int>();

            foreach (var suit in suits)
            {
                if (suit.Count() < 3)
                {
                    continue;
                }
                var simpleSets = new List <List <int> >();
                foreach (var set in suit)
                {
                    simpleSets.Add(new List <int> {
                        U.simplify(set[0]), U.simplify(set[1]), U.simplify(set[2])
                    });
                }
                if (simpleSets.Contains(one, comp) && simpleSets.Contains(two, comp) && simpleSets.Contains(three, comp))
                {
                    return(true);
                }
            }
            return(false);
        }
Ejemplo n.º 8
0
        //
        //         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);
        }
Ejemplo n.º 9
0
        //
        //         Calculate hand fu with explanations
        //         :param hand:
        //         :param win_tile: 136 tile format
        //         :param win_group: one set where win tile exists
        //         :param config: HandConfig object
        //         :param valued_tiles: dragons, player wind, round wind
        //         :param melds: opened sets
        //         :return:
        //
        public static (List <(int, string)>, int) calculate_fu(
            List <List <int> > hand,
            int win_tile,
            List <int> win_group,
            HandConfig config,
            List <int> valued_tiles = null,
            List <Meld> melds       = null)
        {
            var win_tile_34 = win_tile / 4;

            if (valued_tiles == null)
            {
                valued_tiles = new List <int>();
            }
            if (melds == null)
            {
                melds = new List <Meld>();
            }
            var fu_details = new List <(int, string)>();

            if (hand.Count == 7)
            {
                return(new List <(int, string)>()
                {
                    (25, BASE)
                }, 25);
            }
            var pair = (from x in hand
                        where U.is_pair(x)
                        select x).ToList()[0];
            var pon_sets = (from x in hand
                            where U.is_pon_or_kan(x)
                            select x).ToList();
            var copied_opened_melds = (from x in melds
                                       where x.type == Meld.CHI
                                       select x.tiles_34).ToList();
            var closed_chi_sets = new List <List <int> >();

            foreach (var x in hand)
            {
                if (!copied_opened_melds.Contains(x))
                {
                    closed_chi_sets.Add(x);
                }
                else
                {
                    copied_opened_melds.Remove(x);
                }
            }
            var is_open_hand = (from x in melds
                                select x.opened).Any();

            if (closed_chi_sets.Contains(win_group))
            {
                var tile_index = U.simplify(win_tile_34);
                // penchan
                if (U.contains_terminals(win_group))
                {
                    // 1-2-... wait
                    if (tile_index == 2 && win_group.FindIndex(x => x == win_tile_34) == 2)
                    {
                        fu_details.Add((2, PENCHAN));
                    }
                    else if (tile_index == 6 && win_group.FindIndex(x => x == win_tile_34) == 0)
                    {
                        // 8-9-... wait
                        fu_details.Add((2, PENCHAN));
                    }
                }
                // kanchan waiting 5-...-7
                if (win_group.FindIndex(x => x == win_tile_34) == 1)
                {
                    fu_details.Add((2, KANCHAN));
                }
            }
            // valued pair
            var count_of_valued_pairs = valued_tiles.Count(x => x == pair[0]);

            if (count_of_valued_pairs == 1)
            {
                fu_details.Add((2, VALUED_PAIR));
            }
            // east-east pair when you are on east gave double fu
            if (count_of_valued_pairs == 2)
            {
                fu_details.Add((4, DOUBLE_VALUED_PAIR));
            }
            // pair wait
            if (U.is_pair(win_group))
            {
                fu_details.Add((2, PAIR_WAIT));
            }
            foreach (var set_item in pon_sets)
            {
                var open_meld = (from x in melds
                                 where set_item == x.tiles_34
                                 select x).ToList().FirstOrDefault();
                var set_was_open = open_meld != null && open_meld.opened;
                var is_kan_set   = open_meld != null && (open_meld.type == Meld.KAN || open_meld.type == Meld.SHOUMINKAN);
                var is_honor     = (C.TERMINAL_INDICES.Concat(C.HONOR_INDICES)).Contains(set_item[0]);
                // we win by ron on the third pon tile, our pon will be count as open
                if (!config.is_tsumo && set_item == win_group)
                {
                    set_was_open = true;
                }
                if (is_honor)
                {
                    if (is_kan_set)
                    {
                        if (set_was_open)
                        {
                            fu_details.Add((16, OPEN_TERMINAL_KAN));
                        }
                        else
                        {
                            fu_details.Add((32, CLOSED_TERMINAL_KAN));
                        }
                    }
                    else if (set_was_open)
                    {
                        fu_details.Add((4, OPEN_TERMINAL_PON));
                    }
                    else
                    {
                        fu_details.Add((8, CLOSED_TERMINAL_PON));
                    }
                }
                else if (is_kan_set)
                {
                    if (set_was_open)
                    {
                        fu_details.Add((8, OPEN_KAN));
                    }
                    else
                    {
                        fu_details.Add((16, CLOSED_KAN));
                    }
                }
                else if (set_was_open)
                {
                    fu_details.Add((2, OPEN_PON));
                }
                else
                {
                    fu_details.Add((4, CLOSED_PON));
                }
            }
            var add_tsumo_fu = fu_details.Count > 0 || config.options.fu_for_pinfu_tsumo;

            if (config.is_tsumo && add_tsumo_fu)
            {
                // 2 additional fu for tsumo (but not for pinfu)
                fu_details.Add((2, TSUMO));
            }
            if (is_open_hand && fu_details.Count == 0 && config.options.fu_for_open_pinfu)
            {
                // there is no 1-20 hands, so we have to add additional fu
                fu_details.Add((2, HAND_WITHOUT_FU));
            }
            if (is_open_hand || config.is_tsumo)
            {
                fu_details.Add((20, BASE));
            }
            else
            {
                fu_details.Add((30, BASE));
            }
            return(fu_details, round_fu(fu_details));
        }