/// <summary> /// Makes move on the table, and flips the active player. A Move can be created using GetMove(command). /// </summary> public void MakeMove(Move move) { _moveNo++; if (move == null) { throw new NullReferenceException(); } currentMove = move; switch (move.MoveType) { case MoveTypes.Throwaway: GetActivePlayer().RemoveCard(move.CardPlayed); CardsOnTable.Add(move.CardPlayed); break; case MoveTypes.Pickup: GetActivePlayer().RemoveCard(move.CardPlayed); GetActivePlayer().AddCardsToLocalDeck(move.CardsPickedUp.Concat(new List <byte> { move.CardPlayed }).ToList()); CardsOnTable.RemoveAll(x => move.CardsPickedUp.Contains(x)); break; case MoveTypes.Build: break; case MoveTypes.Capture: break; default: throw new Exception(Errorstr.NoMove()); } FlipActivePlayer(); }
/*********************************************************************/ /************************** UTILITY METHODS **************************/ /*********************************************************************/ /// <summary> /// Assumes all BuildNames are extracted beforehand (example: alpha, beta). Run /// ExtractBuildNamesFromString() if there is uncertainty. /// </summary> private static List <byte> ExtractCardsFromString(string cmd) { cmd = cmd.Replace("10", "T"); string remain = cmd; List <byte> result = new List <byte>(); while (remain.Length > 0) { if (!charcardValAbbr.Contains(char.ToUpper(remain[0]))) { throw new UnparseableMoveException(Errorstr.CardFormat(), cmd); } if (remain.Length > 1 && cardSuitAbbrAscii.Contains(remain[1])) //example 5h { result.Add(ExtractCardFromString(remain.Substring(0, 2))); remain = remain.Substring(2); } else //examples 9, 92 (only parses 9 in both scenarios) { result.Add(ExtractCardFromString(remain.Substring(0, 1))); remain = remain.Substring(1); } } return(result); }
/// <summary> /// These cards will enter the player's Hand (playable cards), and not their local deck (earned cards). /// </summary> /// <param name="newCards">Cards received directly from Deck. Must be limited to max number of cards available in Hand at once.</param> public bool ReceiveCards(List <byte> newCards) { if (newCards.Count > (MAX_NUMBER_OF_CARDS - CountCardsInHand)) { throw new Exception(Errorstr.TooManyCards(Name + "'s hand", MAX_NUMBER_OF_CARDS, newCards.Count)); } _hand.AddRange(newCards); return(true); }
public Move AddCardsToExistingBuild(Build buildName, List <byte> cardsToAdd) { if ((cardsToAdd != null) && (!cardsToAdd.Any())) { CardsAddedToExistingBuild = new Tuple <Build, List <byte> >(buildName, cardsToAdd); } else { throw new Exception(Errorstr.EmptyBuild()); } return(this); }
public Move CreateNewBuild(List <byte> cardsInNewBuild) { if ((cardsInNewBuild != null) && (!cardsInNewBuild.Any())) { NewBuildCards = cardsInNewBuild; } else { throw new Exception(Errorstr.EmptyBuild()); } return(this); }
private static byte ExtractCardFromString(string cmd) { cmd = cmd.Replace("10", "T"); cmd = cmd.ToLower(); if (cmd.Length < 1 || cmd.Length > 2) { throw new UnparseableMoveException(Errorstr.CardFormat(), cmd); } CardVals value = CardVals.NONE; CardSuits suit = CardSuits.NONE; char cmdValue = cmd[0]; char cmdSuit = '\0'; if (cmd.Length == 2) { cmdSuit = cmd[1]; } foreach (CardVals val in Enum.GetValues(typeof(CardVals))) { char valabbr = char.ToLower(GetCardValAbbr((byte)val, true)[0]); if (valabbr == cmdValue) { value = val; break; } } if (value == CardVals.NONE) { throw new UnparseableMoveException(Errorstr.CardFormat(), cmd); } if (cmdSuit != '\0') { cmdSuit = char.ToLower(cmdSuit); foreach (CardSuits suitf in Enum.GetValues(typeof(CardSuits))) { char suitabbr = GetCardSuitAbbr((byte)suitf, true); if (suitabbr == cmdSuit) { suit = suitf; break; } } if (suit == CardSuits.NONE) { throw new UnparseableMoveException("Invalid suit provided to a card", cmd); } } byte result = GetCardDigit(value, suit); return(result); }
/// <summary> /// Adds cards directly to the deck at a specified index. /// </summary> /// <param name="atIndex">For atIndex = 0 being the top-most position, state the index to insert the first card.</param> /// <param name="cards">How many cards should be inserted?</param> public virtual Deck AddCards(short atIndex, List <byte> cards) { if (cards.Count + CardCount <= DECK_SIZE) { _cardDeck.InsertRange(atIndex, cards); } else { throw new Exception(Errorstr.TooManyCards("Adding cards", DECK_SIZE, cards.Count)); } canCreateNewDeck = false; return(this); }
/// <summary> /// Remove cards directly from this deck. NOTE: Use DrawCards() instead to have the function return the removed cards. /// </summary> /// <param name="startIndex">For startIndex = 0 being the top card, state index of first removable card.</param> /// <param name="count">From startIndex, how many cards should be removed?</param> public Deck RemoveCards(short startIndex, short count) { if (count == 0) { return(this); } if (count <= _cardDeck.Count) { _cardDeck.RemoveRange(startIndex, count); } else { throw new Exception(Errorstr.TooManyCards("Removing cards", CardCount, count)); } return(this); }
public Table(Deck deck, Player playerOne, Player playerTwo) { if (playerOne == null || p2 == playerTwo) { throw new NullReferenceException(); } p1 = playerOne; p2 = playerTwo; if ((deck.GetDeck().Count - INITIAL_CARDS_ON_TABLE) % CARDS_PER_PLAYER != 0) { throw new Exception(Errorstr.UnevenDeck()); } if (deck.GetDeck().Count != DECK_SIZE) { throw new Exception( Errorstr.WrongCardCount("The table", DECK_SIZE, deck.GetDeck().Count)); } TURN = Players.One; _deck = deck; }
private static Move Throwaway(string[] cmdArgs) { byte card = 0; if (cmdArgs.Length != 2) { throw new UnparseableMoveException("Two arguments expected. First argument throwaway, " + "second argument the card that is being thrown away.", string.Join(' ', cmdArgs)); } string throwawayCard = cmdArgs[1]; if (ExtractBuildNamesFromString(ref throwawayCard)?.Count() != 0) { throw new UnparseableMoveException("Build names cannot be used when throwing away cards.", string.Join(' ', cmdArgs)); } try { card = ExtractCardsFromString(throwawayCard)[0]; } catch (Exception ex) { if (ex is ArgumentOutOfRangeException || ex is ArgumentNullException || ex is UnparseableMoveException) { throw new UnparseableMoveException(Errorstr.NoMove(), string.Join(' ', cmdArgs)); } else { throw ex; } } card = GetCorrespondingCards(new List <byte> { card }, table.GetActivePlayer().Hand, (table.GetActivePlayer().PlayerNo == Players.One) ? CardLocations.PlayerOneHand : CardLocations.PlayerTwoHand)[0]; return(new Move(MoveTypes.Throwaway, card)); }
private static Move Pickup(string[] cmdArgs) { if (cmdArgs.Length < 2 || cmdArgs.Length > 3) { throw new UnparseableMoveException("Two or three arguments expected. First argument pickup, " + "second argument card on table, third argument card in hand.", string.Join(' ', cmdArgs)); } if (cmdArgs.Length == 2) { //"pickup 4" should be interpreted as "use the sole 4 in hand to pick up the sole 4 on table" cmdArgs = new string[3] { cmdArgs[0], cmdArgs[1], cmdArgs[1] } } ; string fromTable = cmdArgs[1]; string fromHand = cmdArgs[2]; if (ExtractBuildNamesFromString(ref fromTable)?.Count() != 0 || ExtractBuildNamesFromString(ref fromHand)?.Count() != 0) { throw new UnparseableMoveException("Build names cannot be used when picking up cards. Use capture instead.", string.Join(' ', cmdArgs)); } List <byte> playOnTableRaw, playOnTable; byte playFromHandRaw, playFromHand; playOnTableRaw = playOnTable = new List <byte>(); playFromHandRaw = playFromHand = 0; try { playOnTableRaw = ExtractCardsFromString(fromTable); playFromHandRaw = ExtractCardFromString(fromHand); } catch (Exception ex) { if (ex is ArgumentOutOfRangeException || ex is ArgumentNullException) { throw new UnparseableMoveException(Errorstr.NoMove(), string.Join(' ', cmdArgs)); } else { throw ex; } } playOnTable = GetCorrespondingCards(playOnTableRaw, table.CardsOnTable, CardLocations.Table); playFromHand = GetCorrespondingCards(new List <byte> { playFromHandRaw }, table.GetActivePlayer().Hand, (table.GetActivePlayer().PlayerNo == Players.One) ? CardLocations.PlayerOneHand : CardLocations.PlayerTwoHand)[0]; if (ContainsPictureCard(playOnTable.ToList())) { if (playOnTable.Count != 1 || !CardsMatchInValue(playFromHand, playOnTable[0])) { throw new IllegalPickupException( "Cannot pickup multiple picture cards at once", playFromHand, (byte)GetCardValue(playFromHand)); } } else { //if no error, then valid move Build build = new Build(BuildNames.NONE, playOnTable, (byte)GetCardValue(playFromHand)); } return(new Move(MoveTypes.Pickup).PlayCard(playFromHand).PickupCards(playOnTable)); }
/// <summary> /// Use this method at round end. Will assign point values and summary to players themselves. /// </summary> public void ScoreRound(byte currentRound) { if (_roundHasBeenScored) { throw new Exception(Errorstr.DuplicateRoundScore()); } List <ScoreableAttributes> p1Captures, p2Captures; p1Captures = new List <ScoreableAttributes>(); p2Captures = new List <ScoreableAttributes>(); SetActivePlayer(Players.One); /*STATIC VALUES*/ List <ScoreableAttributes> staticScoreables = CardNumberByStaticAttribute.Select(x => x.Key).ToList(); /*DYNAMIC VALUES*/ int p1CardCount, p2CardCount, p1SpadeCount, p2SpadeCount; p1SpadeCount = p2SpadeCount = 0; p1CardCount = p1.LocalDeck.CardCount; p2CardCount = p2.LocalDeck.CardCount; /*EVALUATE CARDS*/ do { Player player = GetActivePlayer(); List <ScoreableAttributes> captures = new List <ScoreableAttributes>(); CardVals value = CardVals.NONE; CardSuits suit = CardSuits.NONE; while (player.LocalDeck.CardCount > 0) { byte card = player.LocalDeck.DrawCards(1)[0]; value = GetCardValue(card); suit = GetCardSuit(card); /*STATIC*/ staticScoreables.Where(attr => CardNumberByStaticAttribute[attr].Equals(card)).ToList() .ForEach(attr => { captures.Add(attr); }); staticScoreables.RemoveAll(attr => captures.Contains(attr)); //efficiency reasons /*DYNAMIC*/ if (TURN == Players.One) { p1SpadeCount += (suit == CardSuits.Spades) ? 1 : 0; } if (TURN == Players.Two) { p2SpadeCount += (suit == CardSuits.Spades) ? 1 : 0; } } if (TURN == Players.One) { p1Captures.AddRange(captures); } else { p2Captures.AddRange(captures); } FlipActivePlayer(); } while (TURN != Players.One); /* EVAL DYNAMICS */ if (p1CardCount > p2CardCount) { p1Captures.Add(ScoreableAttributes.MostCards); } else if (p2CardCount > p1CardCount) { p2Captures.Add(ScoreableAttributes.MostCards); } if (p1SpadeCount > p2SpadeCount) { p1Captures.Add(ScoreableAttributes.MostSpades); } else if (p2SpadeCount > p1SpadeCount) { p2Captures.Add(ScoreableAttributes.MostSpades); } /* Conclusion - scores are evaluated by player */ p1.AddNewScoreLogEntry(p1Captures); p2.AddNewScoreLogEntry(p2Captures); _roundHasBeenScored = true; }