private static bool IsIipeiko(HoraPattern hp, InfoForResult ifr)
        {
            //門前でない場合は終了
            if (ifr.IsMenzen == false)
            {
                return false;
            }

            //一盃口対象である門前順子またはロンした明順のみ抜き出し
            var ansyuns = hp.WithoutHeadTartsuList.Where(e => e.IsAnsyun() || (e.IsMinsyun() && e.IsRonedTartsu))
                                                  .OrderBy(e => e.TartsuStartPaiSyu);
            var prevStartPaisyu = -1;
            foreach (var ansyun in ansyuns)
            {
                if (ansyun.TartsuStartPaiSyu == prevStartPaisyu)
                {
                    return true;
                }
                prevStartPaisyu = ansyun.TartsuStartPaiSyu;
            }
            return false;
        }
 private static bool IsShosushi(HoraPattern hp)
 {
     return MJUtil.IsWindPaiId(hp.Head.TartsuStartPaiSyu)
         && hp.WithoutHeadTartsuList.Count(e => MJUtil.IsWindPaiId(e.TartsuStartPaiSyu)) == 3;
 }
 private static bool IsSuuanko(HoraPattern hp)
 {
     return hp.WithoutHeadTartsuList.Count(e => e.TartsuType == MJUtil.TartsuType.ANKO
                                             || e.TartsuType == MJUtil.TartsuType.ANKANTSU)
                                             >= 4;
 }
 private static bool IsSankantsu(HoraPattern hp)
 {
     return hp.WithoutHeadTartsuList.Count(e => e.TartsuType == MJUtil.TartsuType.ANKANTSU
                                             || e.TartsuType == MJUtil.TartsuType.MINKANTSU)
                                             >= 3;
 }
        private static bool IsSansyokuDoujun(HoraPattern hp)
        {
            var syuntsuStartIndex = new bool[MJUtil.LENGTH_SYU_ALL];

            foreach (var tartsu in hp.WithoutHeadTartsuList)
            {
                if (tartsu.TartsuType == MJUtil.TartsuType.ANSYUN || tartsu.TartsuType == MJUtil.TartsuType.MINSYUN)
                {
                    syuntsuStartIndex[tartsu.TartsuStartPaiSyu] = true;
                }
            }

            var syuLength = 9;
            var manzuBase = 0;
            var pinzuBase = syuLength;
            var souzuBase = syuLength * 2;

            for (int i = 0; i < syuLength; i++)
            {
                if (syuntsuStartIndex[manzuBase + i] && syuntsuStartIndex[pinzuBase + i] && syuntsuStartIndex[souzuBase + i])
                {
                    return true;
                }
            }
            return false;
        }
        private static bool IsPinfu(HoraPattern hp, InfoForResult ifr)
        {
            int headSyu = hp.Head.TartsuStartPaiSyu;

            //頭が役牌でないか判定
            if (ifr.Isbakaze(headSyu) || ifr.IsJifuu(headSyu) || MJUtil.IsDragonPaiId(headSyu))
            {
                return false;
            }

            //門前順子またはロン和了明順メンツではない場合ピンフではない
            foreach (var tartsu in hp.WithoutHeadTartsuList) {
                if ( ( (tartsu.IsAnsyun()) || ( tartsu.IsMinsyun() && tartsu.IsRonedTartsu) ) == false)
                {
                    return false;
                }
            }

            //リャンメン待ちか判定
            int lastAddedSyu = ifr.GetLastAddedSyu();
            foreach (var tartsu in hp.WithoutHeadTartsuList )
            {
                if ( (tartsu.TartsuStartPaiSyu == lastAddedSyu) && (lastAddedSyu % 9 != 6)
                    || (tartsu.TartsuStartPaiSyu == lastAddedSyu - 2) && (lastAddedSyu % 9 != 2))
                {
                    return true;
                }
            }
            return false;
        }
        private static bool IsRyuiso(HoraPattern hp)
        {
            var greenCount = 0;

            foreach(var tartsu in hp.TartsuList)
            {
                if( tartsu.TartsuType == MJUtil.TartsuType.ANSYUN
                    || tartsu.TartsuType == MJUtil.TartsuType.MINSYUN)
                {
                    if (MJUtil.IsGreenInSyuntsu(tartsu.TartsuStartPaiSyu))
                    {
                        greenCount++;
                    }
                }
                else
                {
                    if (MJUtil.IsGreenPai(tartsu.TartsuStartPaiSyu))
                    {
                        greenCount++;
                    }
                }
            }

            return greenCount == 5;
        }
        private static int CalcFu(HoraPattern horaMentsu, Field field, InfoForResult ifpc)
        {
            int fuSum = 0;
            int futei = 20;
            fuSum += futei;

            //門前ロンの場合
            if (ifpc.IsMenzen && (!ifpc.IsTsumo)) {
                fuSum += 10;
            }

            //頭が役牌の場合
            int headSyuId = horaMentsu.TartsuList.Where(e => e.IsHead()).First().TartsuStartPaiSyu;
            if (ifpc.Isbakaze(headSyuId)) {
                fuSum += 2;
            }
            if (ifpc.IsJifuu(headSyuId)) {
                fuSum += 2;
            }
            if (MJUtil.IsDragonPaiId(headSyuId)) {
                fuSum += 2;
            }

            //ツモの場合
            if (ifpc.IsTsumo) {
                fuSum += 2;
            }

            int multiple;

            foreach (var tartsu in horaMentsu.TartsuList)
            {
                if (tartsu.IsYaochuTartsu())
                {
                    multiple = 2;
                }
                else
                {
                    multiple = 1;
                }

                switch (tartsu.TartsuType)
                {
                    case MJUtil.TartsuType.MINKO:
                        fuSum += 2 * multiple;
                        continue;
                    case MJUtil.TartsuType.ANKO:
                        fuSum += 4 * multiple;
                        continue;
                    case MJUtil.TartsuType.MINKANTSU:
                        fuSum += 8 * multiple;
                        continue;
                    case MJUtil.TartsuType.ANKANTSU:
                        fuSum += 16 * multiple;
                        continue;
                }

            }

            int lastAddedSyu = ifpc.GetLastAddedSyu();

            //待ちによる符加算
            //単騎待ちの場合
            if (horaMentsu.Head.IsRonedTartsu || horaMentsu.Head.TartsuStartPaiSyu == ifpc.GetLastAddedSyu())
            {
                fuSum += 2;
            }
            else
            {
                //カンチャンorペンチャンの場合
                for (int i = 1; i < horaMentsu.TartsuList.Count; i++) {
                    if ((horaMentsu.TartsuList[i].IsAnsyun() || (horaMentsu.TartsuList[i].IsMinsyun() && horaMentsu.TartsuList[i].IsRonedTartsu) ) == false)
                    {
                        continue;
                    }
                    //順子前提
                    if (lastAddedSyu == horaMentsu.TartsuList[i].TartsuStartPaiSyu + 1) {//カンチャン
                        fuSum += 2;
                        break;
                    } else if ((lastAddedSyu == horaMentsu.TartsuList[i].TartsuStartPaiSyu) && (lastAddedSyu % 9 == 6)) {//7待ちの89ペンチャン
                        fuSum += 2;
                        break;
                    } else if ((lastAddedSyu == horaMentsu.TartsuList[i].TartsuStartPaiSyu + 2) && (lastAddedSyu % 9 == 2)) {//3待ちの12ペンチャン
                        fuSum += 2;
                        break;
                    }
                }
            }

            //喰い平和系の場合そのまま計算すると20符だが、ルール的にピンフ以外は最低30符のため2符足して30符に切り上げる
            if ((fuSum == 20) && (ifpc.IsMenzen == false)) {
                fuSum += 2;
            }

            return (int)(Math.Ceiling(fuSum / 10.0) * 10);
        }
 private static int CalcYakuhaiNum(HoraPattern hp, InfoForResult ifr)
 {
     int yakuhaiNum = 0;
     //TODO
     foreach (var tartsu in hp.WithoutHeadTartsuList)
     {
         //ダブ東、ダブ南の場合があるので自風と場風は独立に判定する
         if (ifr.IsJifuu(tartsu.TartsuStartPaiSyu))
         {
             yakuhaiNum++;
         }
         if (ifr.Isbakaze(tartsu.TartsuStartPaiSyu))
         {
             yakuhaiNum++;
         }
         if (MJUtil.IsDragonPaiId(tartsu.TartsuStartPaiSyu))
         {
             yakuhaiNum++;
         }
     }
     return yakuhaiNum;
 }
 private static bool IsYakuhai(HoraPattern hp, InfoForResult ifr)
 {
     foreach (var tartsu in hp.WithoutHeadTartsuList)
     {
         if (ifr.IsJifuu(tartsu.TartsuStartPaiSyu)
             || ifr.Isbakaze(tartsu.TartsuStartPaiSyu)
             || MJUtil.IsDragonPaiId(tartsu.TartsuStartPaiSyu)
             )
         {
             return true;
         }
     }
     return false;
 }
        public static YakuResult CalcNormalYaku(HoraPattern horaMentsu, InfoForResult ifr, Field field,int[] horaSyu, int[] realPaiNum, int redDoraNum)
        {
            YakuResult result = new YakuResult();

            result.Fu = CalcFu(horaMentsu, field, ifr);
            result.IsTsumo = ifr.IsTsumo;
            result.IsOya = ifr.IsOya;

            //役の文字列取得
            var yakuString = MJUtil.YAKU_STRING;
            //飜数の辞書選択
            var yakuHanNum = ifr.IsMenzen ? MJUtil.YAKU_HAN_MENZEN : MJUtil.YAKU_HAN_FUROED;

            if (ifr.IsDoubleReach)
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.DOUBLEREACH], yakuHanNum[(int)MJUtil.Yaku.DOUBLEREACH] });
            }
            else if (ifr.IsReach)
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.REACH], yakuHanNum[(int)MJUtil.Yaku.REACH] });
            }

            if (ifr.IsTsumo && ifr.IsMenzen)
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.TSUMO], yakuHanNum[(int)MJUtil.Yaku.TSUMO] });
            }
            if (ifr.IsIppatsu)
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.IPPATSU], yakuHanNum[(int)MJUtil.Yaku.IPPATSU] });
            }
            if (IsPinfu(horaMentsu, ifr))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.PINFU], yakuHanNum[(int)MJUtil.Yaku.PINFU] });
                result.Fu = ifr.IsTsumo ? 20 : 30;//ピンフツモは20符、ピンフロンは30符
            }
            if (IsTannyao(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.TANNYAO], yakuHanNum[(int)MJUtil.Yaku.TANNYAO] });
            }

            //一盃口と二盃口は両立しない
            if (IsRyanpeiko(horaMentsu, ifr))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.RYANPEIKO], yakuHanNum[(int)MJUtil.Yaku.RYANPEIKO] });
            }
            else if (IsIipeiko(horaMentsu, ifr))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.IIPEIKOU], yakuHanNum[(int)MJUtil.Yaku.IIPEIKOU] });
            }

            if (IsYakuhai(horaMentsu, ifr))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.YAKUHAI], CalcYakuhaiNum(horaMentsu, ifr)});
            }
            if (ifr.IsHoutei)
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.HOUTEI], yakuHanNum[(int)MJUtil.Yaku.HOUTEI] });
            }
            if (ifr.IsHaitei)
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.HAITEI], yakuHanNum[(int)MJUtil.Yaku.HAITEI] });
            }
            if (ifr.IsRinshan)
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.RINSHAN], yakuHanNum[(int)MJUtil.Yaku.RINSHAN] });
            }
            if (ifr.IsChankan)
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.CHANKAN], yakuHanNum[(int)MJUtil.Yaku.CHANKAN] });
            }
            if (ifr.CalcDoraNum(realPaiNum) > 0)
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.DORA], ifr.CalcDoraNum(realPaiNum) });
            }
            if (redDoraNum > 0)
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.REDDORA], redDoraNum });
            }
            if (IsSansyokuDoujun(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.SANSYOKUDOJUN], yakuHanNum[(int)MJUtil.Yaku.SANSYOKUDOJUN] });
            }

            if (IsIttsuu(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.ITTSUU], yakuHanNum[(int)MJUtil.Yaku.ITTSUU] });
            }

            if (IsSananko(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.SANANKO], yakuHanNum[(int)MJUtil.Yaku.SANANKO] });
            }

            if (IsToitoi(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.TOITOI], yakuHanNum[(int)MJUtil.Yaku.TOITOI] });
            }

            if (IsShosangen(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.SHOSANGEN], yakuHanNum[(int)MJUtil.Yaku.SHOSANGEN] });
            }

            //混老頭とチャンタ系は同時に成立しない
            if (IsHonroto(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.HONROTO], yakuHanNum[(int)MJUtil.Yaku.HONROTO] });
            }
            else
            {
                //純チャンタと混チャンタは同時に成立しない
                if (IsJunChanta(horaMentsu))
                {
                    result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.JUNCHANTA], yakuHanNum[(int)MJUtil.Yaku.JUNCHANTA] });
                }
                else if (IsChanta(horaMentsu))
                {
                    result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.CHANTA], yakuHanNum[(int)MJUtil.Yaku.CHANTA] });
                }
            }

            if (IsSansyokuDoko(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.SANSYOKUDOKO], yakuHanNum[(int)MJUtil.Yaku.SANSYOKUDOKO] });
            }

            if (IsSankantsu(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.SANKANTSU], yakuHanNum[(int)MJUtil.Yaku.SANKANTSU] });
            }

            //混一色と清一色は同時に成立しない
            if (IsHonnitsu(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.HONNITSU], yakuHanNum[(int)MJUtil.Yaku.HONNITSU] });
            }
            else if (IsChinnitsu(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.CHINNITSU], yakuHanNum[(int)MJUtil.Yaku.CHINNITSU] });
            }

            //ここから役満
            if(IsSuuanko(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.SUUANKO], yakuHanNum[(int)MJUtil.Yaku.SUUANKO] });
            }

            if (IsDaisangen(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.DAISANGEN], yakuHanNum[(int)MJUtil.Yaku.DAISANGEN] });
            }

            if (IsShosushi(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.SHOSUSHI], yakuHanNum[(int)MJUtil.Yaku.SHOSUSHI] });
            }

            if (IsDaisushi(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.DAISUSHI], yakuHanNum[(int)MJUtil.Yaku.DAISUSHI] });
            }

            if (IsTsuiso(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.TSUISO], yakuHanNum[(int)MJUtil.Yaku.TSUISO] });
            }

            if (IsRyuiso(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.RYUISO], yakuHanNum[(int)MJUtil.Yaku.RYUISO] });
            }

            if (IsChinroto(horaMentsu)) {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.CHINROTO], yakuHanNum[(int)MJUtil.Yaku.CHINROTO] });
            }

            if(IsChurenpoto(ifr, horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.CHURENPOTO], yakuHanNum[(int)MJUtil.Yaku.CHURENPOTO] });
            }

            if (IsSukantsu(horaMentsu))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.SUKANTSU], yakuHanNum[(int)MJUtil.Yaku.SUKANTSU] });
            }

            if (IsTenho(ifr))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.TENHO], yakuHanNum[(int)MJUtil.Yaku.TENHO] });
            }

            if( IsChiho(ifr))
            {
                result.yakus.Add(new List<object>() { yakuString[(int)MJUtil.Yaku.CHIHO], yakuHanNum[(int)MJUtil.Yaku.CHIHO] });
            }

            if (HasYakuman(result.yakus))
            {
                result.yakus = SelectYakuman(result.yakus);
                result.YakumanMultiple = result.yakus.Count;
            }

            //飜数計算
            result.Han = CalcHanSum(result.yakus);

            result.HasYakuExcludeDora = CalcHanSumWithoutDora(result.yakus) > 0;
            return result;
        }
 private static bool IsTsuiso(HoraPattern hp)
 {
     return hp.TartsuList.Count(e => MJUtil.IsJihaiPaiId(e.TartsuStartPaiSyu)) == 5;
 }
 private static bool IsToitoi(HoraPattern hp)
 {
     foreach (var tartsu in hp.WithoutHeadTartsuList)
     {
         if (tartsu.IsAnsyun()
             || tartsu.IsMinsyun())
         {
             return false;
         }
     }
     return true;
 }
        private static bool IsTannyao(HoraPattern hp)
        {
            foreach (var tartsu in hp.TartsuList)
            {
                if(tartsu.IsYaochuTartsu())
                {
                    return false;
                }

            }
            return true;
        }
        private static bool IsIttsuu(HoraPattern hp)
        {
            var syuntsuStartIndex = new bool[MJUtil.LENGTH_SYU_ALL];

            foreach (var tartsu in hp.WithoutHeadTartsuList)
            {
                if (tartsu.TartsuType == MJUtil.TartsuType.ANSYUN || tartsu.TartsuType == MJUtil.TartsuType.MINSYUN)
                {
                    syuntsuStartIndex[tartsu.TartsuStartPaiSyu] = true;
                }
            }

            var syuLength = 9;
            var manzuBase = 0;
            var pinzuBase = syuLength;
            var souzuBase = syuLength * 2;

            var result =
                   (syuntsuStartIndex[manzuBase] && syuntsuStartIndex[manzuBase + 3] && syuntsuStartIndex[manzuBase + 6])
                  || (syuntsuStartIndex[pinzuBase] && syuntsuStartIndex[pinzuBase + 3] && syuntsuStartIndex[pinzuBase + 6])
                  || (syuntsuStartIndex[souzuBase] && syuntsuStartIndex[souzuBase + 3] && syuntsuStartIndex[souzuBase + 6]);

            return result;
        }
        private static bool IsChinroto(HoraPattern hp)
        {
            if (hp.TartsuList.Count(e => e.TartsuType == MJUtil.TartsuType.ANSYUN
                   || e.TartsuType == MJUtil.TartsuType.MINSYUN)
                   > 0)
            {
                return false;
            }

            return hp.TartsuList.Count(e => MJUtil.IsRotoPai(e.TartsuStartPaiSyu)) == 5;
        }
 private static bool IsJunChanta(HoraPattern hp)
 {
     foreach (var tartsu in hp.TartsuList)
     {
         if (tartsu.TartsuType == MJUtil.TartsuType.ANSYUN || tartsu.TartsuType == MJUtil.TartsuType.MINSYUN)
         {
             if ((tartsu.TartsuStartPaiSyu % 9 == 0) || (tartsu.TartsuStartPaiSyu % 9 == 6))
             {
                 continue;
             }
         }
         else
         {
             if (MJUtil.IsRotoPai(tartsu.TartsuStartPaiSyu))
             {
                 continue;
             }
         }
         return false;
     }
     return true;
 }
        private static bool IsChurenpoto(InfoForResult ifr,HoraPattern horaMentsu)
        {
            if (ifr.IsMenzen == false)
            {
                return false;
            }

            var horaSyuWithoutAnkan = new int[MJUtil.LENGTH_SYU_ALL];

            foreach (var tartsu in horaMentsu.TartsuList)
            {
                // count only in Tehai (HEAD, ANSHYN, ANKO)
                var isNotFuroTartsu = tartsu.TartsuType == MJUtil.TartsuType.HEAD ||
                                      tartsu.TartsuType == MJUtil.TartsuType.ANSYUN ||
                                      tartsu.TartsuType == MJUtil.TartsuType.ANKO;

                if (isNotFuroTartsu == false)
                {
                    return false;
                }

                if (tartsu.TartsuType == MJUtil.TartsuType.HEAD)
                {
                    horaSyuWithoutAnkan[tartsu.TartsuStartPaiSyu] += 2;
                }
                else if (tartsu.TartsuType == MJUtil.TartsuType.ANSYUN)
                {
                    horaSyuWithoutAnkan[tartsu.TartsuStartPaiSyu] += 1;
                    horaSyuWithoutAnkan[tartsu.TartsuStartPaiSyu + 1] += 1;
                    horaSyuWithoutAnkan[tartsu.TartsuStartPaiSyu + 2] += 1;
                }
                else if (tartsu.TartsuType == MJUtil.TartsuType.ANKO)
                {
                    horaSyuWithoutAnkan[tartsu.TartsuStartPaiSyu] += 3;
                }

            }

            for (int mps = 0; mps < 3; mps++)
            {
                if (
                       (horaSyuWithoutAnkan[0 + mps * 9] >= 3)
                    && (horaSyuWithoutAnkan[1 + mps * 9] >= 1)
                    && (horaSyuWithoutAnkan[2 + mps * 9] >= 1)
                    && (horaSyuWithoutAnkan[3 + mps * 9] >= 1)
                    && (horaSyuWithoutAnkan[4 + mps * 9] >= 1)
                    && (horaSyuWithoutAnkan[5 + mps * 9] >= 1)
                    && (horaSyuWithoutAnkan[6 + mps * 9] >= 1)
                    && (horaSyuWithoutAnkan[7 + mps * 9] >= 1)
                    && (horaSyuWithoutAnkan[8 + mps * 9] >= 3)
                )
                {
                    return true;
                }
            }
            return false;
        }
        private static bool IsRyanpeiko(HoraPattern hp, InfoForResult ifr)
        {
            //門前でない場合は終了
            if (ifr.IsMenzen == false)
            {
                return false;
            }

            //4ターツ全てが門前順子またはロンした明順でない場合は終了
            if (hp.WithoutHeadTartsuList.Count( e => e.IsAnsyun() || (e.IsMinsyun()&&e.IsRonedTartsu) ) != 4)
            {
                return false;
            }

            var sorted = hp.WithoutHeadTartsuList.OrderBy(e => e.TartsuStartPaiSyu).ToList();

            if (sorted[0].TartsuStartPaiSyu == sorted[1].TartsuStartPaiSyu && sorted[2].TartsuStartPaiSyu == sorted[3].TartsuStartPaiSyu)
            {
                return true;
            }

            return false;
        }
 private static bool IsDaisangen(HoraPattern hp)
 {
     return hp.WithoutHeadTartsuList.Count(e => MJUtil.IsDragonPaiId( e.TartsuStartPaiSyu ) ) == 3;
 }
 private static bool IsSananko(HoraPattern hp)
 {
     return hp.WithoutHeadTartsuList.Count(e => e.IsAnko() || e.IsAnkantsu() )
         >= 3;
 }
 private static bool IsDaisushi(HoraPattern hp)
 {
     return hp.WithoutHeadTartsuList.Count(e => MJUtil.IsWindPaiId(e.TartsuStartPaiSyu)) == 4;
 }
        private static bool IsSansyokuDoko(HoraPattern hp)
        {
            var syu = new int[MJUtil.LENGTH_SYU_ALL];

            foreach( var tartsu in hp.WithoutHeadTartsuList)
            {
                if( tartsu.TartsuType == MJUtil.TartsuType.ANKO
                    || tartsu.TartsuType == MJUtil.TartsuType.MINKO
                    || tartsu.TartsuType == MJUtil.TartsuType.ANKANTSU
                    || tartsu.TartsuType == MJUtil.TartsuType.MINKANTSU)
                {
                    syu[tartsu.TartsuStartPaiSyu]++;
                }
            }

            for(int i=0; i< MJUtil.LENGTH_SYU_ONE_NUMBERS; i++)
            {
                if ( syu[i + MJUtil.LENGTH_SYU_ONE_NUMBERS * 0] >= 1
                  && syu[i + MJUtil.LENGTH_SYU_ONE_NUMBERS * 1] >= 1
                  && syu[i + MJUtil.LENGTH_SYU_ONE_NUMBERS * 2] >= 1)
                {
                    return true;
                }
            }

            return false;
        }
        private static bool IsHonnitsu(HoraPattern hp)
        {
            var hasManzu = false;
            var hasPinzu = false;
            var hasSouzu = false;
            var hasJi = false;

            foreach (var tartsu in hp.TartsuList)
            {
                if( MJUtil.IsJihaiPaiId(tartsu.TartsuStartPaiSyu))
                {
                    hasJi |= true;
                }
                else
                {
                    var div = tartsu.TartsuStartPaiSyu / MJUtil.LENGTH_SYU_ONE_NUMBERS;
                    hasManzu |= (div == 0);
                    hasPinzu |= (div == 1);
                    hasSouzu |= (div == 2);
                }
            }
            var isOneColor = ( hasManzu && !hasPinzu && !hasSouzu)
                        || (!hasManzu &&  hasPinzu && !hasSouzu)
                        || (!hasManzu && !hasPinzu &&  hasSouzu);
            return isOneColor && hasJi;
        }
        private static bool IsShosangen(HoraPattern hp)
        {
            if (MJUtil.IsDragonPaiId(hp.Head.TartsuStartPaiSyu) == false)
            {
                return false;
            }

            var doragonCount = 0;
            foreach (var tartsu in hp.WithoutHeadTartsuList)
            {
                if (MJUtil.IsDragonPaiId(tartsu.TartsuStartPaiSyu))
                {
                    doragonCount++;
                }
            }

            //頭が三元牌かつ三元牌ターツが2つ以上ある場合
            return doragonCount >= 2;
        }
        private static bool IsHonroto(HoraPattern hp)
        {
            foreach (var tartsu in hp.TartsuList)
            {
                if (tartsu.TartsuType == MJUtil.TartsuType.ANSYUN || tartsu.TartsuType == MJUtil.TartsuType.MINSYUN)
                {
                    return false;
                }

                if (MJUtil.IsYaochuPai(tartsu.TartsuStartPaiSyu) == false)
                {
                    return false;
                }
            }
            return true;
        }
        private static void reSplit(int start, int[] syu, ref List<Tartsu> work, ref List<HoraPattern> resultList)
        {
            if (syuIsZero(syu))
            {
                HoraPattern result = new HoraPattern(work);
                resultList.Add(result);
                return;
            }

            for (int i = start; i < MJUtil.LENGTH_SYU_ALL; i++)
            {

                if (syu[i] >= 3)
                {
                    syu[i] -= 3;
                    Tartsu ts = new Tartsu(MJUtil.TartsuType.ANKO, i);
                    work.Add(ts);
                    reSplit(i, syu, ref work, ref resultList);
                    work.Remove(ts);
                    syu[i] += 3;
                }
                if ((i <= 24) && ((syu[i] >= 1) && (syu[i + 1] >= 1) && (syu[i + 2] >= 1)) && ((i % 9) < 7)  )
                {
                    syu[i]--;
                    syu[i + 1]--;
                    syu[i + 2]--;
                    Tartsu ts = new Tartsu(MJUtil.TartsuType.ANSYUN, i);
                    work.Add(ts);
                    reSplit(i, syu, ref work, ref resultList);
                    work.Remove(ts);
                    syu[i]++;
                    syu[i + 1]++;
                    syu[i + 2]++;
                }

            }
        }
 private static bool IsSukantsu(HoraPattern hp)
 {
     return hp.TartsuList.Count(e => e.TartsuType == MJUtil.TartsuType.ANKANTSU
                                  || e.TartsuType == MJUtil.TartsuType.MINKANTSU)
                                   == 4;
 }