// Defining Game Flow. // You need to be able to identify states, transitions, rules to determine transitions, // and be able to identify rules that apply only in specific states. // A script probably also ought to be able to request a transition. (Like for win conditions.) // There is an implicit and undeleteable Start and End state. define state Setup. define state DrawPhase. define state PlayPhase. define state DiscardPhase. define transition Start to Setup. define transition Setup to Draw. define transition Draw to Play. define transition Play to Discard. define transition Discard to Draw. define transition Play to End. define group Turn { Draw, Play, Discard } // Implications of the type heirarchy. if Card.Type is BodyPart then Card.Type is Thing. if Card.Type is Arm then Card.Type is BodyPart. if Card.Type is Leg then Card.Type is BodyPart. if Card.Type is Head then Card.Type is BodyPart. if Card.Type is Torso then Card.Type is BodyPart. if Card.Type is Minion then Card.Type is Thing. if Card.Type is Equipment then Card.Type is Thing. // Somehow, you need to be able to define new commands/operations/action types. A 'move' action is probably so // common that no game wouldn't have it, and the language should support built-in keywords for handling it, // as would maybe a 'pick' command, but you also need to be able to define additional commands. And it would // be pretty cool if there were a way for you to integrate these new commands into the language as well. // The 'move' operation is basically one defined by a Player picking an Item of some type or another that is // in some current Source location and desires to move it to some Target location, with an optional Purpose or Role. There needs to be code defined // that indicates what happens when a move is performed, but in addition, there needs to be a way for game rules // to indicate whether a proposed move is allowed or not. // `find` is another operation that seems super common--the equivalent of the game detecting things with certain criteria. // Rules need to be able to specify whether these operations can affect the parameters. // Sufficiency vs. Neccessity: Some rules would indicate that if some condition isn't true, then you can't use the specific // criteria. Others would say that if some condition is true, then you can. The intent would be to progress through the logical // rules (like Prolog does) to find a way to apply the desired conditions matching all necessity constraints on the way to finding // a sufficiency constraint. // Interestingly, the instructional action syntax below will provide additional necessity constraints for the context of any given // action. Though these could be expressed elsewhere and turned on before the operation and turned off after the operation. define operation Move(Originator (Player), Card (Item), Reason (Tag), Source (CardGroup), Destination (CardGroup)). // These are other custom actions, which are basically just shortcuts for the Move operation. define operation Play(Originator (Player), Card (Item), Destination (CardGroup)) is Move(Originator, Card, empty, Originator.Hand, Destination). define operation Discard(Originator (Player), Card (Item)) is Move(Originator, Card, empty, Originator.Hand, State.General.Discard). define operation Draw(Originator (Player)) is Move(Originator, State.Common.Draw.Top, empty, State.General.Draw, Originator.Hand). Move(_, Card.Type is not Head, _, _, Destination.Name is Head) is not allowed. Move(_, Card.Type is not Torso, _, _, Destination.Name is Torso) is not allowed. Move(_, Card.Type is not Arm, _, _, Destination.Name is LeftArm) is not allowed. Move(_, Card.Type is not Arm, _, _, Destination.Name is RightArm) is not allowed. Move(_, Card.Type is not Leg, _, _, Destination.Name is LeftLeg) is not allowed. Move(_, Card.Type is not Leg, _, _, Destination.Name is RightLeg) is not allowed. // I thought that you could say 'Card where Card.Type is not Leg' but that seems redundant. I would assume as long as you're using the same name as the definition, you shouldn't need to do that. It is implied. Move(_, Card where Card.Type is not Minion, _, _, Destination.Name is Minions) is not allowed. // I don't love the fact that I end up needing to write all of these in sort of a negative way. Move(_, Card where Card.Type is not Equipment, _, _, Destination.Name is Equipment) is not allowed. // I don't love the fact that I end up needing to write all of these in sort of a negative way. Move(_, _, _, _, Destination type of Socket and Destination.Contents is not empty) is not allowed. Move(not Originator.PlayArea.Contains(Card.Name is "Iron Bar"), Card.Name is "Lower Leg", _, Destination is Originator.PlayArea) is not allowed. // THIS IS COMPLICATED AND UNINTUITIVE!!! Move(not Originator.PlayArea.Contains(Card.Name is "Bolts"), Card.Name is "Bloody Head", _, Destination is Originator.PlayArea) is not allowed. // THIS IS COMPLICATED AND UNINTUITIVE!!! Move(_, Card is in Source, _, Source, _) is not allowed. Move(Originator, _, _, Source.Owner is Originator, Destination.Owner is Originator) is necessary. // Perhaps an inverted way to write 'is not allowed'. // A rule to filter out moves by players that aren't active. This would theoretically also mean you can't move // cards around when it's not your turn, which is perhaps not always true. Move(Player where Player is not ActivePlayer, _, _, _, _) is not allowed. // If nothing prevented you, the move should be considered allowed. Move(_, _, _, _, _) is allowed. // ------------------- ACTIONS BELOW ------------------------------------- // Destroy a piece of equipment. { ActivePlayer picks Item for Destruction where Item of type Card and Item.Type is Equipment. move Item to State.Common.Discard. } // Or... { ActivePlayer targets Item where Item of type Card and Item.Type is Equipment. discard Item. } // Destroy all arms. { find all Items for Destruction where Item of type Card and Item.Type is Arm. discard Items. } // Discard your hand and destroy up to three body parts. { find Cards in ActivePlayer.Hand. discard Cards. ActivePlayer picks up to 3 Cards in *.PlayArea where Card.Type is BodyPart. discard Cards. } // Make an opponent discard cards until they have 3 or less. { ActivePlayer picks Player of type Player. while Player.Hand.Count > 3 { Player identifies Card in Player.Hand. discard Card. } } // Retrieve an action from the discard pile. { ActivePlayer picks Card in State.General.Discard. move Card to ActivePlayer.Hand. } // Destroy a minion. { ActivePlayer picks Card for Destruction in *.PlayArea where Card.Type is Minion. discard Card. } // Draw a card; if it is not a body part of equipment, discard it. { ActivePlayer reveals Card from State.General.Draw. if Card.Type is BodyPart or Card.Type is Equipment move Card to ActivePlayer.Hand. else discard Card. } // Gain control of a minion. { ActivePlayer picks Card for Stealing in *.PlayArea where Card.Type is Minion. move Card to ActivePlayer.Hand. } // Discard 2 cards to acquire a Body Part or piece of equipment from an opponent. { ActivePlayer picks 2 Cards in ActivePlayer.Hand. discard Cards. ActivePlayer picks Card in *.PlayArea where Card.Type is Equipment or Card.Type is BodyPart. move Card to ActivePlayer.PlayArea. } // Discard a card to force an opponent to discard a card of their choice. { ActivePlayer picks Card in ActivePlayer.Hand. discard Card. ActivePlayer picks Player of type Player. Player picks Card in Player.Hand. // Reusing variable name here. Is that OK? What if it changes type? discard Card. } // Draw cards until you have drawn 3 or until a body part is drawn. { ActivePlayer reveals Card from State.General.Draw. repeat 3 times: { if(Card.Type is BodyPart) { move Card to ActivePlayer.Hand. stop. } else discard Card. } } // Retrieve any action from the discard pile. { ActivePlayer picks Card in State.General.Discard where Card.Type is Action. move Card to ActivePlayer.Hand. } // Draw a card; if it is not lightning strike, discard it. { ActivePlayer reveals Card from State.General.Draw. if(Card.Name is "Lightning Strike") move Card to ActivePlayer.Hand. else discard Card. } // Destroy a body part. { ActivePlayer picks Card in *.PlayArea where Card.Type is BodyPart. discard Card. } // Destroy one of your minions to destroy up to two body parts of an opponent. { ActivePlayer picks Card in ActivePlayer.PlayArea where Card.Type is Minion. discard Card. ActivePlayer picks up to 2 Cards in *.PlayArea where Card.Type is BodyPart. discard Cards. } // Destroy one of your minions. Pick an opponent. Look at their hand and take a card of your choice from it. { ActivePlayer picks Card in ActivePlayer.PlayArea where Card.Type is Minion. discard Card. ActivePlayer picks Opponent. // !!! SOMEHOW HANDLE VIEWING OPPONENTS CARDS !!! ActivePlayer picks Card in Opponent.Hand. move Card to ActivePlayer.Hand. } // Exchange a card of your choice from your hand with a random card from an opponent's hand. { ActivePlayer picks Outgoing in ActivePlayer.Hand. ActivePlayer picks Opponent. ActivePlayer picks Incoming in Opponent.Hand. // Intentionally _not_ able to view. Just picking a random card. move Outgoing to Opponent.Hand. move Incoming to ActivePlayer.Hand. } // Destroy the Hound to destroy a minion. { ActivePlayer picks Card in ActivePlayer.PlayArea where Card.Name is "The Hound". discard Card. ActivePlayer picks Card in *.PlayArea where Card.Type is Minion. discard Card. } // Shuffle the discard pile into the draw pile. { find all Cards in State.General.Discard. move Cards to State.General.Draw. shuffle State.General.Draw. } // Destroy all legs. { find all Cards in *.PlayArea where Card.LegCount > 0. discard Cards. } // Make a player discard 2 cards of their choice. { ActivePlayer picks Opponent. Opponent picks 2 Cards in Opponent.Hand. discard Cards. } // Choose a body part from the discard pile and put it into your hand. { ActivePlayer picks Card in State.General.Discard where Card.Type is BodyPart. move Card to ActivePlayer.Hand. } // If any player has a Lightning Strike or Thunderstorm card in their hand, they must discard it. { find all Cards in *.Hand where Card.Name is "Lightning Strike" or Card.Name is "Thunderstorm". discard Cards. } /* In this framework, you really do need to be able to define custom operations with elements in the game (including players and pretty much everything else). These are method-like definitions. At some level, you need to be able to specify exactly how things tie together. But just as importantly, I think you need to be able to tie these new unique actions into the DSL. Not all actions will be mappable into the DSL, but I'd think the majority could be. The real trick with these operations is that it's hard to know how to map parameters for these operations into aspects of the DSL. This feels a little bit like the semantics that HLSL has to me. Basically, I think most operations will have certain standard ways that they are represented. You'd apply attributes to the arguments that specify which semantic is used for that. If you can map all parameters to a semantic, and additionally specify a keyword or identifier for the operation, then you'll be able to use the DSL syntax for specifying the operation. What operations _do_ exist? * Move. * Shuffle. * Deal. * Find. * Discard. * Draw. * Picks. */ Card: Name: Rotting Torso Description: Category: Torso Card (2): Name: Bolts Description: Category: Thing Card: Name: Thunderstorm Description: "Quick, get it ready! Draw three cards." Category: Thing Event: Play as Card // This specifies the Play operation and for if this card is used in the Card field. Owner draws Card. Owner draws Card. Owner draws Card. // Is there a way to specify this in a loop? Or with a 3 symbol? Card: Name: Broken Arm Description: Category: Arm Card: Name: Broken Leg Description: Category: Leg Card (2): Name: Bloody Head Description: This can only be put in play if you already control a body and bolts. // Should these be put in quotes? Rules: Play(_, this, _) where Owner.PlayArea.Contains(Card where Card.Type is Body) and Owner.PlayArea.Contains(Card where Card.Name is "Bolts")) is necessary. Card: Name: Woodcutter's Head Description: Category: Head Card: Name: Iron Bar Description: Category: Thing Card: Name: Lower Leg Description: Category: Leg Rules: Play(_, this, _) where Owner.PlayArea.Contains(Card where Card.Name is "Iron Bar") is necessary. Card: Name: Graverobber Description: "Action: Choose a Body Part from the discard pile and put it in your hand." Category: Minion Event: Activate as Card Owner picks Card from State.General.Discard. // this.Owner? move Card to Owner.Hand. Card: Name: Lost on the Moors Description: "Action: Destroy a Minion." Category: Action Event: Play as Card Owner picks Card from State.*.PlayArea.Minions where Card.Owner is not Owner. // Target another person's minion. discard Card. Card: Name: "Saboteur" Description: "Action: Discard 2 cards to acquire a Body Part or piece of Equipment from an opponent." Category: Action Event: Play as Card Owner picks 2 Cards from Owner.Hand. discard Cards. Owner picks Card from State.*.PlayArea.* where Card.Owner is not Owner and (Card.Type is Equipment or Card.Type is BodyPart). move Card to State.*.PlayArea. Card: Name: "The Hound" Description: "Opponents may not steal Body Parts or Equipment from you. Action: Dstroy the HOund to destroy a Minion." Category: Minion Event: Play as Card add rule named "Hound Protection Rule": Play(). Event: Move as Card, State.General.Discard as Destination remove rule named "Hound Protection Rule". Event: Activate as Card discard this. Card: Name: "Mob with Torches" Description: "At the end of a Player's turn, if that player has more than four cards in their hand, destroy all Minions and Body Parts they control and destroy Mob with Torches." Event: BeforeEnd Discard if ActivePlayer.Hand.Count > 4 find Cards in ActivePlayer.PlayArea where Card.Type is Staff or Card.Type is BodyPart. discard Cards. discard this. Card (2): Name: "Lightning Strike" Description: "If you control a Head, a Body, two Arms, and two Legs, you win the game." Event: Play as Card if (find Cards in ActivePlayer.PlayArea where Card.Type is Head).Count >= 1 and (find Cards in ActivePlayer.PlayArea where Card.Type is Torso).Count >= 1 and (find Cards in ActivePlayer.PlayArea where Card.Type is Arm).Count >= 2 and (find Cards in ActivePlayer.PlayArea.Sum(Card.LegCount)) >= 2 ActivePlayer.HasWon = true. Card: Name: "Twisted Arm" Description: "" Category: Arm Card: Name: "Bony Torso" Description: "" Category: Torso Card: Name: "Call the Police" Description: "Make an opponent discard cards until they have 3 or less." Category: Action Event: Play as Card ActivePlayer picks Player of type Player. while Player.Hand.Count > 3 { Player identifies Card in Player.Hand. discard Card. } Card: Name: "Igor" Description: "Action: Draw a card; if it is not a Body Part or Equipment, discard it." Category: Staff Event: Activate as Card Owner draws Card. if Card.Type is BodyPart or Card.Type is Equipment move Card to Owner.Hand. else discard Card. Card: Name: "Dredging the River" Description: "Draw cards until you have drawn 3 or until a Body Part is drawn." Category: Action Event: Play as Card ActivePlayer reveals Card from State.General.Draw. repeat 3 times: { if(Card.Type is BodyPart) { move Card to ActivePlayer.Hand. stop. } else discard Card. } Card: Name: "Brainwashing" Description: "Gain control of a member of staff." Category: Action Event: Play as Card ActivePlayer picks Card for Stealing in *.PlayArea where Card.Type is Minion. move Card to ActivePlayer.Hand. Card: Name: "Skeletal Arm" Description: "" Category: Arm Card: Name: "Doberman Legs" Description: "This card counts as two legs. This card can only be played if the Hound is in play and replaces it." LegCount: 2 Category: Leg Rules: Play(_, this, _) where *.PlayArea.Contains(Card where Card.Name is "The Hound") is necessary. Event: Play as Card find Card where Card.Name is "The Hound". discard Card. Card: Name: "Flock of Bats" Description: "Action: Discard a card to force an opponent to discard a card of their choice." Category: Leg Event: Activate as Card ActivePlayer picks Card in ActivePlayer.Hand. discard Card. ActivePlayer picks Player of type Player. Player picks Card in Player.Hand. // Reusing variable name here. Is that OK? What if it changes type? discard Card. Card: Name: "Undertaker" Description: "Action: Whenever a Minion goes to the discard pile from play, you may draw a card." Category: Minion Event: Discard(Card where Card.Type is Minion) option for this.Controller: this.Controller draws Card. Card: Name: "Farewell to Arms" Description: "Destroy all Arms." Category: Action Event: Play as Card find all Items for Destruction where Item of type Card and Item.Type is Arm. discard Items. Card: Name: "Professor's Head" Description: "When Professor's Head comes into play, you may draw a card." Category: Action Event: Play as Card option for ActivePlayer: ActivePlayer draws Card. Card: Name: "Fragile Torso" Description: "Any Player may discard their hand to destroy Fragile Torso." Category: Action Rules: Activate(_, this, _) is allowed. // Overrides the normal rule that you can't activate a card that isn't yours. Event: Activate as Card find Cards in ActivePlayer.Hand. discard Cards. discard this. Card: Name: "Angry Mob" Description: "Discard your hand and destroy up to three body parts." Category: Action Event: Play as Card find Cards in ActivePlayer.Hand. discard Cards. ActivePlayer picks up to 3 Cards in *.PlayArea where Card.Type is BodyPart. discard Cards. Card: Name: "Bright Sunshiney Day" Description: "Make a player discard 2 cards of their choice." Category: Action Event: Play as Card ActivePlayer picks Player of type Player. Player picks 2 Cards from Player.Hand. discard Cards. Card: Name: "Mind-swap Device" Description: "Action: Exchange a card of your choice from your hand with a random card from an opponent's hand." Category: Action Event: Play as Card ActivePlayer picks Outgoing in ActivePlayer.Hand. ActivePlayer picks Opponent. ActivePlayer picks Incoming in Opponent.Hand. // Intentionally _not_ able to view. Just picking a random card. move Outgoing to Opponent.Hand. move Incoming to ActivePlayer.Hand. Card: Name: "Lovely Day" Description: "If any player has a Lightning Strike or Thunderstorm card in their hand, they must discard it." Category: Action Event: Play as Card find all Cards in *.Hand where Card.Name is "Lightning Strike" or Card.Name is "Thunderstorm". discard Cards. Card: Name: "Mind-Draining Device" Description: "Players must discard down to four cards at the end of their turns." Category: Equipment Event: Play as Card add rule named "Mind Drain Rule": // I DON'T KNOW HOW TO EXPRESS THIS RIGHT NOW. RULES AFFECTING GAME FLOW ARE HARD! Event: Move as Card, State.General.Discard as Destination remove rule named "Mind Drain Rule". Card: Name: "Necronomicon" Description: "During their draw phase, if a player has less than two cards, they draw up to 3 instead of the usual draw phase." Category: Equipment Event: Play as Card add rule named "Necronomicon Rule": // Another game flow rule. Event: Move as Card, State.General.Discard as Destination remove rule named "Necronomicon Rule". Card: Name: "Learn from Experience" Description: "Retrieve any Action from the discard pile." Category: Action Event: Play as Card ActivePlayer picks Card in State.General.Discard where Card.Type is Action. move Card to ActivePlayer.Hand. Card: Name: "Lightning Conductor" Description: "Action: Draw a card; if it si not Lightning Strike, discard it." Category: Equipment Event: Activate as Card. ActivePlayer reveals Card from State.General.Draw. if(Card.Name is "Lightning Strike") move Card to ActivePlayer.Hand. else discard Card. Card: Name: "Leading the Mob" Description: "Destroy one of your Minions to destroy two body parts of an opponent." Category: Action Event: Activate as Card. ActivePlayer picks Card in ActivePlayer.PlayArea where Card.Type is Minion. discard Card. ActivePlayer picks Enemy of type Player. ActivePlayer picks up to 2 Cards in Enemy.PlayArea where Card.Type is BodyPart. discard Cards. Card: Name: "Stolen Plans" Description: "Destroy one of your Minions. Look at the opponent's hand and take a card of your choice from it." Category: Action Event: Play as Card ActivePlayer picks Card in ActivePlayer.PlayArea where Card.Type is Minion. discard Card. ActivePlayer picks Opponent. // !!! SOMEHOW HANDLE VIEWING OPPONENTS CARDS !!! ActivePlayer picks Card in Opponent.Hand. move Card to ActivePlayer.Hand. Card: Name: "Maggot Infestation" Description: "Destroy a Body Part." Category: Action Event: Play as Card ActivePlayer picks Card in *.PlayArea where Card.Type is BodyPart. discard Card. Card: Name: "Shallow Grave" Description: "Shuffle the discard pile into the draw pile." Category: Action Event: Play as Card find all Cards in State.General.Discard. move Cards to State.General.Draw. shuffle State.General.Draw. Card: Name: "I Was Very Drunk" Description: "Destroy all Legs." Category: Action Event: Play as Card find all Cards in *.PlayArea where Card.LegCount > 0. discard Cards. Card: Name: "Virulent Disease" Description: "At the end of each player's turn, they must destroy a Minion they control. If they have no Minions, destroy Virulent Disease." Category: Thing Event: BeforeEnd Discard find all Cards in ActivePlayer.PlayArea where Card.Type is Minion. if Cards.Count >= 1: ActivePlayer picks Card in Cards. discard Card. else: discard this. Card: Name: "Inspiration" Description: "All players draw 2 cards." Category: Action Event: Play as Card for Player in Players of type Player: Player draws Card. Player draws Card. Card: Name: "Transplant Doctor" Description: "Whenever a Body Part goes to the discard pile from play, you may draw a card." Category: Minion Event: Move(_, Card where Card.Type is BodyPart, _, _, State.General.Discard) option for this.Controller: this.Controller draws Card. Card: Name: "Malfunction" Description: "Destroy a piece of equipment." Category: Action Event: Play as Card ActivePlayer picks Card where Card.Type is Equipment. discard Card. Card: Name: "Bubbling Potion" Description: "During this turn, you may play any number of cards from your hand (but may not use any actions from Things in play.". Category: Action Event: Play as Card add rule named "Bubbling Potion Rule 1": Activate(Card where Card.Location is *.PlayArea) is not allowed. add rule named "Bubbling Potion Rule 2": Play(Card where Card.Type is Action) is allowed. // This is not quite right. This allows an action to be played, but that's already in the general rules. This needs to change the Play stage to allow _any_ of these, rather than the usual 1. Event: BeforeEnd Play remove rule named "Bubbling Potion Rule 1". remove rule named "Bubbling Potion Rule 2". Card: Name: "Metal Arm" Description: "" Category: Arm Rules: if Card.Name is "Metal Arm" then Card.Type is not BodyPart and Card.Type is Equipment. Card: Name: "Metal Leg" Description: "" Category: Leg Rules: if Card.Name is "Metal Leg" then Card.Type is not BodyPart and Card.Type is Equipment. ItemDefinition: Name: "Card" Subtype: "" // Don't need this line, but it allows you to define a type hierarchy. Most things shouldn't need this, but it's an option. Properties: Property: Name: "Name" Type: Text Required: true DefaultValue: "" // This is useless if Required is true, simply because a real value is required, and so nothing will have the default value. Property: Name: "Type" Type: Tag Required: true DefaultValue: Nothing Property: Name: "Description" Type: Text Required: false DefaultValue = "" /* What if transitioning to another stage was just another operation? If so, then perhaps the game needs the ability to initiate specific actions. To be fair, any "actor" in the system probably ought to be able to push forward actions at any point in time, and the rule system should be able to reject any of those actions that shouldn't be allowed. Related: How do I ensure that any moment in which the player tries to draw a card but nothing is in the draw pile that before giving up on the situation, the game has the ability to shuffle the discard pile back into the draw pile? The game ought to be able to suggest at any point in time, even when in the middle of like a "Draw 2" that the discard pile should be shuffled back into the draw pile. Also Related: One thing I don't think I've accounted for at all here is how things like "skip a turn" would work. Things that are directly associated with game flow and future and past play just don't seem to have a great answer yet. */ // Going with the above paradigm, perhaps something like this... // A conditional rule. When certain conditions hold, the rule is valid. Otherwise it is disabled. when ActivePlayer.Hand.Count <= 5 then Transition(ActivePlayer, EndTurn) is allowed. // The active player can end their turn by request. when ActivePlayer.Hand.Count > 5 then Transition(ActivePlayer, EndTurn) is not allowed. // The player cannot end their turn until they discard down to 5 cards. // You can only play one Thing card per turn. when State.GameState is PlayPhase and State.History.CurrentTurn.Moves where Move.Card.Type is Thing > 0 then Move(ActivePlayer, Card where Card.Type is Thing, ActivePlayer.Hand, *.PlayArea.*) is not allowed. // You can only play one Action card per turn. when State.GameState is PlayPhase and State.History.CurrentTurn.Activations // CurrentTurn.Operations.Where(a => a.Type is Action) then Activate(ActivePlayer, _, _, _, _) is not allowed and Play(ActivePlayer, Card.Type is Action, _, _, _) is not allowed. // When a player's turn ends, automatically advance to the next player and automatically advance to the Draw phase. after Transition(_, EndTurn) then ActivePlayer = Players.Cycle(). transition to DrawPhase. after Transition(_, DrawPhase) then move Card from State.General.Draw to ActivePlayer.Hand. transition to PlayPhase. after Transition(_, Setup) then find all Cards in Input.Deck. move Cards to State.General.Draw. shuffle State.General.Draw. deal 5 from State.General.Draw. ActivePlayer = Players.Cycle(). transition to Draw. // Somehow define "deal" like this: Deal(Number amount, CardGroup source) { for Player in Players: { repeat amount times: { take Card from source. move Card to Player.Hand. } } } /* One thought I had that might make life a little bit easier for people building games is to have something like "rule bundles". The idea would be, there are lots of games that share common idioms. The whole "draw a card at the start of your turn and discard if you have more than X cards at the end of your turn" is a common idiom. So is "play moves clockwise". It would be nice if you could do a couple of things here. First, if you could click