diff --git a/README.md b/README.md index 3ee2d47..1857877 100644 --- a/README.md +++ b/README.md @@ -107,12 +107,13 @@ We subdivide the score into the following sections: ### Missing Constraints -- [ ] Symbol(■) - Draw One Card -- [ ] Symbol - Second card face up -- [ ] Symbol - Second card face down +- [x] Symbol (■) - Draw One Card +- [ ] Symbol (**=**) - Second card face up +- [ ] Symbol (≂) - Second card face down - [ ] Symbol (✠) - Simultaneous play - [ ] Since the model misses out on the turn-dynamics, and treats symbols as global counters (instead of being attached to specific cards), there are some additional constraints that will be required. Without these, I'm expecting to see the same card being used for multiple symbols. Some sort of **Symbol counter** per round that keeps track of total number of cards you've claimed for symbols would be a better approach. - [ ] **Additional Card Play**. Every round, all players can opt to play one extra card per artist they've already played. Note that this rule is very ambigously worded in the rules. I'm planning to implement the "blessed" variant. See https://boardgamegeek.com/thread/473713/playing-additional-cards-during-scoring for more details. +- [ ] In case `DrawOne` card is the last card of a round, then `PlayableCards` for that round does not increase by 1, but only for the subsequent rounds. Since I'm maintaining awards as a boolean on the (Round,Artist) tuple, this becomes quite hard to model. Unless this gets violated in the winning entries, I don't plan to model this. ## TODO diff --git a/drawone.mzn b/drawone.mzn new file mode 100644 index 0000000..ee587f5 --- /dev/null +++ b/drawone.mzn @@ -0,0 +1,19 @@ +array[Rounds,Players,Artists] of var bool: DrawOneCard; + +% Total Playable Cards for any round are set equal to the Starting Hand +array[Rounds,Players] of var int: PlayableCards; + +% Playable Cards in any round = Starting Cards + Draw One cards that give you an extra playable card +constraint forall(p in Players, r in Rounds) ( + PlayableCards[r,p] = StartingCardsInHand[r,p] + sum(a in Artists) (DrawOneCard[r,p,a]) +); + +% Every artist only has a single Draw One Card +constraint forall(a in Artists) ( + sum(p in Players, r in Rounds) (DrawOneCard[r,p,a]) = 1 +); + +% Isolated count for DrawOne, you can only play your draw one, if you've atleast played that artist this round +constraint forall(p in Players, r in Rounds, a in Artists) ( + visible_count_per_round_per_artist_per_player[r,p,a] >= DrawOneCard[r,p,a] +); \ No newline at end of file diff --git a/gameplay.mzn b/gameplay.mzn index 93c047c..fdddfea 100644 --- a/gameplay.mzn +++ b/gameplay.mzn @@ -8,9 +8,10 @@ include "artists.mzn"; include "dealing.mzn"; % Ignoring these for now % include "double.mzn"; -% include "drawone.mzn"; +include "drawone.mzn"; % include "hidden.mzn"; % include "simultaneous.mzn"; +include "symbols.mzn"; /* This file includes the core gameplay rules @@ -42,18 +43,26 @@ constraint forall(r in Rounds, p in Players) ( % Calculate maximum cards any player can play in first round array[Rounds,Players] of var int: StartingCardsInHand; -% Round 1 Starting Hand is 13 cards -constraint forall(p in Players) (StartingCardsInHand[Round1,p] = CardsDealtPerRound[Round1]); -constraint forall(p in Players) ( - StartingCardsInHand[Round2,p] = StartingCardsInHand[Round1,p] - TotalCardsPlayed[Round1,p] + CardsDealtPerRound[Round2] -); -constraint forall(p in Players) ( - StartingCardsInHand[Round3,p] = StartingCardsInHand[Round2,p] - TotalCardsPlayed[Round2,p] + CardsDealtPerRound[Round3] -); -constraint forall(p in Players) ( - StartingCardsInHand[Round4,p] = StartingCardsInHand[Round3,p] - TotalCardsPlayed[Round3,p] + CardsDealtPerRound[Round4] + +% Starting Cards for First Round = Cards Dealt +constraint forall(p in Players) ( + StartingCardsInHand[Round1,p] = CardsDealtPerRound[Round1] ); +% Playable Card Calculation in drawone.mzn + +% Starting cards for subsequent rounds = Playable Cards from previous round - Cards Played + cards dealt +constraint forall(p in Players) ( + StartingCardsInHand[Round2,p] = PlayableCards[Round1,p] - TotalCardsPlayed[Round1,p] + CardsDealtPerRound[Round2] +); +constraint forall(p in Players) ( + StartingCardsInHand[Round3,p] = PlayableCards[Round2,p] - TotalCardsPlayed[Round2,p] + CardsDealtPerRound[Round3] +); +constraint forall(p in Players) ( + StartingCardsInHand[Round4,p] = PlayableCards[Round3,p] - TotalCardsPlayed[Round3,p] + CardsDealtPerRound[Round4] +); + +% For every round, you must start with more cards than you play constraint forall(r in Rounds, p in Players) ( StartingCardsInHand[r,p] >= TotalCardsPlayed[r,p] ); @@ -82,39 +91,32 @@ constraint first_player[Round4] = if last_player[Round3] = card(Players) then 1 constraint Pn1 = if (first_player[Round1] < last_player[Round1]) then first_player[Round1]..last_player[Round1] - else + else Players diff (first_player[Round1]..last_player[Round1]) endif; constraint Pn2 = if (first_player[Round2] < last_player[Round2]) then first_player[Round2]..last_player[Round2] - else + else Players diff first_player[Round2]..last_player[Round2] endif; constraint Pn3 = if (first_player[Round3] < last_player[Round3]) then first_player[Round3]..last_player[Round3] - else + else Players diff first_player[Round3]..last_player[Round3] endif; constraint Pn4 = if (first_player[Round4] < last_player[Round4]) then first_player[Round4]..last_player[Round4] - else + else Players diff first_player[Round4]..last_player[Round4] endif; constraint forall(p in Players) (TotalCardsPlayed[Round1, p] = if p in Pn1 then NominalTurnCount[Round1] else NominalTurnCount[Round1] - 1 endif); constraint forall(p in Players) (TotalCardsPlayed[Round2, p] = if p in Pn2 then NominalTurnCount[Round2] else NominalTurnCount[Round2] - 1 endif); constraint forall(p in Players) (TotalCardsPlayed[Round3, p] = if p in Pn3 then NominalTurnCount[Round3] else NominalTurnCount[Round3] - 1 endif); -constraint forall(p in Players) (TotalCardsPlayed[Round4, p] = if p in Pn3 then NominalTurnCount[Round4] else NominalTurnCount[Round4] - 1 endif); - -% Total Playable Cards for any round are set equal to the Starting Hand -% TODO: Move this to `drawone` -array[Rounds,Players] of var int: PlayableCards; -constraint forall(p in Players, r in Rounds) ( - PlayableCards[r,p] = StartingCardsInHand[r,p] -); +constraint forall(p in Players) (TotalCardsPlayed[Round4, p] = if p in Pn3 then NominalTurnCount[Round4] else NominalTurnCount[Round4] - 1 endif); \ No newline at end of file diff --git a/symbols.mzn b/symbols.mzn new file mode 100644 index 0000000..1488fab --- /dev/null +++ b/symbols.mzn @@ -0,0 +1,15 @@ +% This file maintains common symbol constraints +% Since we are modelling each symbol individually (and not "on-a-card"), this results in +% symbol counts being calculated in isolation. +% Sanity constraints on each symbol file individually ensure +% that atleast one card of the symbol was played by the correct played +% they do not ensure that across symbols +% and hence, the same card may end up getting counted twice for different symbols. +% this file prevents such issues +% and may ultimately end up replacing separate symbol counters + +constraint forall(r in Rounds, a in Artists) ( + sum (p in Players) ( + visible_count_per_round_per_artist_per_player[r,p,a] - DrawOneCard[r,p,a] + ) >= awards_per_round_per_artist[r,a] +); \ No newline at end of file