Ejemplo n.º 1
0
        public DiscardResponse OnDiscard(VisibleBoard board, Tile tile, int who, DiscardActions suggestedActions)
        {
            if ((suggestedActions & DiscardActions.Ron) != 0)
            {
                return(DiscardResponse.Ron());
            }

            if ((suggestedActions & DiscardActions.Kan) != 0)
            {
                return(DiscardResponse.Daiminkan());
            }

            if ((suggestedActions & DiscardActions.Pon) != 0)
            {
                var impossibleToKan = ImpossibleToKan(board);
                if (!impossibleToKan.Contains(tile.TileType))
                {
                    var tiles   = board.Watashi.ConcealedTiles.Where(t => t.TileType == tile.TileType).Take(2).ToList();
                    var discard = FindDiscard(board);
                    return(tiles.Contains(discard) ? DiscardResponse.Pass() : DiscardResponse.Pon(tiles[0], tiles[1], discard));
                }
            }

            return(DiscardResponse.Pass());
        }
Ejemplo n.º 2
0
        public DrawResponse OnDraw(VisibleBoard board, Tile tile, DrawActions suggestedActions)
        {
            if (suggestedActions.HasFlag(DrawActions.Tsumo))
            {
                return(DrawResponse.Tsumo());
            }

            if (suggestedActions.HasFlag(DrawActions.Riichi))
            {
                var tileTypeId = board.Watashi.Hand.GetHighestUkeIreDiscard();
                var discard    = board.Watashi.ConcealedTiles.First(i => i.TileType.TileTypeId == tileTypeId);
                return(DrawResponse.Riichi(discard));
            }

            if (suggestedActions.HasFlag(DrawActions.KyuushuKyuuhai) && (board.Watashi.Hand.Shanten > 2 || board.Seats.Any(s => s.DeclaredRiichi)))
            {
                return(DrawResponse.KyuushuKyuuhai());
            }

            {
                var tileTypeId = board.Watashi.Hand.GetHighestUkeIreDiscard();
                // Prefer tsumogiri
                if (tile.TileType.TileTypeId == tileTypeId)
                {
                    return(DrawResponse.Discard(tile));
                }

                var discard = board.Watashi.ConcealedTiles.First(i => i.TileType.TileTypeId == tileTypeId);
                return(DrawResponse.Discard(discard));
            }
        }
Ejemplo n.º 3
0
        public DiscardResponse OnDiscard(VisibleBoard board, Tile tile, int who, DiscardActions suggestedActions)
        {
            if (suggestedActions.HasFlag(DiscardActions.Ron))
            {
                return(DiscardResponse.Ron());
            }

            // Call value honors if it improves shanten. But don't call if already tenpai (all discards would be furiten)
            var shanten = board.Watashi.Hand.Shanten;

            if (shanten > 0 && suggestedActions.HasFlag(DiscardActions.Pon) && !suggestedActions.HasFlag(DiscardActions.Kan))
            {
                var tileType = tile.TileType;
                if (tileType.TileTypeId >= 31 || tileType == board.RoundWind || tileType == board.Watashi.SeatWind)
                {
                    var t = board.Watashi.Hand.WithPon(tileType);
                    if (t.Shanten < shanten)
                    {
                        var tilesInHand = board.Watashi.ConcealedTiles.Where(i => i.TileType.TileTypeId == tileType.TileTypeId).ToList();

                        var tileTypeId = t.GetHighestUkeIreDiscard();
                        var discard    = board.Watashi.ConcealedTiles.First(i => i.TileType.TileTypeId == tileTypeId);

                        return(DiscardResponse.Pon(tilesInHand[0], tilesInHand[1], discard));
                    }
                }
            }

            return(DiscardResponse.Pass());
        }
Ejemplo n.º 4
0
        public DrawResponse OnDraw(VisibleBoard board, Tile tile, DrawActions suggestedActions)
        {
            if ((suggestedActions & DrawActions.Tsumo) != 0)
            {
                return(DrawResponse.Tsumo());
            }

            if ((suggestedActions & DrawActions.KyuushuKyuuhai) != 0)
            {
                return(DrawResponse.KyuushuKyuuhai());
            }

            if ((suggestedActions & DrawActions.Kan) != 0)
            {
                var ankanTileType = board.Watashi.ConcealedTiles.GroupBy(t => t.TileType).FirstOrDefault(t => t.Count() == 4)?.Key;
                if (ankanTileType != null)
                {
                    return(DrawResponse.Ankan(ankanTileType));
                }

                var shouminkanTile = board.Watashi.ConcealedTiles.FirstOrDefault(t => board.Watashi.Melds.Any(m => m.MeldType == MeldType.Koutsu && m.LowestTile.TileType == t.TileType));
                if (shouminkanTile != null)
                {
                    return(DrawResponse.Shouminkan(tile));
                }
            }

            return(DrawResponse.Discard(FindDiscard(board)));
        }
Ejemplo n.º 5
0
 internal override bool CanExecute(VisibleBoard board, DrawActions possibleActions)
 {
     return(possibleActions.HasFlag(DrawActions.Kan) &&
            !board.Watashi.DeclaredRiichi &&
            HasTile(board, _tile) &&
            board.Watashi.Melds.Any(m => m.MeldType == MeldType.Koutsu && m.LowestTile.TileType == _tile.TileType));
 }
Ejemplo n.º 6
0
            internal override bool CanExecute(VisibleBoard board, DrawActions possibleActions)
            {
                if (!possibleActions.HasFlag(DrawActions.Kan) || board.Watashi.ConcealedTiles.Count(t => t.TileType == _tileType) != 4 || board.Watashi.CurrentDraw == null)
                {
                    return(false);
                }

                return(!board.Watashi.DeclaredRiichi || !board.Watashi.Hand.IsUkeIreChangedByAnkan(board.Watashi.CurrentDraw.TileType, _tileType));
            }
Ejemplo n.º 7
0
        private Tile FindDiscard(VisibleBoard board)
        {
            var impossibleToKan = ImpossibleToKan(board);

            var grouped   = board.Watashi.ConcealedTiles.GroupBy(t => t.TileType).OrderBy(g => g.Count()).ToList();
            var toDiscard = grouped.FirstOrDefault(g => impossibleToKan.Contains(g.Key)) ?? grouped.First();

            return(toDiscard.First());
        }
Ejemplo n.º 8
0
        private static HashSet <TileType> ImpossibleToKan(VisibleBoard board)
        {
            var visibleDiscards   = board.Seats.SelectMany(s => s.Discards);
            var visibleMelded     = board.Seats.Skip(1).SelectMany(s => s.Melds.SelectMany(m => m.Tiles));
            var visibleIndicators = board.DoraIndicators;
            var impossibleToKan   = visibleDiscards.Concat(visibleMelded).Concat(visibleIndicators).Select(t => t.TileType).Distinct().ToHashSet();

            return(impossibleToKan);
        }
Ejemplo n.º 9
0
 public Player()
 {
     Name            = "Player";
     Score           = 0;
     HiddenBoard     = new HiddenBoard();
     VisibleBoard    = new VisibleBoard();
     armada          = new ShipFleet();
     rowSelection    = 0;
     columnSelection = 0;
 }
Ejemplo n.º 10
0
        private static async Task Start(Decider decider, Board board, Wall wall, ISpectator spectator)
        {
            State state          = new Start();
            var   spectatorBoard = new VisibleBoard(board);

            while (!state.IsFinal)
            {
                state.Update(board, wall);
                spectator.Updated(spectatorBoard);
                await state.Decide(board, decider);

                state = state.Advance();
            }

            spectator.Updated(spectatorBoard);
        }
Ejemplo n.º 11
0
            internal override bool CanExecute(VisibleBoard board, DiscardActions possibleActions)
            {
                if (board.CurrentDiscard == null)
                {
                    return(false);
                }

                var tileType = board.CurrentDiscard.TileType;

                return(possibleActions.HasFlag(DiscardActions.Pon) &&
                       _tile0.TileType == tileType &&
                       _tile1.TileType == tileType &&
                       _discardAfterCall.TileType != tileType && // kuikae
                       HasTile(board, _tile0) &&
                       HasTile(board, _tile1) &&
                       HasTile(board, _discardAfterCall));
            }
Ejemplo n.º 12
0
        public TenhouClient(IPlayer player, ISpectator spectator)
        {
            _player    = player;
            _spectator = spectator;
            _lobby     = _player.Lobby;
            _playerId  = _player.Id;

            var folderName = MakeFolderName(_playerId);

            _directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TenhouAi", folderName);
            if (!Directory.Exists(_directory))
            {
                Directory.CreateDirectory(_directory);
            }

            _sessionLogFileName = Path.Combine(_directory, Path.GetRandomFileName() + ".txt");

            _wall         = new FakeWall();
            _board        = new Board(_wall);
            _visibleBoard = new VisibleBoard(_board);
        }
Ejemplo n.º 13
0
            internal override bool CanExecute(VisibleBoard board, DiscardActions possibleActions)
            {
                if (board.CurrentDiscard == null)
                {
                    return(false);
                }

                var tileType = board.CurrentDiscard.TileType;
                var tileTypeIds = new[] { _tile0.TileType.TileTypeId, _tile1.TileType.TileTypeId, tileType.TileTypeId }.OrderBy(x => x).ToList();

                var isValidDiscardForKanchanCase = tileTypeIds[1] == tileType.TileTypeId && _discardAfterCall.TileType != tileType;
                var isValidDiscard = isValidDiscardForKanchanCase || Kuikae.IsValidDiscardForNonKanchanChii(tileType, _discardAfterCall.TileType);

                return(possibleActions.HasFlag(DiscardActions.Chii) &&
                       tileTypeIds[0] + 1 == tileTypeIds[1] &&
                       tileTypeIds[1] + 1 == tileTypeIds[2] &&
                       isValidDiscard &&
                       HasTile(board, _tile0) &&
                       HasTile(board, _tile1) &&
                       HasTile(board, _discardAfterCall));
            }
Ejemplo n.º 14
0
 protected static bool HasTile(VisibleBoard board, Tile tile)
 {
     return(board.Watashi.ConcealedTiles.Contains(tile));
 }
Ejemplo n.º 15
0
 public void Updated(VisibleBoard board)
 {
 }
Ejemplo n.º 16
0
 public bool Chankan(VisibleBoard board, Tile tile, int who)
 {
     Delay(50);
     return(_player.Chankan(board, tile, who));
 }
Ejemplo n.º 17
0
 public DiscardResponse OnDiscard(VisibleBoard board, Tile tile, int who, DiscardActions suggestedActions)
 {
     Delay(50);
     return(_player.OnDiscard(board, tile, who, suggestedActions));
 }
Ejemplo n.º 18
0
 public DrawResponse OnDraw(VisibleBoard board, Tile tile, DrawActions suggestedActions)
 {
     Delay(50);
     return(_player.OnDraw(board, tile, suggestedActions));
 }
Ejemplo n.º 19
0
 public bool Chankan(VisibleBoard board, Tile tile, int who)
 {
     return(true);
 }
Ejemplo n.º 20
0
 internal override bool CanExecute(VisibleBoard board, DrawActions possibleActions)
 {
     return(possibleActions.HasFlag(DrawActions.KyuushuKyuuhai));
 }
Ejemplo n.º 21
0
 internal override bool CanExecute(VisibleBoard board, DrawActions possibleActions)
 {
     return(HasTile(board, _tile));
 }
Ejemplo n.º 22
0
 internal override bool CanExecute(VisibleBoard board, DiscardActions possibleActions)
 {
     return(true);
 }
Ejemplo n.º 23
0
 public void Updated(VisibleBoard board)
 {
     Broadcast(s => s.Updated(board));
 }
Ejemplo n.º 24
0
 internal override bool CanExecute(VisibleBoard board, DiscardActions possibleActions)
 {
     return(possibleActions.HasFlag(DiscardActions.Kan));
 }
Ejemplo n.º 25
0
 internal override bool CanExecute(VisibleBoard board, DrawActions possibleActions)
 {
     return(possibleActions.HasFlag(DrawActions.Riichi) &&
            HasTile(board, _tile) &&
            board.Watashi.Hand.ShantenAfterDiscard(_tile.TileType) == 0);
 }
Ejemplo n.º 26
0
 internal abstract bool CanExecute(VisibleBoard board, DiscardActions possibleActions);