private bool HasGameWinnerFromZones(out Player winner) { if (IsInfoEnabled) log.Info("HasGameWinnerFromZones?"); var requiredN = RequiredAdjacentZoneCount[players.Length]; var requiredT = RequiredTotalZoneCount[players.Length]; if (IsDebugEnabled) log.Debug("Must have {0} adjacent or {1} total zone", requiredN, requiredT); foreach (var p in players) { var playerN = Table.GetAdjacentZoneCount(p); var playerT = Table.GetOccupiedZoneCount(p); if (IsInfoEnabled) log.Info("Player {0} has {1} adjacent & {2} total.", p, playerN, playerT); if (playerN == requiredN || playerT == requiredT) { winner = p; return true; } } winner = null; return false; }
private bool HasGameWinnerIfTableFull(out Player winner) { if (IsInfoEnabled) log.Info("HasGameWinnerIfTableFull?"); if (Table.FreeZoneCount > 0) { if (IsInfoEnabled) log.Info("Table is not full yet."); winner = null; return false; } var playerZones = players.ToLookup(p => Table.GetOccupiedZoneCount(p)); winner = GetTopPlayerByScore(playerZones); return true; }
private void FromHandToDesk(Player p, Card c) { var state = states[p]; Debug.Assert(state.Hand.Contains(c)); Debug.Assert(!state.Desk.Contains(c)); state.Hand.Remove(c); state.Desk.Add(c); }
private void FromHandToPool(Player p, Card c) { var state = states[p]; deck.Pool(c); state.Hand.Remove(c); }
private void ExpectCurrentPlayer(Player p) { if (p != currentPlayer) throw new InvalidOperationException("Player {0} is not the active player.".F(p)); }
private Card ExpectInstanceOnDesk(Player p, CardType card) { var state = states[p]; var retval = state.Desk.FirstOrDefault(c => c.Kind == card); if (retval == null) { if (IsWarnEnabled) log.Warn("Expected card ON DESK {0} for {1}, not found", p, card); throw new InvalidOperationException("Player {0} does not have {1} in hand.".F(p, card)); } return retval; }
/// <summary> /// The player can move one card from Desk to Hand. /// </summary> public void RetrieveCard(Player p, Card card) { ExpectStep(Steps.RetrieveCard); ExpectCurrentPlayer(p); // -> selected card goes into hand (from desk) // specials cannot be retrieved // if card is null the player did not retrieve anything if (card != null) { var instance = ExpectInstanceOnDesk(p, card.Kind); if (instance.IsSpecial) throw new InvalidOperationException("Special cards cannot be retrieved. ({0}, {1})".F(p, card)); FromDeskToHand(p, instance); } // sc -> pool FromHandToPool(p, ExpectInstanceInHand(p, CardType.Scarecrow)); CurrentStep = Steps.PlayerDone; }
private void CalcNextStarter(Player winner) { if (IsInfoEnabled) log.Info("Game did not end, calculating next player."); // null -> the player next to the previous starter will start Player starter = null; if (winner != null) { // player having the most C on desk starts the next round // if no one has C on desk the winner will start the next round // if there is a tie then the last winner starts // if there is no winner the next player to the one starting the last round will start (eww) var courtesans = states.ToLookup(kvp => kvp.Value.Desk.Count(c => c.Kind == CardType.Courtesan), kvp => kvp.Key); if (log.IsDebugEnabled) { foreach (var g in courtesans) log.Debug("{0} courtesans: {1}", g.Key, String.Join(", ", g.Select(p => p.ToString()))); } starter = (courtesans[0].Count() == players.Length) ? winner : GetTopPlayerByScore(courtesans); // returns null if there is a tie } else { if (IsInfoEnabled) log.Info("Battle finished with tie, player after {0} starts.", players[battleStartPlayer]); } if (starter == null) { battleStartPlayer = (battleStartPlayer + 1) % players.Length; if (IsInfoEnabled) log.Info("Next player starts ({0})", players[battleStartPlayer]); } else { battleStartPlayer = Array.IndexOf<Player>(players, starter); if (IsInfoEnabled) log.Info("Calculated player starts ({0})", starter); } }
public void PlayCard(Player p, Card card) { ExpectStep(Steps.PlayerStart); ExpectCurrentPlayer(p); if (IsDebugEnabled) log.Debug("{0} played card {1}", p, card); card = ExpectInstanceInHand(p, card.Kind); // when a card transitions into a different state // then its state handler will select the next player switch (card.Kind) { // ask the player to select // which card to retrieve from the desk case CardType.Scarecrow: CurrentStep = Steps.RetrieveCard; return; // ask the player to protect/unprotect a zone // remove top non-specials case CardType.Bishop: CurrentStep = Steps.ProtectZone; return; // end of battle case CardType.Key: FromHandToPool(p, card); explicitNext = Steps.Key; return; // remove all winters from desk case CardType.Spring: FromDeskToPool(CardType.Winter); break; // remove all springs from desk case CardType.Winter: FromDeskToPool(CardType.Spring); break; } CurrentStep = Steps.PlayerDone; // just place the card on the desk FromHandToDesk(p, card); }
/// <summary> /// Bishop was played: /// - The player can mark one zone as Protected. (Use null to remove the current protection.) /// - Bishop also removes the largest card(s) from the desk /// </summary> public void ProtectZone(Player p, string zone) { ExpectStep(Steps.ProtectZone); ExpectCurrentPlayer(p); Table.ProtectedZone = zone; // bishop -> pool FromHandToPool(p, ExpectInstanceInHand(p, CardType.Bishop)); // technically the tops card must be removed when the bishop is played // OTOH the client can still fail while entering the marked zone // so delay the removal until every input is valid RemoveTopCards(); CurrentStep = Steps.PlayerDone; }
/// <summary> /// The player will not play more cards in this turn. /// </summary> /// <param name="p"></param> public void Pass(Player p) { ExpectStep(Steps.PlayerStart); ExpectCurrentPlayer(p); if (IsDebugEnabled) log.Debug("{0} passed", p); states[p].DidPass = true; CurrentStep = (states.Values.All(s => s.DidPass)) ? Steps._AllPassed : Steps.PlayerDone; }
/// <summary> /// Move to the next player /// </summary> public void NextPlayer() { CurrentStep = Steps.PlayerStart; for (var i = 0; i < players.Length; i++) { currentPlayerIndex = (currentPlayerIndex + 1) % players.Length; currentPlayer = players[currentPlayerIndex]; if (!states[currentPlayer].DidPass) return; } throw new InvalidOperationException("Everyone did pass and still looking for next?"); }
public void NewBattle() { ExpectStep(Steps.BattleStart); BattleIndex++; log.Info("New Battle: " + RoundIndex); foreach (var state in states.Values) { state.DidPass = false; // desk -> pool deck.Pool(state.Desk); state.Desk.Clear(); } if (IsDebugEnabled) log.Debug("BattleStartPlayer: " + players[battleStartPlayer]); currentPlayerIndex = battleStartPlayer; currentPlayer = players[battleStartPlayer]; }
public void MarkZone(Player p, string zone) { ExpectStep(Steps.MarkZone); ExpectCurrentPlayer(p); Table.CurrentZone = zone; if (IsInfoEnabled) log.Info("Player {0} marked zone {1}", p, zone); }
public void DropHand(Player p) { var state = states[p]; if (IsDebugEnabled) log.Debug("Dropping cards of {0}", p); // hand -> pool deck.Pool(state.Hand); state.Hand.Clear(); }