diff --git a/awards.mzn b/awards.mzn index 1548b72..8193126 100644 --- a/awards.mzn +++ b/awards.mzn @@ -17,7 +17,7 @@ constraint forall(a in Artists) ( sum(col(awards_per_round_per_artist,a)) = 1 ); % awards can only be given if an artist's card was played that turn constraint forall(r in Rounds, a in Artists) ( - awards_per_round_per_artist[r,a] -> cards_per_artist_per_round[r,a] > 0 + awards_per_round_per_artist[r,a] -> CardsForArtist[r,a] > 0 ); % Set award_bonus_per_round_per_artist = array[5] with bonus that can be added to ranking scores diff --git a/dealing.mzn b/dealing.mzn new file mode 100644 index 0000000..cfb18c0 --- /dev/null +++ b/dealing.mzn @@ -0,0 +1,27 @@ +% This file deals with dealing of new cards every Round + +% Usable variable from here is CardsDealtPerRound[Rounds] +array[Rounds] of var int: CardsDealtPerRound; + +constraint CardsDealtPerRound[Round1] = 13; +constraint CardsDealtPerRound[Round2] = + if card(Players) < 4 then + 6 + else if card(Players) = 4 then + 4 + else + 2 + endif +endif; + +constraint CardsDealtPerRound[Round3] = + if card(Players) < 4 then + 6 + else if card(Players) = 4 then + 4 + else + 2 + endif +endif; + +constraint CardsDealtPerRound[Round4] = if card(Players) = 2 then 3 else 0 endif; \ No newline at end of file diff --git a/double.mzn b/double.mzn new file mode 100644 index 0000000..a1e8e52 --- /dev/null +++ b/double.mzn @@ -0,0 +1,34 @@ +% DOUBLE CARDS +% - Double cards are counted as VISIBLE +% - Double cards CANNOT breach the 6 LIMIT +% Total number of DOUBLE CARDS for each artist = 1 +% FOR EVERY ROUND+ARTIST combination, only 1 player should have played a double card +% TODO: Check if this is still correct after a second round + +% Whether you played a double this round +array[Rounds,Players,Artists] of var bool: double_played; + + +constraint forall(a in Artists) ( + sum(p in Players, r in Rounds) (double_played[r,p,a]) = 1 +); + +% What is the extra cards you can possibly play +array[Rounds,Players,Artists] of var bool: bonus_due_to_double_cards; + +constraint forall(a in Artists, r in Rounds, p in Players) ( + % If this player played more than 2 cards of this artist + if visible_count_per_round_per_artist_per_player[r,p,a] >=2 + % And this artist is the winning artist this round + /\ row(sorted_artists_per_round,r)[1] = a + % And you closed this round + /\ visible_count_per_round_per_artist_per_player[r,p,a] = max_visible_cards + % and they are claiming their double now + /\ double_played[r,p,a] then + bonus_due_to_double_cards[r,p,a] = true + else + bonus_due_to_double_cards[r,p,a] = false + endif +); + +% array[Rounds,Players] of var int: negs_due_to_double_cards; \ No newline at end of file diff --git a/enumtest.mzn b/enumtest.mzn new file mode 100644 index 0000000..a85047a --- /dev/null +++ b/enumtest.mzn @@ -0,0 +1,14 @@ +include "globals.mzn"; +% Since the documentation is unclear, wrote this test to figure +% out whether enums wrap around or not. +enum Letters; +Letters= {A,B,C}; + +var Letters: x; +var Letters: y; +var Letters: z; + +constraint x = enum_next(Letters, y); +constraint y = B; +% This is unsatisfiable, because nothing comes after x=C +constraint z = enum_next(Letters, x); \ No newline at end of file diff --git a/gameplay.mzn b/gameplay.mzn index 82d9c07..0b08ddf 100644 --- a/gameplay.mzn +++ b/gameplay.mzn @@ -5,6 +5,12 @@ include "ranking.mzn"; include "scoring.mzn"; include "sanity.mzn"; include "artists.mzn"; +include "dealing.mzn"; +% Ignoring these for now +% include "double.mzn"; +% include "drawone.mzn"; +% include "hidden.mzn"; +% include "simultaneous.mzn"; /* This file includes the core gameplay rules @@ -14,65 +20,103 @@ include "artists.mzn"; % Calculate total cards of an artist played per round constraint forall (a in Artists, r in Rounds) ( - cards_per_artist_per_round[r, a] = sum(p in Players) (visible_count_per_round_per_artist_per_player[r,p,a]) + CardsForArtist[r, a] = sum(p in Players) (visible_count_per_round_per_artist_per_player[r,p,a]) ); % Max number of visible cards can be 6 for any artist per player -var 5..6: max_visible_cards; -constraint max_visible_cards = if card(Players)>2 then 6 else 5 endif; +var 5..6: MaxVisibleCards; +constraint MaxVisibleCards = if card(Players)>2 then 6 else 5 endif; -% Maximum max_visible_cards of the artist with maximum cards -constraint forall(r in Rounds) (max(row(cards_per_artist_per_round,r)) = max_visible_cards); +% Maximum MaxVisibleCards of the artist with maximum cards +constraint forall(r in Rounds) (max(row(CardsForArtist,r)) = MaxVisibleCards); % second highest value should not be the max -constraint forall(r in Rounds) (sort(row(cards_per_artist_per_round, r))[4] != max_visible_cards); +constraint forall(r in Rounds) (sort(row(CardsForArtist, r))[4] != MaxVisibleCards); -% DOUBLE CARDS -% - Double cards are counted as VISIBLE -% - Double cards CANNOT breach the 6 LIMIT -% Total number of DOUBLE CARDS for each artist = 1 -% FOR EVERY ROUND+ARTIST combination, only 1 player should have played a double card -% TODO: Check if this is still correct after a second round -constraint forall(a in Artists) ( - sum(p in Players, r in Rounds) (double_played[r,p,a]) = 1 +% Temporary variable to see how many cards you've played TOTAL per round +array[Rounds,Players] of var int: TotalCardsPlayed; +constraint forall(r in Rounds, p in Players) ( +% TODO: Change this to played cards from VISIBLE (hidden) + TotalCardsPlayed[r,p] = sum(a in Artists) (visible_count_per_round_per_artist_per_player[r,p,a]) ); -array[Rounds,Players] of var int: max_cards_per_round_per_player; - -% What is the extra cards you can possibly play -array[Rounds,Players,Artists] of var bool: bonus_due_to_double_cards; - -constraint forall(a in Artists, r in Rounds, p in Players) ( - % If this player played more than 2 cards of this artist - if visible_count_per_round_per_artist_per_player[r,p,a] >=2 - % And this artist is the winning artist this round - /\ row(sorted_artists_per_round,r)[1] = a - % And you closed this round - /\ visible_count_per_round_per_artist_per_player[r,p,a] = max_visible_cards - % and they are claiming their double now - /\ double_played[r,p,a] then - bonus_due_to_double_cards[r,p,a] = true - else - bonus_due_to_double_cards[r,p,a] = false - endif -); - -% array[Rounds,Players] of var int: negs_due_to_double_cards; - -% constraint forall(r in Rounds, p in Players) ( - -% ); - % Calculate maximum cards any player can play in first round -% constraint forall(p in Players) ( -% CardsInHand[Round1,p] = 13 -% ); - -% TODO: This is actual not VISIBLE, but TOTAL cards LIMIT -% TODO: This does not consider any of the symbols -% IMPLIED RULE: You can max play 13 cards in Round 1 -constraint forall(p in Players) ( - sum(a in Artists) ( - visible_count_per_round_per_artist_per_player[Round1,p,a] - ) <= max_cards_per_round_per_player[Round1,p] +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] +); + +% TURN ORDER STUFF +constraint forall(r in Rounds) ( + NominalTurnCount[r] = TotalCardsPlayed[r, last_player[r]] +); + +%All players who played nominal turns +var set of Players: Pn1; +var set of Players: Pn2; +var set of Players: Pn3; +var set of Players: Pn4; +%All players who played sub-nominal turns +var set of Players: Px1; +var set of Players: Px2; +var set of Players: Px3; +var set of Players: Px4; + +set of int: emptySet = 1..0; + +constraint Pn1 = if (first_player[Round1] < last_player[Round1]) then + first_player[Round1]..last_player[Round1] + else + set_diff(Players,first_player[Round1]..last_player[Round1]) + endif; + + +constraint Pn2 = if (first_player[Round2] < last_player[Round2]) then + first_player[Round2]..last_player[Round2] + else + set_diff(Players,first_player[Round2]..last_player[Round2]) + endif; + + +constraint Pn3 = if (first_player[Round3] < last_player[Round3]) then + first_player[Round3]..last_player[Round3] + else + set_diff(Players,first_player[Round3]..last_player[Round3]) + endif; + + +constraint Pn4 = if (first_player[Round4] < last_player[Round4]) then + first_player[Round4]..last_player[Round4] + else + set_diff(Players,first_player[Round4]..last_player[Round4]) + endif; + +constraint Px1 = set_diff(Players,Pn1); +constraint Px2 = set_diff(Players,Pn2); +constraint Px3 = set_diff(Players,Pn3); +constraint Px4 = set_diff(Players,Pn4); + +constraint forall(p in Players) (p in Pn1 -> TotalCardsPlayed[Round1, p] = NominalTurnCount[Round1]); +constraint forall(p in Players) (p in Pn2 -> TotalCardsPlayed[Round2, p] = NominalTurnCount[Round2]); +constraint forall(p in Players) (p in Pn3 -> TotalCardsPlayed[Round3, p] = NominalTurnCount[Round3]); +constraint forall(p in Players) (p in Pn3 -> TotalCardsPlayed[Round4, p] = NominalTurnCount[Round4]); + +constraint forall(p in Players) (p in Px1 -> TotalCardsPlayed[Round1, p] = NominalTurnCount[Round1] - 1); +constraint forall(p in Players) (p in Px2 -> TotalCardsPlayed[Round2, p] = NominalTurnCount[Round2] - 1); +constraint forall(p in Players) (p in Px3 -> TotalCardsPlayed[Round3, p] = NominalTurnCount[Round3] - 1); +constraint forall(p in Players) (p in Px3 -> TotalCardsPlayed[Round4, p] = NominalTurnCount[Round4] - 1); + +% 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] ); diff --git a/modernart.mzn b/modernart.mzn index 5587b7c..ee50a0d 100644 --- a/modernart.mzn +++ b/modernart.mzn @@ -3,9 +3,9 @@ enum Players; enum Artists; enum Rounds; -Players = {Nemo,Jana}; +Players = {Nemo,Jana, Adam}; Artists = {Krypto,KarlGitter,ChristinP,Yoko,LiteMetal}; -Rounds = {Round1}; +Rounds = {Round1, Round2, Round3, Round4}; % Number of cards per round per player per artist array[Rounds,Players,Artists] of var int: visible_count_per_round_per_artist_per_player; @@ -19,20 +19,16 @@ array[Rounds] of var Players: last_player; % Total points that an artist has in a given round array[Rounds,Artists] of var int: total_score_per_round_per_artist; -% Whether you played a double this round -array[Rounds,Players,Artists] of var bool: double_played; - % Score a player gets in each given round -array[Rounds,Players] of var int: score_per_round_per_player; +array[Rounds,Players] of var int: RoundScore; % Final score of a player -array[Players] of var int: score_per_player; +array[Players] of var int: Score; % Total number of a cards of an artist that were PLAYED this round -array[Rounds, Artists] of var int: cards_per_artist_per_round; +array[Rounds, Artists] of var int: CardsForArtist; -% Dumb constraints to help maximize score -constraint score_per_round_per_player[Round1,Nemo] > score_per_round_per_player[Round1,Jana]; -% constraint score_per_round_per_player[Round1,Jana] > 10; -% constraint score_per_round_per_player[Round1,Adam] > 5; -solve maximize sum(p in Players)(score_per_player[p]); \ No newline at end of file +% Number of Turns played by the closing player this round +array[Rounds] of var int: NominalTurnCount; + +solve maximize Score[Nemo]; \ No newline at end of file diff --git a/ranking.mzn b/ranking.mzn index 75cf873..f4d1232 100644 --- a/ranking.mzn +++ b/ranking.mzn @@ -5,7 +5,7 @@ array[Rounds,Artists] of var int: ranking_score_per_artist_per_round; array[Rounds,1..card(Artists)] of var Artists: sorted_artists_per_round; % Decide the top artists by picking the cards per artist for that round, and sorting them -constraint forall(r in Rounds)(row(sorted_artists_per_round,r)= reverse(arg_sort(row(cards_per_artist_per_round, r)))); +constraint forall(r in Rounds)(row(sorted_artists_per_round,r)= reverse(arg_sort(row(CardsForArtist, r)))); % Top three artists get ranking score in each round as 3,2,1 others get 0 constraint forall(r in Rounds) (ranking_score_per_artist_per_round[r, row(sorted_artists_per_round,r)[1]] = 3); diff --git a/sanity.mzn b/sanity.mzn index 00524f6..52c1921 100644 --- a/sanity.mzn +++ b/sanity.mzn @@ -1,6 +1,6 @@ % Sanity check constraint forall (a in Artists, r in Rounds) ( - cards_per_artist_per_round[r,a]>=0 + CardsForArtist[r,a]>=0 ); % So they don't go negative constraint forall (a in Artists, r in Rounds, p in Players) ( @@ -12,10 +12,20 @@ constraint forall (a in Artists, r in Rounds) ( ranking_score_per_artist_per_round[r,a] >=0 ); +% No game can have less than 1 Nominal Turn (Number of turns played by the Closing Player) +constraint forall(r in Rounds) (NominalTurnCount[r] >=1); + +constraint forall(r in Rounds, p in Players) ( + StartingCardsInHand[r,p] >=0 +); + % Round 1 Player 1 constraint first_player[Round1] = Nemo; % Visible Cards per round per player for every artist > 0 constraint forall(a in Artists) ( sum(p in Players, r in Rounds) (visible_count_per_round_per_artist_per_player[r,p,a])>=0 -); \ No newline at end of file +); + +% This is a 2-5 player game +constraint 2<= assert(card(Players)) <=5 \ No newline at end of file diff --git a/scoring.mzn b/scoring.mzn index 74d25d5..dc89f3e 100644 --- a/scoring.mzn +++ b/scoring.mzn @@ -8,14 +8,12 @@ constraint forall(r in Rounds, a in Artists) ( % 1. Per Round constraint forall(r in Rounds, p in Players) ( - score_per_round_per_player[r,p] = - - sum(a in Artists) ( + RoundScore[r,p] = sum(a in Artists) ( visible_count_per_round_per_artist_per_player[r,p,a] * ranking_score_per_artist_per_round[r,a] ) ); % 2. For the whole game constraint forall(p in Players) ( - score_per_player[p] = sum(r in Rounds) (score_per_round_per_player[r,p]) + Score[p] = sum(r in Rounds) (RoundScore[r,p]) );