├── Binaries ├── Autofac │ ├── Autofac.dll │ ├── Autofac.Configuration.dll │ ├── Autofac.Integration.Web.dll │ └── Autofac.Integration.Web.Mvc.dll ├── Newtonsoft.Json.dll ├── Rx │ ├── System.CoreEx.dll │ ├── System.Reactive.dll │ ├── System.Interactive.dll │ ├── System.Observable.dll │ └── System.Observable.xml ├── nunit.framework.dll ├── Microsoft.Web.Mvc.dll ├── MvcContrib │ ├── MvcContrib.dll │ └── MvcContrib.FluentHtml.dll └── SpecFlow │ ├── TechTalk.SpecFlow.dll │ ├── TechTalk.SpecFlow.Parser.dll │ └── TechTalk.SpecFlow.Generator.dll ├── Dominion.Web ├── Global.asax ├── Content │ ├── jqueryUI │ │ └── images │ │ │ ├── ui-icons_222222_256x240.png │ │ │ ├── ui-icons_2e83ff_256x240.png │ │ │ ├── ui-icons_454545_256x240.png │ │ │ ├── ui-icons_888888_256x240.png │ │ │ ├── ui-icons_cd0a0a_256x240.png │ │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ │ ├── ui-bg_flat_75_ffffff_40x100.png │ │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ │ ├── ui-bg_glass_75_dadada_1x400.png │ │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ │ │ ├── ui-bg_glass_95_fef1ec_1x400.png │ │ │ └── ui-bg_highlight-soft_75_cccccc_1x100.png │ └── HTMLPage1.htm ├── ViewModels │ ├── PlayerActionResultViewModel.cs │ ├── GameViewModel.cs │ └── NewGameViewModel.cs ├── ActionFilters │ └── InjectClientAttribute.cs ├── Views │ ├── Home │ │ └── ViewPlayers.aspx │ └── Shared │ │ └── site.Master ├── Web.config ├── Bootstrap │ └── AutofacConfig.cs ├── Web.Debug.config ├── Web.Release.config └── Properties │ └── AssemblyInfo.cs ├── Dominion.Rules ├── CardTypes │ ├── IMoneyCard.cs │ ├── ICurseCard.cs │ ├── ITreasureCard.cs │ ├── IVictoryCard.cs │ ├── ISCoreCard.cs │ ├── SameTypeEqualityComparer.cs │ └── IActionCard.cs ├── DiscardPile.cs ├── ICard.cs ├── TrashPile.cs ├── Activities │ ├── WaitingForPlayersActivity.cs │ ├── PlayActionsActivity.cs │ ├── DoBuysActivity.cs │ ├── IActivity.cs │ ├── ExtensionMethods.cs │ ├── GainACardActivity.cs │ └── SelectReactionActivity.cs ├── ILongLivedCardEffect.cs ├── LimitedSupplyCardPile.cs ├── DurationEffect.cs ├── PlayArea.cs ├── NullZone.cs ├── EnumerableCardZone.cs ├── CardPile.cs ├── Hand.cs ├── ReactionEffect.cs ├── GameScores.cs ├── UnlimitedSupplyCardPile.cs ├── Card.cs ├── PassiveCardEffectBase.cs ├── MyExtensions.cs ├── CardBank.cs └── Properties │ └── AssemblyInfo.cs ├── Dominion.WinForms ├── app.config ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ └── AssemblyInfo.cs └── Program.cs ├── .gitignore ├── Dominion.Specs ├── Cards │ ├── Smithy.feature │ ├── Gardens.feature │ ├── Woodcutter.feature │ ├── Festival.feature │ ├── Laboratory.feature │ ├── Market.feature │ ├── WorkersVillage.feature │ ├── CouncilRoom.feature │ ├── Feast.feature │ ├── Harem.feature │ ├── GreatHall.feature │ ├── Moneylender.feature │ ├── Chapel.feature │ ├── MerchantShip.feature │ ├── Wharf.feature │ ├── ShantyTown.feature │ ├── Familiar.feature │ ├── Tactician.feature │ ├── CountingHouse.feature │ ├── Witch.feature │ ├── SeaHag.feature │ ├── KingsCourt.feature │ ├── Cutpurse.feature │ ├── Coppersmith.feature │ ├── Mine.feature │ ├── Courtyard.feature │ ├── Moat.feature │ ├── Workshop.feature │ ├── Expand.feature │ ├── Remodel.feature │ ├── Nobles.feature │ ├── TreasureMap.feature │ ├── Cellar.feature │ ├── University.feature │ ├── City.feature │ ├── Chancellor.feature │ ├── Duke.feature │ ├── Vineyard.feature │ ├── Envoy.feature │ ├── Warehouse.feature │ ├── Salvager.feature │ ├── Apprentice.feature │ ├── Mountebank.feature │ ├── TradingPost.feature │ ├── Explorer.feature │ ├── Baron.feature │ ├── Adventurer.feature │ ├── Torturer.feature │ └── Apothecary.feature ├── TurnMechanics.feature ├── TurnOrder.feature ├── Hosted │ ├── GameHost.feature │ └── Reactions.feature ├── GameLog.feature ├── Scoring.feature ├── Bindings │ ├── Extensions.cs │ ├── BindingBase.cs │ └── ScoringBindings.cs ├── GameEnd.feature └── Properties │ └── AssemblyInfo.cs ├── Dominion.GameHost ├── IGameActionMessage.cs ├── AI │ ├── BehaviourBased │ │ ├── ProbabilityExtensions.cs │ │ ├── SkipBuyBehaviour.cs │ │ ├── SkipActionsBehaviour.cs │ │ ├── CommentOnGameEndBehaviour.cs │ │ ├── DefaultSelectFromRevealedBehaviour.cs │ │ ├── BuyPotionBehaviour.cs │ │ ├── DefaultMakeChoiceBehaviour.cs │ │ ├── BigMoneyBuyBehaviour.cs │ │ ├── DefaultSelectFixedNumberOfCardsToPassOrTrashBehaviour.cs │ │ ├── BigMoneyAI.cs │ │ ├── DefaultSelectUpToNumberOfCardsToTrashBehaviour.cs │ │ ├── PlaySimpleActionsBehaviour.cs │ │ ├── DefaultDiscardOrRedrawCardsBehaviour.cs │ │ ├── SimpleAI.cs │ │ ├── DefaultSelectFixedNumberOfCardsForPlayBehaviour.cs │ │ ├── ProbabilityAI.cs │ │ ├── SelectFixedNumberOfCardsBehaviourBase.cs │ │ └── BuySimpleActionsBehaviour.cs │ ├── Treasure.cs │ └── VictoryCards.cs ├── BeginGameMessage.cs ├── EndTurnMessage.cs ├── MoveToBuyStepMessage.cs ├── CardBuilderExtensions.cs ├── BuyCardMessage.cs ├── PlayCardMessage.cs ├── ChoiceMessage.cs ├── ChooseAPileMessage.cs ├── SimpleStartingConfiguration.cs ├── ChosenStartingConfiguration.cs └── Properties │ └── AssemblyInfo.cs ├── README.markdown ├── Dominion.AIWorkbench ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ └── AssemblyInfo.cs └── Program.cs ├── Dominion.Cards ├── Treasure │ ├── Gold.cs │ ├── Copper.cs │ ├── Silver.cs │ ├── Platinum.cs │ └── Potion.cs ├── Curses │ └── Curse.cs ├── Actions │ ├── Village.cs │ ├── Woodcutter.cs │ ├── Smithy.cs │ ├── WorkersVillage.cs │ ├── Bazaar.cs │ ├── Laboratory.cs │ ├── Workshop.cs │ ├── Festival.cs │ ├── Courtyard.cs │ ├── University.cs │ ├── Market.cs │ ├── Harem.cs │ ├── Cellar.cs │ ├── CouncilRoom.cs │ ├── Expand.cs │ ├── ShantyTown.cs │ ├── Feast.cs │ ├── City.cs │ ├── Moat.cs │ ├── Ironworks.cs │ ├── MerchantShip.cs │ ├── Familiar.cs │ ├── Chapel.cs │ ├── Wharf.cs │ ├── Witch.cs │ ├── Coppersmith.cs │ ├── Cutpurse.cs │ ├── SeaHag.cs │ ├── TreasureMap.cs │ ├── Transmute.cs │ ├── Moneylender.cs │ ├── Tribute.cs │ ├── GhostShip.cs │ ├── CountingHouse.cs │ ├── Militia.cs │ ├── KingsCourt.cs │ ├── FishingVillage.cs │ ├── ThroneRoom.cs │ ├── Chancellor.cs │ ├── Spy.cs │ ├── Warehouse.cs │ ├── Explorer.cs │ ├── Rabble.cs │ ├── Apothecary.cs │ └── Salvager.cs ├── Victory │ ├── Duke.cs │ ├── Vineyard.cs │ ├── Colony.cs │ ├── Province.cs │ ├── Estate.cs │ ├── Duchy.cs │ └── Gardens.cs ├── Hybrid │ └── GreatHall.cs ├── TestCard.cs └── Properties │ └── AssemblyInfo.cs ├── Dominion.Tests ├── HelperExtensions.cs ├── CardMovementTests.cs └── Properties │ └── AssemblyInfo.cs ├── Dominion.5.1.ReSharper └── LICENSE.txt /Binaries/Autofac/Autofac.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/Autofac/Autofac.dll -------------------------------------------------------------------------------- /Binaries/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /Binaries/Rx/System.CoreEx.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/Rx/System.CoreEx.dll -------------------------------------------------------------------------------- /Binaries/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/nunit.framework.dll -------------------------------------------------------------------------------- /Binaries/Microsoft.Web.Mvc.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/Microsoft.Web.Mvc.dll -------------------------------------------------------------------------------- /Binaries/Rx/System.Reactive.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/Rx/System.Reactive.dll -------------------------------------------------------------------------------- /Binaries/MvcContrib/MvcContrib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/MvcContrib/MvcContrib.dll -------------------------------------------------------------------------------- /Binaries/Rx/System.Interactive.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/Rx/System.Interactive.dll -------------------------------------------------------------------------------- /Binaries/Rx/System.Observable.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/Rx/System.Observable.dll -------------------------------------------------------------------------------- /Binaries/SpecFlow/TechTalk.SpecFlow.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/SpecFlow/TechTalk.SpecFlow.dll -------------------------------------------------------------------------------- /Dominion.Web/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="Dominion.Web.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /Binaries/Autofac/Autofac.Configuration.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/Autofac/Autofac.Configuration.dll -------------------------------------------------------------------------------- /Binaries/Autofac/Autofac.Integration.Web.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/Autofac/Autofac.Integration.Web.dll -------------------------------------------------------------------------------- /Binaries/MvcContrib/MvcContrib.FluentHtml.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/MvcContrib/MvcContrib.FluentHtml.dll -------------------------------------------------------------------------------- /Binaries/SpecFlow/TechTalk.SpecFlow.Parser.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/SpecFlow/TechTalk.SpecFlow.Parser.dll -------------------------------------------------------------------------------- /Binaries/Autofac/Autofac.Integration.Web.Mvc.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/Autofac/Autofac.Integration.Web.Mvc.dll -------------------------------------------------------------------------------- /Binaries/SpecFlow/TechTalk.SpecFlow.Generator.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Binaries/SpecFlow/TechTalk.SpecFlow.Generator.dll -------------------------------------------------------------------------------- /Dominion.Rules/CardTypes/IMoneyCard.cs: -------------------------------------------------------------------------------- 1 | namespace Dominion.Rules.CardTypes 2 | { 3 | public interface IMoneyCard : ITreasureCard 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /Dominion.Rules/CardTypes/ICurseCard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Dominion.Rules.CardTypes 4 | { 5 | public interface ICurseCard : IScoreCard 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /Dominion.Web/Content/jqueryUI/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Dominion.Web/Content/jqueryUI/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /Dominion.Web/Content/jqueryUI/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Dominion.Web/Content/jqueryUI/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /Dominion.Web/Content/jqueryUI/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Dominion.Web/Content/jqueryUI/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /Dominion.Web/Content/jqueryUI/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Dominion.Web/Content/jqueryUI/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /Dominion.Web/Content/jqueryUI/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Dominion.Web/Content/jqueryUI/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /Dominion.Web/Content/jqueryUI/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Dominion.Web/Content/jqueryUI/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /Dominion.WinForms/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Dominion.Web/Content/jqueryUI/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Dominion.Web/Content/jqueryUI/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /Dominion.Web/Content/jqueryUI/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Dominion.Web/Content/jqueryUI/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /Dominion.Web/Content/jqueryUI/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Dominion.Web/Content/jqueryUI/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /Dominion.Web/Content/jqueryUI/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Dominion.Web/Content/jqueryUI/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /Dominion.Web/Content/jqueryUI/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Dominion.Web/Content/jqueryUI/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /Dominion.Web/Content/jqueryUI/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Dominion.Web/Content/jqueryUI/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /Dominion.Rules/CardTypes/ITreasureCard.cs: -------------------------------------------------------------------------------- 1 | namespace Dominion.Rules.CardTypes 2 | { 3 | public interface ITreasureCard : ICard 4 | { 5 | CardCost Value { get; } 6 | } 7 | } -------------------------------------------------------------------------------- /Dominion.Web/Content/jqueryUI/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulbatum/Dominion/HEAD/Dominion.Web/Content/jqueryUI/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | obj 2 | bin 3 | _ReSharper.* 4 | *.csproj.user 5 | *.resharper.user 6 | *.ReSharper.user 7 | *.resharper 8 | *.suo 9 | *.cache 10 | *~ 11 | *.swp 12 | Dominion.Web/Content/Images/Cards 13 | *.Publish.xml -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Smithy.feature: -------------------------------------------------------------------------------- 1 | Feature: Smithy 2 | 3 | Scenario: Play Smithy 4 | Given A new game with 3 players 5 | And Player1 has a Smithy in hand instead of a Copper 6 | When Player1 plays a Smithy 7 | Then Player1 should have 7 cards in hand -------------------------------------------------------------------------------- /Dominion.Web/ViewModels/PlayerActionResultViewModel.cs: -------------------------------------------------------------------------------- 1 | using Dominion.GameHost; 2 | 3 | namespace Dominion.Web.ViewModels 4 | { 5 | public class PlayerActionResultViewModel 6 | { 7 | public GameViewModel GameState { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Gardens.feature: -------------------------------------------------------------------------------- 1 | Feature: Gardens 2 | 3 | Scenario: GardensInDeck 4 | Given A new game with 3 players 5 | And Player1 has a Gardens in hand instead of a Copper 6 | When The game is scored 7 | Then Player1 should have 4 victory points 8 | -------------------------------------------------------------------------------- /Dominion.GameHost/IGameActionMessage.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | 3 | namespace Dominion.GameHost 4 | { 5 | public interface IGameActionMessage 6 | { 7 | void UpdateGameState(Game game); 8 | void Validate(Game game); 9 | } 10 | } -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Dominion # 2 | 3 | This is a C# implementation of [Dominion](http://www.riograndegames.com/games.html?id=278), a board/card game. 4 | 5 | Be aware that the web client isn't very usable after cloning the repository because I do not distribute the card images. 6 | -------------------------------------------------------------------------------- /Dominion.Rules/CardTypes/IVictoryCard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Dominion.Rules.CardTypes 7 | { 8 | public interface IVictoryCard : IScoreCard 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Woodcutter.feature: -------------------------------------------------------------------------------- 1 | Feature: Woodcutter 2 | 3 | Scenario: Play Woodcutter 4 | Given A new game with 3 players 5 | And Player1 has a Woodcutter in hand instead of a Copper 6 | When Player1 plays a Woodcutter 7 | Then Player1 should have 2 buys 8 | Then Player1 should have 2 to spend -------------------------------------------------------------------------------- /Dominion.Web/Content/HTMLPage1.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Dominion.AIWorkbench/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Dominion.WinForms/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Dominion.Rules/CardTypes/ISCoreCard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Dominion.Rules.CardTypes 7 | { 8 | public interface IScoreCard : ICard 9 | { 10 | int Score(EnumerableCardZone allCards); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Dominion.Rules/DiscardPile.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Dominion.Rules 5 | { 6 | public class DiscardPile : EnumerableCardZone 7 | { 8 | public ICard TopCard 9 | { 10 | get { return this.Cards.Last(); } 11 | } 12 | 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /Dominion.Cards/Treasure/Gold.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules.CardTypes; 2 | using Dominion.Rules; 3 | 4 | namespace Dominion.Cards.Treasure 5 | { 6 | public class Gold : Card, IMoneyCard 7 | { 8 | public Gold() 9 | : base(6) 10 | { } 11 | 12 | public CardCost Value { get { return 3; } } 13 | } 14 | } -------------------------------------------------------------------------------- /Dominion.Cards/Treasure/Copper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dominion.Rules; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Cards.Treasure 6 | { 7 | public class Copper : Card, IMoneyCard 8 | { 9 | public Copper() : base(0) 10 | {} 11 | 12 | public CardCost Value { get { return 1; } } 13 | } 14 | } -------------------------------------------------------------------------------- /Dominion.Cards/Treasure/Silver.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules.CardTypes; 2 | using Dominion.Rules; 3 | 4 | namespace Dominion.Cards.Treasure 5 | { 6 | public class Silver : Card, IMoneyCard 7 | { 8 | public Silver() 9 | : base(3) 10 | { } 11 | 12 | public CardCost Value { get { return 2; } } 13 | } 14 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Festival.feature: -------------------------------------------------------------------------------- 1 | Feature: Festival 2 | 3 | Scenario: Play Festival 4 | Given A new game with 3 players 5 | And Player1 has a Festival in hand instead of a Copper 6 | When Player1 plays a Festival 7 | Then Player1 should have 2 to spend 8 | Then Player1 should have 2 buys 9 | Then Player1 should have 2 remaining action 10 | -------------------------------------------------------------------------------- /Dominion.Cards/Treasure/Platinum.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.CardTypes; 3 | 4 | namespace Dominion.Cards.Treasure 5 | { 6 | public class Platinum : Card, IMoneyCard 7 | { 8 | public Platinum() 9 | : base(9) 10 | { } 11 | 12 | public CardCost Value { get { return 5; } } 13 | } 14 | } -------------------------------------------------------------------------------- /Dominion.Rules/ICard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace Dominion.Rules 3 | { 4 | public interface ICard 5 | { 6 | CardCost Cost { get; } 7 | CardZone CurrentZone { get; } 8 | Guid Id { get; } 9 | void MoveTo(CardZone targetZone); 10 | string Name { get; } 11 | string ToString(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Dominion.Rules/TrashPile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Dominion.Rules 7 | { 8 | public class TrashPile : EnumerableCardZone 9 | { 10 | public ICard TopCard 11 | { 12 | get { return this.Cards.Last(); } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Dominion.Cards/Curses/Curse.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.CardTypes; 3 | 4 | namespace Dominion.Cards.Curses 5 | { 6 | public class Curse : Card, ICurseCard 7 | { 8 | public Curse() : base(0) { } 9 | 10 | public int Score(EnumerableCardZone allCards) 11 | { 12 | return -1; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Laboratory.feature: -------------------------------------------------------------------------------- 1 | Feature: Laboratory 2 | 3 | Background: 4 | Given A new game with 3 players 5 | And Player1 has a Laboratory in hand instead of a Copper 6 | When Player1 plays a Laboratory 7 | 8 | Scenario: Gain 2 Cards 9 | Then Player1 should have 6 cards in hand 10 | 11 | Scenario: Gain 1 Action 12 | Then Player1 should have 1 remaining action 13 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Market.feature: -------------------------------------------------------------------------------- 1 | Feature: Market 2 | 3 | Scenario: Play Market 4 | Given A new game with 3 players 5 | And Player1 has a Market in hand instead of a Copper 6 | When Player1 plays a Market 7 | Then Player1 should have 5 cards in hand 8 | Then Player1 should have 1 remaining action 9 | Then Player1 should have 2 buys 10 | Then Player1 should have 1 to spend 11 | -------------------------------------------------------------------------------- /Dominion.Rules/Activities/WaitingForPlayersActivity.cs: -------------------------------------------------------------------------------- 1 | namespace Dominion.Rules.Activities 2 | { 3 | public class WaitingForPlayersActivity : ActivityBase 4 | { 5 | public WaitingForPlayersActivity(Player waitingPlayer) 6 | : base(null, waitingPlayer, "Waiting for other players...", ActivityType.WaitingForOtherPlayers, null) 7 | { 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/WorkersVillage.feature: -------------------------------------------------------------------------------- 1 | Feature: Workers Village 2 | 3 | Scenario: Workers Village is +1 card +2 actions +1 buy 4 | Given A new game with 3 players 5 | And Player1 has a WorkersVillage in hand instead of a Copper 6 | When Player1 plays a WorkersVillage 7 | Then Player1 should have 5 cards in hand 8 | Then Player1 should have 2 remaining actions 9 | Then Player1 should have 2 buys -------------------------------------------------------------------------------- /Dominion.Specs/Cards/CouncilRoom.feature: -------------------------------------------------------------------------------- 1 | Feature: Council Room 2 | 3 | Scenario: Play CouncilRoom 4 | Given A new game with 3 players 5 | And Player1 has a CouncilRoom in hand instead of a Copper 6 | When Player1 plays a CouncilRoom 7 | Then Player1 should have 2 buys 8 | And Player1 should have 8 cards in hand 9 | And Player2 should have 6 cards in hand 10 | And Player3 should have 6 cards in hand -------------------------------------------------------------------------------- /Dominion.Tests/HelperExtensions.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | 3 | namespace Dominion.Tests 4 | { 5 | public static class HelperExtensions 6 | { 7 | public static CardZone AddNewCards(this CardZone targetZone, int count) where T : Card, new() 8 | { 9 | count.Times(() => new T().MoveTo(targetZone)); 10 | return targetZone; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Dominion.Cards/Treasure/Potion.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.CardTypes; 3 | 4 | namespace Dominion.Cards.Treasure 5 | { 6 | public class Potion : Card, ITreasureCard 7 | { 8 | public Potion() : base(4) 9 | { 10 | } 11 | 12 | public CardCost Value 13 | { 14 | get { return CardCost.Potion; } 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Dominion.Rules/Activities/PlayActionsActivity.cs: -------------------------------------------------------------------------------- 1 | namespace Dominion.Rules.Activities 2 | { 3 | public class PlayActionsActivity : ActivityBase 4 | { 5 | public PlayActionsActivity(Player activePlayer, int actions) 6 | : base(null, activePlayer, string.Format("Play actions. You have {0} action(s) remaining.", actions), ActivityType.PlayActions, null) 7 | { 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Village.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.CardTypes; 3 | namespace Dominion.Cards.Actions 4 | { 5 | public class Village : Card, IActionCard 6 | { 7 | public Village() : base(3) 8 | {} 9 | 10 | public void Play(TurnContext context) 11 | { 12 | context.RemainingActions += 2; 13 | context.DrawCards(1); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Dominion.Rules/Activities/DoBuysActivity.cs: -------------------------------------------------------------------------------- 1 | namespace Dominion.Rules.Activities 2 | { 3 | public class DoBuysActivity : ActivityBase 4 | { 5 | public DoBuysActivity(Player activePlayer, int buys, CardCost buyValue) 6 | : base(null, activePlayer, string.Format("Select card(s) to buy. You have {0} buy(s) for a total of {1}.", buys, buyValue), ActivityType.DoBuys, null) 7 | { 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Dominion.Rules/ILongLivedCardEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules.CardTypes; 6 | 7 | namespace Dominion.Rules 8 | { 9 | public interface ILongLivedCardEffect 10 | { 11 | ICard SourceCard { get; } 12 | void OnTurnStarting(TurnContext context); 13 | bool IsFinished { get; } 14 | } 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Woodcutter.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.CardTypes; 3 | 4 | namespace Dominion.Cards.Actions 5 | { 6 | public class Woodcutter : Card, IActionCard 7 | { 8 | public Woodcutter() 9 | : base(3) 10 | { } 11 | 12 | public void Play(TurnContext context) 13 | { 14 | context.AvailableSpend += 2; 15 | context.Buys += 1; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Dominion.Cards/Victory/Duke.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Dominion.Rules; 4 | using Dominion.Rules.CardTypes; 5 | 6 | namespace Dominion.Cards.Victory 7 | { 8 | public class Duke : Card, IVictoryCard 9 | { 10 | public Duke() : base(5) 11 | { 12 | } 13 | 14 | public int Score(EnumerableCardZone allCards) 15 | { 16 | return allCards.OfType().Count(); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Dominion.Cards/Victory/Vineyard.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Dominion.Rules; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Cards.Victory 6 | { 7 | public class Vineyard : Card, IVictoryCard 8 | { 9 | public Vineyard() : base(CardCost.Parse("0P")) 10 | {} 11 | 12 | public int Score(EnumerableCardZone allCards) 13 | { 14 | return allCards.OfType().Count() / 3; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Smithy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | using Dominion.Rules.CardTypes; 7 | 8 | namespace Dominion.Cards.Actions 9 | { 10 | public class Smithy : Card, IActionCard 11 | { 12 | public Smithy() : base(4) { } 13 | 14 | public void Play(TurnContext context) 15 | { 16 | context.DrawCards(3); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Feast.feature: -------------------------------------------------------------------------------- 1 | Feature: Feast 2 | 3 | Background: 4 | Given A new game with 3 players 5 | And Player1 has a Feast in hand instead of a Copper 6 | When Player1 plays a Feast 7 | 8 | Scenario: Player must choose a card to gain 9 | Then Player1 must gain a card of cost 5 or less 10 | 11 | Scenario: Player gains card 12 | When Player1 gains a Silver 13 | Then Player1 should have a Silver on top of the discard pile 14 | Then There should be a Feast on top of the trash pile 15 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Harem.feature: -------------------------------------------------------------------------------- 1 | Feature: Harem 2 | 3 | Scenario: Harem is worth 2 victory points 4 | Given A new game with 3 players 5 | And Player1 has a Harem in hand instead of a Copper 6 | When The game is scored 7 | Then Player1 should have 5 victory points 8 | 9 | Scenario: Harem is worth 2 spend 10 | Given A new game with 3 players 11 | And Player1 has a hand of Copper, Copper, Estate, Estate, Harem 12 | When Player1 moves to the buy step 13 | Then Player1 should have 4 to spend 14 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/GreatHall.feature: -------------------------------------------------------------------------------- 1 | Feature: Great Hall 2 | 3 | Background: 4 | Given A new game with 3 players 5 | 6 | Scenario: GreatHallInDeck 7 | And Player1 has a GreatHall in hand instead of a Copper 8 | When The game is scored 9 | Then Player1 should have 4 victory points 10 | 11 | Scenario: PlayGreatHall 12 | And Player1 has a GreatHall in hand instead of a Copper 13 | When Player1 plays a GreatHall 14 | Then Player1 should have 5 cards in hand 15 | Then Player1 should have 1 remaining action -------------------------------------------------------------------------------- /Dominion.Web/ViewModels/GameViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Web.Mvc; 4 | using Dominion.GameHost; 5 | using Dominion.Rules; 6 | 7 | namespace Dominion.Web.ViewModels 8 | { 9 | 10 | 11 | public static class CardImageHelper 12 | { 13 | public static string ResolveCardImage(this UrlHelper urlHelper, string cardName) 14 | { 15 | return urlHelper.Content(string.Format("~/Content/Images/Cards/{0}.jpg", cardName)); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/WorkersVillage.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.CardTypes; 3 | 4 | namespace Dominion.Cards.Actions 5 | { 6 | public class WorkersVillage : Card, IActionCard 7 | { 8 | public WorkersVillage() 9 | : base(4) 10 | { } 11 | 12 | public void Play(TurnContext context) 13 | { 14 | context.RemainingActions += 2; 15 | context.DrawCards(1); 16 | context.Buys += 1; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Dominion.Cards/Victory/Colony.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.CardTypes; 3 | 4 | namespace Dominion.Cards.Victory 5 | { 6 | public class Colony : Card, IVictoryCard 7 | { 8 | public Colony() 9 | : base(11) 10 | { } 11 | 12 | public int Value 13 | { 14 | get { return 10; } 15 | } 16 | 17 | public int Score(EnumerableCardZone allCards) 18 | { 19 | return Value; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Dominion.Cards/Victory/Province.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules.CardTypes; 2 | using Dominion.Rules; 3 | 4 | namespace Dominion.Cards.Victory 5 | { 6 | public class Province : Card, IVictoryCard 7 | { 8 | public Province() 9 | : base(8) 10 | {} 11 | 12 | public int Value 13 | { 14 | get { return 6; } 15 | } 16 | 17 | public int Score(EnumerableCardZone allCards) 18 | { 19 | return Value; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Dominion.Rules/Activities/IActivity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Dominion.Rules.Activities 5 | { 6 | public interface IActivity 7 | { 8 | string Message { get; } 9 | bool IsSatisfied { get; } 10 | Player Player { get; } 11 | ActivityType Type { get; } 12 | Guid Id { get; } 13 | IDictionary Properties { get; } 14 | string Source { get; } 15 | ActivityHint Hint { get; } 16 | } 17 | } -------------------------------------------------------------------------------- /Dominion.Rules/CardTypes/SameTypeEqualityComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Dominion.Rules.CardTypes 5 | { 6 | public class SameTypeEqualityComparer : EqualityComparer 7 | { 8 | public override bool Equals(T x, T y) 9 | { 10 | return GetHashCode(x) == GetHashCode(y); 11 | } 12 | 13 | public override int GetHashCode(T obj) 14 | { 15 | return obj.GetType().GetHashCode(); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Dominion.Cards/Victory/Estate.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules.CardTypes; 2 | using Dominion.Rules; 3 | namespace Dominion.Cards.Victory 4 | { 5 | public class Estate : Card, IVictoryCard 6 | { 7 | public Estate() : base(2) 8 | { 9 | Value = 1; 10 | } 11 | 12 | public int Value 13 | { 14 | get;private set; 15 | } 16 | 17 | public int Score(EnumerableCardZone allCards) 18 | { 19 | return Value; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Bazaar.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Dominion.Rules; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Cards.Actions 6 | { 7 | public class Bazaar : Card, IActionCard 8 | { 9 | public Bazaar() : base(5) 10 | { 11 | } 12 | 13 | public void Play(TurnContext context) 14 | { 15 | context.DrawCards(1); 16 | context.RemainingActions += 2; 17 | context.AvailableSpend += 1; 18 | } 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Dominion.Rules/LimitedSupplyCardPile.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | namespace Dominion.Rules 4 | { 5 | public class LimitedSupplyCardPile : CardPile 6 | { 7 | public override bool IsEmpty 8 | { 9 | get { return this.CardCount == 0; } 10 | } 11 | 12 | public override ICard TopCard 13 | { 14 | get { return Cards.FirstOrDefault(); } 15 | } 16 | 17 | public override bool IsLimited 18 | { 19 | get { return true; } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Dominion.Cards/Victory/Duchy.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules.CardTypes; 2 | using Dominion.Rules; 3 | 4 | namespace Dominion.Cards.Victory 5 | { 6 | public class Duchy : Card, IVictoryCard 7 | { 8 | public Duchy() 9 | : base(5) 10 | { 11 | Value = 3; 12 | } 13 | 14 | public int Value 15 | { 16 | get; 17 | private set; 18 | } 19 | 20 | public int Score(EnumerableCardZone allCards) 21 | { 22 | return Value; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Dominion.Rules/DurationEffect.cs: -------------------------------------------------------------------------------- 1 | namespace Dominion.Rules 2 | { 3 | public abstract class DurationEffect : ILongLivedCardEffect 4 | { 5 | public DurationEffect(ICard sourceCard) 6 | { 7 | SourceCard = sourceCard; 8 | IsFinished = false; 9 | } 10 | 11 | public ICard SourceCard { get; set; } 12 | public bool IsFinished { get; set; } 13 | 14 | public virtual void OnTurnStarting(TurnContext context) 15 | { 16 | IsFinished = true; 17 | } 18 | 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /Dominion.Rules/PlayArea.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Rules 6 | { 7 | public class PlayArea : EnumerableCardZone 8 | { 9 | public void SortForScoring() 10 | { 11 | foreach(var card in this.Cards 12 | .OrderByDescending(c => c is IScoreCard ? ((IScoreCard)c).Score(this) : -100) 13 | .ThenBy(c => c.Name)) 14 | { 15 | card.MoveTo(this); 16 | } 17 | } 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Laboratory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | using Dominion.Rules.CardTypes; 7 | 8 | namespace Dominion.Cards.Actions 9 | { 10 | public class Laboratory : Card, IActionCard 11 | { 12 | public Laboratory() : base(5) 13 | { 14 | } 15 | 16 | public void Play(TurnContext context) 17 | { 18 | context.RemainingActions += 1; 19 | context.DrawCards(2); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Workshop.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dominion.Rules; 3 | using Dominion.Rules.Activities; 4 | using Dominion.Rules.CardTypes; 5 | 6 | namespace Dominion.Cards.Actions 7 | { 8 | public class Workshop : Card, IActionCard 9 | { 10 | public Workshop() : base(3) 11 | { 12 | } 13 | 14 | public void Play(TurnContext context) 15 | { 16 | context.AddSingleActivity( 17 | Activities.GainACardCostingUpToX(context.Game.Log, context.ActivePlayer, 4, this), this); 18 | } 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /Dominion.Cards/Victory/Gardens.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dominion.Rules.CardTypes; 3 | using Dominion.Rules; 4 | 5 | namespace Dominion.Cards.Victory 6 | { 7 | public class Gardens : Card, IVictoryCard 8 | { 9 | 10 | public Gardens() 11 | : base(4) 12 | { 13 | } 14 | 15 | public int Score(EnumerableCardZone allCards) 16 | { 17 | return (allCards.CardCount / 10); 18 | } 19 | 20 | 21 | public int Value 22 | { 23 | get { return 0; } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Dominion.WinForms/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Windows.Forms; 5 | 6 | namespace Dominion 7 | { 8 | static class Program 9 | { 10 | /// 11 | /// The main entry point for the application. 12 | /// 13 | [STAThread] 14 | static void Main() 15 | { 16 | Application.EnableVisualStyles(); 17 | Application.SetCompatibleTextRenderingDefault(false); 18 | Application.Run(new GameForm()); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Moneylender.feature: -------------------------------------------------------------------------------- 1 | Feature: Moneylender 2 | 3 | Scenario: Moneylender with copper in hand 4 | Given A new game with 3 players 5 | And Player1 has a hand of Moneylender, Copper, Estate, Estate, Estate 6 | When Player1 plays a Moneylender 7 | Then Player1 should have 3 to spend 8 | And There should be a Copper on top of the trash pile 9 | 10 | Scenario: Moneylender without copper in hand 11 | Given A new game with 3 players 12 | And Player1 has a hand of Moneylender, Estate, Estate, Estate, Estate 13 | When Player1 plays a Moneylender 14 | Then Player1 should have 0 to spend 15 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Festival.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | using Dominion.Rules.CardTypes; 7 | 8 | namespace Dominion.Cards.Actions 9 | { 10 | public class Festival : Card, IActionCard 11 | { 12 | public Festival() : base(5) 13 | { 14 | } 15 | 16 | public void Play(TurnContext context) 17 | { 18 | context.RemainingActions += 2; 19 | context.Buys += 1; 20 | context.AvailableSpend += 2; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Chapel.feature: -------------------------------------------------------------------------------- 1 | Feature: Chapel 2 | 3 | Background: 4 | Given A new game with 3 players 5 | And Player1 has a hand of Chapel, Estate, Estate, Copper, Copper 6 | When Player1 plays a Chapel 7 | 8 | Scenario: Player must select a number of cards to trash 9 | Then Player1 may select up to 4 cards from their hand 10 | 11 | Scenario: Player trashes one card 12 | And Player1 selects a Copper to trash 13 | Then There should be a Copper on top of the trash pile 14 | 15 | Scenario: Player trashes nothing 16 | And Player1 selects nothing to trash 17 | Then Player1 should have 4 cards in hand 18 | -------------------------------------------------------------------------------- /Dominion.Rules/NullZone.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Dominion.Rules 4 | { 5 | public class NullZone : CardZone 6 | { 7 | protected override void AddCard(ICard card) 8 | { 9 | // NO OP 10 | } 11 | 12 | protected override void RemoveCard(ICard card) 13 | { 14 | // NO OP 15 | } 16 | 17 | public override int CardCount 18 | { 19 | get 20 | { 21 | throw new NotSupportedException("A null zone cannot be considered to have a card count"); 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Courtyard.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.Activities; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Cards.Actions 6 | { 7 | public class Courtyard : Card, IActionCard 8 | { 9 | public Courtyard() : base(2) 10 | { 11 | } 12 | 13 | public void Play(TurnContext context) 14 | { 15 | context.DrawCards(3); 16 | if (context.ActivePlayer.Hand.CardCount > 0) 17 | context.AddSingleActivity(Activities.PutCardFromHandOnTopOfDeck(context, this), this); 18 | } 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/ProbabilityExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Dominion.GameHost.AI.BehaviourBased 4 | { 5 | public static class ProbabilityExtensions 6 | { 7 | public static IEnumerable> GetCumulativeTotals(this IEnumerable> input) 8 | { 9 | var temp = 0; 10 | foreach (var item in input) 11 | { 12 | yield return new KeyValuePair(item.Key, item.Value + temp); 13 | temp += item.Value; 14 | } 15 | } 16 | 17 | } 18 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/University.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.Activities; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Cards.Actions 6 | { 7 | public class University : Card, IActionCard 8 | { 9 | public University() : base(CardCost.Parse("2P")) 10 | { 11 | } 12 | 13 | public void Play(TurnContext context) 14 | { 15 | context.RemainingActions += 2; 16 | context.AddSingleActivity( 17 | Activities.GainAnActionCardCostingUpToX(context.Game.Log, context.ActivePlayer, 5, this, true), this); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/SkipBuyBehaviour.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules.Activities; 2 | 3 | namespace Dominion.GameHost.AI.BehaviourBased 4 | { 5 | public class SkipBuyBehaviour : IAIBehaviour 6 | { 7 | public bool CanRespond(ActivityModel activity, GameViewModel state) 8 | { 9 | return activity.ParseType() == ActivityType.DoBuys; 10 | } 11 | 12 | public void Respond(IGameClient client, ActivityModel activity, GameViewModel state) 13 | { 14 | var message = new EndTurnMessage(client.PlayerId); 15 | client.AcceptMessage(message); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/MerchantShip.feature: -------------------------------------------------------------------------------- 1 | Feature: Merchant Ship 2 | 3 | Scenario: Player plays Merchant Ship and gains +2 coin immediately 4 | Given A new game with 2 players 5 | And Player1 has a MerchantShip in hand instead of a Copper 6 | When Player1 plays a MerchantShip 7 | Then Player1 should have 2 to spend 8 | 9 | Scenario: Player plays Merchant Ship and gains +2 coin on the following turn 10 | Given A new game with 2 players 11 | And Player1 has a MerchantShip in hand instead of a Copper 12 | When Player1 plays a MerchantShip 13 | And Player1 ends their turn 14 | And Player2 ends their turn 15 | Then Player1 should have 2 to spend -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Market.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | using Dominion.Rules.CardTypes; 7 | 8 | namespace Dominion.Cards.Actions 9 | { 10 | public class Market : Card, IActionCard 11 | { 12 | public Market() 13 | : base(5) 14 | { 15 | } 16 | 17 | public void Play(TurnContext context) 18 | { 19 | context.DrawCards(1); 20 | context.RemainingActions += 1; 21 | context.Buys += 1; 22 | context.AvailableSpend += 1; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Harem.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Dominion.Rules; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Cards.Hybrid 6 | { 7 | public class Harem : Card, IMoneyCard, IVictoryCard 8 | { 9 | public Harem() : base(6) 10 | { 11 | ScoringValue = 2; 12 | } 13 | 14 | public CardCost Value { get { return 2; } } 15 | 16 | public int ScoringValue 17 | { 18 | get; 19 | private set; 20 | } 21 | 22 | public int Score(EnumerableCardZone allCards) 23 | { 24 | return ScoringValue; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Cellar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | using Dominion.Rules.Activities; 7 | using Dominion.Rules.CardTypes; 8 | 9 | namespace Dominion.Cards.Actions 10 | { 11 | public class Cellar : Card, IActionCard 12 | { 13 | public Cellar() 14 | : base(2) 15 | { 16 | } 17 | 18 | public void Play(TurnContext context) 19 | { 20 | context.RemainingActions += 1; 21 | context.AddSingleActivity(Activities.DiscardCardsToDrawCards(context, this), this); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/SkipActionsBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dominion.Rules.Activities; 3 | 4 | namespace Dominion.GameHost.AI.BehaviourBased 5 | { 6 | public class SkipActionsBehaviour : IAIBehaviour 7 | { 8 | public bool CanRespond(ActivityModel activity, GameViewModel state) 9 | { 10 | return activity.ParseType() == ActivityType.PlayActions; 11 | } 12 | 13 | public void Respond(IGameClient client, ActivityModel activity, GameViewModel state) 14 | { 15 | var message = new MoveToBuyStepMessage(client.PlayerId); 16 | client.AcceptMessage(message); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Dominion.GameHost/BeginGameMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Dominion.Rules; 4 | using Dominion.Rules.CardTypes; 5 | 6 | namespace Dominion.GameHost 7 | { 8 | public class BeginGameMessage : IGameActionMessage 9 | { 10 | public void UpdateGameState(Game game) 11 | { 12 | TurnContext tempQualifier = game.CurrentTurn; 13 | if (tempQualifier.ActivePlayer.Hand.OfType().Any() == false || tempQualifier.RemainingActions == 0) 14 | tempQualifier.MoveToBuyStep(); 15 | } 16 | 17 | public void Validate(Game game) 18 | { 19 | 20 | } 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /Dominion.Web/ViewModels/NewGameViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace Dominion.Web.ViewModels 7 | { 8 | public class NewGameViewModel 9 | { 10 | public int NumberOfPlayers { get; set; } 11 | 12 | /// 13 | /// A comma delimited list of player names, or types of AI players. 14 | /// 15 | public string Names { get; set; } 16 | 17 | public IList CardsToChooseFrom { get; set; } 18 | 19 | public IList ChosenCards { get; set; } 20 | 21 | public bool UseProsperty { get; set; } 22 | } 23 | } -------------------------------------------------------------------------------- /Dominion.Rules/EnumerableCardZone.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Dominion.Rules 6 | { 7 | public abstract class EnumerableCardZone : CardZone, IEnumerable 8 | { 9 | public IEnumerator GetEnumerator() 10 | { 11 | return this.Cards.GetEnumerator(); 12 | } 13 | 14 | IEnumerator IEnumerable.GetEnumerator() 15 | { 16 | return GetEnumerator(); 17 | } 18 | 19 | public override string ToString() 20 | { 21 | return string.Join(", ", this.Select(c => c.Name).ToArray()); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Wharf.feature: -------------------------------------------------------------------------------- 1 | Feature: Wharf 2 | 3 | Scenario: Player plays Wharf and draws 2 cards and gains a buy 4 | Given A new game with 2 players 5 | And Player1 has a Wharf in hand instead of a Copper 6 | When Player1 plays a Wharf 7 | Then Player1 should have 6 cards in hand 8 | And Player1 should have 2 buys 9 | 10 | Scenario: Player plays Wharf and draws 2 cards and gains a buy on the following turn 11 | Given A new game with 2 players 12 | And Player1 has a Wharf in hand instead of a Copper 13 | When Player1 plays a Wharf 14 | And Player1 ends their turn 15 | And Player2 ends their turn 16 | Then Player1 should have 7 cards in hand 17 | And Player1 should have 2 buys -------------------------------------------------------------------------------- /Dominion.Cards/Actions/CouncilRoom.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | using Dominion.Rules.CardTypes; 7 | 8 | namespace Dominion.Cards.Actions 9 | { 10 | public class CouncilRoom : Card, IActionCard 11 | { 12 | public CouncilRoom() 13 | : base(5) 14 | { 15 | 16 | } 17 | 18 | public void Play(TurnContext context) 19 | { 20 | context.DrawCards(4); 21 | context.Buys += 1; 22 | 23 | foreach (var opponent in context.Opponents) 24 | opponent.DrawCards(1); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/ShantyTown.feature: -------------------------------------------------------------------------------- 1 | Feature: ShantyTown 2 | 3 | Scenario: Play Shanty Town with no other actions in hand 4 | Given A new game with 2 players 5 | And Player1 has a ShantyTown in hand instead of a Copper 6 | When Player1 plays a ShantyTown 7 | Then Player1 should have 2 remaining action 8 | Then Player1 should have 6 cards in hand 9 | 10 | Scenario: Play Shanty Town with another action in hand 11 | Given A new game with 2 players 12 | And Player1 has a ShantyTown in hand instead of a Copper 13 | And Player1 has a ShantyTown in hand instead of a Copper 14 | When Player1 plays a ShantyTown 15 | Then Player1 should have 2 remaining action 16 | Then Player1 should have 4 cards in hand 17 | -------------------------------------------------------------------------------- /Dominion.Specs/TurnMechanics.feature: -------------------------------------------------------------------------------- 1 | Feature: Turn Mechanics 2 | In order to have my turn 3 | As a dominion player 4 | I can perform certain actions 5 | 6 | Background: 7 | Given A new game with 3 players 8 | 9 | Scenario: Discard hand at end of turn 10 | When Player1 ends their turn 11 | Then Player1 should have 5 cards in the discard pile 12 | 13 | Scenario: Draw cards after discarding at end of turn 14 | When Player1 ends their turn 15 | Then Player1 should have 5 cards in hand 16 | 17 | Scenario: Use single action 18 | Given Player1 has a Smithy in hand instead of a Copper 19 | When Player1 plays a Smithy 20 | Then Player1 should have 0 actions remaining 21 | And Smithy should be in play 22 | 23 | -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/CommentOnGameEndBehaviour.cs: -------------------------------------------------------------------------------- 1 | namespace Dominion.GameHost.AI.BehaviourBased 2 | { 3 | public class CommentOnGameEndBehaviour : IAIBehaviour 4 | { 5 | private readonly string _comment; 6 | 7 | public CommentOnGameEndBehaviour(string comment) 8 | { 9 | _comment = comment; 10 | } 11 | 12 | public virtual bool CanRespond(ActivityModel activity, GameViewModel state) 13 | { 14 | return state.Status.GameIsComplete; 15 | } 16 | 17 | public virtual void Respond(IGameClient client, ActivityModel activity, GameViewModel state) 18 | { 19 | client.SendChatMessage(_comment); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Expand.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Dominion.Rules; 3 | using Dominion.Rules.Activities; 4 | using Dominion.Rules.CardTypes; 5 | 6 | namespace Dominion.Cards.Actions 7 | { 8 | public class Expand : Card, IActionCard 9 | { 10 | public Expand() : base(7) 11 | { 12 | } 13 | 14 | public void Play(TurnContext context) 15 | { 16 | context.AddEffect(this, new ExpandEffect()); 17 | } 18 | 19 | public class ExpandEffect : Remodel.RemodelEffect 20 | { 21 | public ExpandEffect() 22 | :base(3, "Select a card to Expand.") 23 | { 24 | 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/DefaultSelectFromRevealedBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Dominion.Rules.Activities; 3 | 4 | namespace Dominion.GameHost.AI.BehaviourBased 5 | { 6 | public class DefaultSelectFromRevealedBehaviour : IAIBehaviour 7 | { 8 | public bool CanRespond(ActivityModel activity, GameViewModel state) 9 | { 10 | return activity.ParseType() == ActivityType.SelectFromRevealed; 11 | } 12 | 13 | public void Respond(IGameClient client, ActivityModel activity, GameViewModel state) 14 | { 15 | var selected = state.Revealed.First(); 16 | client.AcceptMessage(new SelectCardsMessage(client.PlayerId, new[] { selected.Id })); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Dominion.GameHost/EndTurnMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dominion.Rules; 3 | 4 | namespace Dominion.GameHost 5 | { 6 | public class EndTurnMessage : IGameActionMessage 7 | { 8 | public EndTurnMessage(Guid playerId) 9 | { 10 | PlayerId = playerId; 11 | } 12 | 13 | public Guid PlayerId { get; private set; } 14 | 15 | public void UpdateGameState(Game game) 16 | { 17 | game.EndTurn(); 18 | } 19 | 20 | public void Validate(Game game) 21 | { 22 | if (game.ActivePlayer.Id != PlayerId) 23 | throw new InvalidOperationException(string.Format("Player '{0}' is not active.", PlayerId)); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/ShantyTown.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Dominion.Rules; 5 | using Dominion.Rules.Activities; 6 | using Dominion.Rules.CardTypes; 7 | 8 | namespace Dominion.Cards.Actions 9 | { 10 | public class ShantyTown : Card, IActionCard 11 | { 12 | public ShantyTown() : base(3) 13 | { 14 | } 15 | 16 | public void Play(TurnContext context) 17 | { 18 | context.RemainingActions += 2; 19 | 20 | context.Game.Log.LogRevealHand(context.ActivePlayer); 21 | 22 | if (context.ActivePlayer.Hand.OfType().Count() == 0) 23 | context.DrawCards(2); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Dominion.GameHost/AI/Treasure.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Dominion.Cards.Treasure; 3 | using Dominion.Rules; 4 | 5 | namespace Dominion.GameHost.AI 6 | { 7 | public static class Treasure 8 | { 9 | public static IList Basic = GetBasicTreasure(); 10 | 11 | private static IList GetBasicTreasure() 12 | { 13 | var list = new List(); 14 | list.AddTreasure(); 15 | list.AddTreasure(); 16 | list.AddTreasure(); 17 | return list; 18 | } 19 | 20 | private static void AddTreasure(this IList list) where T : Card 21 | { 22 | list.Add(typeof(T).Name); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Dominion.GameHost/MoveToBuyStepMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dominion.Rules; 3 | 4 | namespace Dominion.GameHost 5 | { 6 | public class MoveToBuyStepMessage : IGameActionMessage 7 | { 8 | public MoveToBuyStepMessage(Guid playerId) 9 | { 10 | PlayerId = playerId; 11 | } 12 | 13 | public Guid PlayerId { get; private set; } 14 | 15 | public void UpdateGameState(Game game) 16 | { 17 | game.CurrentTurn.MoveToBuyStep(); 18 | } 19 | 20 | public void Validate(Game game) 21 | { 22 | if (game.ActivePlayer.Id != PlayerId) 23 | throw new InvalidOperationException(string.Format("Player '{0}' is not active.", PlayerId)); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Dominion.GameHost/AI/VictoryCards.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Dominion.Cards.Victory; 3 | using Dominion.Rules; 4 | 5 | namespace Dominion.GameHost.AI 6 | { 7 | public static class VictoryCards 8 | { 9 | public static IList Basic = GetBasicVP(); 10 | 11 | private static IList GetBasicVP() 12 | { 13 | var list = new List(); 14 | list.AddCard(); 15 | list.AddCard(); 16 | list.AddCard(); 17 | list.AddCard(); 18 | return list; 19 | } 20 | 21 | private static void AddCard(this IList list) where T : Card 22 | { 23 | list.Add(typeof(T).Name); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Familiar.feature: -------------------------------------------------------------------------------- 1 | Feature: Familiar 2 | 3 | Scenario: Buy Familiar 4 | Given A new game with 3 players 5 | And Familiar is available to buy 6 | And Player1 has a hand of Potion, Copper, Copper, Copper, Copper 7 | When Player1 moves to the buy step 8 | And Player1 buys a Familiar 9 | Then Player1 should have a Familiar on top of the discard pile 10 | And Player1 should have 1 to spend 11 | 12 | Scenario: Play Familiar 13 | Given A new game with 3 players 14 | And Player1 has a Familiar in hand instead of a Copper 15 | When Player1 plays a Familiar 16 | Then Player1 should have 5 cards in hand 17 | Then Player1 should have 1 action remaining 18 | Then Player2 should have a Curse on top of the discard pile 19 | Then Player3 should have a Curse on top of the discard pile 20 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Tactician.feature: -------------------------------------------------------------------------------- 1 | Feature: Tactitian 2 | 3 | Scenario: Play Tactician with a deck of 10 cards 4 | Given A new game with 2 players 5 | And Player1 has a Tactician in hand instead of a Copper 6 | When Player1 plays a Tactician 7 | And Player1 ends their turn 8 | And Player2 ends their turn 9 | Then Player1 should have 9 cards in hand 10 | And Player1 should have 2 remaining actions 11 | And Player1 should have 2 buys 12 | 13 | Scenario: Play Tactician with no cards in hand 14 | Given A new game with 2 players 15 | And Player1 has a hand of Tactician 16 | When Player1 plays a Tactician 17 | And Player1 ends their turn 18 | And Player2 ends their turn 19 | Then Player1 should have 5 cards in hand 20 | And Player1 should have 1 remaining action 21 | And Player1 should have 1 buy -------------------------------------------------------------------------------- /Dominion.Web/ActionFilters/InjectClientAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Web.Mvc; 4 | using Dominion.GameHost; 5 | using Dominion.Web.Controllers; 6 | using Dominion.Web.Bootstrap; 7 | using Autofac; 8 | 9 | namespace Dominion.Web.ActionFilters 10 | { 11 | public class InjectClientAttribute : ActionFilterAttribute 12 | { 13 | public override void OnActionExecuting(ActionExecutingContext filterContext) 14 | { 15 | Guid playerId = Guid.Parse((string) filterContext.RouteData.Values["id"]); 16 | var multiHost = AutofacConfig.Container.Resolve(); 17 | var controller = (IHasGameClient)filterContext.Controller; 18 | controller.Client = multiHost.FindClient(playerId); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/CountingHouse.feature: -------------------------------------------------------------------------------- 1 | Feature: Counting House 2 | 3 | 4 | Scenario: Counting House does nothing when there are no coppers in the discard pile 5 | Given A new game with 1 players 6 | And Player1 has a CountingHouse in hand instead of a Copper 7 | When Player1 plays a CountingHouse 8 | Then Player1 should have 4 cards in hand 9 | 10 | Scenario: Counting House retrieves coppers 11 | Given A new game with 3 players 12 | And Player1 has a hand of CountingHouse, Estate, Estate, Copper, Copper 13 | And Player1 has a Copper in the discard pile 14 | And Player1 has a Copper in the discard pile 15 | When Player1 plays a CountingHouse 16 | Then Player1 should have a hand of Estate, Estate, Copper, Copper, Copper, Copper 17 | And Player1 should have 0 cards in the discard pile 18 | 19 | 20 | -------------------------------------------------------------------------------- /Dominion.5.1.ReSharper: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Feast.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dominion.Rules; 3 | using Dominion.Rules.Activities; 4 | using Dominion.Rules.CardTypes; 5 | 6 | namespace Dominion.Cards.Actions 7 | { 8 | public class Feast : Card, IActionCard 9 | { 10 | public Feast() : base(4) { } 11 | 12 | public void Play(TurnContext context) 13 | { 14 | context.Trash(context.ActivePlayer, this); 15 | context.AddEffect(this, new FeastEffect()); 16 | } 17 | } 18 | 19 | public class FeastEffect : CardEffectBase 20 | { 21 | public override void Resolve(TurnContext context, ICard source) 22 | { 23 | _activities.Add(Activities.GainACardCostingUpToX(context.Game.Log, context.ActivePlayer, 5, source)); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Witch.feature: -------------------------------------------------------------------------------- 1 | Feature: Witch 2 | 3 | Scenario: Play Witch 4 | Given A new game with 3 players 5 | And Player1 has a Witch in hand instead of a Copper 6 | When Player1 plays a Witch 7 | Then Player1 should have 6 cards in hand 8 | Then Player2 should have a Curse on top of the discard pile 9 | Then Player3 should have a Curse on top of the discard pile 10 | 11 | Scenario: Play Witch with only 1 Curse left 12 | Given A new game with 3 players 13 | Given There is only 1 Curse left 14 | And Player2 has a Witch in hand instead of a Copper 15 | When Player1 ends their turn 16 | When Player2 plays a Witch 17 | Then Player2 should have 6 cards in hand 18 | Then Player3 should have a Curse on top of the discard pile 19 | Then Player1 should not have a Curse on top of the discard pile 20 | 21 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/SeaHag.feature: -------------------------------------------------------------------------------- 1 | Feature: SeaHag 2 | 3 | Scenario: Play sea hag 4 | Given A new game with 3 players 5 | And Player1 has a SeaHag in hand instead of a Copper 6 | When Player1 plays a SeaHag 7 | Then Player1 should have 4 cards in hand 8 | Then Player2 should have a Curse on top of the deck 9 | Then Player2 should have 1 card in the discard pile 10 | Then Player3 should have a Curse on top of the deck 11 | Then Player3 should have 1 card in the discard pile 12 | 13 | Scenario: Sea hag with no cards in deck or discard pile 14 | Given A new game with 2 players 15 | And Player1 has a SeaHag in hand instead of a Copper 16 | And Player2 has an empty deck 17 | When Player1 plays a SeaHag 18 | Then Player2 should have a Curse on top of the deck 19 | Then Player2 should have 0 cards in the discard pile 20 | -------------------------------------------------------------------------------- /Dominion.Specs/TurnOrder.feature: -------------------------------------------------------------------------------- 1 | Feature: Turn Order 2 | In order to play the game 3 | As a dominion player 4 | I alternate with the other players, taking turns 5 | 6 | Scenario: Player1 goes first 7 | Given A new game with 3 players 8 | Then Player1 is the active player 9 | 10 | Scenario: Player2 goes second 11 | Given A new game with 3 players 12 | When Player1 ends their turn 13 | Then Player2 is the active player 14 | 15 | Scenario: Player3 goes third 16 | Given A new game with 3 players 17 | When Player1 ends their turn 18 | When Player2 ends their turn 19 | Then Player3 is the active player 20 | 21 | Scenario: Player1 goes after Player3 22 | Given A new game with 3 players 23 | When Player1 ends their turn 24 | When Player2 ends their turn 25 | When Player3 ends their turn 26 | Then Player1 is the active player -------------------------------------------------------------------------------- /Dominion.Cards/Actions/City.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dominion.Rules; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Cards.Actions 6 | { 7 | public class City : Card, IActionCard 8 | { 9 | public City() 10 | : base(5) 11 | { 12 | } 13 | 14 | public void Play(TurnContext context) 15 | { 16 | context.RemainingActions += 2; 17 | context.DrawCards(1); 18 | 19 | var emptyPileCount = context.Game.Bank.EmptyPileCount; 20 | 21 | if(emptyPileCount >= 1) 22 | context.DrawCards(1); 23 | 24 | if(emptyPileCount >= 2) 25 | { 26 | context.AvailableSpend += 1; 27 | context.Buys += 1; 28 | } 29 | 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Dominion.Web/Views/Home/ViewPlayers.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Views/Shared/site.Master" %> 2 | <%@ Import Namespace="Dominion.Web.Controllers" %> 3 | 4 | 5 | 6 | Game key: <%= Model.GameKey %> 7 | <% foreach(var item in Model.Slots) 8 | { 9 | using(Html.BeginForm("JoinGame", "Home", new {id = item.Key })) 10 | { %> 11 | <%= item.Value %> <%=Html.SubmitButton("join", "Play") %> 12 | <%} 13 | } 14 | %> 15 | 16 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Moat.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dominion.Rules; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Cards.Actions 6 | { 7 | public class Moat : Card, IActionCard, IReactionCard 8 | { 9 | public Moat() : base(2) 10 | { 11 | } 12 | 13 | public void Play(TurnContext context) 14 | { 15 | context.DrawCards(2); 16 | } 17 | 18 | public void React(AttackEffect attackEffect, Player player, TurnContext currentTurn) 19 | { 20 | attackEffect.Nullify(player); 21 | currentTurn.Game.Log.LogMessage("{0} reveals a moat and nullifies the attack.", player.Name); 22 | } 23 | 24 | public bool ContinueReactingIfOnlyReaction 25 | { 26 | get { return false; } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Dominion.Rules/CardPile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Dominion.Rules 4 | { 5 | public abstract class CardPile : CardZone 6 | { 7 | public Guid Id { get; set; } 8 | public abstract bool IsEmpty { get; } 9 | public abstract ICard TopCard { get; } 10 | public abstract bool IsLimited { get; } 11 | 12 | private string _cachedName; 13 | 14 | public string Name 15 | { 16 | get 17 | { 18 | // The pile could run out, lets remember the name. 19 | if (_cachedName == null) 20 | _cachedName = TopCard.Name; 21 | 22 | return _cachedName; 23 | } 24 | } 25 | 26 | public CardPile() 27 | { 28 | Id = Guid.NewGuid(); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/KingsCourt.feature: -------------------------------------------------------------------------------- 1 | Feature: Kings Court 2 | 3 | Scenario: Player must choose which card to use Kings Court effect on 4 | Given A new game with 3 players 5 | And Player1 has a KingsCourt in hand instead of a Copper 6 | And Player1 has a Market in hand instead of a Copper 7 | When Player1 plays a KingsCourt 8 | Then Player1 must select 1 action card 9 | 10 | Scenario: Player uses Kings Court's effect on a Market 11 | Given A new game with 3 players 12 | And Player1 has a KingsCourt in hand instead of a Copper 13 | And Player1 has a Market in hand instead of a Copper 14 | When Player1 plays a KingsCourt 15 | And Player1 selects a Market to KingsCourt 16 | Then Player1 should have 6 cards in hand 17 | And Player1 should have 3 remaining actions 18 | And Player1 should have 4 buys 19 | And Player1 should have 3 to spend -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Cutpurse.feature: -------------------------------------------------------------------------------- 1 | Feature: Cutpurse 2 | 3 | Scenario: Cutpurse is played and players discard copper 4 | Given A new game with 3 players 5 | And Player1 has a Cutpurse in hand instead of a Copper 6 | When Player1 plays a Cutpurse 7 | Then Player1 should have 2 to spend 8 | And Player2 should have 4 cards in hand 9 | And Player2 should have a Copper on top of the discard pile 10 | And Player3 should have 4 cards in hand 11 | And Player3 should have a Copper on top of the discard pile 12 | 13 | Scenario: Cutpurse is played but opponent has no copper 14 | Given A new game with 2 players 15 | And Player1 has a Cutpurse in hand instead of a Copper 16 | And Player2 has a hand of Estate, Estate, Silver, Silver, Silver 17 | When Player1 plays a Cutpurse 18 | Then All actions should be resolved 19 | And Player2 should have 5 cards in hand 20 | -------------------------------------------------------------------------------- /Dominion.Cards/Hybrid/GreatHall.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.CardTypes; 3 | 4 | namespace Dominion.Cards.Hybrid 5 | { 6 | public class GreatHall : Card, IActionCard, IVictoryCard 7 | { 8 | public GreatHall() : base(3) 9 | { 10 | Value = 1; 11 | } 12 | 13 | public void Play(TurnContext context) 14 | { 15 | context.DrawCards(1); 16 | context.RemainingActions += 1; 17 | } 18 | 19 | public int Value 20 | { 21 | get; 22 | set; 23 | } 24 | 25 | public int Score(EnumerableCardZone allCards) 26 | { 27 | return Value; 28 | } 29 | 30 | public void PlayFromOtherAction(TurnContext context) 31 | { 32 | Play(context); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/BuyPotionBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Dominion.Cards.Treasure; 3 | 4 | namespace Dominion.GameHost.AI.BehaviourBased 5 | { 6 | public class BuyPotionBehaviour : BuyBehaviourBase 7 | { 8 | public override bool CanRespond(ActivityModel activity, GameViewModel state) 9 | { 10 | var potionPile = state.Bank.SingleOrDefault(p => p.Is()); 11 | return base.CanRespond(activity, state) 12 | && potionPile != null 13 | && potionPile.CanBuy 14 | && state.Status.AvailableSpend.Money == potionPile.Cost; 15 | } 16 | 17 | protected override CardPileViewModel SelectPile(GameViewModel state, IGameClient client) 18 | { 19 | return state.Bank.Single(p => p.Is()); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Coppersmith.feature: -------------------------------------------------------------------------------- 1 | Feature: Coppersmith 2 | 3 | Background: 4 | Given A new game with 3 players 5 | And Player1 has a hand of Coppersmith, Copper, Copper, Copper, ThroneRoom 6 | 7 | Scenario: Copper is improved in value 8 | When Player1 plays a Coppersmith 9 | And Player1 moves to the buy step 10 | Then Player1 should have 6 to spend 11 | 12 | Scenario: Coppersmith is cumulative 13 | When Player1 plays a ThroneRoom 14 | And Player1 selects a Coppersmith to ThroneRoom 15 | And Player1 moves to the buy step 16 | Then Player1 should have 9 to spend 17 | 18 | Scenario: Coppersmith only modifies Copper value 19 | Given A new game with 3 players 20 | And Player1 has a hand of Coppersmith, Copper, Silver, Gold, ThroneRoom 21 | When Player1 plays a Coppersmith 22 | And Player1 moves to the buy step 23 | Then Player1 should have 7 to spend 24 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Mine.feature: -------------------------------------------------------------------------------- 1 | Feature: Mine 2 | 3 | Background: 4 | Given A new game with 3 players 5 | And Player1 has a hand of Mine, Copper, Silver, Estate, Estate 6 | And Player1 has a Copper in the discard pile 7 | When Player1 plays a Mine 8 | 9 | Scenario: Player must only choose a treasure card to mine 10 | Then Player1 must select 1 treasure card to mine 11 | 12 | Scenario: Player must choose a treasure card to gain 13 | And Player1 selects a Silver to mine 14 | Then Player1 must gain a treasure card of cost 6 or less 15 | 16 | Scenario: Player mines Copper into Silver 17 | And Player1 selects a Copper to mine 18 | And Player1 gains a Silver 19 | Then Player1 should have a hand of Silver, Estate, Estate, Silver 20 | 21 | Scenario: Mined card is trashed 22 | And Player1 selects a Copper to mine 23 | Then There should be a Copper on top of the trash pile -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Courtyard.feature: -------------------------------------------------------------------------------- 1 | Feature: Courtyard 2 | 3 | Scenario: Player plays Courtyard, draws 3 and puts one card from hand back on top 4 | Given A new game with 3 players 5 | And Player1 has a hand of Courtyard, Militia, Copper, Copper, Estate 6 | When Player1 plays a Courtyard 7 | Then Player1 should have 7 cards in hand 8 | And Player1 must select 1 card to put on top of the deck 9 | When Player1 selects a Militia to put on top 10 | Then Player1 should have 6 cards in hand 11 | And Player1 should have a Militia on top of the deck 12 | 13 | 14 | Scenario: Courtyard is played with no other cards in hand, no discards and no deck 15 | Given A new game with 3 players 16 | And Player1 has a hand of Courtyard 17 | And Player1 has an empty deck 18 | When Player1 plays a Courtyard 19 | Then Player1 should have 0 cards in hand 20 | And All actions should be resolved 21 | -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/DefaultMakeChoiceBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Dominion.Rules.Activities; 3 | 4 | namespace Dominion.GameHost.AI.BehaviourBased 5 | { 6 | public class DefaultMakeChoiceBehaviour : IAIBehaviour 7 | { 8 | public virtual bool CanRespond(ActivityModel activity, GameViewModel state) 9 | { 10 | return activity.ParseType() == ActivityType.MakeChoice; 11 | } 12 | 13 | public void Respond(IGameClient client, ActivityModel activity, GameViewModel state) 14 | { 15 | var options = activity.ParseOptions(); 16 | 17 | Choice choice = options.First(); 18 | 19 | if (options.Contains(Choice.Yes)) 20 | choice = Choice.Yes; 21 | 22 | client.AcceptMessage(new ChoiceMessage(client.PlayerId, choice.ToString())); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Ironworks.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.Activities; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Cards.Actions 6 | { 7 | public class Ironworks : Card, IActionCard 8 | { 9 | public Ironworks() 10 | : base(4) 11 | { } 12 | 13 | public void Play(TurnContext context) 14 | { 15 | var activity = Activities.GainACardCostingUpToX(context.Game.Log, context.ActivePlayer, 4, this); 16 | activity.AfterCardGained = card => 17 | { 18 | if (card is IActionCard) context.RemainingActions += 1; 19 | if (card is ITreasureCard) context.AvailableSpend += 1; 20 | if (card is IVictoryCard) context.DrawCards(1); 21 | }; 22 | 23 | context.AddSingleActivity(activity, this); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/MerchantShip.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.CardTypes; 3 | 4 | namespace Dominion.Cards.Actions 5 | { 6 | public class MerchantShip : Card, IDurationCard 7 | { 8 | public MerchantShip() : base(5) 9 | {} 10 | 11 | public void Play(TurnContext context) 12 | { 13 | context.AvailableSpend += 2; 14 | context.AddLongLivedEffect(new MerchantShipEffect(this)); 15 | } 16 | 17 | public class MerchantShipEffect : DurationEffect 18 | { 19 | public MerchantShipEffect(ICard sourceCard) : base(sourceCard) 20 | {} 21 | 22 | public override void OnTurnStarting(TurnContext context) 23 | { 24 | base.OnTurnStarting(context); 25 | context.AvailableSpend += 2; 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Moat.feature: -------------------------------------------------------------------------------- 1 | Feature: Moat 2 | 3 | Scenario: Moat draws 2 cards 4 | Given A new game with 3 players 5 | And Player1 has a Moat in hand instead of a Copper 6 | When Player1 plays a Moat 7 | Then Player1 should have 6 cards in hand 8 | 9 | Scenario: Moat is a reaction 10 | Given A new game with 3 players 11 | And Player1 has a Militia in hand instead of a Copper 12 | And Player2 has a Moat in hand instead of a Copper 13 | When Player1 plays a Militia 14 | Then Player2 may reveal a reaction 15 | 16 | Scenario: Moat protects from attacks 17 | Given A new game with 3 players 18 | And Player1 has a Militia in hand instead of a Copper 19 | And Player2 has a Moat in hand instead of a Copper 20 | When Player1 plays a Militia 21 | When Player2 reveals Moat 22 | And Player2 is done with reactions 23 | Then Player2 must wait 24 | And Player3 must select 2 cards to discard -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Familiar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dominion.Cards.Curses; 3 | using Dominion.Rules; 4 | using Dominion.Rules.CardTypes; 5 | 6 | namespace Dominion.Cards.Actions 7 | { 8 | public class Familiar : Card, IActionCard 9 | { 10 | public Familiar() : base(new CardCost(3, 1)) 11 | {} 12 | 13 | public void Play(TurnContext context) 14 | { 15 | context.DrawCards(1); 16 | context.RemainingActions += 1; 17 | context.AddEffect(this, new FamiliarAttack()); 18 | } 19 | 20 | private class FamiliarAttack : AttackEffect 21 | { 22 | public override void Attack(Player victim, TurnContext context, ICard source) 23 | { 24 | var gainUtil = new GainUtility(context, victim); 25 | gainUtil.Gain(); 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Workshop.feature: -------------------------------------------------------------------------------- 1 | Feature: Workshop 2 | 3 | Scenario: Player must choose a card to gain 4 | Given A new game with 3 players 5 | And Player1 has a Workshop in hand instead of a Copper 6 | When Player1 plays a Workshop 7 | Then Player1 must gain a card of cost 4 or less 8 | 9 | Scenario: Player gains card 10 | Given A new game with 3 players 11 | And Player1 has a Workshop in hand instead of a Copper 12 | When Player1 plays a Workshop 13 | When Player1 gains a Silver 14 | Then Player1 should have a Silver on top of the discard pile 15 | 16 | @Hosted 17 | Scenario: Valid choices for workshop gain are marked accordingly in view 18 | Given A new hosted game with 3 players 19 | And Player1 has a Workshop in hand instead of a Copper 20 | When The game begins 21 | And Player1 tells the host to play Workshop 22 | Then Player1's view includes a Silver in the bank that can be gained -------------------------------------------------------------------------------- /Dominion.Rules/Hand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace Dominion.Rules 5 | { 6 | public class Hand : EnumerableCardZone 7 | { 8 | 9 | } 10 | 11 | public class RevealZone : EnumerableCardZone 12 | { 13 | public RevealZone(Player owner) 14 | { 15 | Owner = owner; 16 | } 17 | 18 | // The owner of the cards in the reveal zone 19 | public Player Owner { get; private set; } 20 | 21 | public void LogReveal(IGameLog log) 22 | { 23 | if(this.CardCount > 0) 24 | log.LogMessage("{0} revealed {1}.", Owner.Name, this); 25 | else 26 | { 27 | log.LogMessage("{0} revealed nothing.", Owner.Name); 28 | } 29 | } 30 | } 31 | 32 | public class LongLivedCardZone : EnumerableCardZone 33 | { 34 | } 35 | } -------------------------------------------------------------------------------- /Dominion.Rules/ReactionEffect.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Dominion.Rules.Activities; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Rules 6 | { 7 | public class ReactionEffect : CardEffectBase 8 | { 9 | private readonly AttackEffect _attackEffect; 10 | 11 | public ReactionEffect(AttackEffect attackEffect) 12 | { 13 | _attackEffect = attackEffect; 14 | } 15 | 16 | public override void Resolve(TurnContext context, ICard source) 17 | { 18 | foreach(var opponent in context.Opponents) 19 | { 20 | var reactions = opponent.Hand.OfType(); 21 | 22 | if(reactions.Count() > 0) 23 | _activities.Add(new SelectReactionActivity(context, opponent, _attackEffect)); 24 | } 25 | } 26 | 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /Dominion.Cards/TestCard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | 7 | namespace Dominion.Cards 8 | { 9 | public class TestCard : Card 10 | { 11 | public TestCard(CardCost cost) 12 | : base(cost) 13 | { 14 | } 15 | } 16 | 17 | public class TestCardPile : CardPile 18 | { 19 | public TestCardPile(CardCost cost) 20 | { 21 | AddCard(new TestCard(cost)); 22 | } 23 | 24 | public override bool IsEmpty 25 | { 26 | get { return !Cards.Any(); } 27 | } 28 | 29 | public override ICard TopCard 30 | { 31 | get { return Cards.First(); } 32 | } 33 | 34 | public override bool IsLimited 35 | { 36 | get { return true; } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/BigMoneyBuyBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace Dominion.GameHost.AI.BehaviourBased 5 | { 6 | public class BigMoneyBuyBehaviour : BuyBehaviourBase 7 | { 8 | public override bool CanRespond(ActivityModel activity, GameViewModel state) 9 | { 10 | return base.CanRespond(activity, state) && 11 | GetValidBuys(state) 12 | .Any(pile => Treasure.Basic.Contains(pile.Name)); 13 | } 14 | 15 | protected override CardPileViewModel SelectPile(GameViewModel state, IGameClient client) 16 | { 17 | return GetValidBuys(state) 18 | .Where(pile => Treasure.Basic.Contains(pile.Name)) 19 | .OrderByDescending(pile => pile.Cost) 20 | .First(); 21 | } 22 | 23 | } 24 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Expand.feature: -------------------------------------------------------------------------------- 1 | Feature: Expand 2 | 3 | Scenario: Player must choose a card to Expand 4 | Given A new game with 3 players 5 | And Player1 has a Expand in hand instead of a Copper 6 | When Player1 plays a Expand 7 | Then Player1 must select 1 card to Expand 8 | 9 | Scenario: Player Expands Copper 10 | Given A new game with 3 players 11 | And Player1 has a Expand in hand instead of a Copper 12 | When Player1 plays a Expand 13 | And Player1 selects a Copper to Expand 14 | Then Player1 must gain a card of cost 3 or less 15 | 16 | Scenario: Player Expands Copper choosing silver 17 | Given A new game with 3 players 18 | And Player1 has a Expand in hand instead of a Copper 19 | When Player1 plays a Expand 20 | And Player1 selects a Copper to Expand 21 | And Player1 gains a Silver 22 | Then There should be a Copper on top of the trash pile 23 | Then Player1 should have a Silver on top of the discard pile 24 | -------------------------------------------------------------------------------- /Dominion.Rules/Activities/ExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Dominion.Rules.CardTypes; 5 | 6 | namespace Dominion.Rules.Activities 7 | { 8 | public static class ExtensionMethods 9 | { 10 | public static string ToOrderString(this int number) 11 | { 12 | switch(number) 13 | { 14 | case 1: return "first"; 15 | case 2: return "second"; 16 | case 3: return "third"; 17 | case 4: return "fourth"; 18 | case 5: return "fifth"; 19 | case 6: return "sixth"; 20 | case 7: return "seventh"; 21 | case 8: return "eighth"; 22 | case 9: return "ninth"; 23 | case 10: return "tenth"; 24 | default: return number + "th"; 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Remodel.feature: -------------------------------------------------------------------------------- 1 | Feature: Remodel 2 | 3 | Scenario: Player must choose a card to remodel 4 | Given A new game with 3 players 5 | And Player1 has a Remodel in hand instead of a Copper 6 | When Player1 plays a Remodel 7 | Then Player1 must select 1 card to remodel 8 | 9 | Scenario: Player remodels copper 10 | Given A new game with 3 players 11 | And Player1 has a Remodel in hand instead of a Copper 12 | When Player1 plays a Remodel 13 | And Player1 selects a Copper to remodel 14 | Then Player1 must gain a card of cost 2 or less 15 | 16 | Scenario: Player remodels copper choosing estate 17 | Given A new game with 3 players 18 | And Player1 has a Remodel in hand instead of a Copper 19 | When Player1 plays a Remodel 20 | And Player1 selects a Copper to remodel 21 | And Player1 gains a Estate 22 | Then There should be a Copper on top of the trash pile 23 | Then Player1 should have a Estate on top of the discard pile 24 | -------------------------------------------------------------------------------- /Dominion.GameHost/CardBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Dominion.Rules; 3 | using System; 4 | using Dominion.Rules.CardTypes; 5 | 6 | namespace Dominion.GameHost 7 | { 8 | public static class CardBuilderExtensions 9 | { 10 | public static CardPile WithNewCards(this CardPile targetPile, int count) where T : ICard, new() 11 | { 12 | count.Times(() => new T().MoveTo(targetPile)); 13 | return targetPile; 14 | } 15 | 16 | public static CardPile WithNewCards(this CardPile targetPile, string cardName, int count) 17 | { 18 | count.Times(() => CardFactory.CreateCard(cardName).MoveTo(targetPile)); 19 | return targetPile; 20 | } 21 | 22 | public static IEnumerable NewCards(this int count) where T : Card, new() 23 | { 24 | return count.Items(() => new T()); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Chapel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | using Dominion.Rules.Activities; 7 | using Dominion.Rules.CardTypes; 8 | 9 | namespace Dominion.Cards.Actions 10 | { 11 | public class Chapel : Card, IActionCard 12 | { 13 | public Chapel() 14 | : base(2) 15 | { 16 | } 17 | 18 | public void Play(TurnContext context) 19 | { 20 | context.AddEffect(this, new ChapelEffect()); 21 | } 22 | 23 | private class ChapelEffect : CardEffectBase 24 | { 25 | public override void Resolve(TurnContext context, ICard source) 26 | { 27 | var activity = Activities.SelectUpToXCardsToTrash(context, context.ActivePlayer, 4, source); 28 | _activities.Add(activity); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Wharf.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.CardTypes; 3 | 4 | namespace Dominion.Cards.Actions 5 | { 6 | public class Wharf : Card, IDurationCard 7 | { 8 | public Wharf() 9 | : base(5) 10 | { } 11 | 12 | public void Play(TurnContext context) 13 | { 14 | context.DrawCards(2); 15 | context.Buys += 1; 16 | context.AddLongLivedEffect(new WharfEffect(this)); 17 | } 18 | 19 | public class WharfEffect : DurationEffect 20 | { 21 | public WharfEffect(ICard sourceCard) 22 | : base(sourceCard) 23 | { } 24 | 25 | public override void OnTurnStarting(TurnContext context) 26 | { 27 | base.OnTurnStarting(context); 28 | context.DrawCards(2); 29 | context.Buys += 1; 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Nobles.feature: -------------------------------------------------------------------------------- 1 | Feature: Nobles 2 | 3 | Background: 4 | Given A new game with 3 players 5 | And Player1 has a hand of Nobles, Copper, Silver, Estate, Estate 6 | When Player1 plays a Nobles 7 | 8 | Scenario: Player must choose between cards or actions 9 | Then Player1 must choose from DrawCards, GainActions 10 | 11 | Scenario: Player gets 3 Cards for DrawCards 12 | And Player1 chooses to draw 3 cards (DrawCards) 13 | Then Player1 should have 7 cards in hand 14 | And Player1 should have 0 actions remaining 15 | 16 | Scenario: Player gets 2 Actions for GainActions 17 | And Player1 chooses to gain 2 actions (GainActions) 18 | Then Player1 should have 2 actions remaining 19 | And Player1 should have 4 cards in hand 20 | 21 | Scenario: Is Worth 2 Victory Points 22 | Given A new game with 3 players 23 | And Player1 has a Nobles in hand instead of a Copper 24 | When The game is scored 25 | Then Player1 should have 5 victory points -------------------------------------------------------------------------------- /Dominion.Specs/Cards/TreasureMap.feature: -------------------------------------------------------------------------------- 1 | Feature: Treasure Map 2 | 3 | Scenario: Playing treasure map with another treasure map in hand gets the gold 4 | Given A new game with 3 players 5 | And Player1 has a hand of TreasureMap, TreasureMap, Copper, Copper, Estate 6 | And Player1 has a deck of Estate, Copper, Copper, Copper, Estate 7 | When Player1 plays a TreasureMap 8 | Then The trash pile should be TreasureMap, TreasureMap 9 | And Player1 should have a deck of: Gold, Gold, Gold, Gold, Estate, Copper, Copper, Copper, Estate 10 | 11 | Scenario: Playing treasure map without another one in hand just trashes it 12 | Given A new game with 3 players 13 | And Player1 has a hand of TreasureMap, Copper, Copper, Copper, Estate 14 | And Player1 has a deck of Estate, Copper, Copper, Copper, Estate 15 | When Player1 plays a TreasureMap 16 | Then The trash pile should be TreasureMap 17 | And Player1 should have a deck of: Estate, Copper, Copper, Copper, Estate 18 | -------------------------------------------------------------------------------- /Dominion.Specs/Hosted/GameHost.feature: -------------------------------------------------------------------------------- 1 | Feature: Game Host 2 | In order to play with other people 3 | As a Dominion player 4 | I want to interact with the game 5 | And know when the game state changes 6 | 7 | Scenario: Game Begins 8 | Given A new hosted game with 3 players 9 | When The game begins 10 | Then All players should recieve 1 game state update 11 | 12 | Scenario: Player interacts with game 13 | Given A new hosted game with 3 players 14 | When The game begins 15 | And Player1 tells the host to buy Copper 16 | Then All players should recieve 2 game state updates 17 | 18 | Scenario: Player plays an action that requires other players to make decisions 19 | Given A new hosted game with 3 players 20 | And Player1 has a Militia in hand instead of a Copper 21 | When The game begins 22 | And Player1 tells the host to play Militia 23 | Then The host should tell Player2 to discard 2 cards 24 | Then The host should tell Player3 to discard 2 cards -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Cellar.feature: -------------------------------------------------------------------------------- 1 | Feature: Cellar 2 | 3 | Background: 4 | Given A new game with 3 players 5 | And Player1 has a hand of Cellar, Estate, Estate, Copper, Copper 6 | When Player1 plays a Cellar 7 | 8 | Scenario: Player must select a number of cards to discard 9 | Then Player1 may select up to 4 cards from their hand 10 | 11 | Scenario: Player discards one card to Cellar 12 | And Player1 selects a Copper to discard 13 | Then Player1 should have a Copper on top of the discard pile 14 | And Player1 should have 1 actions remaining 15 | 16 | Scenario: Player discards two cards to Cellar 17 | And Player1 selects cards [Copper, Estate] to discard 18 | Then Player1 should have a Estate on top of the discard pile 19 | And Player1 should have 1 actions remaining 20 | 21 | Scenario: Player discards nothing to Cellar 22 | And Player1 selects nothing to discard 23 | Then Player1 should have 4 cards in hand 24 | And Player1 should have 1 actions remaining 25 | -------------------------------------------------------------------------------- /Dominion.GameHost/BuyCardMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Dominion.Rules; 4 | 5 | namespace Dominion.GameHost 6 | { 7 | public class BuyCardMessage : IGameActionMessage 8 | { 9 | public BuyCardMessage(Guid playerId, Guid pileId) 10 | { 11 | PlayerId = playerId; 12 | PileId = pileId; 13 | } 14 | 15 | public Guid PlayerId { get; private set; } 16 | public Guid PileId { get; private set; } 17 | 18 | public void UpdateGameState(Game game) 19 | { 20 | CardPile pile = game.Bank.Piles.Single(p => p.Id == PileId); 21 | game.CurrentTurn.Buy(pile); 22 | } 23 | 24 | public void Validate(Game game) 25 | { 26 | if(game.ActivePlayer.Id != PlayerId) 27 | throw new InvalidOperationException(string.Format("Player '{0}' is not active.", PlayerId)); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Witch.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Text; 4 | using Dominion.Rules; 5 | using Dominion.Rules.CardTypes; 6 | using Dominion.Cards.Curses; 7 | 8 | namespace Dominion.Cards.Actions 9 | { 10 | public class Witch : Card, IActionCard, IAttackCard 11 | { 12 | public Witch() 13 | : base(5) 14 | { 15 | 16 | } 17 | 18 | public void Play(TurnContext context) 19 | { 20 | context.DrawCards(2); 21 | context.AddEffect(this, new WitchAttack()); 22 | } 23 | 24 | private class WitchAttack : AttackEffect 25 | { 26 | public override void Attack(Player victim, TurnContext context, ICard source) 27 | { 28 | var gainUtil = new GainUtility(context, victim); 29 | gainUtil.Gain(); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/University.feature: -------------------------------------------------------------------------------- 1 | Feature: University 2 | 3 | Scenario: Player plays University and must select an action card to gain 4 | Given A new game with 3 players 5 | And Player1 has a University in hand instead of a Copper 6 | When Player1 plays a University 7 | Then Player1 may gain an action card of cost 5 or less 8 | And Player1 should have 2 remaining actions 9 | 10 | Scenario: Player plays University and selects an action 11 | Given A new game with 3 players 12 | And Player1 has a University in hand instead of a Copper 13 | When Player1 plays a University 14 | And Player1 gains a Moat 15 | Then All actions should be resolved 16 | Then Player1 should have a Moat on top of the discard pile 17 | 18 | Scenario: Player plays University and chooses not to gain 19 | Given A new game with 3 players 20 | And Player1 has a University in hand instead of a Copper 21 | When Player1 plays a University 22 | And Player1 gains nothing 23 | Then All actions should be resolved 24 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Coppersmith.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | using Dominion.Rules.CardTypes; 7 | using Dominion.Cards.Treasure; 8 | 9 | namespace Dominion.Cards.Actions 10 | { 11 | public class Coppersmith : Card, IActionCard 12 | { 13 | public Coppersmith() 14 | : base(4) 15 | { 16 | } 17 | 18 | public void Play(TurnContext context) 19 | { 20 | context.AddPassiveCardEffect(new CoppersmithPassiveEffect()); 21 | } 22 | 23 | private class CoppersmithPassiveEffect : PassiveCardEffectBase 24 | { 25 | public override CardCost ModifyValue(CardCost currentValue, ITreasureCard card) 26 | { 27 | if (card is Copper) 28 | return currentValue + 1; 29 | 30 | return currentValue; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/City.feature: -------------------------------------------------------------------------------- 1 | Feature: City 2 | 3 | Scenario: Play City with no empty piles 4 | Given A new game with 3 players 5 | And Player1 has a City in hand instead of a Copper 6 | When Player1 plays a City 7 | Then Player1 should have 2 remaining actions 8 | Then Player1 should have 5 cards in hand 9 | 10 | Scenario: Play City with 1 empty pile 11 | Given A new game with 3 players 12 | Given There are 1 empty piles 13 | And Player1 has a City in hand instead of a Copper 14 | When Player1 plays a City 15 | Then Player1 should have 2 remaining actions 16 | Then Player1 should have 6 cards in hand 17 | 18 | Scenario: Play City with 2 empty piles 19 | Given A new game with 3 players 20 | Given There are 2 empty piles 21 | And Player1 has a City in hand instead of a Copper 22 | When Player1 plays a City 23 | Then Player1 should have 2 remaining actions 24 | Then Player1 should have 6 cards in hand 25 | Then Player1 should have 1 to spend 26 | Then Player1 should have 2 buys 27 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Chancellor.feature: -------------------------------------------------------------------------------- 1 | Feature: Chancellor 2 | 3 | Background: 4 | Given A new game with 3 players 5 | And Player1 has a Chancellor in hand instead of a Copper 6 | 7 | Scenario: Chancellor is +2 money 8 | When Player1 plays a Chancellor 9 | Then Player1 should have 2 to spend 10 | 11 | Scenario: Player may choose whether to use Chancellor's effect 12 | When Player1 plays a Chancellor 13 | Then Player1 must choose whether to use Chancellor's effect (Yes or No) 14 | 15 | Scenario: Player uses Chancellor's effect 16 | When Player1 plays a Chancellor 17 | When Player1 chooses to move their deck to the discard pile (Yes) 18 | Then Player1 should have a deck of 0 cards 19 | And Player1 should have 5 cards in the discard pile 20 | 21 | Scenario: Player does not use Chancellor's effect 22 | When Player1 plays a Chancellor 23 | When Player1 chooses to leave their deck as is (No) 24 | Then Player1 should have a deck of 5 cards 25 | And Player1 should have 0 cards in the discard pile 26 | 27 | -------------------------------------------------------------------------------- /Dominion.Rules/Activities/GainACardActivity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Dominion.Rules.Activities 4 | { 5 | public class GainACardActivity : SelectPileActivity 6 | { 7 | private readonly CardZone _destination; 8 | 9 | public Action AfterCardGained { get; set; } 10 | 11 | public GainACardActivity(IGameLog log, Player player, string message, ISelectionSpecification specification, CardZone destination, ICard source) 12 | : base(log, player, message, specification, source) 13 | { 14 | _destination = destination; 15 | Hint = ActivityHint.GainCards; 16 | } 17 | 18 | public override void SelectPile(CardPile pile) 19 | { 20 | base.SelectPile(pile); 21 | 22 | var card = pile.TopCard; 23 | card.MoveTo(_destination); 24 | Log.LogGain(Player, card); 25 | 26 | if (AfterCardGained != null) 27 | AfterCardGained(card); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Duke.feature: -------------------------------------------------------------------------------- 1 | Feature: Duke 2 | 3 | Scenario: Duke is worth zero points if there are no duchies in the deck 4 | Given A new game with 3 players 5 | And Player1 has a hand of Copper, Copper, Copper, Copper, Copper 6 | And Player1 has a deck of Copper, Copper, Copper, Copper, Duke 7 | When The game is scored 8 | Then Player1 should have 0 victory points 9 | 10 | Scenario: Duke is worth one point if there is one duchy in the deck 11 | Given A new game with 3 players 12 | And Player1 has a hand of Copper, Copper, Copper, Copper, Copper 13 | And Player1 has a deck of Copper, Duchy, Copper, Copper, Duke 14 | When The game is scored 15 | Then Player1 should have 4 victory points 16 | 17 | Scenario: Duke is worth five points if there are five duchies in the deck 18 | Given A new game with 3 players 19 | And Player1 has a hand of Duchy, Duchy, Duchy, Duchy, Duchy 20 | And Player1 has a deck of Duke, Copper, Copper, Copper, Copper 21 | When The game is scored 22 | Then Player1 should have 20 victory points -------------------------------------------------------------------------------- /Dominion.GameHost/PlayCardMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Dominion.Rules; 4 | using Dominion.Rules.CardTypes; 5 | 6 | namespace Dominion.GameHost 7 | { 8 | public class PlayCardMessage : IGameActionMessage 9 | { 10 | public PlayCardMessage(Guid playerId, Guid cardId) 11 | { 12 | PlayerId = playerId; 13 | CardId = cardId; 14 | } 15 | 16 | public Guid PlayerId { get; private set; } 17 | public Guid CardId { get; private set; } 18 | 19 | public void UpdateGameState(Game game) 20 | { 21 | ICard card = game.CurrentTurn.ActivePlayer.Hand.Single(c => c.Id == CardId); 22 | game.CurrentTurn.Play((IActionCard) card); 23 | } 24 | 25 | public void Validate(Game game) 26 | { 27 | if (game.ActivePlayer.Id != PlayerId) 28 | throw new InvalidOperationException(string.Format("Player '{0}' is not active.", PlayerId)); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Cutpurse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Dominion.Cards.Treasure; 4 | using Dominion.Rules; 5 | using Dominion.Rules.CardTypes; 6 | 7 | namespace Dominion.Cards.Actions 8 | { 9 | public class Cutpurse : Card, IActionCard, IAttackCard 10 | { 11 | public Cutpurse() : base(4) 12 | { 13 | } 14 | 15 | public void Play(TurnContext context) 16 | { 17 | context.AvailableSpend += 2; 18 | context.AddEffect(this, new CutpurseAttack()); 19 | } 20 | 21 | public class CutpurseAttack : AttackEffect 22 | { 23 | public override void Attack(Player victim, TurnContext context, ICard source) 24 | { 25 | var copper = victim.Hand.FirstOrDefault(c => c is Copper); 26 | 27 | if (copper != null) 28 | context.DiscardCard(victim, copper); 29 | else 30 | context.Game.Log.LogRevealHand(victim); 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Vineyard.feature: -------------------------------------------------------------------------------- 1 | Feature: Vineyard 2 | 3 | Scenario: Vineyard is worth zero points if there are 2 (or less) actions in the deck 4 | Given A new game with 3 players 5 | And Player1 has a hand of Copper, Copper, Copper, Copper, Copper 6 | And Player1 has a deck of Copper, Copper, Smithy, Smithy, Vineyard 7 | When The game is scored 8 | Then Player1 should have 0 victory points 9 | 10 | Scenario: Vineyard is worth one point if there are 3 actions in the deck 11 | Given A new game with 3 players 12 | And Player1 has a hand of Copper, Copper, Copper, Copper, Copper 13 | And Player1 has a deck of Copper, Smithy, Smithy, Smithy, Vineyard 14 | When The game is scored 15 | Then Player1 should have 1 victory point 16 | 17 | Scenario: Vineyard is worth two points if there are 6 actions in the deck 18 | Given A new game with 3 players 19 | And Player1 has a hand of Copper, Copper, Copper, Smithy, Smithy 20 | And Player1 has a deck of Smithy, Smithy, Smithy, Smithy, Vineyard 21 | When The game is scored 22 | Then Player1 should have 2 victory points -------------------------------------------------------------------------------- /Dominion.Web/Views/Shared/site.Master: -------------------------------------------------------------------------------- 1 | <%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %> 2 | 3 | 4 | 5 | 6 | 7 | <asp:ContentPlaceHolder ID="TitleContent" runat="server" /> 8 | <%= Html.Css("Site.css") %> 9 | <%= Html.Css("jqueryUI/jquery-ui-1.8.4.custom.css")%> 10 | <%= Html.Script("jquery-1.4.1.min.js", "jquery-1.4.1.js")%> 11 | <%= Html.Script("jquery-ui-1.8.4.custom.min.js")%> 12 | <%= Html.Script("jquery.tmpl.js")%> 13 | <%= Html.Script("jquery.form.js")%> 14 | <%= Html.Script("jquery.layout-1.3.0.rc29.4.js")%> 15 | <%= Html.Script("jquery.thumbhover.js")%> 16 | <%= Html.Script("jquery.hotkeys-0.7.9.js")%> 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Dominion.Rules/CardTypes/IActionCard.cs: -------------------------------------------------------------------------------- 1 | namespace Dominion.Rules.CardTypes 2 | { 3 | public interface IActionCard : ICard 4 | { 5 | void Play(TurnContext context); 6 | } 7 | 8 | public interface IReactionCard : ICard 9 | { 10 | void React(AttackEffect attackEffect, Player player, TurnContext currentTurn); 11 | 12 | /// 13 | /// Does it make sense for the player's reaction window to stay open if this was the only reaction in their hand? 14 | /// For example, if you only have a moat in your hand, once its revealed, there is no point in keeping the reaction window open. The rules say you can, but there is no point. 15 | /// Secret Chamber on the other hand, might draw you another reaction, so its worth keeping the window open. 16 | /// 17 | bool ContinueReactingIfOnlyReaction { get; } 18 | } 19 | 20 | public interface IAttackCard : ICard 21 | { 22 | 23 | } 24 | 25 | public interface IDurationCard : IActionCard 26 | { 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /Dominion.Rules/GameScores.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Dominion.Rules.CardTypes; 5 | 6 | namespace Dominion.Rules 7 | { 8 | public class GameScores : Dictionary 9 | { 10 | private readonly Game _game; 11 | 12 | public GameScores(Game game) 13 | { 14 | _game = game; 15 | } 16 | 17 | public void Score(Player player) 18 | { 19 | player.Discards.MoveAll(player.PlayArea); 20 | player.Hand.MoveAll(player.PlayArea); 21 | player.Deck.MoveAll(player.PlayArea); 22 | 23 | player.PlayArea.SortForScoring(); 24 | 25 | this[player] = player.PlayArea.OfType().Sum(c => c.Score(player.PlayArea)); 26 | } 27 | 28 | public Player Winner 29 | { 30 | get 31 | { 32 | return _game.Players 33 | .Last(player => this[player] == this.Values.Max()); 34 | } 35 | } 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/DefaultSelectFixedNumberOfCardsToPassOrTrashBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Dominion.Cards.Victory; 5 | using Dominion.Rules.Activities; 6 | 7 | namespace Dominion.GameHost.AI.BehaviourBased 8 | { 9 | public class DefaultSelectFixedNumberOfCardsToPassOrTrashBehaviour : SelectFixedNumberOfCardsBehaviourBase 10 | { 11 | public override bool CanRespond(ActivityModel activity, GameViewModel state) 12 | { 13 | return base.CanRespond(activity, state) && 14 | (activity.ParseHint() == ActivityHint.PassCards || activity.ParseHint() == ActivityHint.TrashCards); 15 | } 16 | 17 | protected override IEnumerable PrioritiseCards(GameViewModel state, ActivityModel activity) 18 | { 19 | return state.Hand 20 | .OrderByDescending(c => c.Is(CardType.Curse)) 21 | .ThenByDescending(c => c.Is()) 22 | .ThenBy(c => c.Cost); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/BigMoneyAI.cs: -------------------------------------------------------------------------------- 1 | namespace Dominion.GameHost.AI.BehaviourBased 2 | { 3 | public class BigMoneyAI : BehaviourBasedAI 4 | { 5 | public BigMoneyAI() 6 | { 7 | Behaviours.Add(new CommentOnGameEndBehaviour("The game is over? But I was about to buy a Province!")); 8 | 9 | Behaviours.Add(new DefaultDiscardOrRedrawCardsBehaviour()); 10 | Behaviours.Add(new DefaultMakeChoiceBehaviour()); 11 | Behaviours.Add(new DefaultSelectFixedNumberOfCardsToPassOrTrashBehaviour()); 12 | Behaviours.Add(new DefaultSelectFromRevealedBehaviour()); 13 | Behaviours.Add(new DefaultSelectFixedNumberOfCardsForPlayBehaviour()); 14 | Behaviours.Add(new DefaultSelectUpToNumberOfCardsToTrashBehaviour()); 15 | 16 | Behaviours.Add(new SkipActionsBehaviour()); 17 | 18 | Behaviours.Add(new BuyPointsBehaviour(6)); 19 | Behaviours.Add(new BigMoneyBuyBehaviour()); 20 | Behaviours.Add(new SkipBuyBehaviour()); 21 | 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/SeaHag.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | using Dominion.Rules.Activities; 7 | using Dominion.Rules.CardTypes; 8 | using Dominion.Cards.Curses; 9 | 10 | namespace Dominion.Cards.Actions 11 | { 12 | public class SeaHag : Card, IActionCard, IAttackCard 13 | { 14 | public SeaHag() : base(4) { } 15 | 16 | public void Play(TurnContext context) 17 | { 18 | context.AddEffect(this, new SeaHagAttack()); 19 | } 20 | 21 | private class SeaHagAttack : AttackEffect 22 | { 23 | public override void Attack(Player victim, TurnContext context, ICard source) 24 | { 25 | if (victim.Deck.CardCount + victim.Discards.CardCount > 0) 26 | victim.Deck.MoveTop(1, victim.Discards); 27 | 28 | var gainUtil = new GainUtility(context, victim); 29 | gainUtil.Gain(c => victim.Deck.MoveToTop(c)); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/TreasureMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Dominion.Cards.Treasure; 4 | using Dominion.Rules; 5 | using Dominion.Rules.CardTypes; 6 | 7 | namespace Dominion.Cards.Actions 8 | { 9 | public class TreasureMap : Card, IActionCard 10 | { 11 | public TreasureMap() : base(4) 12 | {} 13 | 14 | public void Play(TurnContext context) 15 | { 16 | context.Trash(context.ActivePlayer, this); 17 | var otherMap = context.ActivePlayer.Hand.OfType().FirstOrDefault(); 18 | if(otherMap != null) 19 | { 20 | context.Trash(context.ActivePlayer, otherMap); 21 | var gainUtil = new GainUtility(context, context.ActivePlayer); 22 | var deck = context.ActivePlayer.Deck; 23 | gainUtil.Gain(deck.MoveToTop); 24 | gainUtil.Gain(deck.MoveToTop); 25 | gainUtil.Gain(deck.MoveToTop); 26 | gainUtil.Gain(deck.MoveToTop); 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Dominion.GameHost/ChoiceMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | using Dominion.Rules.Activities; 7 | 8 | namespace Dominion.GameHost 9 | { 10 | public class ChoiceMessage : IGameActionMessage 11 | { 12 | public ChoiceMessage(Guid playerId, string choice) 13 | { 14 | PlayerId = playerId; 15 | Choice = choice; 16 | } 17 | 18 | public Guid PlayerId { get; private set; } 19 | public string Choice { get; set; } 20 | 21 | public void UpdateGameState(Game game) 22 | { 23 | var player = game.Players.Single(p => p.Id == PlayerId); 24 | var activity = game.GetPendingActivity(player) as ChoiceActivity; 25 | 26 | if (activity == null) 27 | throw new InvalidOperationException("There must be a corresponding activity"); 28 | 29 | activity.MakeChoice(Choice); 30 | } 31 | 32 | public void Validate(Game game) 33 | { 34 | 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Dominion.Specs/GameLog.feature: -------------------------------------------------------------------------------- 1 | Feature: Game Log 2 | In order to know what is going on 3 | As a Dominion player 4 | I want to be told when players do things 5 | 6 | Scenario: A player begins their turn 7 | Given A new game with 3 players 8 | Then The game log should report that Player1's turn has begun 9 | 10 | Scenario: A player plays an action 11 | Given A new game with 3 players 12 | And Player1 has a Woodcutter in hand instead of a Copper 13 | When Player1 plays a Woodcutter 14 | Then The game log should report that Player1 played a Woodcutter 15 | 16 | Scenario: A player buys a card 17 | Given A new game with 3 players 18 | When Player1 moves to the buy step 19 | And Player1 buys a Copper 20 | Then The game log should report that Player1 bought a Copper 21 | 22 | Scenario: The game ends 23 | Given A new game with 3 players 24 | But There is only 1 Province left 25 | And Player1 has 5 Gold in hand 26 | When Player1 moves to the buy step 27 | And Player1 buys a Province 28 | And Player1 ends their turn 29 | Then The game log should report the scores 30 | And Player1 should be the winner 31 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Transmute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dominion.Cards.Treasure; 3 | using Dominion.Cards.Victory; 4 | using Dominion.Rules; 5 | using Dominion.Rules.Activities; 6 | using Dominion.Rules.CardTypes; 7 | 8 | namespace Dominion.Cards.Actions 9 | { 10 | public class Transmute : Card, IActionCard 11 | { 12 | public Transmute() : base(CardCost.Parse("0P")) 13 | {} 14 | 15 | public void Play(TurnContext context) 16 | { 17 | if(context.ActivePlayer.Hand.CardCount > 0) 18 | { 19 | var gainUtility = new GainUtility(context, context.ActivePlayer); 20 | 21 | var activity = Activities.SelectACardToTrash(context, context.ActivePlayer, this, card => 22 | { 23 | if (card is IActionCard) gainUtility.Gain(); 24 | if (card is ITreasureCard) gainUtility.Gain(); 25 | if (card is IVictoryCard) gainUtility.Gain(); 26 | }); 27 | 28 | context.AddSingleActivity(activity, this); 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/DefaultSelectUpToNumberOfCardsToTrashBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Dominion.Cards.Curses; 3 | using Dominion.Cards.Treasure; 4 | using Dominion.Cards.Victory; 5 | using Dominion.Rules.Activities; 6 | 7 | namespace Dominion.GameHost.AI.BehaviourBased 8 | { 9 | public class DefaultSelectUpToNumberOfCardsToTrashBehaviour : IAIBehaviour 10 | { 11 | public virtual bool CanRespond(ActivityModel activity, GameViewModel state) 12 | { 13 | return activity.ParseType() == ActivityType.SelectUpToNumberOfCards 14 | && activity.ParseHint() == ActivityHint.TrashCards; 15 | } 16 | 17 | public void Respond(IGameClient client, ActivityModel activity, GameViewModel state) 18 | { 19 | var idsToTrash = state.Hand.Where(c => c.Is() || c.Is() || c.Is()) 20 | .Select(c => c.Id) 21 | .Take(activity.ParseNumberOfCardsToSelect()) 22 | .ToArray(); 23 | 24 | client.AcceptMessage(new SelectCardsMessage(client.PlayerId, idsToTrash)); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Dominion.Web/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Envoy.feature: -------------------------------------------------------------------------------- 1 | Feature: Envoy 2 | 3 | Scenario: Player plays Envoy, opponent must choose which card they don't draw 4 | Given A new game with 3 players 5 | And Player1 has a Envoy in hand instead of a Copper 6 | And Player1 has a deck of Silver, Copper, Estate, Copper, Copper 7 | When Player1 plays a Envoy 8 | Then Player2 must select a revealed card from: Silver, Copper, Estate, Copper, Copper 9 | 10 | Scenario: Player plays Envoy, draws 4 cards 11 | Given A new game with 3 players 12 | And Player1 has a hand of Envoy, Copper, Estate, Copper, Copper 13 | And Player1 has a deck of Silver, Copper, Estate, Copper, Copper 14 | When Player1 plays a Envoy 15 | When Player2 selects Silver from the revealed cards 16 | Then Player1 should have a hand of Copper, Estate, Copper, Copper, Copper, Estate, Copper, Copper 17 | 18 | Scenario: Player plays Envoy with empty deck and discards 19 | Given A new game with 3 players 20 | And Player1 has a hand of Envoy, Copper, Estate, Copper, Copper 21 | And Player1 has an empty deck 22 | When Player1 plays a Envoy 23 | Then Player1 should have 4 cards in hand 24 | And All actions should be resolved -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Warehouse.feature: -------------------------------------------------------------------------------- 1 | Feature: Warehouse 2 | 3 | Scenario: Player must decide what cards to discard 4 | Given A new game with 3 players 5 | And Player1 has a Warehouse in hand instead of a Copper 6 | When Player1 plays a Warehouse 7 | Then Player1 should have 7 cards in hand 8 | And Player1 should have 1 remaining action 9 | And Player1 must select 3 cards to discard 10 | 11 | Scenario: Player discards 3 cards 12 | Given A new game with 3 players 13 | And Player1 has a Warehouse in hand instead of a Copper 14 | When Player1 plays a Warehouse 15 | And Player1 selects 3 Copper to discard 16 | Then Player1 should have 4 cards in hand 17 | And Player1 should have 1 remaining action 18 | And Player1 should have 3 cards in the discard pile 19 | 20 | Scenario: Play warehouse with a total of two cards in hand, deck and discard pile 21 | Given A new game with 3 players 22 | And Player1 has a hand of Warehouse, Copper 23 | And Player1 has an empty deck 24 | When Player1 plays a Warehouse 25 | Then Player1 should have 0 cards in hand 26 | And Player1 should have 1 remaining action 27 | And Player1 should have 1 card in the discard pile -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Moneylender.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Dominion.Rules; 5 | using Dominion.Rules.Activities; 6 | using Dominion.Rules.CardTypes; 7 | using Dominion.Cards.Treasure; 8 | 9 | namespace Dominion.Cards.Actions 10 | { 11 | public class Moneylender : Card, IActionCard 12 | { 13 | public Moneylender() 14 | : base(4) 15 | { } 16 | 17 | public void Play(TurnContext context) 18 | { 19 | context.AddEffect(this, new MoneylenderEffect()); 20 | } 21 | 22 | private class MoneylenderEffect : CardEffectBase 23 | { 24 | public override void Resolve(TurnContext context, ICard source) 25 | { 26 | if (context.ActivePlayer.Hand.OfType().Any()) 27 | { 28 | var copperCard = context.ActivePlayer.Hand.OfType().FirstOrDefault(); 29 | context.Trash(context.ActivePlayer, copperCard); 30 | context.AvailableSpend += 3; 31 | }; 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/PlaySimpleActionsBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Dominion.Rules.Activities; 4 | 5 | namespace Dominion.GameHost.AI.BehaviourBased 6 | { 7 | public class PlaySimpleActionsBehaviour : IAIBehaviour 8 | { 9 | 10 | public bool CanRespond(ActivityModel activity, GameViewModel state) 11 | { 12 | return activity.ParseType() == ActivityType.PlayActions && 13 | state.Hand.Select(c => c.Name).Intersect(AISupportedActions.All).Any(); 14 | } 15 | 16 | public void Respond(IGameClient client, ActivityModel activity, GameViewModel state) 17 | { 18 | var action = state.Hand 19 | .Where(c => c.Is(CardType.Action)) 20 | .Where(c => AISupportedActions.All.Contains(c.Name)) 21 | .OrderByDescending(c => AISupportedActions.PlusActions.Contains(c.Name)) 22 | .ThenByDescending(c => c.Cost) 23 | .First(); 24 | 25 | var message = new PlayCardMessage(client.PlayerId, action.Id); 26 | client.AcceptMessage(message); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Dominion.GameHost/ChooseAPileMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Dominion.Rules; 4 | using Dominion.Rules.Activities; 5 | 6 | namespace Dominion.GameHost 7 | { 8 | public class ChooseAPileMessage : IGameActionMessage 9 | { 10 | public ChooseAPileMessage(Guid playerId, Guid pileId) 11 | { 12 | PlayerId = playerId; 13 | PileId = pileId; 14 | } 15 | 16 | public Guid PlayerId { get; private set; } 17 | public Guid PileId { get; private set; } 18 | 19 | public void UpdateGameState(Game game) 20 | { 21 | var player = game.Players.Single(p => p.Id == PlayerId); 22 | var pile = game.Bank.Piles.SingleOrDefault(p => p.Id == PileId); 23 | var activity = game.GetPendingActivity(player) as ISelectPileActivity; 24 | 25 | if (activity == null) 26 | throw new InvalidOperationException("There must be a corresponding activity"); 27 | 28 | activity.SelectPile(pile); 29 | } 30 | 31 | public void Validate(Game game) 32 | { 33 | 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010 Paul Batum, Glenn Condron, Trent Kerin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /Dominion.Specs/Hosted/Reactions.feature: -------------------------------------------------------------------------------- 1 | Feature: Reactions 2 | In order to play the game to it's fullest potential 3 | As a dominion player 4 | I want to be able to pull neat tricks with reactions 5 | 6 | Scenario: Player uses Secret Chamber, draws a Moat, uses Moat, uses Secret Chamber again putting both reactions back on top of the deck 7 | Given A new hosted game with 3 players 8 | And Player1 has a Militia in hand instead of a Copper 9 | And Player2 has a hand of SecretChamber, Copper, Copper, Copper, Estate 10 | And Player2 has a deck of Moat, Estate, Estate, Copper, Copper 11 | When Player1 tells the host to play Militia 12 | And Player2 tells the host to reveal SecretChamber 13 | And Player2 tells the host to put Copper on top 14 | And Player2 tells the host to put Copper on top 15 | And Player2 tells the host to reveal Moat 16 | And Player2 tells the host to reveal SecretChamber 17 | And Player2 tells the host to put SecretChamber on top 18 | And Player2 tells the host to put Moat on top 19 | Then Player2 should have a hand of Copper, Estate, Estate, Copper, Copper 20 | And Player2 should have a deck of: Moat, SecretChamber, Estate, Copper, Copper 21 | 22 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Tribute.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Dominion.Rules; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Cards.Actions 6 | { 7 | public class Tribute : Card, IActionCard 8 | { 9 | public Tribute() 10 | : base(5) 11 | { 12 | 13 | } 14 | 15 | public void Play(TurnContext context) 16 | { 17 | var leftPlayer = context.Opponents.FirstOrDefault(); 18 | if (leftPlayer != null) 19 | { 20 | var revealZone = new RevealZone(leftPlayer); 21 | leftPlayer.Deck.MoveTop(2, revealZone); 22 | revealZone.LogReveal(context.Game.Log); 23 | 24 | foreach (var card in revealZone.WithDistinctTypes()) 25 | { 26 | if (card is IActionCard) context.RemainingActions += 2; 27 | if (card is ITreasureCard) context.AvailableSpend += 2; 28 | if (card is IVictoryCard) context.DrawCards(2); 29 | } 30 | 31 | revealZone.MoveAll(leftPlayer.Discards); 32 | } 33 | 34 | 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/DefaultDiscardOrRedrawCardsBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Dominion.Rules.Activities; 5 | 6 | namespace Dominion.GameHost.AI.BehaviourBased 7 | { 8 | public class DefaultDiscardOrRedrawCardsBehaviour : SelectFixedNumberOfCardsBehaviourBase 9 | { 10 | public override bool CanRespond(ActivityModel activity, GameViewModel state) 11 | { 12 | return base.CanRespond(activity, state) && 13 | (activity.ParseHint() == ActivityHint.DiscardCards || activity.ParseHint() == ActivityHint.RedrawCards); 14 | } 15 | 16 | protected override IEnumerable PrioritiseCards(GameViewModel state, ActivityModel activity) 17 | { 18 | 19 | return state.Hand 20 | .Where(c => !activity.HasTypeRestriction() || c.Types.Contains(activity.ParseTypeRestriction())) 21 | .OrderByDescending(c => c.Is(CardType.Treasure) == false) 22 | .ThenByDescending(c => c.Is(CardType.Action) == false) 23 | .ThenBy(c => c.Cost); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/SimpleAI.cs: -------------------------------------------------------------------------------- 1 | namespace Dominion.GameHost.AI.BehaviourBased 2 | { 3 | public class SimpleAI : BehaviourBasedAI 4 | { 5 | public SimpleAI() 6 | { 7 | Behaviours.Add(new CommentOnGameEndBehaviour("The game is over? But I was about to buy a Province!")); 8 | 9 | Behaviours.Add(new DefaultDiscardOrRedrawCardsBehaviour()); 10 | Behaviours.Add(new DefaultMakeChoiceBehaviour()); 11 | Behaviours.Add(new DefaultSelectFixedNumberOfCardsToPassOrTrashBehaviour()); 12 | Behaviours.Add(new DefaultSelectFromRevealedBehaviour()); 13 | Behaviours.Add(new DefaultSelectFixedNumberOfCardsForPlayBehaviour()); 14 | Behaviours.Add(new DefaultSelectUpToNumberOfCardsToTrashBehaviour()); 15 | 16 | Behaviours.Add(new PlaySimpleActionsBehaviour()); 17 | Behaviours.Add(new SkipActionsBehaviour()); 18 | 19 | Behaviours.Add(new BuyPointsBehaviour(6)); 20 | Behaviours.Add(new BuyAlternatingMoneyAndActionsBehaviour()); 21 | Behaviours.Add(new SkipBuyBehaviour()); 22 | 23 | 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/GhostShip.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Text; 4 | using Dominion.Rules; 5 | using Dominion.Rules.Activities; 6 | using Dominion.Rules.CardTypes; 7 | 8 | namespace Dominion.Cards.Actions 9 | { 10 | public class GhostShip : Card, IActionCard, IAttackCard 11 | { 12 | public GhostShip() 13 | : base(5) 14 | { 15 | } 16 | 17 | public void Play(TurnContext context) 18 | { 19 | context.ActivePlayer.DrawCards(2); 20 | context.AddEffect(this, new GhostShipAttack()); 21 | } 22 | 23 | private class GhostShipAttack : AttackEffect 24 | { 25 | public override void Attack(Player victim, TurnContext context, ICard source) 26 | { 27 | int cardsToPutBack = victim.Hand.CardCount - 3; 28 | 29 | var activities = Activities.PutMultipleCardsFromHandOnTopOfDeck(context.Game.Log, victim, cardsToPutBack, source); 30 | foreach(var activity in activities) 31 | _activities.Add(activity); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/CountingHouse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Cards.Treasure; 6 | using Dominion.Rules; 7 | using Dominion.Rules.CardTypes; 8 | 9 | namespace Dominion.Cards.Actions 10 | { 11 | public class CountingHouse : Card, IActionCard 12 | { 13 | public CountingHouse() : base(5) 14 | { 15 | } 16 | 17 | public void Play(TurnContext context) 18 | { 19 | var coppers = context.ActivePlayer.Discards.OfType().ToList(); 20 | 21 | if (coppers.Count > 0) 22 | { 23 | context.Game.Log.LogMessage("{0} put {1} Copper from their discard pile into their hand", 24 | context.ActivePlayer.Name, coppers.Count); 25 | 26 | foreach (var copper in coppers) 27 | copper.MoveTo(context.ActivePlayer.Hand); 28 | } 29 | else 30 | { 31 | context.Game.Log.LogMessage("Counting house did nothing - no Copper in discard pile."); 32 | } 33 | 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Dominion.WinForms/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.1 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Dominion.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Militia.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Dominion.Rules; 4 | using Dominion.Rules.Activities; 5 | using Dominion.Rules.CardTypes; 6 | 7 | namespace Dominion.Cards.Actions 8 | { 9 | public class Militia : Card, IActionCard, IAttackCard 10 | { 11 | public Militia() : base(4) 12 | { 13 | } 14 | 15 | public void Play(TurnContext context) 16 | { 17 | context.AvailableSpend += 2; 18 | context.AddEffect(this, new MilitiaAttack()); 19 | } 20 | 21 | private class MilitiaAttack : AttackEffect 22 | { 23 | public override void Attack(Player victim, TurnContext context, ICard source) 24 | { 25 | var numberToDiscard = victim.Hand.CardCount - 3; 26 | 27 | if (numberToDiscard > 0) 28 | _activities.Add(Activities.DiscardCards(context, victim, numberToDiscard, source)); 29 | else 30 | { 31 | context.Game.Log.LogMessage("{0} did not have to discard any cards.", victim.Name); 32 | } 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Salvager.feature: -------------------------------------------------------------------------------- 1 | Feature: Salvager 2 | 3 | Scenario: Salvager trashes a card 4 | Given A new game with 3 players 5 | And Player1 has a Salvager in hand instead of a Copper 6 | When Player1 plays a Salvager 7 | Then Player1 must select 1 card to trash 8 | 9 | Scenario: Salvager trashing estate gives plus 2 spend 10 | Given A new game with 3 players 11 | And Player1 has a hand of Salvager, Estate, Copper, Copper, Copper 12 | When Player1 plays a Salvager 13 | And Player1 selects a Estate to trash 14 | Then Player1 should have 2 to spend 15 | And Player1 should have 2 buys 16 | And There should be a Estate on top of the trash pile 17 | 18 | Scenario: Salvager with no other cards in hand 19 | Given A new game with 3 players 20 | And Player1 has a hand of Salvager 21 | When Player1 plays a Salvager 22 | Then All actions should be resolved 23 | And Player1 should have 2 buys 24 | 25 | Scenario: Salvaging a potion card does not let the player buy a potion card 26 | Given A new game with 3 players 27 | And Player1 has a hand of Salvager, Golem, Estate, Estate, Estate 28 | When Player1 plays a Salvager 29 | And Player1 selects a Golem to trash 30 | Then Player1 should have 4 to spend -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Apprentice.feature: -------------------------------------------------------------------------------- 1 | Feature: Apprentice 2 | 3 | Scenario: Apprentice trashes a card and is +1 action 4 | Given A new game with 3 players 5 | And Player1 has a Apprentice in hand instead of a Copper 6 | When Player1 plays a Apprentice 7 | Then Player1 must select 1 card to trash 8 | And Player1 should have 1 remaining action 9 | 10 | Scenario: Apprentice trashing estate draws 2 cards 11 | Given A new game with 3 players 12 | And Player1 has a hand of Apprentice, Estate, Copper, Copper, Copper 13 | When Player1 plays a Apprentice 14 | And Player1 selects a Estate to trash 15 | Then Player1 should have 5 cards in hand 16 | And There should be a Estate on top of the trash pile 17 | 18 | Scenario: Apprentice with no other cards in hand 19 | Given A new game with 3 players 20 | And Player1 has a hand of Apprentice 21 | When Player1 plays a Apprentice 22 | Then All actions should be resolved 23 | 24 | Scenario: Apprentice trashing Familiar draws 5 cards 25 | Given A new game with 3 players 26 | And Player1 has a hand of Apprentice, Familiar, Estate, Estate, Estate 27 | When Player1 plays a Apprentice 28 | And Player1 selects a Familiar to trash 29 | Then Player1 should have 8 cards in hand -------------------------------------------------------------------------------- /Dominion.Specs/Scoring.feature: -------------------------------------------------------------------------------- 1 | Feature: Scoring 2 | In order to know how well I did in the game 3 | As a Dominion player 4 | I want the scores to be calculated 5 | 6 | Scenario: Players start with 3 points 7 | Given A new game with 3 players 8 | When The game is scored 9 | Then Player1 should have 3 victory points 10 | And Player2 should have 3 victory points 11 | And Player3 should have 3 victory points 12 | 13 | Scenario: Score cards in all regions 14 | Given A new game with 3 players 15 | And Player1 has a Curse in hand instead of a Copper 16 | And Player1 has a GreatHall in play 17 | And Player1 has a Province in the discard pile 18 | When The game is scored 19 | Then Player1 should have 9 victory points 20 | 21 | Scenario: Show sorted deck in play area once game is scored 22 | Given A new game with 3 players 23 | And Player1 has a Curse in hand instead of a Copper 24 | And Player1 has a GreatHall in play 25 | And Player1 has a Province in the discard pile 26 | When The game is scored 27 | Then Player1's play area should start with this sequence of cards: Province, Estate, Estate, Estate, GreatHall, Curse 28 | Then Player2's play area should start with this sequence of cards: Estate, Estate, Estate -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/DefaultSelectFixedNumberOfCardsForPlayBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules.Activities; 6 | 7 | namespace Dominion.GameHost.AI.BehaviourBased 8 | { 9 | public class DefaultSelectFixedNumberOfCardsForPlayBehaviour : SelectFixedNumberOfCardsBehaviourBase 10 | { 11 | public bool CanRespond(ActivityModel activity, GameViewModel state) 12 | { 13 | return base.CanRespond(activity, state) 14 | && activity.ParseHint() == ActivityHint.PlayCards 15 | && state.Hand.Select(c => c.Name).Intersect(AISupportedActions.All).Any(); 16 | } 17 | 18 | protected override IEnumerable PrioritiseCards(GameViewModel state, ActivityModel activity) 19 | { 20 | var actions = state.Hand 21 | .Where(c => c.Is(CardType.Action)) 22 | .Where(c => AISupportedActions.All.Contains(c.Name)) 23 | .OrderByDescending(c => c.Cost) 24 | .Take(activity.ParseNumberOfCardsToSelect()); 25 | 26 | return actions; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Dominion.AIWorkbench/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.1 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Dominion.AIWorkbench.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Dominion.Web/Bootstrap/AutofacConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Web.Mvc; 4 | using Autofac; 5 | using Autofac.Integration.Web; 6 | using Autofac.Integration.Web.Mvc; 7 | using System.Reflection; 8 | using Dominion.GameHost; 9 | using Microsoft.Web.Mvc; 10 | 11 | namespace Dominion.Web.Bootstrap 12 | { 13 | public class AutofacConfig 14 | { 15 | private static IContainer _container; 16 | 17 | 18 | public static IContainer Container 19 | { 20 | get { return _container; } 21 | } 22 | 23 | public static void Initialize() 24 | { 25 | var builder = new ContainerBuilder(); 26 | builder.RegisterControllers(Assembly.GetExecutingAssembly()); 27 | 28 | var host = new MultiGameHost(); 29 | builder.RegisterInstance(host) 30 | .As(); 31 | 32 | _container = builder.Build(); 33 | 34 | var factory = 35 | new MvcDynamicSessionControllerFactory(new AutofacControllerFactory(new ContainerProvider(_container))); 36 | ControllerBuilder.Current.SetControllerFactory(factory); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/KingsCourt.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Dominion.Rules; 3 | using Dominion.Rules.Activities; 4 | using Dominion.Rules.CardTypes; 5 | 6 | namespace Dominion.Cards.Actions 7 | { 8 | public class KingsCourt : Card, IActionCard 9 | { 10 | public KingsCourt() : base(7) 11 | { 12 | } 13 | 14 | public void Play(TurnContext context) 15 | { 16 | context.AddEffect(this, new KingsCourtEffect()); 17 | } 18 | 19 | private class KingsCourtEffect : CardEffectBase 20 | { 21 | public override void Resolve(TurnContext context, ICard source) 22 | { 23 | if (context.ActivePlayer.Hand.OfType().Any()) 24 | { 25 | var activity = Activities.SelectActionToPlayMultipleTimes(context, context.ActivePlayer, context.Game.Log, source, 3); 26 | _activities.Add(activity); 27 | } 28 | else 29 | { 30 | context.Game.Log.LogMessage("{0} did not have any actions to use Kings Court on.", context.ActivePlayer.Name); 31 | } 32 | } 33 | } 34 | 35 | 36 | } 37 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Mountebank.feature: -------------------------------------------------------------------------------- 1 | Feature: Mountebank 2 | 3 | Scenario: Player plays Mountebank when opponents have no curses in hand 4 | Given A new game with 3 players 5 | And Player1 has a Mountebank in hand instead of a Copper 6 | When Player1 plays a Mountebank 7 | Then Player1 should have 2 to spend 8 | Then Player2 should have a discard pile of Copper, Curse 9 | Then Player3 should have a discard pile of Copper, Curse 10 | 11 | Scenario: Player plays Mountebank, opponent must choose whether to discard a curse 12 | Given A new game with 3 players 13 | And Player1 has a Mountebank in hand instead of a Copper 14 | And Player2 has a Curse in hand instead of a Copper 15 | When Player1 plays a Mountebank 16 | Then Player2 must choose whether to discard a Curse (Yes or No) 17 | Then Player3 must wait 18 | 19 | Scenario: Play Mountebank when an opponent is holding a curse 20 | Given A new game with 3 players 21 | And Player1 has a Mountebank in hand instead of a Copper 22 | And Player2 has a Curse in hand instead of a Copper 23 | When Player1 plays a Mountebank 24 | When Player2 chooses to discard a Curse (Yes) 25 | Then Player2 should have a discard pile of Curse 26 | Then Player3 should have a discard pile of Copper, Curse -------------------------------------------------------------------------------- /Dominion.Rules/UnlimitedSupplyCardPile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Dominion.Rules 4 | { 5 | public class UnlimitedSupplyCardPile : CardPile 6 | { 7 | private readonly Func _cardCreator; 8 | 9 | public UnlimitedSupplyCardPile(Func cardCreator) 10 | { 11 | _cardCreator = cardCreator; 12 | } 13 | 14 | public override bool IsEmpty 15 | { 16 | get { return false; } 17 | } 18 | 19 | public override int CardCount 20 | { 21 | get 22 | { 23 | throw new NotSupportedException("A null zone cannot be considered to have a card count"); 24 | } 25 | } 26 | 27 | public override ICard TopCard 28 | { 29 | get { return _cardCreator(); } 30 | } 31 | 32 | public override bool IsLimited 33 | { 34 | get { return false; } 35 | } 36 | 37 | protected override void AddCard(ICard card) 38 | { 39 | // NO OP 40 | } 41 | 42 | protected override void RemoveCard(ICard card) 43 | { 44 | // NO OP 45 | } 46 | 47 | } 48 | } -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/ProbabilityAI.cs: -------------------------------------------------------------------------------- 1 | namespace Dominion.GameHost.AI.BehaviourBased 2 | { 3 | public class ProbabilityAI : BehaviourBasedAI 4 | { 5 | public ProbabilityAI(ProbabilityDistribution buyDistribution) 6 | { 7 | var buyBehaviour = new ProbabilisticBuyBehaviour(buyDistribution); 8 | 9 | Behaviours.Add(new ProbabilisticBuyBehaviour.LearnFromGameResultBehaviour(buyDistribution)); 10 | 11 | Behaviours.Add(new DefaultDiscardOrRedrawCardsBehaviour()); 12 | Behaviours.Add(new DefaultMakeChoiceBehaviour()); 13 | Behaviours.Add(new DefaultSelectFixedNumberOfCardsToPassOrTrashBehaviour()); 14 | Behaviours.Add(new DefaultSelectFromRevealedBehaviour()); 15 | Behaviours.Add(new DefaultSelectFixedNumberOfCardsForPlayBehaviour()); 16 | Behaviours.Add(new DefaultSelectUpToNumberOfCardsToTrashBehaviour()); 17 | 18 | Behaviours.Add(new PlaySimpleActionsBehaviour()); 19 | Behaviours.Add(new SkipActionsBehaviour()); 20 | 21 | Behaviours.Add(new BuyPointsBehaviour(6)); 22 | Behaviours.Add(buyBehaviour); 23 | Behaviours.Add(new SkipBuyBehaviour()); 24 | 25 | 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/FishingVillage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | using Dominion.Rules.CardTypes; 7 | 8 | namespace Dominion.Cards.Actions 9 | { 10 | public class FishingVillage : Card, IDurationCard 11 | { 12 | public FishingVillage() 13 | : base(3) 14 | { 15 | } 16 | 17 | public void Play(TurnContext context) 18 | { 19 | context.RemainingActions += 2; 20 | context.AvailableSpend += 1; 21 | 22 | context.AddLongLivedEffect(new FishingVillageEffect(this)); 23 | } 24 | 25 | public class FishingVillageEffect : DurationEffect 26 | { 27 | public FishingVillageEffect(FishingVillage sourceCard) : base(sourceCard) 28 | {} 29 | 30 | public override void OnTurnStarting(TurnContext context) 31 | { 32 | base.OnTurnStarting(context); 33 | 34 | context.RemainingActions += 1; 35 | context.AvailableSpend += 1; 36 | context.Game.Log.LogMessage("FishingVillage adds one action and one spend"); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Dominion.Rules/Card.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Dominion.Rules 4 | { 5 | public delegate void CardZoneChanger(CardZone targetZone); 6 | 7 | public abstract class Card : Dominion.Rules.ICard 8 | { 9 | private CardZone _currentZone; 10 | private readonly CardZoneChanger _zoneChanger; 11 | 12 | public Guid Id { get; private set; } 13 | 14 | protected Card(CardCost cost) 15 | { 16 | Id = Guid.NewGuid(); 17 | Cost = cost; 18 | _currentZone = new NullZone(); 19 | _zoneChanger = zone => _currentZone = zone; 20 | } 21 | 22 | public void MoveTo(CardZone targetZone) 23 | { 24 | _currentZone.MoveCard(this, targetZone, _zoneChanger); 25 | } 26 | 27 | public CardZone CurrentZone 28 | { 29 | get { return _currentZone; } 30 | } 31 | 32 | public CardCost Cost { get; protected set; } 33 | 34 | 35 | public string Name 36 | { 37 | get { return this.GetType().Name; } 38 | } 39 | 40 | public override string ToString() 41 | { 42 | return this.Name; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Dominion.Specs/Bindings/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.GameHost; 6 | using Dominion.Rules; 7 | using Dominion.Rules.Activities; 8 | 9 | namespace Dominion.Specs.Bindings 10 | { 11 | public static class Extensions 12 | { 13 | public static int GetCountProperty(this IActivity activity) 14 | { 15 | return (int) activity.Properties["NumberOfCardsToSelect"]; 16 | } 17 | 18 | public static CardCost GetCostProperty(this IActivity activity) 19 | { 20 | return (CardCost)activity.Properties["Cost"]; 21 | } 22 | 23 | public static Type GetTypeRestrictionProperty(this IActivity activity) 24 | { 25 | return (Type)activity.Properties["CardsMustBeOfType"]; 26 | } 27 | 28 | public static string GetTypeRestrictionProperty(this ActivityModel activity) 29 | { 30 | return (string) activity.Properties["CardsMustBeOfType"]; 31 | } 32 | 33 | public static string GetCardNames(this CardViewModel[] cards) 34 | { 35 | return string.Join(", ", cards.Select(c => c.Name).ToArray()); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/ThroneRoom.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Dominion.Rules; 5 | using Dominion.Rules.Activities; 6 | using Dominion.Rules.CardTypes; 7 | 8 | namespace Dominion.Cards.Actions 9 | { 10 | public class ThroneRoom : Card, IActionCard 11 | { 12 | public ThroneRoom() : base(4) 13 | { 14 | } 15 | 16 | public void Play(TurnContext context) 17 | { 18 | context.AddEffect(this, new ThroneRoomEffect()); 19 | } 20 | 21 | private class ThroneRoomEffect : CardEffectBase 22 | { 23 | public override void Resolve(TurnContext context, ICard source) 24 | { 25 | if (context.ActivePlayer.Hand.OfType().Any()) 26 | { 27 | var activity = Activities.SelectActionToPlayMultipleTimes(context, context.ActivePlayer, context.Game.Log, source, 2); 28 | _activities.Add(activity); 29 | } 30 | else 31 | { 32 | context.Game.Log.LogMessage("{0} did not have any actions to use Throne Room on.", context.ActivePlayer.Name); 33 | } 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/SelectFixedNumberOfCardsBehaviourBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using Dominion.Rules.Activities; 6 | 7 | namespace Dominion.GameHost.AI.BehaviourBased 8 | { 9 | public abstract class SelectFixedNumberOfCardsBehaviourBase : IAIBehaviour 10 | { 11 | public virtual bool CanRespond(ActivityModel activity, GameViewModel state) 12 | { 13 | return activity.ParseType() == ActivityType.SelectFixedNumberOfCards; 14 | } 15 | 16 | protected abstract IEnumerable PrioritiseCards(GameViewModel state, ActivityModel activity); 17 | 18 | public void Respond(IGameClient client, ActivityModel activity, GameViewModel state) 19 | { 20 | int count = activity.ParseNumberOfCardsToSelect(); 21 | 22 | var ids = PrioritiseCards(state, activity) 23 | .Take(count) 24 | .Select(c => c.Id) 25 | .ToArray(); 26 | 27 | if(ids.Length != count) 28 | Debugger.Break(); 29 | 30 | var message = new SelectCardsMessage(client.PlayerId, ids); 31 | client.AcceptMessage(message); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Chancellor.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.Activities; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Cards.Actions 6 | { 7 | public class Chancellor : Card, IActionCard 8 | { 9 | public Chancellor() 10 | : base(3) 11 | { 12 | } 13 | 14 | public void Play(TurnContext context) 15 | { 16 | context.AvailableSpend += 2; 17 | context.AddEffect(this, new ChancellorEffect()); 18 | } 19 | 20 | public class ChancellorEffect : CardEffectBase 21 | { 22 | public override void Resolve(TurnContext context, ICard source) 23 | { 24 | var player = context.ActivePlayer; 25 | var choiceActivity = Activities.ChooseYesOrNo(context.Game.Log, player, 26 | "Do you wish to put your deck into your discard pile?", 27 | source, 28 | () => 29 | { 30 | context.Game.Log.LogMessage("{0} put his deck in his discard pile", player); 31 | player.Deck.MoveAll(player.Discards); 32 | }); 33 | 34 | _activities.Add(choiceActivity); 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Spy.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Rules; 2 | using Dominion.Rules.Activities; 3 | using Dominion.Rules.CardTypes; 4 | 5 | namespace Dominion.Cards.Actions 6 | { 7 | public class Spy : Card, IAttackCard, IActionCard 8 | { 9 | public Spy() : base(4) 10 | { 11 | } 12 | 13 | public void Play(TurnContext context) 14 | { 15 | context.DrawCards(1); 16 | context.RemainingActions += 1; 17 | context.AddEffect(this, new SpyAttack()); 18 | } 19 | 20 | public class SpyAttack : AttackEffect 21 | { 22 | public override void Resolve(TurnContext context, ICard source) 23 | { 24 | base.Resolve(context, source); 25 | 26 | if(context.ActivePlayer.Deck.TopCard != null) 27 | _activities.Add(Activities.ChooseWhetherToMillTopCard(context, context.ActivePlayer, context.ActivePlayer, source)); 28 | } 29 | 30 | public override void Attack(Player victim, TurnContext context, ICard source) 31 | { 32 | if(victim.Deck.TopCard != null) 33 | _activities.Add(Activities.ChooseWhetherToMillTopCard(context, context.ActivePlayer, victim, source)); 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Dominion.Specs/Bindings/BindingBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using TechTalk.SpecFlow; 5 | 6 | namespace Dominion.Specs.Bindings 7 | { 8 | // Borrowed from Orchard. 9 | // http://orchard.codeplex.com/SourceControl/changeset/view/c0577b633ffa#src%2fOrchard.Specs%2fBindings%2fBindingBase.cs 10 | public class BindingBase 11 | { 12 | protected static T Binding() 13 | { 14 | return (T)ScenarioContext.Current.GetBindingInstance(typeof(T)); 15 | } 16 | 17 | protected Table TableData(params T[] rows) 18 | { 19 | return BuildTable(rows); 20 | } 21 | 22 | protected Table TableData(IEnumerable rows) 23 | { 24 | return BuildTable(rows); 25 | } 26 | 27 | private Table BuildTable(IEnumerable rows) 28 | { 29 | var properties = typeof(T).GetProperties(); 30 | var table = new Table(properties.Select(x => x.Name).ToArray()); 31 | foreach (var row in rows) 32 | { 33 | var row1 = row; 34 | table.AddRow(properties.Select(p => Convert.ToString(p.GetValue(row1, null))).ToArray()); 35 | } 36 | return table; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/TradingPost.feature: -------------------------------------------------------------------------------- 1 | Feature: Trading Post 2 | 3 | Scenario: Player plays trading post and must choose what to trash 4 | Given A new game with 3 players 5 | And Player1 has a hand of TradingPost, Estate, Estate, Copper, Copper 6 | When Player1 plays a TradingPost 7 | Then Player1 must select 2 cards to trash 8 | 9 | Scenario: Player plays trading post and trashes a copper and an estate, gaining a silver 10 | Given A new game with 3 players 11 | And Player1 has a hand of TradingPost, Estate, Estate, Copper, Copper 12 | When Player1 plays a TradingPost 13 | And Player1 selects cards [Estate, Copper] to trash 14 | Then The trash pile should be Estate, Copper 15 | And Player1 should have a hand of Estate, Copper, Silver 16 | 17 | Scenario: Player plays trading post with only one other card in hand - it is trashed and no silver is gained 18 | Given A new game with 3 players 19 | And Player1 has a hand of TradingPost, Estate 20 | When Player1 plays a TradingPost 21 | Then All actions should be resolved 22 | And The trash pile should be Estate 23 | And Player1 should have 0 cards in hand 24 | 25 | Scenario: Player plays trading post with no other cards in hand 26 | Given A new game with 3 players 27 | And Player1 has a hand of TradingPost 28 | When Player1 plays a TradingPost 29 | Then All actions should be resolved 30 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Warehouse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | using Dominion.Rules.Activities; 7 | using Dominion.Rules.CardTypes; 8 | 9 | namespace Dominion.Cards.Actions 10 | { 11 | public class Warehouse : Card, IActionCard 12 | { 13 | public Warehouse() : base(3) 14 | { 15 | 16 | } 17 | 18 | public void Play(TurnContext context) 19 | { 20 | context.RemainingActions += 1; 21 | context.DrawCards(3); 22 | context.AddEffect(this, new WarehouseEffect()); 23 | } 24 | 25 | private class WarehouseEffect : CardEffectBase 26 | { 27 | public override void Resolve(TurnContext context, ICard source) 28 | { 29 | if(context.ActivePlayer.Hand.CardCount < 4) 30 | { 31 | context.DiscardCards(context.ActivePlayer, context.ActivePlayer.Hand); 32 | } 33 | else 34 | { 35 | var discardActivity = Activities.DiscardCards(context, context.ActivePlayer, 3, source); 36 | _activities.Add(discardActivity); 37 | } 38 | 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Dominion.AIWorkbench/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Windows.Forms; 5 | 6 | namespace Dominion.AIWorkbench 7 | { 8 | static class Program 9 | { 10 | /// 11 | /// The main entry point for the application. 12 | /// 13 | [STAThread] 14 | static void Main() 15 | { 16 | Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); 17 | AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); 18 | Application.EnableVisualStyles(); 19 | Application.SetCompatibleTextRenderingDefault(false); 20 | Application.Run(new MDIParent()); 21 | } 22 | 23 | static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 24 | { 25 | MessageBox.Show(e.ExceptionObject.ToString(), "BOOM!", MessageBoxButtons.OK, MessageBoxIcon.Error); 26 | 27 | } 28 | 29 | static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) 30 | { 31 | MessageBox.Show(e.Exception.ToString(), "BOOM!", MessageBoxButtons.OK, MessageBoxIcon.Error); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Explorer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Dominion.Cards.Treasure; 4 | using Dominion.Cards.Victory; 5 | using Dominion.Rules; 6 | using Dominion.Rules.Activities; 7 | using Dominion.Rules.CardTypes; 8 | 9 | namespace Dominion.Cards.Actions 10 | { 11 | public class Explorer : Card, IActionCard 12 | { 13 | public Explorer() 14 | : base(5) 15 | { 16 | } 17 | 18 | public void Play(TurnContext context) 19 | { 20 | var gainUtility = new GainUtility(context, context.ActivePlayer); 21 | Action gainSilver = () => gainUtility.Gain(context.ActivePlayer.Hand); 22 | Action gainGold = () => gainUtility.Gain(context.ActivePlayer.Hand); 23 | 24 | if (context.ActivePlayer.Hand.OfType().Any()) 25 | { 26 | var activity = Activities.ChooseYesOrNo( 27 | context.Game.Log, 28 | context.ActivePlayer, 29 | "Reveal a Province to gain a Gold?", 30 | this, 31 | gainGold, 32 | gainSilver); 33 | context.AddSingleActivity(activity, this); 34 | } 35 | else 36 | { 37 | gainSilver(); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Dominion.Web/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Rabble.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Dominion.Rules; 4 | using Dominion.Rules.Activities; 5 | using Dominion.Rules.CardTypes; 6 | 7 | namespace Dominion.Cards.Actions 8 | { 9 | public class Rabble : Card, IActionCard, IAttackCard 10 | { 11 | public Rabble() 12 | : base(5) 13 | { 14 | } 15 | 16 | public void Play(TurnContext context) 17 | { 18 | context.DrawCards(3); 19 | context.AddEffect(this, new RabbleAttack()); 20 | } 21 | 22 | private class RabbleAttack : AttackEffect 23 | { 24 | public override void Attack(Player victim, TurnContext context, ICard source) 25 | { 26 | var revealZone = new RevealZone(victim); 27 | victim.Deck.MoveTop(3, revealZone); 28 | 29 | revealZone.LogReveal(context.Game.Log); 30 | revealZone.MoveWhere(c => c is IActionCard || c is ITreasureCard, victim.Discards); 31 | 32 | if(revealZone.CardCount == 1) 33 | victim.Deck.MoveToTop(revealZone.Single()); 34 | 35 | foreach (var activity in Activities.SelectMultipleRevealedCardsToPutOnTopOfDeck(context.Game.Log, victim, revealZone, source)) 36 | _activities.Add(activity); 37 | } 38 | 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Dominion.GameHost/AI/BehaviourBased/BuySimpleActionsBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Dominion.Rules.Activities; 4 | 5 | namespace Dominion.GameHost.AI.BehaviourBased 6 | { 7 | public class BuySimpleActionsBehaviour : BuyBehaviourBase 8 | { 9 | private readonly Random _random = new Random(); 10 | 11 | public override bool CanRespond(ActivityModel activity, GameViewModel state) 12 | { 13 | return base.CanRespond(activity, state) 14 | && (GetValidBuys(state).Any(pile => AISupportedActions.All.Contains(pile.Name)) 15 | || (activity.ParseType() == ActivityType.SelectPile && (bool)activity.Properties["IsOptional"])); 16 | } 17 | 18 | protected override CardPileViewModel SelectPile(GameViewModel state, IGameClient client) 19 | { 20 | var options = GetValidBuys(state) 21 | .Where(pile => AISupportedActions.All.Contains(pile.Name)) 22 | .OrderByDescending(pile => pile.Cost) 23 | .ThenBy(pile => _random.Next(100)) 24 | .ToList(); 25 | 26 | var message = string.Format("I considered {0}.", string.Join(", ", options.Select(x => x.Name).ToArray())); 27 | client.SendChatMessage(message); 28 | 29 | return options.FirstOrDefault(); 30 | } 31 | 32 | 33 | } 34 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Explorer.feature: -------------------------------------------------------------------------------- 1 | Feature: Explorer 2 | 3 | Scenario: Player must decide whether to reveal province after playing explorer 4 | Given A new game with 3 players 5 | And Player1 has a hand of Explorer, Province, Copper, Copper, Estate 6 | When Player1 plays an Explorer 7 | Then Player1 must choose whether to reveal a Province (Yes or No) 8 | 9 | Scenario: Player reveals a province and gains a gold 10 | Given A new game with 3 players 11 | And Player1 has a hand of Explorer, Province, Copper, Copper, Estate 12 | When Player1 plays an Explorer 13 | And Player1 chooses to gain a Gold (Yes) 14 | Then Player1 should have a hand of Province, Copper, Copper, Estate, Gold 15 | 16 | Scenario: Player chooses not to reveal a province and gains a silver 17 | Given A new game with 3 players 18 | And Player1 has a hand of Explorer, Province, Copper, Copper, Estate 19 | When Player1 plays an Explorer 20 | And Player1 chooses to gain a Silver (No) 21 | Then Player1 should have a hand of Province, Copper, Copper, Estate, Silver 22 | 23 | Scenario: Player does not have a Province in hand and gains a silver 24 | Given A new game with 3 players 25 | And Player1 has a hand of Explorer, Estate, Copper, Copper, Estate 26 | When Player1 plays an Explorer 27 | Then All actions should be resolved 28 | And Player1 should have a hand of Estate, Copper, Copper, Estate, Silver 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Binaries/Rx/System.Observable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | System.Observable 5 | 6 | 7 | 8 | 9 | Represents a push-style collection. 10 | 11 | 12 | 13 | 14 | Subscribes an observer to the observable sequence. 15 | 16 | 17 | 18 | 19 | Supports push-style iteration over an observable sequence. 20 | 21 | 22 | 23 | 24 | Notifies the observer of a new value in the sequence. 25 | 26 | 27 | 28 | 29 | Notifies the observer that an exception has occurred. 30 | 31 | 32 | 33 | 34 | Notifies the observer of the end of the sequence. 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Dominion.Specs/GameEnd.feature: -------------------------------------------------------------------------------- 1 | Feature: Game End 2 | In order to avoid playing Dominion forever 3 | As a Dominion player 4 | I want the game to end at some point 5 | 6 | Scenario: Game ends when last province is bought 7 | Given A new game with 3 players 8 | But There is only 1 Province left 9 | And Player1 has 5 Gold in hand 10 | When Player1 moves to the buy step 11 | And Player1 buys a Province 12 | And Player1 ends their turn 13 | Then The game should have ended 14 | 15 | Scenario Outline: Game ends when piles are exhausted 16 | Given A new game with players 17 | And There are empty piles 18 | When Player1 ends their turn 19 | Then The game should have ended 20 | 21 | Examples: 22 | |player count |empty pile count | 23 | |1 |3 | 24 | |2 |3 | 25 | |3 |3 | 26 | |4 |3 | 27 | |5 |4 | 28 | |6 |4 | 29 | 30 | Scenario: Game still ends when more piles are exhausted than necessary 31 | Given A new game with 4 players 32 | And There are 4 empty piles 33 | When Player1 ends their turn 34 | Then The game should have ended 35 | 36 | Scenario: Game isn't over until the last turn ends 37 | Given A new game with 3 players 38 | But There is only 1 Province left 39 | And Player1 has 5 Gold in hand 40 | When Player1 moves to the buy step 41 | And Player1 buys a Province 42 | Then The game should not have ended 43 | 44 | -------------------------------------------------------------------------------- /Dominion.Web/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Baron.feature: -------------------------------------------------------------------------------- 1 | Feature: Baron 2 | 3 | Scenario: Player plays baron with no estate in hand 4 | Given A new game with 3 players 5 | And Player1 has a hand of Baron, Copper, Copper, Copper, Copper 6 | When Player1 plays a Baron 7 | Then Player1 should have an Estate on top of the discard pile 8 | And Player1 should have 2 buys 9 | 10 | Scenario: Player plays baron with an estate in hand and must choose 11 | Given A new game with 3 players 12 | And Player1 has a hand of Baron, Estate, Copper, Copper, Copper 13 | When Player1 plays a Baron 14 | Then Player1 must choose whether to use Chancellor's effect (Yes or No) 15 | 16 | Scenario: Player plays baron with an estate in hand and chooses to discard it 17 | Given A new game with 3 players 18 | And Player1 has a hand of Baron, Estate, Copper, Copper, Copper 19 | When Player1 plays a Baron 20 | When Player1 chooses to discard the estate (Yes) 21 | Then Player1 should have 4 to spend 22 | Then Player1 should have an Estate on top of the discard pile 23 | And Player1 should have a hand of Copper, Copper, Copper 24 | 25 | Scenario: Player plays baron with an estate in hand and chooses not to discard 26 | Given A new game with 3 players 27 | And Player1 has a hand of Baron, Estate, Copper, Copper, Copper 28 | When Player1 plays a Baron 29 | When Player1 chooses to keep the estate (No) 30 | Then Player1 should have 0 to spend 31 | And Player1 should have an Estate on top of the discard pile -------------------------------------------------------------------------------- /Dominion.GameHost/SimpleStartingConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Dominion.Cards.Hybrid; 2 | using Dominion.Cards.Victory; 3 | using Dominion.Rules; 4 | using Dominion.Cards.Actions; 5 | 6 | namespace Dominion.GameHost 7 | { 8 | public class SimpleStartingConfiguration : StartingConfiguration 9 | { 10 | public SimpleStartingConfiguration(int numberOfPlayers) : base(numberOfPlayers) 11 | {} 12 | 13 | public override void InitializeBank(Dominion.Rules.CardBank bank) 14 | { 15 | bank.AddCardPile(new LimitedSupplyCardPile().WithNewCards(10)); 16 | bank.AddCardPile(new LimitedSupplyCardPile().WithNewCards(10)); 17 | bank.AddCardPile(new LimitedSupplyCardPile().WithNewCards(10)); 18 | bank.AddCardPile(new LimitedSupplyCardPile().WithNewCards(10)); 19 | bank.AddCardPile(new LimitedSupplyCardPile().WithNewCards(10)); 20 | bank.AddCardPile(new LimitedSupplyCardPile().WithNewCards(10)); 21 | bank.AddCardPile(new LimitedSupplyCardPile().WithNewCards(10)); 22 | bank.AddCardPile(new LimitedSupplyCardPile().WithNewCards(10)); 23 | bank.AddCardPile(new LimitedSupplyCardPile().WithNewCards(10)); 24 | bank.AddCardPile(new LimitedSupplyCardPile().WithNewCards(10)); 25 | base.InitializeBank(bank); 26 | } 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Dominion.Rules/PassiveCardEffectBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules.CardTypes; 6 | 7 | namespace Dominion.Rules 8 | { 9 | /// 10 | /// 11 | /// 12 | public interface IPassiveCardEffect 13 | { 14 | /// 15 | /// 16 | /// 17 | /// The current cost of the card, potentially already modified 18 | /// The card whose cost is being modified 19 | /// 20 | int ModifyCost(int currentCost, ICard card); 21 | 22 | /// 23 | /// 24 | /// 25 | /// The current value of the card, potentially already modified 26 | /// The card whose value is being modified 27 | /// 28 | CardCost ModifyValue(CardCost currentValue, ITreasureCard card); 29 | } 30 | 31 | public class PassiveCardEffectBase : IPassiveCardEffect 32 | { 33 | public virtual int ModifyCost(int currentCost, ICard card) 34 | { 35 | return currentCost; 36 | } 37 | 38 | public virtual CardCost ModifyValue(CardCost currentValue, ITreasureCard card) 39 | { 40 | return currentValue; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Adventurer.feature: -------------------------------------------------------------------------------- 1 | Feature: Adventurer 2 | 3 | Scenario: Play Adventurer but reveal no treasure 4 | Given A new game with 3 players 5 | And Player1 has a hand of Adventurer, Copper, Copper, Copper, Copper 6 | And Player1 has a deck of Estate, Estate, Estate, Estate, Estate 7 | When Player1 plays a Adventurer 8 | Then Player1 should have a hand of Copper, Copper, Copper, Copper 9 | And Player1 should have 0 cards in deck 10 | And Player1 should have a discard pile of Estate, Estate, Estate, Estate, Estate 11 | 12 | Scenario: Play Adventurer but reveal only one treasure 13 | Given A new game with 3 players 14 | And Player1 has a hand of Adventurer, Copper, Copper, Copper, Copper 15 | And Player1 has a deck of Estate, Estate, Estate, Copper, Estate 16 | When Player1 plays a Adventurer 17 | Then Player1 should have a hand of Copper, Copper, Copper, Copper, Copper 18 | And Player1 should have 0 cards in deck 19 | And Player1 should have a discard pile of Estate, Estate, Estate, Estate 20 | 21 | Scenario: Play Adventurer and reveal two treasure 22 | Given A new game with 3 players 23 | And Player1 has a hand of Adventurer, Copper, Copper, Copper, Copper 24 | And Player1 has a deck of Estate, Copper, Estate, Copper, Silver 25 | When Player1 plays a Adventurer 26 | Then Player1 should have a hand of Copper, Copper, Copper, Copper, Copper, Copper 27 | And Player1 should have a deck of: Silver 28 | And Player1 should have a discard pile of Estate, Estate 29 | -------------------------------------------------------------------------------- /Dominion.Rules/MyExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Dominion.Rules.CardTypes; 5 | 6 | namespace Dominion.Rules 7 | { 8 | public static class MyExtensions 9 | { 10 | public static void Times(this int count, Action action) 11 | { 12 | if (action != null) 13 | { 14 | for (int i = 1; i <= count; i++) 15 | action(); 16 | } 17 | } 18 | 19 | public static IEnumerable Items(this int count, Func builder) 20 | { 21 | if (builder == null) 22 | yield break; 23 | 24 | for (int i = 1; i <= count; i++) 25 | yield return builder(); 26 | } 27 | 28 | public static IEnumerable Items(this int count, Func builder) 29 | { 30 | if (builder == null) 31 | yield break; 32 | 33 | for (int i = 1; i <= count; i++) 34 | yield return builder(i); 35 | } 36 | 37 | public static IEnumerable WithDistinctTypes(this IEnumerable input) 38 | { 39 | return input.Distinct(new SameTypeEqualityComparer()); 40 | } 41 | 42 | public static bool AllSame(this IEnumerable items, Func selector) 43 | { 44 | return items.Select(selector).Distinct().Count() < 2; 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Torturer.feature: -------------------------------------------------------------------------------- 1 | Feature: Torturer 2 | 3 | Scenario: Player plays Torturer and opponents must decide whether to discard cards or gain a curse 4 | Given A new game with 3 players 5 | And Player1 has a Torturer in hand instead of a Copper 6 | When Player1 plays a Torturer 7 | Then Player1 should have 7 cards in hand 8 | And Player2 must choose whether to discard cards (Yes or No) 9 | And Player3 must choose whether to discard cards (Yes or No) 10 | 11 | Scenario: Player plays Torturer and opponent decides to discard cards 12 | Given A new game with 2 players 13 | And Player1 has a Torturer in hand instead of a Copper 14 | When Player1 plays a Torturer 15 | And Player2 chooses to discard cards (Yes) 16 | Then Player2 must select 2 cards to discard 17 | 18 | Scenario: Player plays Torturer and opponent decides to gain a curse 19 | Given A new game with 2 players 20 | And Player1 has a Torturer in hand instead of a Copper 21 | When Player1 plays a Torturer 22 | And Player2 chooses to gain a curse (No) 23 | Then Player2 should have 6 cards in hand 24 | And All actions should be resolved 25 | 26 | Scenario: Player decides to discard to torturer with only 1 card in hand 27 | Given A new game with 2 players 28 | And Player1 has a Torturer in hand instead of a Copper 29 | And Player2 has a hand of Copper 30 | When Player1 plays a Torturer 31 | And Player2 chooses to discard cards (Yes) 32 | Then Player2 should have 0 cards in hand 33 | And All actions should be resolved 34 | -------------------------------------------------------------------------------- /Dominion.Specs/Bindings/ScoringBindings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Dominion.Rules; 4 | using TechTalk.SpecFlow; 5 | 6 | namespace Dominion.Specs.Bindings 7 | { 8 | [Binding] 9 | public class ScoringBindings : BindingBase 10 | { 11 | private GameScores _scores; 12 | private Game _game; 13 | 14 | [When(@"The game is scored")] 15 | public void WhenTheGameIsScored() 16 | { 17 | var gameBinding = Binding(); 18 | _game = gameBinding.Game; 19 | _game.Score(); 20 | _scores = _game.Scores; 21 | } 22 | 23 | [Then(@"(.*) should have (\d+) victory point[s]?")] 24 | public void ThenPlayerShouldHaveVictoryPoints(string playerName, int victoryPoints) 25 | { 26 | var player = _game.Players.Single(p => p.Name == playerName); 27 | _scores[player].ShouldEqual(victoryPoints); 28 | } 29 | 30 | [Then(@"(.*)'s play area should start with this sequence of cards: (.*)")] 31 | public void ThenPlayerPlayAreaShouldStartWithThisSequenceOfCards(string playerName, string sequence) 32 | { 33 | var player = _game.Players.Single(p => p.Name == playerName); 34 | string playAreaCardNames = string.Join(",", player.PlayArea.Select(c => c.Name).ToArray()); 35 | 36 | playAreaCardNames.ShouldStartWith(sequence.Replace(" ","")); 37 | } 38 | 39 | 40 | } 41 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Apothecary.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Dominion.Cards.Treasure; 3 | using Dominion.Rules; 4 | using Dominion.Rules.Activities; 5 | using Dominion.Rules.CardTypes; 6 | 7 | namespace Dominion.Cards.Actions 8 | { 9 | public class Apothecary : Card, IActionCard 10 | { 11 | public Apothecary() : base(CardCost.Parse("2P")) 12 | { 13 | } 14 | 15 | public void Play(TurnContext context) 16 | { 17 | context.DrawCards(1); 18 | context.RemainingActions += 1; 19 | 20 | context.AddEffect(this, new ApothecaryEffect()); 21 | } 22 | 23 | public class ApothecaryEffect : CardEffectBase 24 | { 25 | public override void Resolve(TurnContext context, ICard source) 26 | { 27 | var revealZone = new RevealZone(context.ActivePlayer); 28 | context.ActivePlayer.Deck.MoveTop(4, revealZone); 29 | 30 | revealZone.LogReveal(context.Game.Log); 31 | revealZone.MoveWhere(c => c is Copper || c is Potion, context.ActivePlayer.Hand); 32 | 33 | if (revealZone.CardCount == 1) 34 | context.ActivePlayer.Deck.MoveToTop(revealZone.Single()); 35 | 36 | foreach (var activity in Activities.SelectMultipleRevealedCardsToPutOnTopOfDeck(context.Game.Log, context.ActivePlayer, revealZone, source)) 37 | _activities.Add(activity); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Dominion.Cards/Actions/Salvager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Rules; 6 | using Dominion.Rules.Activities; 7 | using Dominion.Rules.CardTypes; 8 | 9 | namespace Dominion.Cards.Actions 10 | { 11 | public class Salvager : Card, IActionCard 12 | { 13 | public Salvager() 14 | : base(4) 15 | { 16 | } 17 | 18 | public void Play(TurnContext context) 19 | { 20 | context.Buys += 1; 21 | context.AddEffect(this, new SalvagerEffect()); 22 | } 23 | 24 | private class SalvagerEffect : CardEffectBase 25 | { 26 | public override void Resolve(TurnContext context, ICard source) 27 | { 28 | if (context.ActivePlayer.Hand.CardCount > 0) 29 | { 30 | var activity = new SelectCardsActivity(context, "Select a card to trash", 31 | SelectionSpecifications.SelectExactlyXCards(1), source); 32 | 33 | activity.AfterCardsSelected = cardList => 34 | { 35 | var cardToSalvage = cardList.Single(); 36 | context.AvailableSpend += cardToSalvage.Cost.Money; 37 | context.Trash(context.ActivePlayer, cardToSalvage); 38 | }; 39 | _activities.Add(activity); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Dominion.Rules/Activities/SelectReactionActivity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Dominion.Rules.CardTypes; 5 | 6 | namespace Dominion.Rules.Activities 7 | { 8 | public class SelectReactionActivity : SelectCardsActivity 9 | { 10 | private readonly TurnContext _currentTurn; 11 | private readonly AttackEffect _attackEffect; 12 | 13 | public SelectReactionActivity(TurnContext currentTurn, Player player, AttackEffect attackEffect) 14 | : base(currentTurn.Game.Log, player, "Select a reaction to use, click Done when finished.", SelectionSpecifications.SelectUpToXCards(1), null) 15 | { 16 | _currentTurn = currentTurn; 17 | _attackEffect = attackEffect; 18 | Specification.CardTypeRestriction = typeof (IReactionCard); 19 | } 20 | 21 | public void SelectReaction(IReactionCard reaction) 22 | { 23 | if (reaction == null) 24 | IsSatisfied = true; 25 | else 26 | reaction.React(_attackEffect, this.Player, _currentTurn); 27 | } 28 | 29 | public override void SelectCards(IEnumerable cards) 30 | { 31 | CheckCards(cards); 32 | 33 | var reaction = cards.OfType().SingleOrDefault(); 34 | SelectReaction(reaction); 35 | } 36 | 37 | 38 | public void CloseWindow() 39 | { 40 | SelectReaction(null); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /Dominion.Web/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Dominion.Web")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Dominion.Web")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("ef516fc7-fc3d-4a8d-8f7f-c90d852702fa")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /Dominion.GameHost/ChosenStartingConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Reflection; 6 | using Dominion.Cards.Actions; 7 | using Dominion.Cards.Treasure; 8 | using Dominion.Rules; 9 | 10 | namespace Dominion.GameHost 11 | { 12 | public class ChosenStartingConfiguration : StartingConfiguration 13 | { 14 | private readonly bool _useProsperity; 15 | IList _chosenCards; 16 | 17 | public ChosenStartingConfiguration(int numberOfPlayers, IEnumerable chosenCards, bool useProsperity) 18 | : base(numberOfPlayers) 19 | { 20 | _useProsperity = useProsperity; 21 | if (chosenCards.Count() != 10) 22 | { 23 | string error = string.Format("Passed card collection contains {0} cards. Expected exactly 10.", chosenCards.Count()); 24 | throw new ArgumentException(error, "chosenCards"); 25 | } 26 | 27 | _chosenCards = chosenCards.ToList(); 28 | } 29 | 30 | public override void InitializeBank(CardBank bank) 31 | { 32 | foreach (string card in _chosenCards) 33 | bank.AddCardPile(new LimitedSupplyCardPile().WithNewCards(card, GetStartingCount(card))); 34 | 35 | if (_useProsperity) 36 | AddProsperityCards(bank); 37 | 38 | base.InitializeBank(bank); 39 | } 40 | 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Dominion.Rules/CardBank.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Dominion.Rules 6 | { 7 | public class CardBank 8 | { 9 | private IList _piles; 10 | private IList _gameEndPiles; 11 | 12 | public CardBank() 13 | { 14 | _piles = new List(); 15 | _gameEndPiles = new List(); 16 | } 17 | 18 | public IEnumerable Piles 19 | { 20 | get { return _piles; } 21 | } 22 | 23 | public void AddCardPile(CardPile pile) 24 | { 25 | _piles.Add(pile); 26 | } 27 | 28 | public void AddCardPileWhichEndsTheGameWhenEmpty(CardPile pile) 29 | { 30 | AddCardPile(pile); 31 | _gameEndPiles.Add(pile); 32 | } 33 | 34 | public int EmptyPileCount 35 | { 36 | get 37 | { 38 | return _piles.Count(x => x.IsEmpty); 39 | } 40 | } 41 | 42 | public int EmptyGameEndingPilesCount 43 | { 44 | get { return _gameEndPiles.Count(x => x.IsEmpty); } 45 | } 46 | 47 | public CardPile Pile() 48 | { 49 | return this.Piles.Single(x => x.Name == typeof(T).Name); 50 | } 51 | 52 | public CardPile NonEmptyPile() 53 | { 54 | var pile = this.Pile(); 55 | return pile.IsEmpty ? null : pile; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Dominion.Specs/Cards/Apothecary.feature: -------------------------------------------------------------------------------- 1 | Feature: Apothecary 2 | 3 | Scenario: Play Apothecary with all potions and coppers on top 4 | Given A new game with 3 players 5 | And Player1 has an Apothecary in hand instead of a Copper 6 | And Player1 has a deck of Estate, Copper, Potion, Copper, Copper 7 | When Player1 plays an Apothecary 8 | Then All actions should be resolved 9 | And Player1 should have 9 cards in hand 10 | And Player1 should have 1 action remaining 11 | 12 | Scenario: Play Apothecary with no potions or coppers on top 13 | Given A new game with 3 players 14 | And Player1 has an Apothecary in hand instead of a Copper 15 | And Player1 has a deck of Copper, Estate, Curse, Silver, Gold 16 | When Player1 plays an Apothecary 17 | Then Player1 must select a revealed card from: Estate, Curse, Silver, Gold 18 | When Player1 selects Estate from the revealed cards 19 | Then Player1 must select a revealed card from: Curse, Silver, Gold 20 | When Player1 selects Silver from the revealed cards 21 | Then Player1 must select a revealed card from: Curse, Gold 22 | When Player1 selects Curse from the revealed cards 23 | Then Player1 should have a deck of: Gold, Curse, Silver, Estate 24 | And All actions should be resolved 25 | 26 | Scenario: Apothecary is played with no other cards in hand, no discards and no deck 27 | Given A new game with 3 players 28 | And Player1 has a hand of Apothecary 29 | And Player1 has an empty deck 30 | When Player1 plays a Apothecary 31 | Then Player1 should have 0 cards in hand 32 | And All actions should be resolved 33 | 34 | -------------------------------------------------------------------------------- /Dominion.WinForms/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Dominion")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Dominion")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("97e03baf-f688-4fd8-9f2c-9c3509b27e2e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Dominion.Tests/CardMovementTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Dominion.Cards.Treasure; 6 | using Dominion.Rules; 7 | using NUnit.Framework; 8 | 9 | namespace Dominion.Tests 10 | { 11 | [TestFixture] 12 | public class CardMovementTests 13 | { 14 | private CardZone _zone1; 15 | private CardZone _zone2; 16 | private Card _card; 17 | 18 | [SetUp] 19 | public void SetUp() 20 | { 21 | _zone1 = new CardZone(); 22 | _zone2 = new CardZone(); 23 | _card = new Copper(); 24 | } 25 | 26 | [Test] 27 | public void Card_should_start_in_null_zone() 28 | { 29 | _card.CurrentZone.ShouldBeOfType(); 30 | } 31 | 32 | [Test] 33 | public void Card_should_change_current_zone_when_moved() 34 | { 35 | _card.MoveTo(_zone1); 36 | _card.CurrentZone.ShouldEqual(_zone1); 37 | } 38 | 39 | [Test] 40 | public void Card_should_be_added_to_target_zone_when_moved() 41 | { 42 | _card.MoveTo(_zone1); 43 | _zone1.CardCount.ShouldEqual(1); 44 | } 45 | 46 | [Test] 47 | public void Card_should_be_removed_from_old_zone_when_moved() 48 | { 49 | _card.MoveTo(_zone1); 50 | _card.MoveTo(_zone2); 51 | _zone1.CardCount.ShouldEqual(0); 52 | _zone2.CardCount.ShouldEqual(1); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Dominion.Cards/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Dominion.Cards")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Dominion.Cards")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9f8ab823-49ae-47d4-9128-0984d7997eca")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Dominion.Rules/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Dominion.Rules")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Dominion.Rules")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("eb828059-6b22-4e34-8e06-ea937fdfe662")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Dominion.Specs/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Dominion.Specs")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Dominion.Specs")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("6b24e9cf-c860-4691-aaa9-e7dc21c827e1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Dominion.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Dominion.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Dominion.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("77564d3e-11a3-4858-9f79-ac442a5760b6")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Dominion.GameHost/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Dominion.GameHost")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Dominion.GameHost")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("2c8a1718-3bcb-4297-aa41-e5d113d6e0e0")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Dominion.AIWorkbench/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Dominion.AIWorkbench")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Dominion.AIWorkbench")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9e70f450-028e-4395-8e8f-6a5c838ce8e3")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | --------------------------------------------------------------------------------