public Hint(Player p, int? suit, int? num) { this.For = p; // Check hint content; if (suit.HasValue && num.HasValue) throw new ArgumentException("both dimensions"); this.Suit = suit; this.Number = num; // Find matching card positions. this.Positions = new List<int>(); var cards = p.Hand(); for (int i = 0; i < cards.Count; i++) { bool match = num.HasValue ? num.Value == cards[i].Number : suit.Value == cards[i].Suit; if (match) this.Positions.Add(i); } if (Positions.Count <= 0) throw new ArgumentException("no matching cards"); }
public void AddOtherPlayersHintsToActions(List<Move> actions, Player initialPlayer) { foreach (var player in game.Players.Where(player => player != this && player != initialPlayer && player.WillPlayAgain)) { player.AddHintsToPossibleActions(actions); } }
public IEnumerable<Move> GetPossibleActions(Player initialPlayer) { var actions = new List<Move>(); AddGainToPossibleActions(actions); if (game.CanBurn()) AddBurnToPossibleActions(actions); if (game.CanHint()) AddOtherPlayersHintsToActions(actions, initialPlayer); actions.Add(Yolo()); return actions; }
public NumberHint(Player targetPlayer, int number) { TargetPlayer = targetPlayer; Number = number; }
public SuitHint(Player targetPlayer, Card.Suit suit) { TargetPlayer = targetPlayer; Suit = suit; }
public Simulation(Game game) { this.game = game;//.Copy(); initialScore = game.GetScore(); initialPlayer = game.GetCurrentPlayer(); }
public Move Play(Player me) { return Move.DoPlay(me.Cards[0]); }
public Move Play(Player me) { // Narrow down card possibilities by process of elimination. me.RestrictCards(); // Re-evaluate all cards based on new information in hand, board, and opponents' hands. foreach (HeldCard c in me.Cards) { c.Label = c.State(me); } // TODO: override states based on last hint (requires history) // TODO: immediately PLAY on recent hints according to position? // Keep any queued cards that have a known number or suit (likely received a hint). foreach (HeldCard c in me.Cards.Where(c => c.Label == Intent.QUEUE && (c.Number().HasValue || c.Suit().HasValue))) { c.Label = Intent.KEEP; } Player next = me.Next(); // Send critical hints, if possible. if (me.Game.Hints > 0) { // For playable cards, or cards wrongly marked playable, hint number, then suit (top of queue first). foreach (HeldCard c in next.Cards) { bool canPlay = me.Game.Deck.AllowPlay(c.Actual); if ((canPlay && c.Label != Intent.PLAY) || (!canPlay && c.Label == Intent.PLAY)) { if (!c.Number().HasValue) return Move.DoHint(new Hint(next, null, c.Actual.Number)); if (!c.Suit().HasValue) return Move.DoHint(new Hint(next, c.Actual.Suit, null)); } } // For pole cards that shouldn't be discarded, hint suit. This should move them into state KEEP. // Only hint when there are no PLAY or DISCARD cards, since these are higher priority. // TODO: enable this once we have better hinting. At the moment it does not help. /* if (next.Cards.FirstOrDefault(c => c.Label == Intent.PLAY || c.Label == Intent.DISCARD) == null) { var pole = next.Cards.FirstOrDefault(c => c.Label == Intent.QUEUE); if (pole != null && pole.Actual.LastChance(next, me)) { //if (!pole.Number().HasValue) return Move.DoHint(new Hint(next, null, pole.Actual.Number)); if (!pole.Suit().HasValue) return Move.DoHint(new Hint(next, pole.Actual.Suit, null)); } } */ } // Play cards that are ready (lowest number first). HeldCard play = me.Cards.Where(c => c.Label == Intent.PLAY) .OrderBy(c => c.Number().GetValueOrDefault(int.MaxValue)) .FirstOrDefault(); if (play != null) return Move.DoPlay(play); // Discard when we have cards ready to go (any order). HeldCard disc = me.Cards.FirstOrDefault(c => c.Label == Intent.DISCARD); if (disc != null) return Move.DoDiscard(disc); // TODO: send non-critical hints, like suit, especially when many hints are available // TODO: special hints for 5s? // Otherwise discard the first card from queue. HeldCard discq = me.Cards.FirstOrDefault(c => c.Label == Intent.QUEUE); if (discq != null) return Move.DoDiscard(discq); // TODO: Non-critical hint? // If we really have to, discard any card from the keep stack. // TODO: discard the _safest_ card (highest, or least played). return Move.DoPlay(me.Cards[0]); }