/// <summary> /// 各TileKindsが取りうる順列を列挙します。 /// </summary> /// <param name="source"></param> /// <param name="count"></param> /// <returns></returns> public static IList <TileKinds> Permutations(this TileKinds source, int count) { var result = new List <TileKinds>(); PermutationsInnner(source, count, new TileKinds(), result); return(result); }
public void Init(float length, int x, int y, TileKinds initialTileKind, GameObject parentGO) { column = x; row = y; tileKind = initialTileKind; this.gameObject.transform.SetParent(parentGO.transform); this.SetSize(length); Vector2 screenScale = this.GetComponent<RectTransform>().localScale; this.gameObject.transform.localPosition = new Vector3(x+0.5f, -y-0.5f, 1f) * length * screenScale.x; this.SetTileKind(); }
public override bool IsConditionMet(IList <TileKinds> hand, object[] args = null) { var chiSets = hand.Where(x => x.IsChi); if (chiSets.Count() < 3) { return(false); } var manChi = new List <TileKinds>(); var pinChi = new List <TileKinds>(); var souChi = new List <TileKinds>(); foreach (var item in chiSets) { if (item[0].IsMan) { manChi.Add(item); } if (item[0].IsPin) { pinChi.Add(item); } if (item[0].IsSou) { souChi.Add(item); } } foreach (var manItem in manChi) { foreach (var pinItem in pinChi) { foreach (var souItem in souChi) { var manNum = new TileKinds(manItem.Select(x => x.Simplify)); var pinNum = new TileKinds(pinItem.Select(x => x.Simplify)); var souNum = new TileKinds(souItem.Select(x => x.Simplify)); if (manNum.Equals(pinNum) && pinNum.Equals(souNum)) { return(true); } } } } return(false); }
private static void PermutationsInnner(TileKinds stock, int depth, TileKinds current, IList <TileKinds> result) { if (depth == 0) { result.Add(current); return; } for (var i = 0; i < stock.Count(); i++) { var copyOfStock = new TileKinds(stock); var copyOfCurrent = new TileKinds(current) { copyOfStock[i] }; copyOfStock.RemoveAt(i); PermutationsInnner(copyOfStock, depth - 1, copyOfCurrent, result); } }
private static TileKinds FindPairs(Tiles34 tiles34, int firstIndex = 0, int secondIndex = 33) { var pairIndices = new TileKinds(); for (var x = firstIndex; x <= secondIndex; x++) { //字牌の刻子は無視する(途中で分断して対子にはできない) if (HONOR_INDICES.Contains(x) && tiles34[x] != 2) { continue; } if (tiles34[x] >= 2) { pairIndices.Add(new TileKind(x)); } } return(pairIndices); }
private static IEnumerable <IEnumerable <TileKinds> > FindValidCombinations(Tiles34 tiles34, int firstIndex, int secondIndex, bool handNotCompleted = false) { //Tiles34[0,1,1,1,2,...]=>TileKinds[1,2,3,4,4,...] var indices = new TileKinds(); for (var x = firstIndex; x <= secondIndex; x++) { if (tiles34[x] > 0) { var l = indices.ToList(); l.AddRange(Enumerable.Repeat(new TileKind(x), tiles34[x])); indices = new TileKinds(l); } } if (indices.Count == 0) { return(new List <IEnumerable <TileKinds> >()); } //TileKindsのnP3全順列を列挙 //[1,2,3,4,4]=>[[1,2,3],[1,2,4],[1,3,2],[1,3,4],[1,4,2],[1,4,3],[1,4,4],...] var t = indices.Permutations(3); var allPossibleCombinations = t.Select(x => new TileKinds(x)); //刻子、順子の形をしている順列を抜きだす var validCombinations = new List <TileKinds>(); foreach (var combination in allPossibleCombinations) { if (combination.IsChi || combination.IsPon) { validCombinations.Add(combination); } } if (validCombinations.Count == 0) { return(new List <IEnumerable <TileKinds> >()); } var countOfNeededCombinations = indices.Count / 3; //有り得る順列のセットが一通りしかないとき if (countOfNeededCombinations == validCombinations.Count && indices.Equals(validCombinations.Aggregate( (x, y) => new TileKinds(Enumerable.Concat(x, y))))) { return new List <IEnumerable <TileKinds> > { validCombinations } } ; var validCombinationsCopy = new List <TileKinds>(validCombinations); foreach (var item in validCombinations) { if (!item.IsPon) { continue; } var countOfSets = 1; var countOfTiles = 0; while (countOfSets > countOfTiles) { countOfTiles = indices.Count(x => item[0].Equals(x)) / 3; countOfSets = validCombinationsCopy.Count(x => item[0].Equals(x[0]) && item[1].Equals(x[1]) && item[2].Equals(x[2])); if (countOfSets > countOfTiles) { validCombinationsCopy.Remove(item); } } } validCombinations = validCombinationsCopy; validCombinationsCopy = new List <TileKinds>(validCombinations); foreach (var item in validCombinations) { if (!item.IsChi) { continue; } var countOfSets = 5; var countOfPossibleSets = 4; while (countOfSets > countOfPossibleSets) { countOfSets = validCombinationsCopy.Count(x => item[0].Equals(x[0]) && item[1].Equals(x[1]) && item[2].Equals(x[2])); if (countOfSets > countOfPossibleSets) { validCombinationsCopy.Remove(item); } } } validCombinations = validCombinationsCopy; if (handNotCompleted) { return new List <IEnumerable <TileKinds> >() { validCombinations } } ; var possibleCombinations = new TileKinds(Enumerable.Range(0, validCombinations.Count)) .Permutations(countOfNeededCombinations); var combinationsResults = new List <IEnumerable <TileKinds> >(); foreach (var combination in possibleCombinations) { var result = new List <TileKind>(); foreach (var item in combination) { result.AddRange(validCombinations[item.Value]); } result.Sort((x, y) => x.CompareTo(y)); if (!indices.Equals(new TileKinds(result))) { continue; } var results = new List <TileKinds>(); foreach (var item in combination) { results.Add(validCombinations[item.Value]); } results.Sort((x, y) => x[0].CompareTo(y[0])); if (!combinationsResults.Contains_(results)) { combinationsResults.Add(results); } } return(combinationsResults); }
public static (List <FuDetail>, int) CalculateFu(IList <TileKinds> hand, TileId winTile, TileKinds winGroup, HandConfig config, IList <int> valuedTiles = null, IList <Meld> melds = null) { var winTileKind = winTile.ToTileKind(); if (valuedTiles is null) { valuedTiles = new List <int>(); } if (melds is null) { melds = new List <Meld>(); } var fuDetails = new List <FuDetail>(); if (hand.Count == 7) { fuDetails = new List <FuDetail> { new FuDetail(25, BASE) }; return(fuDetails, 25); } var pair = hand.Where(x => x.IsPair) .ToList()[0]; var ponSets = hand.Where(x => x.IsPon); var copiedOpenedMelds = melds.Where(x => x.Type == MeldType.CHI) .Select(x => x.TileKinds) .ToList(); var closedChiSets = new List <TileKinds>(); foreach (var x in hand) { if (!copiedOpenedMelds.Contains(x)) { closedChiSets.Add(x); } else { copiedOpenedMelds.Remove(x); } } var IsOpenHand = melds.Any(x => x.Opened); if (closedChiSets.Contains(winGroup)) { var tileIndex = winTileKind.Simplify; //ペンチャン if (winGroup.ContainsTerminal()) { //ペン12 if (tileIndex == 2 && winGroup.IndexOf(winTileKind) == 2) { fuDetails.Add(new FuDetail(2, PENCHAN)); } //ペン89 else if (tileIndex == 6 && winGroup.IndexOf(winTileKind) == 0) { fuDetails.Add(new FuDetail(2, PENCHAN)); } } //カン57 if (winGroup.IndexOf(winTileKind) == 1) { fuDetails.Add(new FuDetail(2, KANCHAN)); } } //符あり雀頭 var countOfValuedPairs = valuedTiles.Count(x => x == pair[0].Value); if (countOfValuedPairs == 1) { fuDetails.Add(new FuDetail(2, VALUED_PAIR)); } //雀頭ダブ東南4符 if (countOfValuedPairs == 2) { fuDetails.Add(new FuDetail(2, VALUED_PAIR)); fuDetails.Add(new FuDetail(2, VALUED_PAIR)); } //シャンポン待ち if (winGroup.IsPair) { fuDetails.Add(new FuDetail(2, PAIR_WAIT)); } foreach (var setItem in ponSets) { var openMelds = melds.Where(x => setItem.Equals(x.TileKinds)) .ToList(); var openMeld = openMelds.Count == 0 ? null : openMelds[0]; var setWasOpen = !(openMeld is null) && openMeld.Opened; var isKan = !(openMeld is null) && (openMeld.Type == MeldType.KAN || openMeld.Type == MeldType.CHANKAN); var isYaochu = YAOCHU_INDICES.Contains(setItem[0].Value); if (!config.IsTsumo && setItem.Equals(winGroup)) { setWasOpen = true; } if (isYaochu) { if (isKan) { if (setWasOpen) { fuDetails.Add(new FuDetail(16, OPEN_TERMINAL_KAN)); } else { fuDetails.Add(new FuDetail(32, CLOSED_TERMINAL_KAN)); } } else { if (setWasOpen) { fuDetails.Add(new FuDetail(4, OPEN_TERMINAL_PON)); } else { fuDetails.Add(new FuDetail(8, CLOSED_TERMINAL_PON)); } } } else { if (isKan) { if (setWasOpen) { fuDetails.Add(new FuDetail(8, OPEN_KAN)); } else { fuDetails.Add(new FuDetail(16, CLOSED_KAN)); } } else { if (setWasOpen) { fuDetails.Add(new FuDetail(2, OPEN_PON)); } else { fuDetails.Add(new FuDetail(4, CLOSED_PON)); } } } } var addTsumoFu = fuDetails.Count > 0 || config.Options.FuForPinfuTsumo; if (config.IsTsumo && addTsumoFu) { fuDetails.Add(new FuDetail(2, TSUMO)); } if (IsOpenHand && fuDetails.Count == 0 && config.Options.FuForOpenPinfu) { fuDetails.Add(new FuDetail(2, HAND_WITHOUT_FU)); } if (IsOpenHand || config.IsTsumo) { fuDetails.Add(new FuDetail(20, BASE)); } else { fuDetails.Add(new FuDetail(30, BASE)); } return(fuDetails, RoundFu(fuDetails)); }