Ejemplo n.º 1
0
        /// <summary>
        /// Filter: if the next-but-one player has too few cards, filter out any cards that would skip right to them.
        /// </summary>
        protected void FilterAnySkipsIfNextButOneWinning(List <Card> possibleCards)
        {
            if (CurrentHand.Count <= Config.PlayToWinThreshold)
            {
                // not filtering anything; I'm about to win!
                return;
            }

            bool nextButOnePlayerHasTooFewCards = (
                NextButOnePlayer != null &&
                CurrentCardCounts.ContainsKey(NextButOnePlayer) &&
                CurrentCardCounts[NextButOnePlayer] <= Config.PlayToWinThreshold
                );
            bool nextPlayerHasTooFewCards = (
                NextPlayer != null &&
                CurrentCardCounts.ContainsKey(NextPlayer) &&
                CurrentCardCounts[NextPlayer] <= Config.PlayToWinThreshold
                );

            if (nextButOnePlayerHasTooFewCards)
            {
                int nextButOneCount = CurrentCardCounts[NextButOnePlayer];
                if (nextPlayerHasTooFewCards)
                {
                    int nextCount = CurrentCardCounts[NextPlayer];
                    if (nextCount < nextButOneCount)
                    {
                        StrategyLogger.LogDebug(
                            "both next ({NextPlayer}) and next-but-one ({NextButOnePlayer}) player have <= {CardCountThreshold} cards, but next has fewer ({NextCardCount}) than next-but-one ({NextButOneCardCount}); not filtering out cards that would skip next and make it next-but-one's turn",
                            NextPlayer, NextButOnePlayer, Config.PlayToWinThreshold, nextCount, nextButOneCount
                            );
                        return;
                    }

                    StrategyLogger.LogDebug(
                        "both next ({NextPlayer}) and next-but-one ({NextButOnePlayer}) have <= {CardCountThreshold} cards, but next has more ({NextCardCount}) than next-but-one ({NextButOneCardCount}); filtering out cards that would skip next and make it next-but-one's turn",
                        NextPlayer, NextButOnePlayer, Config.PlayToWinThreshold, nextCount, nextButOneCount
                        );
                }
                else
                {
                    StrategyLogger.LogDebug(
                        "next-but-one player ({NextButOnePlayer}) has <= {CardCountThreshold} cards and next ({NextPlayer}) is not a danger; filtering out cards that would skip next and make it next-but-one's turn",
                        NextButOnePlayer, Config.PlayToWinThreshold, NextPlayer
                        );
                }

                possibleCards.RemoveAll(c => c.Value == CardValue.DrawTwo || c.Value == CardValue.WildDrawFour || c.Value == CardValue.Skip);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Filter: if the previous player has too few cards, filter out reverses.
        /// </summary>
        protected void FilterReverseIfPreviousWinning(List <Card> possibleCards)
        {
            if (CurrentHand.Count <= Config.PlayToWinThreshold)
            {
                // not filtering anything; I'm about to win!
                return;
            }

            // PreviousPlayer is null if it would equal NextPlayer otherwise
            if (PreviousPlayer != null && CurrentCardCounts.ContainsKey(PreviousPlayer) && CurrentCardCounts[PreviousPlayer] <= Config.PlayToWinThreshold)
            {
                StrategyLogger.LogDebug(
                    "previous player ({PreviousPlayer}) has {CardCountThreshold} cards or less ({CardCount}); filtering out reverses",
                    PreviousPlayer, Config.PlayToWinThreshold, CurrentCardCounts[PreviousPlayer]
                    );
                possibleCards.RemoveAll(c => c.Value == CardValue.Reverse);
            }
        }
Ejemplo n.º 3
0
        protected virtual void ProcessJsonEvent(JObject evt)
        {
            var eventName = (string)evt["event"];

            CommunicationLogger.LogDebug("received event {EventName}", eventName);

            bool playNow = false;

            switch (eventName)
            {
            case CurrentPlayerEventName:
            {
                // my turn? not my turn? (legacy)
                var currentPlayer = (string)evt["player"];
                playNow = (currentPlayer == ConnectionManager.MyNickname);
                break;
            }

            case CurrentPlayerOrderEventName:
            {
                // my turn? not my turn?
                var upcomingPlayers = (JArray)evt["order"];
                playNow    = ((string)upcomingPlayers[0] == ConnectionManager.MyNickname);
                NextPlayer = (upcomingPlayers.Count > 1)
                        ? (string)upcomingPlayers[1]
                        : null;
                // if upcomingPlayers.Count <= 2, then NextPlayer == PreviousPlayer
                PreviousPlayer = (upcomingPlayers.Count > 2)
                        ? (string)upcomingPlayers.Last
                        : null;
                // if upcomingPlayers.Count <= 2, then NextButOnePlayer == me
                NextButOnePlayer = (upcomingPlayers.Count > 2)
                        ? (string)upcomingPlayers[2]
                        : null;
                CurrentPlayers.Clear();
                CurrentPlayers.UnionWith(upcomingPlayers.Select(tok => (string)tok));
                break;
            }

            case CardCountsEventName:
            {
                var cardCounts = (JArray)evt["counts"];
                CurrentCardCounts.Clear();
                foreach (var playerAndCount in cardCounts.OfType <JObject>())
                {
                    var player = (string)playerAndCount["player"];
                    var count  = (int)playerAndCount["count"];
                    CurrentCardCounts[player] = count;
                }
                break;
            }

            case TopCardEventName:
            {
                var currentCardName = (string)evt["current_card"];
                TopCard = CardUtils.ParseColorAndValue(currentCardName).Value;
                break;
            }

            case HandInfoEventName:
            {
                var handCards = (JArray)evt["hand"];
                CurrentHand = handCards
                              .Select(e => CardUtils.ParseColorAndValue((string)e))
                              .Where(cav => cav.HasValue)
                              .Select(cav => cav.Value)
                              .ToList();
                if (LastHandCount > 0 && Config.ManyCardsCurseThreshold > 0 && CurrentHand.Count - LastHandCount >= Config.ManyCardsCurseThreshold)
                {
                    StrategyLogger.LogDebug("cursing because of overfilled hand");
                    Curse();
                }
                LastHandCount = CurrentHand.Count;
                break;
            }

            case CardDrawnEventName:
            {
                var player = (string)evt["player"];
                if (player == ConnectionManager.MyNickname)
                {
                    playNow = true;
                }
                break;
            }
            }

            if (playNow)
            {
                PlayACard();
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Strategy: try to destroy the next player if they are close to winning.
        /// </summary>
        protected StrategyContinuation StrategyDestroyNextPlayerIfDangerous(List <Card> possibleCards)
        {
            if (NextPlayer == null || !CurrentCardCounts.ContainsKey(NextPlayer))
            {
                // not sure who my next player is or how many cards they have
                return(StrategyContinuation.ContinueToNextStrategy);
            }

            StrategyLogger.LogDebug("next player {Nickname} has {CardCount} cards", NextPlayer, CurrentCardCounts[NextPlayer]);

            if (CurrentCardCounts[NextPlayer] > Config.PlayToWinThreshold)
            {
                // not dangerous
                return(StrategyContinuation.ContinueToNextStrategy);
            }

            // the player after me has too few cards; try finding an evil card first
            StrategyLogger.LogDebug("trying to find an evil card");

            // offensive cards first: D2, WD4
            possibleCards.AddRange(CurrentHand.Where(hc => hc.Color == TopCard.Color && hc.Value == CardValue.DrawTwo));
            possibleCards.AddRange(CurrentHand.Where(hc => hc.Value == CardValue.WildDrawFour));

            if (possibleCards.Count == 0)
            {
                // defensive cards next: S, R
                possibleCards.AddRange(CurrentHand.Where(hc =>
                                                         hc.Color == TopCard.Color && (
                                                             hc.Value == CardValue.Skip ||
                                                             hc.Value == CardValue.Reverse
                                                             )
                                                         ));
            }

            if (possibleCards.Count > 0)
            {
                StrategyLogger.LogDebug("we have at least one evil card for the next player ({Cards})", possibleCards.StringJoin(", "));

                // don't add the next pick
                return(StrategyContinuation.SkipAllOtherStrategiesUnlessFilteredEmpty);
            }
            else if (!DrewLast)
            {
                if (CurrentHand.Count <= Config.PlayToWinThreshold)
                {
                    StrategyLogger.LogDebug("not risking emergency strategic draw for evil card");
                }
                else if (Config.EmergencyStrategicDrawPercentage > 0)
                {
                    var emergencyStrategicDraw = (Randomizer.Next(100) < Config.EmergencyStrategicDrawPercentage);
                    if (emergencyStrategicDraw)
                    {
                        StrategyLogger.LogDebug("emergency strategic draw for evil card");
                        DrawACard();
                        return(StrategyContinuation.DontPlayCard);
                    }
                    else
                    {
                        StrategyLogger.LogDebug("skipping emergency strategic draw for evil card");
                    }
                }
            }

            return(StrategyContinuation.ContinueToNextStrategy);
        }
Ejemplo n.º 5
0
        protected virtual void HandleChannelMessage(object sender, IChannelMessageEventArgs args, MessageFlags flags)
        {
            if (flags.HasFlag(MessageFlags.UserBanned))
            {
                return;
            }

            if (args.SenderNickname == ConnectionManager.MyNickname)
            {
                return;
            }

            if (Config.UnoChannel != args.Channel)
            {
                return;
            }

            if (IsBotCommand(args.Message, "?join"))
            {
                ConnectionManager.SendChannelMessage(args.Channel, "!botjoin");

                // don't curse if the number of cards jumps up from 1 to 7 ;)
                LastHandCount = 0;

                return;
            }

            if (IsBotCommand(args.Message, "?leave"))
            {
                ConnectionManager.SendChannelMessage(args.Channel, "!leave");
                return;
            }

            if (args.Message.StartsWith("??color "))
            {
                var denyColor = false;
                if (!CurrentPlayers.Contains(args.SenderNickname))
                {
                    // player is not taking part
                    StrategyLogger.LogDebug("denying {Nickname}'s color request because they are a spectator", args.SenderNickname);
                    denyColor = true;
                }
                if (CurrentCardCounts.Values.All(v => v > Config.PlayToWinThreshold))
                {
                    // everybody has more than two cards
                    StrategyLogger.LogDebug("denying {Nickname}'s color request because everybody has more than {CardCount} cards", args.SenderNickname, Config.PlayToWinThreshold);
                    denyColor = true;
                }
                if (CurrentCardCounts.ContainsKey(args.SenderNickname) && CurrentCardCounts[args.SenderNickname] <= Config.PlayToWinThreshold)
                {
                    // the person who is asking has two cards or less
                    StrategyLogger.LogDebug("denying {Nickname}'s color request because they have {CardThreshold} cards or fewer ({CardCount})", args.SenderNickname, Config.PlayToWinThreshold, CurrentCardCounts[args.SenderNickname]);
                    denyColor = true;
                }
                if (CurrentHand.Count <= Config.PlayToWinThreshold)
                {
                    // I have two cards or less
                    StrategyLogger.LogDebug("denying {Nickname}'s color request because I have {CardThreshold} cards or fewer ({CardCount})", args.SenderNickname, Config.PlayToWinThreshold, CurrentHand.Count);
                    denyColor = true;
                }

                if (denyColor)
                {
                    ConnectionManager.SendChannelMessageFormat(args.Channel, "Sorry, {0}, no can do.", args.SenderNickname);
                    return;
                }

                var colorString = args.Message.Substring(("??color ").Length);
                var color       = CardUtils.ParseColor(colorString);
                if (!color.HasValue || color == CardColor.Wild)
                {
                    ConnectionManager.SendChannelMessage(args.Channel, "Uhh, what color is that?");
                    return;
                }

                ColorRequest = color;

                // can I change the color?
                if (CurrentHand.Any(c => c.Color == CardColor.Wild))
                {
                    ConnectionManager.SendChannelMessageFormat(args.Channel, "Yeah, I think that's doable, {0}.", args.SenderNickname);
                }
                else if (CurrentHand.Any(c => c.Color == color))
                {
                    ConnectionManager.SendChannelMessageFormat(args.Channel, "No color changers, but I'll try, {0}.", args.SenderNickname);
                }
                else
                {
                    ConnectionManager.SendChannelMessageFormat(args.Channel, "Ain't got the cards, {0}, but I'll try...", args.SenderNickname);
                }

                return;
            }

            var runtimeTweakMatch = RuntimeTweakPattern.Match(args.Message);

            if (runtimeTweakMatch.Success)
            {
                if (!Config.RuntimeTweakable)
                {
                    ConnectionManager.SendChannelMessageFormat(args.Channel, "Sorry, {0}, I'm not allowed to do that.", args.SenderNickname);
                    return;
                }

                try
                {
                    ConfigTweaking.TweakConfig(Config, runtimeTweakMatch.Groups["property"].Value, runtimeTweakMatch.Groups["value"].Value);
                }
                catch (ArgumentException ae)
                {
                    ConnectionManager.SendChannelMessageFormat(args.Channel, "That didn't work out, {0}: {1}", args.SenderNickname, ae.Message);
                    return;
                }
                ConnectionManager.SendChannelMessageFormat(args.Channel, "{0}: Done.", args.SenderNickname);

                return;
            }
        }