Ejemplo n.º 1
0
        public SuitScoringBitField(ArrangementGroup arrangements, int fuFootprintIndex)
        {
            _arrangementGroup = arrangements;
            _iipeikouCount    = CalculateIipeikouCount();

            // Yaku
            SanshokuDoujun();
            SanshokuDoukou();
            Tanyao(29);
            IipeikouRyanpeikou(38);
            Chiitoitsu(40);
            Pinfu(51);
            Ankou(32);
            HonitsuChinitsu(20);
            KokushiMusou();
            Chinroutou(37);
            Chuuren(62);
            Chanta(27);
            Honroutou(26);
            Toitoi(31);
            Junchan(49);
            Ittsuu(44);
            Ryuuiisou(28);

            // Fu
            WaitShiftValue |= (long)fuFootprintIndex << 10;
            if (arrangements.HasSquareType)
            {
                OrValue |= 1L << 34;
            }
        }
        private static bool Matches(ArrangementGroup arrangements, Arrangement arrangement, FuConstraint constraint)
        {
            if (constraint.DoujunIndex >= 0 && !arrangement.ContainsShuntsu(constraint.DoujunIndex))
            {
                // open hands with less than 6 tiles in the arrangement can use a meld to get sanshoku
                if (arrangements.TileCount > 5 || !constraint.Open)
                {
                    return(false);
                }
            }

            if (constraint.DoukouIndex >= 0 && !arrangement.ContainsKoutsu(constraint.DoukouIndex))
            {
                // hands with less than 6 tiles in the arrangement can use a meld to get sanshoku. If closed must be ankan
                if (arrangements.TileCount > 5)
                {
                    return(false);
                }
            }

            var hasIipeikou = arrangement.Blocks.Where(b => b.IsShuntsu).GroupBy(s => s.Index).Any(g => g.Count() >= 2);

            if (arrangements.HasIipeikou && !constraint.Open && !hasIipeikou)
            {
                if (!arrangements.HasSquareType || constraint.SquareIsNotSanankou)
                {
                    return(false);
                }
            }

            if (constraint.SquareIsNotSanankou && arrangement.Blocks.Count(b => b.IsKoutsu) >= 3)
            {
                return(false);
            }

            return(true);
        }
        public FuFootprintCreator(ArrangementGroup arrangements)
        {
            // TODO exclude nonstandard hands

            // Fu does not matter for chinitsu
            if (arrangements.TileCount == 14)
            {
                return;
            }

            var constraints = CreateConstraints(arrangements);

            var constraintToFu = new Dictionary <FuConstraint, int>();

            foreach (var constraint in constraints)
            {
                var bestFu = 0;

                foreach (var arrangement in arrangements.Arrangements)
                {
                    if (!Matches(arrangements, arrangement, constraint))
                    {
                        continue;
                    }

                    var winningIndex = constraint.WinningIndex;
                    var pairIndex    = arrangement.Blocks.FirstOrDefault(b => b.IsPair)?.Index;
                    var shuntsus     = arrangement.Blocks.Where(b => b.IsShuntsu).ToList();
                    var fu           = 0;

                    foreach (var koutsu in arrangement.Blocks.Where(b => b.IsKoutsu))
                    {
                        if (constraint.Tsumo || koutsu.Index != winningIndex || HasShuntsuWithWinningTile(arrangement, winningIndex))
                        {
                            fu += koutsu.IsJunchanBlock ? 8 : 4;
                        }
                        else
                        {
                            fu += koutsu.IsJunchanBlock ? 4 : 2;
                        }
                    }

                    if (pairIndex == winningIndex)
                    {
                        fu += 2;
                    }
                    else if (shuntsus.Any(s => s.Index == winningIndex - 1))
                    {
                        fu += 2;
                    }
                    else if (shuntsus.Any(s => s.Index == 0 && winningIndex == 2))
                    {
                        fu += 2;
                    }
                    else if (shuntsus.Any(s => s.Index == 6 && winningIndex == 6))
                    {
                        fu += 2;
                    }

                    bestFu = Math.Max(bestFu, fu);
                }

                constraintToFu.Add(constraint, bestFu);
            }

            foreach (var keyValuePair in constraintToFu)
            {
                Footprint[keyValuePair.Key.Id] = (byte)keyValuePair.Value;
            }
        }
        private static List <FuConstraint> CreateConstraints(ArrangementGroup arrangementGroup)
        {
            var uTypeIndex = arrangementGroup.UTypeIndex;
            var tileCounts = arrangementGroup.TileCounts;

            var constraints = new List <FuConstraint>();

            for (var winningIndex = -1; winningIndex < 9; winningIndex++)
            {
                if (winningIndex == -1 || tileCounts[winningIndex] > 0)
                {
                    AddConstraints(constraints, false, winningIndex, -1, -1);

                    if (uTypeIndex >= 0)
                    {
                        AddConstraints(constraints, false, winningIndex, uTypeIndex, -1);
                        AddConstraints(constraints, false, winningIndex, uTypeIndex + 1, -1);
                        AddConstraints(constraints, false, winningIndex, -1, uTypeIndex);
                        AddConstraints(constraints, false, winningIndex, -1, uTypeIndex + 3);
                    }
                    else if (arrangementGroup.TileCount < 6) // melds can be used for sanshoku here
                    {
                        // could have square in different suit, but not together with sanshoku
                        AddConstraints(constraints, true, winningIndex, -1, -1);

                        for (var i = 0; i < 7; i++)
                        {
                            AddConstraints(constraints, false, winningIndex, i, -1);
                        }

                        for (var i = 0; i < 9; i++)
                        {
                            if (tileCounts[i] < 2 || arrangementGroup.Arrangements.Any(a => a.ContainsKoutsu(i)))
                            {
                                AddConstraints(constraints, false, winningIndex, -1, i);
                            }
                        }
                    }
                    else if (arrangementGroup.TileCount < 9) // melds can't be used for sanshoku here
                    {
                        var shuntsus      = arrangementGroup.Arrangements.SelectMany(a => a.Blocks.Where(b => b.IsShuntsu));
                        var doujunIndexes = shuntsus.Select(s => s.Index).Distinct();
                        foreach (var doujunIndex in doujunIndexes)
                        {
                            AddConstraints(constraints, false, winningIndex, doujunIndex, -1);
                        }

                        var koustsus      = arrangementGroup.Arrangements.SelectMany(a => a.Blocks.Where(b => b.IsKoutsu));
                        var doukouIndexes = koustsus.Select(s => s.Index).Distinct();
                        foreach (var doukouIndex in doukouIndexes)
                        {
                            AddConstraints(constraints, false, winningIndex, -1, doukouIndex);
                        }
                    }
                    else if (arrangementGroup.HasSquareType)
                    {
                        AddConstraints(constraints, true, winningIndex, -1, -1);
                    }
                }
            }

            return(constraints);
        }