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;
                }
            }
        }
Example #4
0
        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}");
                                }
                            }
                        }
                    }
                }
            }
        }