public Tehai(Tehai src) { initialize(); copy(this, src, true); Sort(); }
public void 手配大明槓テスト() { Tehai testTehai = new Tehai(new List <string> { "1m", "2m", "3m", "4m", "5m", "6m", "7m", "8m", "9m", "1s", "2s", "3s", "1m" }); testTehai.Tsumo(new Pai("1m")); //chi var actor = 0; var target = 3; var furopai = new Pai("1m"); var consumed = new List <Pai> { new Pai("1m"), new Pai("1m"), new Pai("1m") }; consumed.Sort(); Assert.IsTrue(testTehai.tehai.Contains(new Pai("1m"))); //実施 testTehai.Daiminkan(actor, target, furopai, consumed); //フーロオブジェクトの構成が正しいか Assert.AreEqual(testTehai.furos[0].ftype, MJUtil.TartsuType.MINKANTSU); Assert.AreEqual(testTehai.furos[0].furopai, furopai); CollectionAssert.AreEqual(testTehai.furos[0].consumed, consumed); //晒した牌が手配に残っていないか Assert.IsFalse(testTehai.tehai.Contains(new Pai("1m"))); }
protected virtual void thinkSutehai(Hai addHai) { _action.SutehaiIndex = Tehai.getJyunTehaiCount(); Tehai tehaiCopy = new Tehai(Tehai); FormatWorker.setCounterFormat(tehaiCopy, null); int maxScore = getCountFormatScore(FormatWorker); for (int i = 0; i < tehaiCopy.getJyunTehaiCount(); i++) { Hai hai = tehaiCopy.removeJyunTehaiAt(i); FormatWorker.setCounterFormat(tehaiCopy, addHai); int score = getCountFormatScore(FormatWorker); if (score > maxScore) { maxScore = score; _action.SutehaiIndex = i; } tehaiCopy.insertJyunTehai(i, hai); } }
public void 手配暗槓テスト() { Tehai testTehai = new Tehai(new List <Pai> { new Pai("1m"), new Pai("1m"), new Pai("1m") }); //ankan var actor = 0; var consumed = new List <Pai> { new Pai("1m"), new Pai("1m"), new Pai("1m"), new Pai("1m") }; consumed.Sort(); Assert.IsTrue(testTehai.tehai.Contains(new Pai("1m"))); //実施 testTehai.Ankan(actor, consumed); //フーロオブジェクトの構成が正しいか Assert.AreEqual(testTehai.furos[0].ftype, MJUtil.TartsuType.ANKANTSU); CollectionAssert.AreEqual(testTehai.furos[0].consumed, consumed); //晒した牌が手配に残っていないか Assert.IsFalse(testTehai.tehai.Contains(new Pai("1m"))); }
protected virtual void thinkReach() { _action.ReachSelectIndex = 0; List <int> reachHaiIndex = _action.ReachHaiIndexList; Tehai tehaiCopy = new Tehai(Tehai); int minScore = int.MaxValue; for (int i = 0; i < reachHaiIndex.Count; i++) { Hai hai = tehaiCopy.removeJyunTehaiAt(reachHaiIndex[i]); // reachHaiIndex[i], not i List <Hai> machiiHais; if (MahjongAgent.tryGetMachiHais(tehaiCopy, out machiiHais)) { for (int m = 0; m < machiiHais.Count; m++) { Hai addHai = machiiHais[m]; FormatWorker.setCounterFormat(tehaiCopy, addHai); int score = MahjongAgent.getAgariScore(tehaiCopy, addHai, JiKaze); if (score <= minScore) { minScore = score; _action.ReachSelectIndex = i; } } } tehaiCopy.insertJyunTehai(i, hai); } }
protected virtual void thinkSelectSuteHai() { thinkSutehai(null); if (_action.SutehaiIndex == Tehai.getJyunTehaiCount()) { _action.SutehaiIndex = Utils.GetRandomNum(0, Tehai.getJyunTehaiCount()); } }
public int CalcShanten(Tehai tehai){ var syu = new int[MJUtil.LENGTH_SYU_ALL]; foreach (var p in tehai.tehai) { syu[p.PaiNumber]++; } return CalcShantenWithFuro(syu, tehai.furos.Count); }
public int CalcShanten(Tehai tehai, string pai) { var syu = new int[MJUtil.LENGTH_SYU_ALL]; foreach (var p in tehai.tehai) { syu[p.PaiNumber]++; } syu[PaiConverter.STRING_TO_ID[pai]]++; return CalcShantenWithFuro(syu, tehai.furos.Count); }
public void 手配ツモテスト() { Tehai testTehai = new Tehai(new List <string> { "1m", "2m", "3m", "4m", "5m", "6m", "7m", "8m", "9m", "1s", "2s", "3s", "4s" }); Assert.IsFalse(testTehai.tehai.Contains(new Pai("5s"))); testTehai.Tsumo(new Pai("5s")); Assert.IsTrue(testTehai.tehai.Contains(new Pai("5s"))); }
public int CalcShanten(Tehai tehai, string pai) { var syu = new int[MJUtil.LENGTH_SYU_ALL]; foreach (var p in tehai.tehai) { syu[p.PaiNumber]++; } syu[PaiConverter.STRING_TO_ID[pai]]++; return(CalcShantenWithFuro(syu, tehai.furos.Count)); }
public int CalcShanten(Tehai tehai) { var syu = new int[MJUtil.LENGTH_SYU_ALL]; foreach (var p in tehai.tehai) { syu[p.PaiNumber]++; } return(CalcShantenWithFuro(syu, tehai.furos.Count)); }
public bool CheckHaiTypeOver9(Tehai tehai, Hai addHai) { if (!_game.isChiHou) { return(false); } if (tehai.getJyunTehaiCount() < Tehai.JYUN_TEHAI_LENGTH_MAX - 1) { return(false); } int[] checkId = { Hai.ID_WAN_1, Hai.ID_WAN_9, Hai.ID_PIN_1, Hai.ID_PIN_9, Hai.ID_SOU_1, Hai.ID_SOU_9, Hai.ID_TON, Hai.ID_NAN, Hai.ID_SYA, Hai.ID_PE, Hai.ID_HAKU, Hai.ID_HATSU, Hai.ID_CHUN }; int[] countNumber = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //length = 13 //手牌をコピーする Hai[] checkHais = tehai.getJyunTehai(); for (int i = 0; i < checkHais.Length; i++) { for (int j = 0; j < checkId.Length; j++) { if (checkHais[i].ID == checkId[j]) { countNumber[j]++; } } } for (int j = 0; j < checkId.Length; j++) { if (addHai.ID == checkId[j]) { countNumber[j]++; } } int totalHaiType = 0; for (int c = 0; c < countNumber.Length; c++) { if (countNumber[c] > 0) { totalHaiType++; } } return(totalHaiType >= 9); }
// 是否可以听牌,只需要检查一个成立的牌. public bool canTenpai(Tehai tehai) { for (int id = Hai.ID_MIN; id <= Hai.ID_MAX; id++) { countFormat.setCounterFormat(tehai, new Hai(id)); if (countFormat.calculateCombisCount(combis) > 0) { return(true); } } return(false); }
public TileId Dahai(int index) { TileId dahai; if (index == 13) { dahai = TsumoTile; TsumoTile = null; } else { dahai = Tehai[index]; Tehai.RemoveAt(index); Tehai.Add(TsumoTile); } return(dahai); }
// hais为听牌列表. public bool tryGetMachiHais(Tehai tehai, out List <Hai> hais) { hais = new List <Hai>(); for (int id = Hai.ID_MIN; id <= Hai.ID_MAX; id++) { Hai addHai = new Hai(id); countFormat.setCounterFormat(tehai, addHai); if (countFormat.calculateCombisCount(combis) > 0) { hais.Add(addHai); } } return(hais.Count > 0); }
// 手牌をコピーする public static void copy(Tehai dest, Tehai src, bool jyunTehaiCopy) { if (jyunTehaiCopy == true) { dest._jyunTehais.Clear(); for (int i = 0; i < src._jyunTehais.Count; i++) { dest._jyunTehais.Add(new Hai(src._jyunTehais[i])); } } dest._fuuros.Clear(); for (int i = 0; i < src._fuuros.Count; i++) { dest._fuuros.Add(new Fuuro(src._fuuros[i])); } }
public void 和了時構成分割テスト() { Tehai testTehai = new Tehai(new List <string> { "1m", "2m", "3m", "4m", "5m", "6m", "7m", "7m", "1m", "1m", "2m", "2m", "3m" }); var isRon = true; var result = SplitedTehaiCalclator.CalcSplitedTehai(testTehai, "3m", isRon); Debug.WriteLine(result.AllHoraPatternList.Count); foreach (var r in result.AllHoraPatternList) { foreach (var t in r.TartsuList) { Debug.WriteLine(t.TartsuType + "," + t.TartsuStartPaiSyu); } Debug.WriteLine(""); } Assert.AreEqual(result.AllHoraPatternList.Count, 4);//testTehaiは111222333の部分が順子3つのパターンと暗刻3つのパターンがある }
public static HoraResult CalcHoraResult(Tehai tehai, InfoForResult ifr, Field field, string horaPai) { //面子手の取りうる和了形を全て列挙 SplitedTehai splited = SplitedTehaiCalclator.CalcSplitedTehai(tehai, horaPai, !ifr.IsTsumo ); List<YakuResult> yakuResultList = new List<YakuResult>(); int[] realPaiNum = tehai.GetRealPaiNum(); if (ifr.IsTsumo == false) { realPaiNum[PaiConverter.STRING_TO_ID[horaPai]]++; } //面子手和了型が0の場合はチートイツか国士無双 if (splited.AllHoraPatternList.Count == 0) { yakuResultList.Add(YakuResultCalclator.CalcSpecialYaku(ifr, field, splited.SyuNum, splited.RedDoraNum)); } else { //面子手の役を計算 foreach (var pattern in splited.AllHoraPatternList) { yakuResultList.Add(YakuResultCalclator.CalcNormalYaku(pattern, ifr, field, splited.SyuNum, realPaiNum, splited.RedDoraNum)); } } Dictionary<YakuResult, PointResult> pointResultMap = new Dictionary<YakuResult, PointResult>(); foreach (var yakuResult in yakuResultList) { //役と符から点数を計算 pointResultMap.Add(yakuResult, PointResultCalclator.AnalyzePoint(yakuResult)); } //一番点数が高い和了形の役と点数を返却 var maxMap = pointResultMap.OrderBy(e => e.Value.HoraPlayerIncome).Last(); HoraResult maxResult = new HoraResult(); maxResult.yakuResult = maxMap.Key; maxResult.pointResult = maxMap.Value; return maxResult; }
public static SplitedTehai CalcSplitedTehai(Tehai tehai, string horaPai, bool isRon) { //手配&和了牌の牌の合計枚数をカウント int[] inHandSyu = new int[MJUtil.LENGTH_SYU_ALL]; foreach (var pai in tehai.tehai) { inHandSyu[pai.PaiNumber]++; } if (isRon) { inHandSyu[PaiConverter.STRING_TO_ID[horaPai]]++; } TehaiSpliter ts = new TehaiSpliter(); //手に残っている手配のターツ構成を全て算出 var splited = ts.SplitTehai(inHandSyu, tehai.furos, horaPai, isRon); foreach (var furopai in tehai.furos) { switch (furopai.ftype) { case MJUtil.TartsuType.MINSYUN: splited.SyuNum[furopai.minPaiSyu]++; splited.SyuNum[furopai.minPaiSyu + 1]++; splited.SyuNum[furopai.minPaiSyu + 2]++; break; case MJUtil.TartsuType.MINKO: splited.SyuNum[furopai.minPaiSyu] += 3; break; case MJUtil.TartsuType.MINKANTSU: splited.SyuNum[furopai.minPaiSyu] += 4; break; } } return(splited); }
public static SplitedTehai CalcSplitedTehai(Tehai tehai, string horaPai, bool isRon) { //手配&和了牌の牌の合計枚数をカウント int[] inHandSyu = new int[MJUtil.LENGTH_SYU_ALL]; foreach (var pai in tehai.tehai) { inHandSyu[pai.PaiNumber]++; } if (isRon) { inHandSyu[PaiConverter.STRING_TO_ID[horaPai]]++; } TehaiSpliter ts = new TehaiSpliter(); //手に残っている手配のターツ構成を全て算出 var splited = ts.SplitTehai(inHandSyu, tehai.furos, horaPai, isRon); foreach (var furopai in tehai.furos) { switch (furopai.ftype) { case MJUtil.TartsuType.MINSYUN: splited.SyuNum[furopai.minPaiSyu]++; splited.SyuNum[furopai.minPaiSyu + 1]++; splited.SyuNum[furopai.minPaiSyu + 2]++; break; case MJUtil.TartsuType.MINKO: splited.SyuNum[furopai.minPaiSyu] += 3; break; case MJUtil.TartsuType.MINKANTSU: splited.SyuNum[furopai.minPaiSyu] += 4; break; } } return splited; }
public static HoraResult CalcHoraResult(Tehai tehai, InfoForResult ifr, Field field, string horaPai) { //面子手の取りうる和了形を全て列挙 SplitedTehai splited = SplitedTehaiCalclator.CalcSplitedTehai(tehai, horaPai, !ifr.IsTsumo); List <YakuResult> yakuResultList = new List <YakuResult>(); //面子手和了型が0の場合はチートイツか国士無双 if (splited.AllHoraPatternList.Count == 0) { yakuResultList.Add(YakuResultCalclator.CalcSpecialYaku(ifr, field, splited.SyuNum)); } else { //面子手の役を計算 foreach (var pattern in splited.AllHoraPatternList) { yakuResultList.Add(YakuResultCalclator.CalcNormalYaku(pattern, ifr, field, splited.SyuNum)); } } Dictionary <YakuResult, PointResult> pointResultMap = new Dictionary <YakuResult, PointResult>(); foreach (var yakuResult in yakuResultList) { //役と符から点数を計算 pointResultMap.Add(yakuResult, PointResultCalclator.AnalyzePoint(yakuResult)); } //一番点数が高い和了形の役と点数を返却 var maxMap = pointResultMap.OrderBy(e => e.Value.HoraPlayerIncome).Last(); HoraResult maxResult = new HoraResult(); maxResult.yakuResult = maxMap.Key; maxResult.pointResult = maxMap.Value; return(maxResult); }
public void 役算出テスト() { //清一色ピンフ一盃口 { Tehai testTehai = new Tehai(new List <string> { "1m", "2m", "3m", "4m", "5m", "6m", "7m", "7m", "1m", "2m", "2m", "3m", "3m", "4m" }); var lastAdded = "4m"; var testIfr = new InfoForResult(); testIfr.IsMenzen = true; testIfr.IsOya = true; testIfr.IsTsumo = true; testIfr.PassedTurn = 10; testIfr.SetLastAddedPai(lastAdded); var result = new HoraResult(); result = ResultCalclator.CalcHoraResult(testTehai, testIfr, new Field(), lastAdded); var yakuMap = result.yakuResult.yakus; Assert.IsTrue(yakuMap.ContainsKey(MJUtil.YAKU_STRING[(int)MJUtil.Yaku.CHINNITSU])); Assert.IsTrue(yakuMap.ContainsKey(MJUtil.YAKU_STRING[(int)MJUtil.Yaku.PINFU])); Assert.IsTrue(yakuMap.ContainsKey(MJUtil.YAKU_STRING[(int)MJUtil.Yaku.IIPEIKOU])); } }
public int GetAgariScore(Tehai tehai, Hai addHai, EKaze jikaze, AgariParam param = null) { if (param == null) { param = AgariParam; param.ResetDoraHais(); } param.setBakaze(getBaKaze()); param.setJikaze(jikaze); param.ResetYakuFlags(); // should reset params or create a new. if (m_activePlayer.IsReach) { if (m_activePlayer.IsDoubleReach) { param.setYakuFlag(EYakuFlagType.DOUBLE_REACH, true); } else { param.setYakuFlag(EYakuFlagType.REACH, true); } } if (m_isTsumo) { param.setYakuFlag(EYakuFlagType.TSUMO, true); if (m_isTenhou) { param.setYakuFlag(EYakuFlagType.TENHOU, true); } else if (m_isChihou) { param.setYakuFlag(EYakuFlagType.TIHOU, true); } } else if (m_isRenhou) { if (getPlayerIndex(jikaze) != OyaIndex) // only ko can Renhou. { param.setYakuFlag(EYakuFlagType.RENHOU, true); } } if (m_isTsumo && m_isRinshan) { param.setYakuFlag(EYakuFlagType.RINSYAN, true); } if (m_isChanKan) { param.setYakuFlag(EYakuFlagType.CHANKAN, true); } if (m_isLast) { if (m_isTsumo) { param.setYakuFlag(EYakuFlagType.HAITEI, true); } else { param.setYakuFlag(EYakuFlagType.HOUTEI, true); } } if (m_activePlayer.IsIppatsu) { param.setYakuFlag(EYakuFlagType.IPPATU, true); } if (GameSettings.UseKuitan) { param.setYakuFlag(EYakuFlagType.KUITAN, true); } return(AgariScoreManager.GetAgariScore(tehai, addHai, param, ref m_combis, ref m_agariInfo)); }
public int CalcShanten(Tehai tehai) { return sf.CalcShanten(tehai); }
public int CalcShanten(Tehai tehai, string pai) { return sf.CalcShanten(tehai, pai); }
/* * // 流局满贯 // * public static void SetNagashiMangan(AgariInfo agariInfo) * { * agariInfo.han = 5; * agariInfo.fu = 30; * agariInfo.scoreInfo = GetScoreInfo(5, 30); * * agariInfo.hanteiYakus = new YakuHelper.YakuHandler[] * { * new YakuHelper.CheckNagashimangan(null) * }; * } */ // 符を計算します public static int CalculateHu(Tehai tehai, Hai addHai, HaiCombi combi, AgariParam param, Yaku yaku) { int countHu = 20; //頭の牌を取得 Hai atamaHai = new Hai(Hai.NumKindToID(combi.atamaNumKind)); // 3元牌なら2符追加 if (atamaHai.Kind == Hai.KIND_SANGEN) { countHu += 2; } // 場風なら2符追加 if ((atamaHai.ID - Hai.ID_TON) == (int)param.getBakaze()) { countHu += 2; } // 自風なら2符追加 if ((atamaHai.ID - Hai.ID_TON) == (int)param.getJikaze()) { countHu += 2; } //平和が成立する場合は、待ちによる2符追加よりも優先される if (yaku.checkPinfu() == false) { // 単騎待ちの場合2符追加 if (addHai.NumKind == combi.atamaNumKind) { countHu += 2; } // 嵌張待ちの場合2符追加 // 数牌の2~8かどうか判定 if (addHai.IsYaochuu == false) { for (int i = 0; i < combi.shunCount; i++) { if ((addHai.NumKind - 1) == combi.shunNumKinds[i]) { countHu += 2; } } } // 辺張待ち(3)の場合2符追加 if (addHai.IsYaochuu == false && addHai.Num == Hai.NUM_3) { for (int i = 0; i < combi.shunCount; i++) { if ((addHai.NumKind - 2) == combi.shunNumKinds[i]) { countHu += 2; } } } // 辺張待ち(7)の場合2符追加 if (addHai.IsYaochuu == false && addHai.Num == Hai.NUM_7) { for (int i = 0; i < combi.shunCount; i++) { if (addHai.NumKind == combi.shunNumKinds[i]) { countHu += 2; } } } } // 暗刻による加点 Hai checkHai = null; for (int i = 0; i < combi.kouCount; i++) { checkHai = new Hai(Hai.NumKindToID(combi.kouNumKinds[i])); // 牌が字牌もしくは1,9 if (checkHai.IsYaochuu == true) { countHu += 8; } else { countHu += 4; } } Fuuro[] fuuros = tehai.getFuuros(); for (int i = 0; i < fuuros.Length; i++) { switch (fuuros[i].Type) { case EFuuroType.MinKou: { // 牌が字牌もしくは1,9 if (fuuros[i].Hais[0].IsYaochuu == true) { countHu += 4; } else { countHu += 2; } } break; case EFuuroType.KaKan: case EFuuroType.DaiMinKan: { // 牌が字牌もしくは1,9 if (fuuros[i].Hais[0].IsYaochuu == true) { countHu += 16; } else { countHu += 8; } } break; case EFuuroType.AnKan: { // 牌が字牌もしくは1,9 if (fuuros[i].Hais[0].IsYaochuu == true) { countHu += 32; } else { countHu += 16; } } break; } } // ツモ上がりで平和が成立していなければ2譜追加 if (param.getYakuFlag(EYakuFlagType.TSUMO) == true) { if (yaku.checkPinfu() == false) { countHu += 2; } } // 面前ロン上がりの場合は10符追加 if (param.getYakuFlag(EYakuFlagType.TSUMO) == false) { if (yaku.isNaki == false) { countHu += 10; } } // 一の位がある場合は、切り上げ if (countHu % 10 != 0) // 23 -> 30. { countHu = countHu - (countHu % 10) + 10; } return(countHu); }
public static int GetAgariScore(Tehai tehai, Hai addHai, AgariParam param, ref HaiCombi[] combis, ref AgariInfo agariInfo) { formatWorker.setCounterFormat(tehai, addHai); // あがりの組み合わせを取得します int combisCount = formatWorker.calculateCombisCount(combis); //Debug.Log ("GetAgariScore() combisCount="+combisCount); combis = formatWorker.getCombis(); /* * /// 1. check Chiitoitsu(七对子) * if( formatWorker.isChiitoitsu() ) * { * Yaku yaku = Yaku.NewYaku_Chiitoitsu(tehai, addHai, param); * * agariInfo.han = yaku.getHan(); * agariInfo.fu = 25; * agariInfo.hanteiYakus = yaku.getHanteiYakus(); * * agariInfo.scoreInfo = GetScoreInfo(agariInfo.han, agariInfo.fu); * * return agariInfo.scoreInfo.koAgari; * } */ /* * /// 2. check Kokushi(国士无双) * if( formatWorker.isKokushi() ) * { * Yaku yaku = Yaku.NewYaku_Kokushi(tehai, addHai, param); * * if( yaku.isKokushi ) * { * agariInfo.han = 13; * agariInfo.fu = 20; * agariInfo.hanteiYakus = yaku.getHanteiYakus(); * * agariInfo.scoreInfo = GetScoreInfo(agariInfo.han, agariInfo.fu); * * return agariInfo.scoreInfo.koAgari; * } * * return 0; * } */ //return combisCount; /// 3. check common combi yaku. if (combisCount <= 0) { return(0); } int[] hanSuuArr = new int[combisCount]; // 役 計算台數 //int[] huSuuArr = new int[combisCount]; // 符 //int[] scoreArr = new int[combisCount]; // 点数(子のロン上がり) int maxAgariScore = 0; // 最大の点数 for (int i = 0; i < combisCount; i++) { Yaku yaku = Yaku.NewYaku_Common(tehai, addHai, combis[i], param); hanSuuArr[i] = yaku.calculateHanSuu();//計算台數 //maxAgariScore += hanSuuArr[i]; //huSuuArr[i] = CalculateHu(tehai, addHai, combis[i], param, yaku); //Score scoreInfo = GetScoreInfo(hanSuuArr[i], huSuuArr[i]); //scoreArr[i] = scoreInfo.koAgari; if (hanSuuArr[i] > maxAgariScore) { agariInfo.han = hanSuuArr[i]; //agariInfo.fu = huSuuArr[i]; agariInfo.hanteiYakus = yaku.getHanteiYakus(); //agariInfo.scoreInfo = scoreInfo; maxAgariScore = hanSuuArr[i]; } } //agariInfo.han = maxAgariScore; //agariInfo.fu = 0; //agariInfo.scoreInfo = GetScoreInfo(5, 30); //agariInfo.hanteiYakus = yaku.getHanteiYakus(); // 最大値を探す //maxAgariScore = 0; //for(int i = 0; i < combisCount; i++) //{ // if( scoreArr[i] > maxAgariScore ) // maxAgariScore = scoreArr[i]; //} //return maxAgariScore; return(combisCount); }
/// <summary> /// Calculate all hai's count in tehai. the 'tehai' should be sorted. /// </summary> public void setCounterFormat(Tehai tehai, Hai addHai) { _counterArr.Clear(); int addHaiNumKind = 0; bool set = true; if (addHai != null) { addHaiNumKind = addHai.NumKind; set = false; } Hai[] jyunTehais = tehai.getJyunTehai(); for (int i = 0; i < jyunTehais.Length;) { int jyunTehaiNumKind = jyunTehais[i].NumKind; // if the first one hai's NK is bigger than the addHai's, // add the addHai to _counterArr firstly, then re-check the first one(as no i++). if (set == false && jyunTehaiNumKind > addHaiNumKind) { _counterArr.Add(new HaiCounterInfo(addHaiNumKind, 1)); set = true; continue; } // in middle range of tehai there exsits one as the same to addHai _counterArr.Add(new HaiCounterInfo(jyunTehaiNumKind, 1)); if (set == false && jyunTehaiNumKind == addHaiNumKind) { _counterArr[_counterArr.Count - 1].count++; set = true; } // check if the after one(at i+1) is the same to current one at 'i' while (++i < jyunTehais.Length) { if (jyunTehaiNumKind == jyunTehais[i].NumKind) { _counterArr[_counterArr.Count - 1].count++; } else { break; } } } // the addHai is the biggest one. if (set == false) { _counterArr.Add(new HaiCounterInfo(addHaiNumKind, 1)); } for (int i = 0; i < _counterArr.Count; i++) { if (_counterArr[i].count > MENTSU_LENGTH_MAX) { _counterArr[i].count = MENTSU_LENGTH_MAX; } } }
public void Dahai(TileId dahai) { Tehai.Remove(dahai); Tehai.Add(TsumoTile); }
protected override EResponse OnHandle_TsumoHai(EKaze fromPlayerKaze, Hai haiToHandle) { _action.Reset(); _action.State = EActionState.Select_Sutehai; if (inTest) { //_action.State = EActionState.Select_Sutehai; //return DisplayMenuList(); } // 手牌をコピーする。 Hai tsumoHai = haiToHandle; // check enable Tsumo int agariScore = MahjongAgent.getAgariScore(Tehai, tsumoHai, JiKaze); if (agariScore > 0) { if (GameSettings.AllowFuriten || !isFuriten()) { _action.IsValidTsumo = true; _action.MenuList.Add(EActionType.Tsumo); if (MahjongAgent.isReach(JiKaze)) { return(DisplayMenuList()); } } else { Utils.LogWarningFormat("Player {0} is enable tsumo but furiten...", JiKaze.ToString()); } } // 九种九牌check if (MahjongAgent.CheckHaiTypeOver9(Tehai, tsumoHai)) { _action.MenuList.Add(EActionType.RyuuKyoku); } // check enable Reach if (CheckReachPreConditions() == true) { List <int> reachHaiIndexList; if (MahjongAgent.tryGetReachHaiIndex(Tehai, tsumoHai, out reachHaiIndexList)) { _action.IsValidReach = true; _action.ReachHaiIndexList = reachHaiIndexList; _action.MenuList.Add(EActionType.Reach); } } // 制限事項。リーチ後のカンをさせない if (!MahjongAgent.isReach(JiKaze)) { if (MahjongAgent.getTotalKanCount() < GameSettings.KanCountMax) { // tsumo kans List <Hai> kanHais = new List <Hai>(); if (Tehai.validAnyTsumoKan(tsumoHai, kanHais)) { _action.setValidTsumoKan(true, kanHais); _action.MenuList.Add(EActionType.Kan); } } } else { if (MahjongAgent.getTotalKanCount() < GameSettings.KanCountMax) { // if player machi hais won't change after setting AnKan, enable to to it. if (Tehai.validAnKan(tsumoHai)) { List <Hai> machiHais; if (MahjongAgent.tryGetMachiHais(Tehai, out machiHais)) { Tehai tehaiCopy = new Tehai(Tehai); tehaiCopy.setAnKan(tsumoHai); tehaiCopy.Sort(); List <Hai> newMachiHais; if (MahjongAgent.tryGetMachiHais(tehaiCopy, out newMachiHais)) { if (machiHais.Count == newMachiHais.Count) { machiHais.Sort(Tehai.Compare); newMachiHais.Sort(Tehai.Compare); bool enableAnkan = true; for (int i = 0; i < machiHais.Count; i++) { if (machiHais[i].ID != newMachiHais[i].ID) { enableAnkan = false; break; } } if (enableAnkan == true) { _action.setValidTsumoKan(true, new List <Hai>() { tsumoHai }); _action.MenuList.Add(EActionType.Kan); _action.MenuList.Add(EActionType.Nagashi); _action.State = EActionState.Select_Kan; } } } } } // end if(valid ankan) } // end kan count check // can Ron or Ankan, sute hai automatically. if (_action.MenuList.Count == 0) { _action.SutehaiIndex = Tehai.getJyunTehaiCount(); // sute the tsumo hai on Reach return(DoResponse(EResponse.SuteHai)); } } // always display menu on pick tsumo hai. return(DisplayMenuList()); }
protected override EResponse OnHandle_SuteHai(EKaze fromPlayerKaze, Hai haiToHandle) { _action.Reset(); if (inTest) { //_action.MenuList.Add(EActionType.Nagashi); //return DisplayMenuList(); } Hai suteHai = haiToHandle; // check Ron int agariScore = MahjongAgent.getAgariScore(Tehai, suteHai, JiKaze); if (agariScore > 0) // Ron { if (GameSettings.AllowFuriten || !isFuriten()) { _action.IsValidRon = true; _action.MenuList.Add(EActionType.Ron); if (MahjongAgent.isReach(JiKaze)) { //_action.MenuList.Add( EActionType.Nagashi ); return(DisplayMenuList()); } else { _action.MenuList.Add(EActionType.Nagashi); } } else { Utils.LogWarningFormat("Player {0} is enable to ron but furiten...", JiKaze.ToString()); } } if (MahjongAgent.getTsumoRemain() <= 0) { return(DoResponse(EResponse.Nagashi)); } if (MahjongAgent.isReach(JiKaze)) { return(DoResponse(EResponse.Nagashi)); } // check menu Kan if (MahjongAgent.getTotalKanCount() < GameSettings.KanCountMax) { if (Tehai.validDaiMinKan(suteHai)) { _action.IsValidDaiMinKan = true; _action.MenuList.Add(EActionType.Kan); } } // check menu Pon if (Tehai.validPon(suteHai)) { _action.IsValidPon = true; _action.MenuList.Add(EActionType.Pon); } // check menu Chii int relation = Mahjong.getRelation(fromPlayerKaze, JiKaze); if (relation == (int)ERelation.KaMiCha) { List <Hai> sarashiHaiRight = new List <Hai>(); if (Tehai.validChiiRight(suteHai, sarashiHaiRight)) { _action.setValidChiiRight(true, sarashiHaiRight); if (!_action.MenuList.Contains(EActionType.Chii)) { _action.MenuList.Add(EActionType.Chii); } } List <Hai> sarashiHaiCenter = new List <Hai>(); if (Tehai.validChiiCenter(suteHai, sarashiHaiCenter)) { _action.setValidChiiCenter(true, sarashiHaiCenter); if (!_action.MenuList.Contains(EActionType.Chii)) { _action.MenuList.Add(EActionType.Chii); } } List <Hai> sarashiHaiLeft = new List <Hai>(); if (Tehai.validChiiLeft(suteHai, sarashiHaiLeft)) { _action.setValidChiiLeft(true, sarashiHaiLeft); if (!_action.MenuList.Contains(EActionType.Chii)) { _action.MenuList.Add(EActionType.Chii); } } } if (_action.MenuList.Count > 0) { _action.MenuList.Add(EActionType.Nagashi); return(DisplayMenuList()); } return(DoResponse(EResponse.Nagashi)); }
public void 点数算出テスト() { //親40符3翻 ダブ東 ツモ 7800点 { var expected = 7800; var tehai = new Tehai(new List <string>() { "1m", "2m", "3m", "4p", "5p", "6p", "7p", "7p", "7p", "9p", "9p", "E", "E", "E" }); var gameId = 0; var playerPosition = 0; var lastAddedPai = "E"; var ifr = new InfoForResult(gameId, playerPosition); ifr.IsTsumo = true; ifr.IsFured = false; ifr.IsMenzen = true; ifr.PassedTurn = 4; ifr.SetLastAddedPai(lastAddedPai); var fd = new Field(); var result = ResultCalclator.CalcHoraResult(tehai, ifr, fd, lastAddedPai); Assert.AreEqual(expected, result.pointResult.HoraPlayerIncome); } //親50符2翻 ツモ 三暗刻 { var expected = 9600; var tehai = new Tehai(new List <string>() { "1m", "1m", "1m", "2p", "2p", "2p", "4p", "5p", "5p", "5p", "6p", "E", "E", "5p" }); var gameId = 0; var playerPosition = 0; var lastAddedPai = "5p"; var ifr = new InfoForResult(gameId, playerPosition); ifr.IsTsumo = true; ifr.IsFured = false; ifr.IsMenzen = true; ifr.PassedTurn = 4; ifr.SetLastAddedPai(lastAddedPai); var fd = new Field(); var result = ResultCalclator.CalcHoraResult(tehai, ifr, fd, lastAddedPai); Assert.AreEqual(expected, result.pointResult.HoraPlayerIncome); } //子20符2翻 タンピン { var expected = 2000; var tehai = new Tehai(new List <string>() { "2m", "3m", "4m", "2p", "3p", "4p", "4p", "5p", "6p", "4s", "5s", "8s", "8s" }); var gameId = 0; var playerPosition = 1; var lastAddedPai = "6s"; var ifr = new InfoForResult(gameId, playerPosition); ifr.IsTsumo = false; ifr.IsFured = false; ifr.IsMenzen = true; ifr.PassedTurn = 4; var fd = new Field(); ifr.SetLastAddedPai(lastAddedPai); var result = ResultCalclator.CalcHoraResult(tehai, ifr, fd, lastAddedPai); Assert.AreEqual(expected, result.pointResult.HoraPlayerIncome); } //子20符3翻 タンヤオ三食一盃口 { var expected = 8000; var tehai = new Tehai(new List <string>() { "2m", "3m", "4m", "2p", "3p", "4p", "2p", "4p", "5s", "5s", "2s", "3s", "4s" }); var gameId = 0; var playerPosition = 1; var lastAddedPai = "3p"; var ifr = new InfoForResult(gameId, playerPosition); ifr.IsTsumo = false; ifr.IsFured = false; ifr.IsMenzen = true; ifr.PassedTurn = 4; var fd = new Field(); ifr.SetLastAddedPai(lastAddedPai); var result = ResultCalclator.CalcHoraResult(tehai, ifr, fd, lastAddedPai); Assert.AreEqual(expected, result.pointResult.HoraPlayerIncome); } //子40符1翻 自摸 { var expected = 1500; var tehai = new Tehai(new List <string>() { "1m", "2m", "3m", "3m", "4m", "5m", "1p", "1p", "1p", "2s", "3s", "4s", "5s", "5s" }); var gameId = 0; var playerPosition = 1; var lastAddedPai = "3m"; var ifr = new InfoForResult(gameId, playerPosition); ifr.IsTsumo = true; ifr.IsFured = false; ifr.IsMenzen = true; ifr.PassedTurn = 4; var fd = new Field(); ifr.SetLastAddedPai(lastAddedPai); var result = ResultCalclator.CalcHoraResult(tehai, ifr, fd, lastAddedPai); Assert.AreEqual(expected, result.pointResult.HoraPlayerIncome); } //子50符2翻 ロン { var expected = 3200; var tehai = new Tehai(new List <string>() { "1m", "1m", "1m", "2m", "2m", "2m", "1p", "1p", "1p", "2p", "3p", "4s", "4s" }); var gameId = 0; var playerPosition = 1; var lastAddedPai = "1p"; var ifr = new InfoForResult(gameId, playerPosition); ifr.IsTsumo = false; ifr.IsFured = false; ifr.IsMenzen = true; ifr.PassedTurn = 4; var fd = new Field(); ifr.SetLastAddedPai(lastAddedPai); var result = ResultCalclator.CalcHoraResult(tehai, ifr, fd, lastAddedPai); Assert.AreEqual(expected, result.pointResult.HoraPlayerIncome); } }
protected override EResponse OnHandle_TsumoHai(EKaze fromPlayerKaze, Hai haiToHandle) { _action.Reset(); if (inTest) { _action.SutehaiIndex = Tehai.getJyunTehaiCount(); return(DoResponse(EResponse.SuteHai)); } Hai tsumoHai = haiToHandle; // ツモあがりの場合は、イベント(ツモあがり)を返す。 int agariScore = MahjongAgent.getAgariScore(Tehai, tsumoHai, JiKaze); if (agariScore > 0) { if (GameSettings.AllowFuriten || !isFuriten()) { return(DoResponse(EResponse.Tsumo_Agari)); } else { Utils.LogWarningFormat("AI {0} is enable tsumo but furiten...", JiKaze.ToString()); } } // 九种九牌check if (MahjongAgent.CheckHaiTypeOver9(Tehai, tsumoHai)) { return(DoResponse(EResponse.Nagashi)); } // リーチの場合は、ツモ切りする if (MahjongAgent.isReach(JiKaze)) { _action.SutehaiIndex = Tehai.getJyunTehaiCount(); return(DoResponse(EResponse.SuteHai)); } // check enable Reach if (CheckReachPreConditions() == true) { List <int> reachHaiIndexList; if (MahjongAgent.tryGetReachHaiIndex(Tehai, tsumoHai, out reachHaiIndexList)) { _action.IsValidReach = true; _action.ReachHaiIndexList = reachHaiIndexList; thinkReach(); return(DoResponse(EResponse.Reach)); } } // 制限事項。リーチ後のカンをさせない if (!MahjongAgent.isReach(JiKaze)) { /* * if( MahjongAgent.getTotalKanCount() < GameSettings.KanCountMax ) * { * // TODO: tsumo kans * List<Hai> kanHais = new List<Hai>(); * if( Tehai.validAnyTsumoKan(tsumoHai, kanHais) ) * { * _action.setValidTsumoKan(true, kanHais); * * } * } */ } else { if (MahjongAgent.getTotalKanCount() < GameSettings.KanCountMax) { // if player machi hais won't change after setting AnKan, enable to to it. if (Tehai.validAnKan(tsumoHai)) { List <Hai> machiHais; if (MahjongAgent.tryGetMachiHais(Tehai, out machiHais)) { Tehai tehaiCopy = new Tehai(Tehai); tehaiCopy.setAnKan(tsumoHai); tehaiCopy.Sort(); List <Hai> newMachiHais; if (MahjongAgent.tryGetMachiHais(tehaiCopy, out newMachiHais)) { if (machiHais.Count == newMachiHais.Count) { machiHais.Sort(Tehai.Compare); newMachiHais.Sort(Tehai.Compare); bool enableAnkan = true; for (int i = 0; i < machiHais.Count; i++) { if (machiHais[i].ID != newMachiHais[i].ID) { enableAnkan = false; break; } } if (enableAnkan == true) { _action.setValidTsumoKan(true, new List <Hai>() { tsumoHai }); return(DoResponse(EResponse.Ankan)); } } } } } } // can Ron or Ankan, sute hai automatically. _action.SutehaiIndex = Tehai.getJyunTehaiCount(); // sute the tsumo hai on Reach return(DoResponse(EResponse.SuteHai)); } thinkSutehai(tsumoHai); return(DoResponse(EResponse.SuteHai)); }
// あがり点を取得する public int getAgariScore(Tehai tehai, Hai addHai, EKaze jikaze) { return(_game.GetAgariScore(tehai, addHai, jikaze)); }
// 打哪些牌可以立直. public bool tryGetReachHaiIndex(Tehai a_tehai, Hai tsumoHai, out List <int> haiIndexList) { haiIndexList = new List <int>(); // 鳴いている場合は、リーチできない。x //if( a_tehai.isNaki() ) // return false; /// find all reach-enabled hais in a_tehai, also the tsumoHai. _reachHaiList.Clear(); // As _jyunTehais won't sort automatically on new hais added, // so we can add tsumo hai directly to simplify the checks. Tehai tehai_copy = new Tehai(a_tehai); tehai_copy.addJyunTehai(tsumoHai); tehai_copy.Sort(); Hai[] jyunTehai = tehai_copy.getJyunTehai(); for (int i = 0; i < jyunTehai.Length; i++) { Hai haiTemp = tehai_copy.removeJyunTehaiAt(i); for (int id = Hai.ID_MIN; id <= Hai.ID_MAX; id++) { countFormat.setCounterFormat(tehai_copy, new Hai(id)); if (countFormat.calculateCombisCount(combis) > 0) { _reachHaiList.Add(new Hai(haiTemp)); break; } } tehai_copy.insertJyunTehai(i, haiTemp); } /// transfer to index list. if (_reachHaiList.Count > 0) { jyunTehai = a_tehai.getJyunTehai(); for (int i = 0; i < _reachHaiList.Count; i++) { for (int j = 0; j < jyunTehai.Length; j++) { if (jyunTehai[j].ID == _reachHaiList[i].ID && !haiIndexList.Contains(j)) { haiIndexList.Add(j); } } if (tsumoHai.ID == _reachHaiList[i].ID && !haiIndexList.Contains(jyunTehai.Length)) { haiIndexList.Add(jyunTehai.Length); } } haiIndexList.Sort(); return(true); } return(false); }
public static int GetAgariScore(Tehai tehai, Hai addHai, AgariParam param, ref HaiCombi[] combis, ref AgariInfo agariInfo) { formatWorker.setCounterFormat(tehai, addHai); // あがりの組み合わせを取得します int combisCount = formatWorker.calculateCombisCount(combis); combis = formatWorker.getCombis(); /// 1. check Chiitoitsu(七对子) if (formatWorker.isChiitoitsu()) { Yaku yaku = Yaku.NewYaku_Chiitoitsu(tehai, addHai, param); agariInfo.han = yaku.getHan(); agariInfo.fu = 25; agariInfo.hanteiYakus = yaku.getHanteiYakus(); agariInfo.scoreInfo = GetScoreInfo(agariInfo.han, agariInfo.fu); return(agariInfo.scoreInfo.koAgari); } /// 2. check Kokushi(国士无双) if (formatWorker.isKokushi()) { Yaku yaku = Yaku.NewYaku_Kokushi(tehai, addHai, param); if (yaku.isKokushi) { agariInfo.han = 13; agariInfo.fu = 20; agariInfo.hanteiYakus = yaku.getHanteiYakus(); agariInfo.scoreInfo = GetScoreInfo(agariInfo.han, agariInfo.fu); return(agariInfo.scoreInfo.koAgari); } return(0); } /// 3. check common combi yaku. if (combisCount <= 0) { return(0); } int[] hanSuuArr = new int[combisCount]; // 役 int[] huSuuArr = new int[combisCount]; // 符 int[] scoreArr = new int[combisCount]; // 点数(子のロン上がり) int maxAgariScore = 0; // 最大の点数 for (int i = 0; i < combisCount; i++) { Yaku yaku = Yaku.NewYaku_Common(tehai, addHai, combis[i], param); hanSuuArr[i] = yaku.calculateHanSuu(); huSuuArr[i] = CalculateHu(tehai, addHai, combis[i], param, yaku); Score scoreInfo = GetScoreInfo(hanSuuArr[i], huSuuArr[i]); scoreArr[i] = scoreInfo.koAgari; if (scoreArr[i] > maxAgariScore) { agariInfo.han = hanSuuArr[i]; agariInfo.fu = huSuuArr[i]; agariInfo.hanteiYakus = yaku.getHanteiYakus(); agariInfo.scoreInfo = scoreInfo; maxAgariScore = scoreArr[i]; } } // 最大値を探す maxAgariScore = 0; for (int i = 0; i < combisCount; i++) { if (scoreArr[i] > maxAgariScore) { maxAgariScore = scoreArr[i]; } } return(maxAgariScore); }
public static SplitedTehai CalcSplitedTehai(Tehai tehai, string horaPaiString, bool isRon) { //手配&和了牌の牌の合計枚数をカウント int[] inHandSyu = new int[MJUtil.LENGTH_SYU_ALL]; var redDoraCount = 0; var horaPai = new Pai(horaPaiString); foreach (var pai in tehai.tehai) { if (pai.IsRedDora) { redDoraCount++; } inHandSyu[pai.PaiNumber]++; } if (isRon) { inHandSyu[PaiConverter.STRING_TO_ID[horaPaiString]]++; } if (horaPai.IsRedDora && isRon) { redDoraCount++; } TehaiSpliter ts = new TehaiSpliter(); //手に残っている手配のターツ構成を全て算出 var splited = ts.SplitTehai(inHandSyu, tehai.furos, horaPaiString, isRon); foreach (var furo in tehai.furos) { switch (furo.furoType) { case MJUtil.TartsuType.MINSYUN: splited.SyuNum[furo.minPaiSyu]++; splited.SyuNum[furo.minPaiSyu + 1]++; splited.SyuNum[furo.minPaiSyu + 2]++; break; case MJUtil.TartsuType.MINKO: splited.SyuNum[furo.minPaiSyu] += 3; break; case MJUtil.TartsuType.MINKANTSU: splited.SyuNum[furo.minPaiSyu] += 4; break; case MJUtil.TartsuType.ANKANTSU: splited.SyuNum[furo.minPaiSyu] += 4; break; } if (furo.furopai.IsRedDora) { redDoraCount++; } foreach(var pai in furo.consumed) { if (pai.IsRedDora) { redDoraCount++; } } } //赤ドラの枚数セット splited.RedDoraNum = redDoraCount; return splited; }