public void SomeHandsByRon(string handString, int roundWind, int seatWind, string discardString, Yaku expectedYaku) { var parser = new ShorthandParser(handString); var tiles = parser.Tiles.Select(t => Tile.FromTileType(t, 0)).ToList(); var melds = new List <State.Meld>(); foreach (var meld in parser.Melds) { var meldTiles = meld.Tiles.Select(t => Tile.FromTileType(t, 0)).ToList(); if (meld.MeldId < 8) { melds.Add(State.Meld.Chii(meldTiles, meldTiles.First())); } else if (meld.MeldId < 7 + 9) { melds.Add(State.Meld.Pon(meldTiles, meldTiles.First())); } else { melds.Add(State.Meld.Ankan(meld.Tiles.First())); } } var winningTile = TileType.FromString(discardString); var(yaku, fu) = ClassicScoreCalculator.Ron(winningTile, roundWind, seatWind, melds, tiles); Assert.Equal(expectedYaku, yaku); }
public void Tsumo(int who, PaymentInformation payment) { CalculationCount += 1; var seat = _board.Seats[who]; var draw = seat.CurrentDraw !; var roundWind = _board.RoundWind.Index; var seatWind = seat.SeatWind.Index; var(yaku, fu) = ClassicScoreCalculator.Tsumo(draw.TileType, roundWind, seatWind, seat.Melds, seat.ConcealedTiles); if ((payment.Yaku & ExternalYaku) == payment.Yaku && yaku != Yaku.None) { return; } if ((yaku & YakuFilter) != (payment.Yaku & YakuFilter) || fu != payment.Fu) { FailureCount += 1; } }
public void Ron(int who, int fromWho, PaymentInformation payment) { CalculationCount += 1; var seat = _board.Seats[who]; if (_currentShouminkanTile == null) { var discard = _board.CurrentDiscard !; var roundWind = _board.RoundWind.Index; var seatWind = seat.SeatWind.Index; var concealedTilesAndDiscard = seat.ConcealedTiles.Concat(new[] { discard }).ToList(); var(yaku, fu) = ClassicScoreCalculator.Ron(discard.TileType, roundWind, seatWind, seat.Melds, concealedTilesAndDiscard); if ((payment.Yaku & ExternalYaku) == payment.Yaku && yaku != Yaku.None) { return; } if ((yaku & YakuFilter) != (payment.Yaku & YakuFilter) || fu != payment.Fu) { FailureCount += 1; } } else { var discard = _currentShouminkanTile; var roundWind = _board.RoundWind.Index; var seatWind = seat.SeatWind.Index; var concealedTilesAndDiscard = seat.ConcealedTiles.Concat(new[] { discard }).ToList(); var(yaku, fu) = ClassicScoreCalculator.Chankan(discard.TileType, roundWind, seatWind, seat.Melds, concealedTilesAndDiscard); if ((payment.Yaku & ExternalYaku) == payment.Yaku && yaku != Yaku.None) { return; } if ((yaku & YakuFilter) != (payment.Yaku & YakuFilter) || fu != payment.Fu) { FailureCount += 1; } } }
private static void WriteWinningHandScores(string workingDirectory) { const int groupKinds = 34 + 21; const int maxGroupsHash = groupKinds * groupKinds * groupKinds * groupKinds; var pairs = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 31, 32 }; foreach (var pair in pairs) { Console.WriteLine($"pair: {pair}"); var path = Path.Combine(workingDirectory, $"standard{pair}.dat"); using var fileStream = File.Create(path); using var binaryWriter = new BinaryWriter(fileStream); var total = 0; for (var groupsHash = 0; groupsHash < maxGroupsHash; groupsHash++) { var tileCounts = new int[34]; tileCounts[pair] += 2; var k = new int[4]; var g = groupsHash; k[0] = g % groupKinds; g /= groupKinds; k[1] = g % groupKinds; g /= groupKinds; k[2] = g % groupKinds; g /= groupKinds; k[3] = g; if (k[0] > k[1] || k[1] > k[2] || k[2] > k[3]) { continue; } AddGroup(tileCounts, k[0]); AddGroup(tileCounts, k[1]); AddGroup(tileCounts, k[2]); AddGroup(tileCounts, k[3]); if (tileCounts.Any(c => c > 4)) { continue; } var invalidKanFlags = 0; for (var i = 0; i < 4; i++) { // Shuntsu can not be kan. No free tile can not be kan if (k[i] >= 34 || tileCounts[k[i]] == 4) { invalidKanFlags |= 2 << (i * 2); } } for (var m = 0; m < 256; m++) { if ((m & invalidKanFlags) != 0) { continue; } var concealedTiles = new int[34]; concealedTiles[pair] += 2; var melds = new List <Meld>(); for (var i = 0; i < 4; i++) { var meldType = (m >> (2 * i)) & 3; if (meldType > 0) { melds.Add(GetMeld(k[i], meldType)); } else { AddGroup(concealedTiles, k[i]); } } var tiles = new List <Tile>(); for (var i = 0; i < 34; i++) { var tileType = TileType.FromTileTypeId(i); for (var j = 0; j < concealedTiles[i]; j++) { var tile = Tile.FromTileType(tileType, j); tiles.Add(tile); } } for (var i = 0; i < 34; i++) { if (concealedTiles[i] == 0) { continue; } var winningTile = TileType.FromTileTypeId(i); var windConfigurations = SimpleWindConfiguration; if (pair >= 27 && pair < 31) { windConfigurations = WindConfigurations[pair - 27]; } foreach (var(roundWind, seatWind) in windConfigurations) { var(tsumoYaku, tsumoFu) = ClassicScoreCalculator.Tsumo(winningTile, roundWind, seatWind, melds, tiles); var tsumoHan = Han.Calculate(tsumoYaku); binaryWriter.Write((byte)tsumoHan); if (tsumoHan < 5) { binaryWriter.Write((byte)tsumoFu); } var(ronYaku, ronFu) = ClassicScoreCalculator.Ron(winningTile, roundWind, seatWind, melds, tiles); var ronHan = Han.Calculate(ronYaku); binaryWriter.Write((byte)ronHan); if (tsumoHan < 5) { binaryWriter.Write((byte)ronFu); } total += 1; if (total % 1000000 == 0) { var percentage = (double)groupsHash / maxGroupsHash; Console.WriteLine($"{percentage:P} {total}"); } } } } } } }