/// <summary> /// Finds the TileTypeId of the discard with highest UkeIre while maintaining shanten. /// </summary> public int GetHighestUkeIreDiscard() { Debug.Assert(TilesInHand() == 14, "Have to be able to discard a tile"); // If we have a winning hand, all discards will lead to worse shanten var currentShanten = CalculateShanten(ArrangementValues); if (currentShanten == 0) { return(ConcealedTiles[0]); } var tileTypeId = 0; var localArrangements = new[] { ArrangementValues[0], ArrangementValues[1], ArrangementValues[2], ArrangementValues[3] }; var highestUkeIre = -1; var highestUkeIreDiscard = -1; for (var suit = 0; suit < 3; ++suit) { for (var index = 0; index < 9; ++index) { if (ConcealedTiles[tileTypeId] > 0) { var kyuuhaiValue = (0b100000001 >> index) & 1; ConcealedTiles[tileTypeId] -= 1; InHandByType[tileTypeId] -= 1; Kokushi.Discard(kyuuhaiValue, ConcealedTiles[tileTypeId]); Chiitoi.Discard(ConcealedTiles[tileTypeId]); Base5Hashes[suit] -= Base5.Table[index]; localArrangements[suit] = SuitClassifiers[suit].GetValue(ConcealedTiles, suit, Base5Hashes); var newShanten = CalculateShanten(localArrangements); if (newShanten == currentShanten) { var ukeIre = SumUkeIre(currentShanten, localArrangements, HonorClassifier); if (ukeIre > highestUkeIre) { highestUkeIre = ukeIre; highestUkeIreDiscard = tileTypeId; } } Base5Hashes[suit] += Base5.Table[index]; Kokushi.Draw(kyuuhaiValue, ConcealedTiles[tileTypeId]); Chiitoi.Draw(ConcealedTiles[tileTypeId]); ConcealedTiles[tileTypeId] += 1; InHandByType[tileTypeId] += 1; } tileTypeId += 1; } localArrangements[suit] = ArrangementValues[suit]; } for (var index = 0; index < 7; ++index) { if (ConcealedTiles[tileTypeId] > 0) { ConcealedTiles[tileTypeId] -= 1; InHandByType[tileTypeId] -= 1; var tileCountAfterDiscard = ConcealedTiles[tileTypeId]; Kokushi.Discard(1, tileCountAfterDiscard); Chiitoi.Discard(tileCountAfterDiscard); var localHonorClassifier = HonorClassifier.Clone(); localArrangements[3] = localHonorClassifier.Discard(tileCountAfterDiscard, JihaiMeldBit >> index & 1); var newShanten = CalculateShanten(localArrangements); if (newShanten == currentShanten) { var ukeIre = SumUkeIre(currentShanten, localArrangements, localHonorClassifier); if (ukeIre > highestUkeIre) { highestUkeIre = ukeIre; highestUkeIreDiscard = tileTypeId; } } Chiitoi.Draw(tileCountAfterDiscard); Kokushi.Draw(1, tileCountAfterDiscard); ConcealedTiles[tileTypeId] += 1; InHandByType[tileTypeId] += 1; } tileTypeId += 1; } Debug.Assert(highestUkeIreDiscard != -1, "There should always be a tile to discard."); return(highestUkeIreDiscard); }
public YakuConfig() { var id = 0; aka_dora = new AkaDora(++id); tenhou = new Tenhou(++id); // Yaku situations tsumo = new Tsumo(++id); riichi = new Riichi(++id); open_riichi = new OpenRiichi(++id); ippatsu = new Ippatsu(++id); chankan = new Chankan(++id); rinshan = new Rinshan(++id); haitei = new Haitei(++id); houtei = new Houtei(++id); daburu_riichi = new DaburuRiichi(++id); daburu_open_riichi = new DaburuOpenRiichi(++id); nagashi_mangan = new NagashiMangan(++id); renhou = new Renhou(++id); // Yaku 1 Han pinfu = new Pinfu(++id); tanyao = new Tanyao(++id); iipeiko = new Iipeikou(++id); haku = new Haku(++id); hatsu = new Hatsu(++id); chun = new Chun(++id); east = new East(++id); south = new South(++id); west = new West(++id); north = new North(++id); yakuhai_place = new YakuhaiPlace(++id); yakuhai_round = new YakuhaiRound(++id); // Yaku 2 Hans sanshoku = new Sanshoku(++id); ittsu = new Ittsu(++id); chantai = new Chanta(++id); honroto = new Honroutou(++id); toitoi = new Toitoi(++id); sanankou = new Sanankou(++id); sankantsu = new Sankantsu(++id); sanshoku_douko = new SanshokuDoukou(++id); chiitoitsu = new Chiitoitsu(++id); shosangen = new Shousangen(++id); // Yaku 3 Hans honitsu = new Honitsu(++id); junchan = new Junchan(++id); ryanpeiko = new Ryanpeikou(++id); // Yaku 6 Hans chinitsu = new Chinitsu(++id); // Yakuman list kokushi = new Kokushi(++id); chuuren_poutou = new ChuurenPoutou(++id); suuankou = new Suuankou(++id); daisangen = new Daisangen(++id); shosuushi = new Shousuushii(++id); ryuisou = new Ryuuiisou(++id); suukantsu = new Suukantsu(++id); tsuisou = new Tsuisou(++id); chinroto = new Chinroutou(++id); daisharin = new Daisharin(++id); daichisei = new Daichisei(++id); // Double yakuman daisuushi = new Daisuushii(++id); daburu_kokushi = new DaburuKokushi(++id); suuankou_tanki = new SuuankouTanki(++id); daburu_chuuren_poutou = new DaburuChuurenPoutou(++id); // Yakuman situations tenhou = new Tenhou(id++); chiihou = new Chiihou(++id); renhou_yakuman = new RenhouYakuman(++id); sashikomi = new Sashikomi(++id); paarenchan = new Paarenchan(++id); // Other dora = new Dora(++id); aka_dora = new AkaDora(++id); }
private int SumUkeIre(int currentShanten, int[] arrangements, ProgressiveHonorClassifier localHonorClassifier) { var ukeIre = 0; var tileTypeId = 0; var localArrangements = new[] { arrangements[0], arrangements[1], arrangements[2], arrangements[3] }; for (var suit = 0; suit < 3; ++suit) { for (var index = 0; index < 9; ++index) { if (InHandByType[tileTypeId] != 4) { var kyuuhaiValue = (0b100000001 >> index) & 1; Kokushi.Draw(kyuuhaiValue, ConcealedTiles[tileTypeId]); Chiitoi.Draw(ConcealedTiles[tileTypeId]); ConcealedTiles[tileTypeId] += 1; Base5Hashes[suit] += Base5.Table[index]; localArrangements[suit] = SuitClassifiers[suit].GetValue(ConcealedTiles, suit, Base5Hashes); var newShanten = CalculateShanten(localArrangements); Debug.Assert(currentShanten >= newShanten); var a = currentShanten - newShanten; var t = (4 - InHandByType[tileTypeId]) * a; ukeIre += t; ConcealedTiles[tileTypeId] -= 1; Base5Hashes[suit] -= Base5.Table[index]; Kokushi.Discard(kyuuhaiValue, ConcealedTiles[tileTypeId]); Chiitoi.Discard(ConcealedTiles[tileTypeId]); } tileTypeId += 1; } localArrangements[suit] = arrangements[suit]; } for (var index = 0; index < 7; ++index) { if (InHandByType[tileTypeId] != 4) { var previousTileCount = ConcealedTiles[tileTypeId]; Kokushi.Draw(1, previousTileCount); Chiitoi.Draw(previousTileCount); localArrangements[3] = localHonorClassifier.Clone().Draw(previousTileCount, JihaiMeldBit >> index & 1); var newShanten = CalculateShanten(localArrangements); Debug.Assert(currentShanten >= newShanten); var a = currentShanten - newShanten; var t = (4 - InHandByType[tileTypeId]) * a; ukeIre += t; Kokushi.Discard(1, previousTileCount); Chiitoi.Discard(previousTileCount); } tileTypeId += 1; } return(ukeIre); }