need some help. We are working on code that will simulate the card game Dominion
ID: 3877258 • Letter: N
Question
need some help. We are working on code that will simulate the card game Dominion. I have provided the relevant code I believe. Please let me know if you need clarification. The following paragraphs are the instructions that must be followed. The code below is pulled from existing code that currently runs properly. The switch runs in the dominion.c file. I have provided the dominion.c and dominion.h files. I am not sure what bugs they want but just some simple bugs that may make the code not work properly.
1) Read the rules and the source code of Dominion, and understand the game sufficiently to be comfortable with testing an implementation of it!. Your first job is to become a “subject expert” in Dominion, since you will be testing an implementation of it. Note that the primary source of information about the Dominion implementation itself is the dominion.c and dominion.h files provided in the class repository. The specification you use will have to combine this information with knowledge about how the game works, discovered by investigation. This is a typical testing experience, where you are not given a complete specification, but must discover one for yourself.
Pick 5 cards implemented in dominion.c. Choose 3 cards of your choice and smithy and adventurer cards are mandatory. Refactor the code so that these cards are implemented in their own functions, rather than as part of the switch statement in cardEffect. You should call the functions for these cards in the appropriate place in cardEffect. The 5 cards I am using is Adventurer, smithy, gardens, outpost, and council room card.
2) Introduce some bug(s) in 4 cards out of these 5 cards, preferably “subtle” ones that might easily escape a decent test suite. By bugs I mean something that does not behave correctly – it may crash, or it may cause incorrect Dominion behavior. Introducing bugs in smithy and adventurer is mandatory. ALL CODE SHOULD BE COMPILED and RUN. Again, the code for the cards is below.
3) Document your changes of the five cards in the, discussing the process of extracting the functions. In addtion, write information of your bugs.
CODE FOR THE CARDS AND cardEFFECT FUNCTION
#include "dominion.h"
#include "dominion_helpers.h"
#include "rngs.h"
#include
#include
#include
int compare(const void* a, const void* b) {
if (*(int*)a > *(int*)b)
return 1;
if (*(int*)a < *(int*)b)
return -1;
return 0;
}
struct gameState* newGame() {
struct gameState* g = malloc(sizeof(struct gameState));
return g;
}
int* kingdomCards(int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8, int k9, int k10) {
int* k = malloc(10 * sizeof(int));
k[0] = k1;
k[1] = k2;
k[2] = k3;
k[3] = k4;
k[4] = k5;
k[5] = k6;
k[6] = k7;
k[7] = k8;
k[8] = k9;
k[9] = k10;
return k;
}
int initializeGame(int numPlayers, int kingdomCards[10], int randomSeed,struct gameState *state) {
int i;
int j;
int it;
//set up random number generator
SelectStream(1);
PutSeed((long)randomSeed);
//check number of players
if (numPlayers > MAX_PLAYERS || numPlayers < 2){
return -1;
}
//set number of players
state->numPlayers = numPlayers;
//check selected kingdom cards are different
for (i = 0; i < 10; i++){
for (j = 0; j < 10; j++){
if (j != i && kingdomCards[j] == kingdomCards[i]){
return -1;
}
}
}
//initialize supply
///////////////////////////////
//set number of Curse cards
if (numPlayers == 2){
state->supplyCount[curse] = 10;
}else if (numPlayers == 3){
state->supplyCount[curse] = 20;
}else{
state->supplyCount[curse] = 30;
}
//set number of Victory cards
if (numPlayers == 2){
state->supplyCount[estate] = 8;
state->supplyCount[duchy] = 8;
state->supplyCount[province] = 8;
}else{
state->supplyCount[estate] = 12;
state->supplyCount[duchy] = 12;
state->supplyCount[province] = 12;
}
//set number of Treasure cards
state->supplyCount[copper] = 60 - (7 * numPlayers);
state->supplyCount[silver] = 40;
state->supplyCount[gold] = 30;
//set number of Kingdom cards
for (i = adventurer; i <= treasure_map; i++){ //loop all cards
for (j = 0; j < 10; j++){ //loop chosen cards
if (kingdomCards[j] == i){
//check if card is a 'Victory' Kingdom card
if (kingdomCards[j] == great_hall || kingdomCards[j] == gardens){
if (numPlayers == 2){
state->supplyCount[i] = 8;
}else{ state->supplyCount[i] = 12; }
}else{
state->supplyCount[i] = 10;
}
break;
}else{ //card is not in the set choosen for the game
state->supplyCount[i] = -1;
}
}
}
////////////////////////
//supply intilization complete
//set player decks
for (i = 0; i < numPlayers; i++){
state->deckCount[i] = 0;
for (j = 0; j < 3; j++){
state->deck[i][j] = estate;
state->deckCount[i]++;
}
for (j = 3; j < 10; j++){
state->deck[i][j] = copper;
state->deckCount[i]++;
}
}
//shuffle player decks
for (i = 0; i < numPlayers; i++){
if ( shuffle(i, state) < 0 ){
return -1;
}
}
//draw player hands
for (i = 0; i < numPlayers; i++){
//initialize hand size to zero
state->handCount[i] = 0;
state->discardCount[i] = 0;
//draw 5 cards
// for (j = 0; j < 5; j++)
// {
// drawCard(i, state);
// }
}
//set embargo tokens to 0 for all supply piles
for (i = 0; i <= treasure_map; i++){
state->embargoTokens[i] = 0;
}
//initialize first player's turn
state->outpostPlayed = 0;
state->phase = 0;
state->numActions = 1;
state->numBuys = 1;
state->playedCardCount = 0;
state->whoseTurn = 0;
state->handCount[state->whoseTurn] = 0;
//int it; move to top
//Moved draw cards to here, only drawing at the start of a turn
for (it = 0; it < 5; it++){
drawCard(state->whoseTurn, state);
}
updateCoins(state->whoseTurn, state, 0);
return 0;
}
int shuffle(int player, struct gameState *state) {
int newDeck[MAX_DECK];
int newDeckPos = 0;
int card;
int i;
if (state->deckCount[player] < 1)
return -1;
qsort ((void*)(state->deck[player]), state->deckCount[player], sizeof(int), compare);
/* SORT CARDS IN DECK TO ENSURE DETERMINISM! */
while (state->deckCount[player] > 0) {
card = floor(Random() * state->deckCount[player]);
newDeck[newDeckPos] = state->deck[player][card];
newDeckPos++;
for (i = card; i < state->deckCount[player]-1; i++) {
state->deck[player][i] = state->deck[player][i+1];
}
state->deckCount[player]--;
}
for (i = 0; i < newDeckPos; i++) {
state->deck[player][i] = newDeck[i];
state->deckCount[player]++;
}
return 0;
}
int playCard(int handPos, int choice1, int choice2, int choice3, struct gameState *state)
{
int card;
int coin_bonus = 0; //tracks coins gain from actions
//check if it is the right phase
if (state->phase != 0){
return -1;
}
//check if player has enough actions
if ( state->numActions < 1 ){
return -1;
}
//get card played
card = handCard(handPos, state);
//check if selected card is an action
if ( card < adventurer || card > treasure_map ){
return -1;
}
//play card
if ( cardEffect(card, choice1, choice2, choice3, state, handPos,& coin_bonus) < 0 ){
return -1;
}
//reduce number of actions
state->numActions--;
//update coins (Treasure cards may be added with card draws)
updateCoins(state->whoseTurn, state, coin_bonus);
return 0;
}
int buyCard(int supplyPos, struct gameState *state) {
int who;
if (DEBUG){
printf("Entering buyCard... ");
}
// I don't know what to do about the phase thing.
who = state->whoseTurn;
if (state->numBuys< 1){
if (DEBUG)
printf("You do not have any buys left ");
return -1;
} else if (supplyCount(supplyPos, state) <1){
if (DEBUG)
printf("There are not any of that type of card left ");
return -1;
} else if (state->coins < getCost(supplyPos)){
if (DEBUG)
printf("You do not have enough money to buy that. You have %d coins. ", state->coins);
return -1;
} else {
state->phase=1;
//state->supplyCount[supplyPos]--;
gainCard(supplyPos, state, 0, who); //card goes in discard, this might be wrong.. (2 means goes into hand, 0 goes into discard)
state->coins = (state->coins) - (getCost(supplyPos));
state->numBuys--;
if (DEBUG)
printf("You bought card number %d for %d coins. You now have %d buys and %d coins. ", supplyPos, getCost(supplyPos), state->numBuys, state->coins);
}
//state->discard[who][state->discardCount[who]] = supplyPos;
//state->discardCount[who]++;
return 0;
}
int numHandCards(struct gameState *state) {
return state->handCount[ whoseTurn(state) ];
}
int handCard(int handPos, struct gameState *state) {
int currentPlayer = whoseTurn(state);
return state->hand[currentPlayer][handPos];
}
int supplyCount(int card, struct gameState *state) {
return state->supplyCount[card];
}
int fullDeckCount(int player, int card, struct gameState *state) {
int i;
int count = 0;
for (i = 0; i < state->deckCount[player]; i++){
if (state->deck[player][i] == card) count++;
}
for (i = 0; i < state->handCount[player]; i++){
if (state->hand[player][i] == card) count++;
}
for (i = 0; i < state->discardCount[player]; i++){
if (state->discard[player][i] == card) count++;
}
return count;
}
int whoseTurn(struct gameState *state) {
return state->whoseTurn;
}
int endTurn(struct gameState *state) {
int k;
int i;
int currentPlayer = whoseTurn(state);
//Discard hand
for (i = 0; i < state->handCount[currentPlayer]; i++){
state->discard[currentPlayer][state->discardCount[currentPlayer]++] = state->hand[currentPlayer][i];//Discard
state->hand[currentPlayer][i] = -1;//Set card to -1
}
state->handCount[currentPlayer] = 0;//Reset hand count
//Code for determining the player
if (currentPlayer < (state->numPlayers - 1)){
state->whoseTurn = currentPlayer + 1;//Still safe to increment
}else{
state->whoseTurn = 0;//Max player has been reached, loop back around to player 1
}
state->outpostPlayed = 0;
state->phase = 0;
state->numActions = 1;
state->coins = 0;
state->numBuys = 1;
state->playedCardCount = 0;
state->handCount[state->whoseTurn] = 0;
//int k; move to top
//Next player draws hand
for (k = 0; k < 5; k++){
drawCard(state->whoseTurn, state);//Draw a card
}
//Update money
updateCoins(state->whoseTurn, state , 0);
return 0;
}
int isGameOver(struct gameState *state) {
int i;
int j;
//if stack of Province cards is empty, the game ends
if (state->supplyCount[province] == 0){
return 1;
}
//if three supply pile are at 0, the game ends
j = 0;
for (i = 0; i < 25; i++){
if (state->supplyCount[i] == 0){
j++;
}
}
if ( j >= 3){
return 1;
}
return 0;
}
int scoreFor (int player, struct gameState *state) {
int i;
int score = 0;
//score from hand
for (i = 0; i < state->handCount[player]; i++){
if (state->hand[player][i] == curse) { score = score - 1; };
if (state->hand[player][i] == estate) { score = score + 1; };
if (state->hand[player][i] == duchy) { score = score + 3; };
if (state->hand[player][i] == province) { score = score + 6; };
if (state->hand[player][i] == great_hall) { score = score + 1; };
if (state->hand[player][i] == gardens) { score = score + ( fullDeckCount(player, 0, state) / 10 ); };
}
//score from discard
for (i = 0; i < state->discardCount[player]; i++){
if (state->discard[player][i] == curse) { score = score - 1; };
if (state->discard[player][i] == estate) { score = score + 1; };
if (state->discard[player][i] == duchy) { score = score + 3; };
if (state->discard[player][i] == province) { score = score + 6; };
if (state->discard[player][i] == great_hall) { score = score + 1; };
if (state->discard[player][i] == gardens) { score = score + ( fullDeckCount(player, 0, state) / 10 ); };
}
//score from deck
for (i = 0; i < state->discardCount[player]; i++){
if (state->deck[player][i] == curse) { score = score - 1; };
if (state->deck[player][i] == estate) { score = score + 1; };
if (state->deck[player][i] == duchy) { score = score + 3; };
if (state->deck[player][i] == province) { score = score + 6; };
if (state->deck[player][i] == great_hall) { score = score + 1; };
if (state->deck[player][i] == gardens) { score = score + ( fullDeckCount(player, 0, state) / 10 ); };
}
return score;
}
int getWinners(int players[MAX_PLAYERS], struct gameState *state) {
int i;
int j;
int highScore;
int currentPlayer;
//get score for each player
for (i = 0; i < MAX_PLAYERS; i++){
//set unused player scores to -9999
if (i >= state->numPlayers){
players[i] = -9999;
}else{
players[i] = scoreFor (i, state);
}
}
//find highest score
j = 0;
for (i = 0; i < MAX_PLAYERS; i++){
if (players[i] > players[j]){
j = i;
}
}
highScore = players[j];
//add 1 to players who had less turns
currentPlayer = whoseTurn(state);
for (i = 0; i < MAX_PLAYERS; i++){
if ( players[i] == highScore&& i > currentPlayer ){
players[i]++;
}
}
//find new highest score
j = 0;
for (i = 0; i < MAX_PLAYERS; i++){
if ( players[i] > players[j] ){
j = i;
}
}
highScore = players[j];
//set winners in array to 1 and rest to 0
for (i = 0; i < MAX_PLAYERS; i++){
if ( players[i] == highScore ){
players[i] = 1;
}else{
players[i] = 0;
}
}
return 0;
}
int drawCard(int player, struct gameState *state)
{ int count;
int deckCounter;
if (state->deckCount[player] <= 0){//Deck is empty
//Step 1 Shuffle the discard pile back into a deck
int i;
//Move discard to deck
for (i = 0; i < state->discardCount[player];i++){
state->deck[player][i] = state->discard[player][i];
state->discard[player][i] = -1;
}
state->deckCount[player] = state->discardCount[player];
state->discardCount[player] = 0;//Reset discard
//Shufffle the deck
shuffle(player, state);//Shuffle the deck up and make it so that we can draw
if (DEBUG){//Debug statements
printf("Deck count now: %d ", state->deckCount[player]);
}
state->discardCount[player] = 0;
//Step 2 Draw Card
count = state->handCount[player];//Get current player's hand count
if (DEBUG){//Debug statements
printf("Current hand count: %d ", count);
}
deckCounter = state->deckCount[player];//Create a holder for the deck count
if (deckCounter == 0)
return -1;
state->hand[player][count] = state->deck[player][deckCounter - 1];//Add card to hand
state->deckCount[player]--;
state->handCount[player]++;//Increment hand count
}else{
int count = state->handCount[player];//Get current hand count for player
int deckCounter;
if (DEBUG){//Debug statements
printf("Current hand count: %d ", count);
}
deckCounter = state->deckCount[player];//Create holder for the deck count
state->hand[player][count] = state->deck[player][deckCounter - 1];//Add card to the hand
state->deckCount[player]--;
state->handCount[player]++;//Increment hand count
}
return 0;
}
int getCost(int cardNumber)
{
switch( cardNumber )
{
case curse:
return 0;
case estate:
return 2;
case duchy:
return 5;
case province:
return 8;
case copper:
return 0;
case silver:
return 3;
case gold:
return 6;
case adventurer:
return 6;
case council_room:
return 5;
case feast:
return 4;
case gardens:
return 4;
case mine:
return 5;
case remodel:
return 4;
case smithy:
return 4;
case village:
return 3;
case baron:
return 4;
case great_hall:
return 3;
case minion:
return 5;
case steward:
return 3;
case tribute:
return 5;
case ambassador:
return 3;
case cutpurse:
return 4;
case embargo:
return 2;
case outpost:
return 5;
case salvager:
return 4;
case sea_hag:
return 4;
case treasure_map:
return 4;
}
return -1;
}
int cardEffect(int card, int choice1, int choice2, int choice3, struct gameState *state, int handPos, int *bonus)
{
int i;
int j;
int k;
int x;
int index;
int currentPlayer = whoseTurn(state);
int nextPlayer = currentPlayer + 1;
int tributeRevealedCards[2] = {-1, -1};
int temphand[MAX_HAND];// moved above the if statement
int drawntreasure=0;
int cardDrawn;
int z = 0;// this is the counter for the temp hand
if (nextPlayer > (state->numPlayers - 1)){
nextPlayer = 0;
}
//uses switch to select card and perform actions
switch( card )
{
case adventurer:
while(drawntreasure<2){
if (state->deckCount[currentPlayer] <1){//if the deck is empty we need to shuffle discard and add to deck
shuffle(currentPlayer, state);
}
drawCard(currentPlayer, state);
cardDrawn = state->hand[currentPlayer][state->handCount[currentPlayer]-1];//top card of hand is most recently drawn card.
if (cardDrawn == copper || cardDrawn == silver || cardDrawn == gold)
drawntreasure++;
else{
temphand[z]=cardDrawn;
state->handCount[currentPlayer]--; //this should just remove the top card (the most recently drawn one).
z++;
}
}
while(z-1>=0){
state->discard[currentPlayer][state->discardCount[currentPlayer]++]=temphand[z-1]; // discard all cards in play that have been drawn
z=z-1;
}
return 0;
case council_room:
//+4 Cards
for (i = 0; i < 4; i++){
drawCard(currentPlayer, state);
}
//+1 Buy
state->numBuys++;
//Each other player draws a card
for (i = 0; i < state->numPlayers; i++){
if ( i != currentPlayer )
{
drawCard(i, state);
}
}
//put played card in played card pile
discardCard(handPos, currentPlayer, state, 0);
return 0;
case feast:
//gain card with cost up to 5
//Backup hand
for (i = 0; i <= state->handCount[currentPlayer]; i++){
temphand[i] = state->hand[currentPlayer][i];//Backup card
state->hand[currentPlayer][i] = -1;//Set to nothing
}
//Backup hand
//Update Coins for Buy
updateCoins(currentPlayer, state, 5);
x = 1;//Condition to loop on
while( x == 1) {//Buy one card
if (supplyCount(choice1, state) <= 0){
if (DEBUG)
printf("None of that card left, sorry! ");
if (DEBUG){
printf("Cards Left: %d ", supplyCount(choice1, state));
}
}else if (state->coins < getCost(choice1)){
printf("That card is too expensive! ");
if (DEBUG){
printf("Coins: %d < %d ", state->coins, getCost(choice1));
}
}else{
if (DEBUG){
printf("Deck Count: %d ", state->handCount[currentPlayer] + state->deckCount[currentPlayer] + state->discardCount[currentPlayer]);
}
gainCard(choice1, state, 0, currentPlayer);//Gain the card
x = 0;//No more buying cards
if (DEBUG){
printf("Deck Count: %d ", state->handCount[currentPlayer] + state->deckCount[currentPlayer] + state->discardCount[currentPlayer]);
}
}
}
//Reset Hand
for (i = 0; i <= state->handCount[currentPlayer]; i++){
state->hand[currentPlayer][i] = temphand[i];
temphand[i] = -1;
}
//Reset Hand
return 0;
case gardens:
return -1;
case mine:
j = state->hand[currentPlayer][choice1]; //store card we will trash
if (state->hand[currentPlayer][choice1] < copper || state->hand[currentPlayer][choice1] > gold){
return -1;
}
if (choice2 > treasure_map || choice2 < curse){
return -1;
}
if ( (getCost(state->hand[currentPlayer][choice1]) + 3) > getCost(choice2) ){
return -1;
}
gainCard(choice2, state, 2, currentPlayer);
//discard card from hand
discardCard(handPos, currentPlayer, state, 0);
//discard trashed card
for (i = 0; i < state->handCount[currentPlayer]; i++){
if (state->hand[currentPlayer][i] == j){
discardCard(i, currentPlayer, state, 0);
break;
}
}
return 0;
case remodel:
j = state->hand[currentPlayer][choice1]; //store card we will trash
if ( (getCost(state->hand[currentPlayer][choice1]) + 2) > getCost(choice2) ){
return -1;
}
gainCard(choice2, state, 0, currentPlayer);
//discard card from hand
discardCard(handPos, currentPlayer, state, 0);
//discard trashed card
for (i = 0; i < state->handCount[currentPlayer]; i++){
if (state->hand[currentPlayer][i] == j){
discardCard(i, currentPlayer, state, 0);
break;
}
}
return 0;
case smithy:
//+3 Cards
for (i = 0; i < 3; i++){
drawCard(currentPlayer, state);
}
//discard card from hand
discardCard(handPos, currentPlayer, state, 0);
return 0;
case village:
//+1 Card
drawCard(currentPlayer, state);
//+2 Actions
state->numActions = state->numActions + 2;
//discard played card from hand
discardCard(handPos, currentPlayer, state, 0);
return 0;
case baron:
state->numBuys++;//Increase buys by 1!
if (choice1 > 0){//Boolean true or going to discard an estate
int p = 0;//Iterator for hand!
int card_not_discarded = 1;//Flag for discard set!
while(card_not_discarded){
if (state->hand[currentPlayer][p] == estate){//Found an estate card!
state->coins += 4;//Add 4 coins to the amount of coins
state->discard[currentPlayer][state->discardCount[currentPlayer]] = state->hand[currentPlayer][p];
state->discardCount[currentPlayer]++;
for (;p < state->handCount[currentPlayer]; p++){
state->hand[currentPlayer][p] = state->hand[currentPlayer][p+1];
}
state->hand[currentPlayer][state->handCount[currentPlayer]] = -1;
state->handCount[currentPlayer]--;
card_not_discarded = 0;//Exit the loop
}
else if (p > state->handCount[currentPlayer]){
if(DEBUG) {
printf("No estate cards in your hand, invalid choice ");
printf("Must gain an estate if there are any ");
}
if (supplyCount(estate, state) > 0){
gainCard(estate, state, 0, currentPlayer);
state->supplyCount[estate]--;//Decrement estates
if (supplyCount(estate, state) == 0){
isGameOver(state);
}
}
card_not_discarded = 0;//Exit the loop
}else{
p++;//Next card
}
}
}else{
if (supplyCount(estate, state) > 0){
gainCard(estate, state, 0, currentPlayer);//Gain an estate
state->supplyCount[estate]--;//Decrement Estates
if (supplyCount(estate, state) == 0){
isGameOver(state);
}
}
}
return 0;
case great_hall:
//+1 Card
drawCard(currentPlayer, state);
//+1 Actions
state->numActions++;
//discard card from hand
discardCard(handPos, currentPlayer, state, 0);
return 0;
case minion:
//+1 action
state->numActions++;
//discard card from hand
discardCard(handPos, currentPlayer, state, 0);
if (choice1){ //+2 coins
state->coins = state->coins + 2;
}else if (choice2){ //discard hand, redraw 4, other players with 5+ cards discard hand and draw 4
//discard hand
while(numHandCards(state) > 0){
discardCard(handPos, currentPlayer, state, 0);
}
//draw 4
for (i = 0; i < 4; i++){
drawCard(currentPlayer, state);
}
//other players discard hand and redraw if hand size> 4
for (i = 0; i < state->numPlayers; i++){
if (i != currentPlayer){
if ( state->handCount[i] > 4 ){
//discard hand
while( state->handCount[i] > 0 ){
discardCard(handPos, i, state, 0);
}
//draw 4
for (j = 0; j < 4; j++){
drawCard(i, state);
}
}
}
}
}
return 0;
case steward:
if (choice1 == 1){
//+2 cards
drawCard(currentPlayer, state);
drawCard(currentPlayer, state);
}else if (choice1 == 2){
//+2 coins
state->coins = state->coins + 2;
}else{
//trash 2 cards in hand
discardCard(choice2, currentPlayer, state, 1);
discardCard(choice3, currentPlayer, state, 1);
}
//discard card from hand
discardCard(handPos, currentPlayer, state, 0);
return 0;
case tribute:
if ((state->discardCount[nextPlayer] + state->deckCount[nextPlayer]) <= 1){
if (state->deckCount[nextPlayer] > 0){
tributeRevealedCards[0] = state->deck[nextPlayer][state->deckCount[nextPlayer]-1];
state->deckCount[nextPlayer]--;
}else if (state->discardCount[nextPlayer] > 0){
tributeRevealedCards[0] = state->discard[nextPlayer][state->discardCount[nextPlayer]-1];
state->discardCount[nextPlayer]--;
}else{
//No Card to Reveal
if (DEBUG){
printf("No cards to reveal ");
}
}
}else{
if (state->deckCount[nextPlayer] == 0){
for (i = 0; i < state->discardCount[nextPlayer]; i++){
state->deck[nextPlayer][i] = state->discard[nextPlayer][i];//Move to deck
state->deckCount[nextPlayer]++;
state->discard[nextPlayer][i] = -1;
state->discardCount[nextPlayer]--;
}
shuffle(nextPlayer,state);//Shuffle the deck
}
tributeRevealedCards[0] = state->deck[nextPlayer][state->deckCount[nextPlayer]-1];
state->deck[nextPlayer][state->deckCount[nextPlayer]--] = -1;
state->deckCount[nextPlayer]--;
tributeRevealedCards[1] = state->deck[nextPlayer][state->deckCount[nextPlayer]-1];
state->deck[nextPlayer][state->deckCount[nextPlayer]--] = -1;
state->deckCount[nextPlayer]--;
}
if (tributeRevealedCards[0] == tributeRevealedCards[1]){//If we have a duplicate card, just drop one
state->playedCards[state->playedCardCount] = tributeRevealedCards[1];
state->playedCardCount++;
tributeRevealedCards[1] = -1;
}
for (i = 0; i <= 2; i ++){
if (tributeRevealedCards[i] == copper || tributeRevealedCards[i] == silver || tributeRevealedCards[i] == gold){//Treasure cards
state->coins += 2;
}
else if (tributeRevealedCards[i] == estate || tributeRevealedCards[i] == duchy || tributeRevealedCards[i] == province || tributeRevealedCards[i] == gardens || tributeRevealedCards[i] == great_hall){//Victory Card Found
drawCard(currentPlayer, state);
drawCard(currentPlayer, state);
}else{//Action Card
state->numActions = state->numActions + 2;
}
}
return 0;
case ambassador:
j = 0; //used to check if player has enough cards to discard
if (choice2 > 2 || choice2 < 0){
return -1;
}
if (choice1 == handPos){
return -1;
}
for (i = 0; i < state->handCount[currentPlayer]; i++){
if (i != handPos && i == state->hand[currentPlayer][choice1] && i != choice1){
j++;
}
}
if (j < choice2){
return -1;
}
if (DEBUG)
printf("Player %d reveals card number: %d ", currentPlayer, state->hand[currentPlayer][choice1]);
//increase supply count for choosen card by amount being discarded
state->supplyCount[state->hand[currentPlayer][choice1]] += choice2;
//each other player gains a copy of revealed card
for (i = 0; i < state->numPlayers; i++){
if (i != currentPlayer){
gainCard(state->hand[currentPlayer][choice1], state, 0, i);
}
}
//discard played card from hand
discardCard(handPos, currentPlayer, state, 0);
//trash copies of cards returned to supply
for (j = 0; j < choice2; j++){
for (i = 0; i < state->handCount[currentPlayer]; i++){
if (state->hand[currentPlayer][i] == state->hand[currentPlayer][choice1]){
discardCard(i, currentPlayer, state, 1);
break;
}
}
}
return 0;
case cutpurse:
updateCoins(currentPlayer, state, 2);
for (i = 0; i < state->numPlayers; i++){
if (i != currentPlayer){
for (j = 0; j < state->handCount[i]; j++){
if (state->hand[i][j] == copper){
discardCard(j, i, state, 0);
break;
}
if (j == state->handCount[i]){
for (k = 0; k < state->handCount[i]; k++)
{
if (DEBUG)
printf("Player %d reveals card number %d ", i, state->hand[i][k]);
}
break;
}
}
}
}
//discard played card from hand
discardCard(handPos, currentPlayer, state, 0);
return 0;
case embargo:
//+2 Coins
state->coins = state->coins + 2;
//see if selected pile is in play
if ( state->supplyCount[choice1] == -1 ){
return -1;
}
//add embargo token to selected supply pile
state->embargoTokens[choice1]++;
//trash card
discardCard(handPos, currentPlayer, state, 1);
return 0;
case outpost:
//set outpost flag
state->outpostPlayed++;
//discard card
discardCard(handPos, currentPlayer, state, 0);
return 0;
case salvager:
//+1 buy
state->numBuys++;
if (choice1)
{
//gain coins equal to trashed card
state->coins = state->coins + getCost( handCard(choice1, state) );
//trash card
discardCard(choice1, currentPlayer, state, 1);
}
//discard card
discardCard(handPos, currentPlayer, state, 0);
return 0;
case sea_hag:
for (i = 0; i < state->numPlayers; i++){
if (i != currentPlayer){
state->discard[i][state->discardCount[i]] = state->deck[i][state->deckCount[i]--]; state->deckCount[i]--;
state->discardCount[i]++;
state->deck[i][state->deckCount[i]--] = curse;//Top card now a curse
}
}
return 0;
case treasure_map:
//search hand for another treasure_map
index = -1;
for (i = 0; i < state->handCount[currentPlayer]; i++){
if (state->hand[currentPlayer][i] == treasure_map&& i != handPos){
index = i;
break;
}
}
if (index > -1){
//trash both treasure cards
discardCard(handPos, currentPlayer, state, 1);
discardCard(index, currentPlayer, state, 1);
//gain 4 Gold cards
for (i = 0; i < 4; i++){
gainCard(gold, state, 1, currentPlayer);
}
//return success
return 1;
}
//no second treasure_map found in hand
return -1;
}
return -1;
}
int discardCard(int handPos, int currentPlayer, struct gameState *state, int trashFlag)
{
//if card is not trashed, added to Played pile
if (trashFlag < 1){
//add card to played pile
state->playedCards[state->playedCardCount] = state->hand[currentPlayer][handPos];
state->playedCardCount++;
}
//set played card to -1
state->hand[currentPlayer][handPos] = -1;
//remove card from player's hand
if ( handPos == (state->handCount[currentPlayer] - 1) ){//last card in hand array is played
//reduce number of cards in hand
state->handCount[currentPlayer]--;
}else if ( state->handCount[currentPlayer] == 1 ){//only one card in hand
//reduce number of cards in hand
state->handCount[currentPlayer]--;
}else{
//replace discarded card with last card in hand
state->hand[currentPlayer][handPos] = state->hand[currentPlayer][ (state->handCount[currentPlayer] - 1)];
//set last card to -1
state->hand[currentPlayer][state->handCount[currentPlayer] - 1] = -1;
//reduce number of cards in hand
state->handCount[currentPlayer]--;
}
return 0;
}
int gainCard(int supplyPos, struct gameState *state, int toFlag, int player)
{
//Note: supplyPos is enum of choosen card
//check if supply pile is empty (0) or card is not used in game (-1)
if ( supplyCount(supplyPos, state) < 1 ){
return -1;
}
//added card for [whoseTurn] current player:
// toFlag = 0 : add to discard
// toFlag = 1 : add to deck
// toFlag = 2 : add to hand
if (toFlag == 1){
state->deck[ player ][ state->deckCount[player] ] = supplyPos;
state->deckCount[player]++;
}
else if (toFlag == 2){
state->hand[ player ][ state->handCount[player] ] = supplyPos;
state->handCount[player]++;
}
else{
state->discard[player][ state->discardCount[player] ] = supplyPos;
state->discardCount[player]++;
}
//decrease number in supply pile
state->supplyCount[supplyPos]--;
return 0;
}
int updateCoins(int player, struct gameState *state, int bonus)
{
int i;
//reset coin count
state->coins = 0;
//add coins for each Treasure card in player's hand
for (i = 0; i < state->handCount[player]; i++) {
if (state->hand[player][i] == copper){
state->coins += 1;
}
else if (state->hand[player][i] == silver){
state->coins += 2;
}
else if (state->hand[player][i] == gold){
state->coins += 3;
}
}
//add bonus
state->coins += bonus;
return 0;
}//end of dominion.c
#ifndef _DOMINION_H
#define _DOMINION_H
// Code from various sources, baseline from Kristen Bartosz
#define MAX_HAND 500
#define MAX_DECK 500
#define MAX_PLAYERS 4
#define DEBUG 0
/* http://dominion.diehrstraits.com has card texts */
/* http://dominion.isotropic.org has other stuff */
/* hand# means index of a card in current active player's hand */
enum CARD
{curse = 0,
estate,
duchy,
province,
copper,
silver,
gold,
adventurer,
/* If no/only 1 treasure found, stop when full deck seen */
council_room,
feast, /* choice1 is supply # of card gained) */
gardens,
mine, /* choice1 is hand# of money to trash, choice2 is supply# of
money to put in hand */
remodel, /* choice1 is hand# of card to remodel, choice2 is supply# */
smithy,
village,
baron, /* choice1: boolean for discard of estate */
/* Discard is always of first (lowest index) estate */
great_hall,
minion, /* choice1: 1 = +2 coin, 2 = redraw */
steward, /* choice1: 1 = +2 card, 2 = +2 coin, 3 = trash 2 (choice2,3) */
tribute,
ambassador, /* choice1 = hand#, choice2 = number to return to supply */
cutpurse,
embargo, /* choice1 = supply# */
outpost,
salvager, /* choice1 = hand# to trash */
sea_hag,
treasure_map
};
struct gameState {
int numPlayers; //number of players
int supplyCount[treasure_map+1]; //this is the amount of a specific type of card given a specific number.
int embargoTokens[treasure_map+1];
int outpostPlayed;
int outpostTurn;
int whoseTurn;
int phase;
int numActions; /* Starts at 1 each turn */
int coins; /* Use as you see fit! */
int numBuys; /* Starts at 1 each turn */
int hand[MAX_PLAYERS][MAX_HAND];
int handCount[MAX_PLAYERS];
int deck[MAX_PLAYERS][MAX_DECK];
int deckCount[MAX_PLAYERS];
int discard[MAX_PLAYERS][MAX_DECK];
int discardCount[MAX_PLAYERS];
int playedCards[MAX_DECK];
int playedCardCount;
};
/* All functions return -1 on failure, and DO NOT CHANGE GAME STATE;
unless specified for other return, return 0 on success */
struct gameState* newGame();
int* kingdomCards(int k1, int k2, int k3, int k4, int k5, int k6, int k7,
int k8, int k9, int k10);
int initializeGame(int numPlayers, int kingdomCards[10], int randomSeed,
struct gameState *state);
/* Responsible for initializing all supplies, and shuffling deck and
drawing starting hands for all players. Check that 10 cards selected
are in fact (different) kingdom cards, and that numPlayers is valid.
Cards not in game should initialize supply position to -1 */
int shuffle(int player, struct gameState *state);
/* Assumes all cards are now in deck array (or hand/played): discard is
empty */
int playCard(int handPos, int choice1, int choice2, int choice3,
struct gameState *state);
/* Play card with index handPos from current player's hand */
int buyCard(int supplyPos, struct gameState *state);
/* Buy card with supply index supplyPos */
int numHandCards(struct gameState *state);
/* How many cards current player has in hand */
int handCard(int handNum, struct gameState *state);
/* enum value of indexed card in player's hand */
int supplyCount(int card, struct gameState *state);
/* How many of given card are left in supply */
int fullDeckCount(int player, int card, struct gameState *state);
/* Here deck = hand + discard + deck */
int whoseTurn(struct gameState *state);
int endTurn(struct gameState *state);
/* Must do phase C and advance to next player; do not advance whose turn
if game is over */
int isGameOver(struct gameState *state);
int scoreFor(int player, struct gameState *state);
/* Negative here does not mean invalid; scores may be negative,
-9999 means invalid input */
int getWinners(int players[MAX_PLAYERS], struct gameState *state);
/* Set array position of each player who won (remember ties!) to
1, others to 0 */
#endif
Explanation / Answer
#include "dominion.h"
#include "dominion_helpers.h"
#include "rngs.h"
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int compare(const void* a, const void* b) {
if (*(int*)a > *(int*)b)
return 1;
if (*(int*)a < *(int*)b)
return -1;
return 0;
}
struct gameState* newGame() {
struct gameState* g = malloc(sizeof(struct gameState));
return g;
}
int* kingdomCards(int k1, int k2, int k3, int k4, int k5, int k6, int k7,
int k8, int k9, int k10) {
int* k = malloc(10 * sizeof(int));
k[0] = k1;
k[1] = k2;
k[2] = k3;
k[3] = k4;
k[4] = k5;
k[5] = k6;
k[6] = k7;
k[7] = k8;
k[8] = k9;
k[9] = k10;
return k;
}
int initializeGame(int numPlayers, int kingdomCards[10], int randomSeed,
struct gameState *state) {
int i;
int j;
int it;
//set up random number generator
SelectStream(1);
PutSeed((long)randomSeed);
//check number of players
if (numPlayers > MAX_PLAYERS || numPlayers < 2)
{
return -1;
}
//set number of players
state->numPlayers = numPlayers;
//check selected kingdom cards are different
for (i = 0; i < 10; i++)
{
for (j = 0; j < 10; j++)
{
if (j != i && kingdomCards[j] == kingdomCards[i])
{
return -1;
}
}
}
//initialize supply
///////////////////////////////
//set number of Curse cards
if (numPlayers == 2)
{
state->supplyCount[curse] = 10;
}
else if (numPlayers == 3)
{
state->supplyCount[curse] = 20;
}
else
{
state->supplyCount[curse] = 30;
}
//set number of Victory cards
if (numPlayers == 2)
{
state->supplyCount[estate] = 8;
state->supplyCount[duchy] = 8;
state->supplyCount[province] = 8;
}
else
{
state->supplyCount[estate] = 12;
state->supplyCount[duchy] = 12;
state->supplyCount[province] = 12;
}
//set number of Treasure cards
state->supplyCount[copper] = 60 - (7 * numPlayers);
state->supplyCount[silver] = 40;
state->supplyCount[gold] = 30;
//set number of Kingdom cards
for (i = adventurer; i <= treasure_map; i++) //loop all cards
{
for (j = 0; j < 10; j++) //loop chosen cards
{
if (kingdomCards[j] == i)
{
//check if card is a 'Victory' Kingdom card
if (kingdomCards[j] == great_hall || kingdomCards[j] == gardens)
{
if (numPlayers == 2){
state->supplyCount[i] = 8;
}
else{ state->supplyCount[i] = 12; }
}
else
{
state->supplyCount[i] = 10;
}
break;
}
else //card is not in the set choosen for the game
{
state->supplyCount[i] = -1;
}
}
}
////////////////////////
//supply intilization complete
//set player decks
for (i = 0; i < numPlayers; i++)
{
state->deckCount[i] = 0;
for (j = 0; j < 3; j++)
{
state->deck[i][j] = estate;
state->deckCount[i]++;
}
for (j = 3; j < 10; j++)
{
state->deck[i][j] = copper;
state->deckCount[i]++;
}
}
//shuffle player decks
for (i = 0; i < numPlayers; i++)
{
if ( shuffle(i, state) < 0 )
{
return -1;
}
}
//draw player hands
for (i = 0; i < numPlayers; i++)
{
//initialize hand size to zero
state->handCount[i] = 0;
state->discardCount[i] = 0;
//draw 5 cards
// for (j = 0; j < 5; j++)
// {
// drawCard(i, state);
// }
}
//set embargo tokens to 0 for all supply piles
for (i = 0; i <= treasure_map; i++)
{
state->embargoTokens[i] = 0;
}
//initialize first player's turn
state->outpostPlayed = 0;
state->phase = 0;
state->numActions = 1;
state->numBuys = 1;
state->playedCardCount = 0;
state->whoseTurn = 0;
state->handCount[state->whoseTurn] = 0;
//int it; move to top
//Moved draw cards to here, only drawing at the start of a turn
for (it = 0; it < 5; it++){
drawCard(state->whoseTurn, state);
}
updateCoins(state->whoseTurn, state, 0);
return 0;
}
int shuffle(int player, struct gameState *state) {
int newDeck[MAX_DECK];
int newDeckPos = 0;
int card;
int i;
if (state->deckCount[player] < 1)
return -1;
qsort ((void*)(state->deck[player]), state->deckCount[player], sizeof(int), compare);
/* SORT CARDS IN DECK TO ENSURE DETERMINISM! */
while (state->deckCount[player] > 0) {
card = floor(Random() * state->deckCount[player]);
newDeck[newDeckPos] = state->deck[player][card];
newDeckPos++;
for (i = card; i < state->deckCount[player]-1; i++) {
state->deck[player][i] = state->deck[player][i+1];
}
state->deckCount[player]--;
}
for (i = 0; i < newDeckPos; i++) {
state->deck[player][i] = newDeck[i];
state->deckCount[player]++;
}
return 0;
}
int playCard(int handPos, int choice1, int choice2, int choice3, struct gameState *state)
{
int card;
int coin_bonus = 0; //tracks coins gain from actions
//check if it is the right phase
if (state->phase != 0)
{
return -1;
}
//check if player has enough actions
if ( state->numActions < 1 )
{
return -1;
}
//get card played
card = handCard(handPos, state);
//check if selected card is an action
if ( card < adventurer || card > treasure_map )
{
return -1;
}
//play card
if ( cardEffect(card, choice1, choice2, choice3, state, handPos, &coin_bonus) < 0 )
{
return -1;
}
//reduce number of actions
state->numActions--;
//update coins (Treasure cards may be added with card draws)
updateCoins(state->whoseTurn, state, coin_bonus);
return 0;
}
int buyCard(int supplyPos, struct gameState *state) {
int who;
if (DEBUG){
printf("Entering buyCard... ");
}
// I don't know what to do about the phase thing.
who = state->whoseTurn;
if (state->numBuys < 1){
if (DEBUG)
printf("You do not have any buys left ");
return -1;
} else if (supplyCount(supplyPos, state) <1){
if (DEBUG)
printf("There are not any of that type of card left ");
return -1;
} else if (state->coins < getCost(supplyPos)){
if (DEBUG)
printf("You do not have enough money to buy that. You have %d coins. ", state->coins);
return -1;
} else {
state->phase=1;
//state->supplyCount[supplyPos]--;
gainCard(supplyPos, state, 0, who); //card goes in discard, this might be wrong.. (2 means goes into hand, 0 goes into discard)
state->coins = (state->coins) - (getCost(supplyPos));
state->numBuys--;
if (DEBUG)
printf("You bought card number %d for %d coins. You now have %d buys and %d coins. ", supplyPos, getCost(supplyPos), state->numBuys, state->coins);
}
//state->discard[who][state->discardCount[who]] = supplyPos;
//state->discardCount[who]++;
return 0;
}
int numHandCards(struct gameState *state) {
return state->handCount[ whoseTurn(state) ];
}
int handCard(int handPos, struct gameState *state) {
int currentPlayer = whoseTurn(state);
return state->hand[currentPlayer][handPos];
}
int supplyCount(int card, struct gameState *state) {
return state->supplyCount[card];
}
int fullDeckCount(int player, int card, struct gameState *state) {
int i;
int count = 0;
for (i = 0; i < state->deckCount[player]; i++)
{
if (state->deck[player][i] == card) count++;
}
for (i = 0; i < state->handCount[player]; i++)
{
if (state->hand[player][i] == card) count++;
}
for (i = 0; i < state->discardCount[player]; i++)
{
if (state->discard[player][i] == card) count++;
}
return count;
}
int whoseTurn(struct gameState *state) {
return state->whoseTurn;
}
int endTurn(struct gameState *state) {
int k;
int i;
int currentPlayer = whoseTurn(state);
//Discard hand
for (i = 0; i < state->handCount[currentPlayer]; i++){
state->discard[currentPlayer][state->discardCount[currentPlayer]++] = state->hand[currentPlayer][i];//Discard
state->hand[currentPlayer][i] = -1;//Set card to -1
}
state->handCount[currentPlayer] = 0;//Reset hand count
//Code for determining the player
if (currentPlayer < (state->numPlayers - 1)){
state->whoseTurn = currentPlayer + 1;//Still safe to increment
}
else{
state->whoseTurn = 0;//Max player has been reached, loop back around to player 1
}
state->outpostPlayed = 0;
state->phase = 0;
state->numActions = 1;
state->coins = 0;
state->numBuys = 1;
state->playedCardCount = 0;
state->handCount[state->whoseTurn] = 0;
//int k; move to top
//Next player draws hand
for (k = 0; k < 5; k++){
drawCard(state->whoseTurn, state);//Draw a card
}
//Update money
updateCoins(state->whoseTurn, state , 0);
return 0;
}
int isGameOver(struct gameState *state) {
int i;
int j;
//if stack of Province cards is empty, the game ends
if (state->supplyCount[province] == 0)
{
return 1;
}
//if three supply pile are at 0, the game ends
j = 0;
for (i = 0; i < 25; i++)
{
if (state->supplyCount[i] == 0)
{
j++;
}
}
if ( j >= 3)
{
return 1;
}
return 0;
}
int scoreFor (int player, struct gameState *state) {
int i;
int score = 0;
//score from hand
for (i = 0; i < state->handCount[player]; i++)
{
if (state->hand[player][i] == curse) { score = score - 1; };
if (state->hand[player][i] == estate) { score = score + 1; };
if (state->hand[player][i] == duchy) { score = score + 3; };
if (state->hand[player][i] == province) { score = score + 6; };
if (state->hand[player][i] == great_hall) { score = score + 1; };
if (state->hand[player][i] == gardens) { score = score + ( fullDeckCount(player, 0, state) / 10 ); };
}
//score from discard
for (i = 0; i < state->discardCount[player]; i++)
{
if (state->discard[player][i] == curse) { score = score - 1; };
if (state->discard[player][i] == estate) { score = score + 1; };
if (state->discard[player][i] == duchy) { score = score + 3; };
if (state->discard[player][i] == province) { score = score + 6; };
if (state->discard[player][i] == great_hall) { score = score + 1; };
if (state->discard[player][i] == gardens) { score = score + ( fullDeckCount(player, 0, state) / 10 ); };
}
//score from deck
for (i = 0; i < state->discardCount[player]; i++)
{
if (state->deck[player][i] == curse) { score = score - 1; };
if (state->deck[player][i] == estate) { score = score + 1; };
if (state->deck[player][i] == duchy) { score = score + 3; };
if (state->deck[player][i] == province) { score = score + 6; };
if (state->deck[player][i] == great_hall) { score = score + 1; };
if (state->deck[player][i] == gardens) { score = score + ( fullDeckCount(player, 0, state) / 10 ); };
}
return score;
}
int getWinners(int players[MAX_PLAYERS], struct gameState *state) {
int i;
int j;
int highScore;
int currentPlayer;
//get score for each player
for (i = 0; i < MAX_PLAYERS; i++)
{
//set unused player scores to -9999
if (i >= state->numPlayers)
{
players[i] = -9999;
}
else
{
players[i] = scoreFor (i, state);
}
}
//find highest score
j = 0;
for (i = 0; i < MAX_PLAYERS; i++)
{
if (players[i] > players[j])
{
j = i;
}
}
highScore = players[j];
//add 1 to players who had less turns
currentPlayer = whoseTurn(state);
for (i = 0; i < MAX_PLAYERS; i++)
{
if ( players[i] == highScore && i > currentPlayer )
{
players[i]++;
}
}
//find new highest score
j = 0;
for (i = 0; i < MAX_PLAYERS; i++)
{
if ( players[i] > players[j] )
{
j = i;
}
}
highScore = players[j];
//set winners in array to 1 and rest to 0
for (i = 0; i < MAX_PLAYERS; i++)
{
if ( players[i] == highScore )
{
players[i] = 1;
}
else
{
players[i] = 0;
}
}
return 0;
}
int drawCard(int player, struct gameState *state)
{ int count;
int deckCounter;
if (state->deckCount[player] <= 0){//Deck is empty
//Step 1 Shuffle the discard pile back into a deck
int i;
//Move discard to deck
for (i = 0; i < state->discardCount[player];i++){
state->deck[player][i] = state->discard[player][i];
state->discard[player][i] = -1;
}
state->deckCount[player] = state->discardCount[player];
state->discardCount[player] = 0;//Reset discard
//Shufffle the deck
shuffle(player, state);//Shuffle the deck up and make it so that we can draw
if (DEBUG){//Debug statements
printf("Deck count now: %d ", state->deckCount[player]);
}
state->discardCount[player] = 0;
//Step 2 Draw Card
count = state->handCount[player];//Get current player's hand count
if (DEBUG){//Debug statements
printf("Current hand count: %d ", count);
}
deckCounter = state->deckCount[player];//Create a holder for the deck count
if (deckCounter == 0)
return -1;
state->hand[player][count] = state->deck[player][deckCounter - 1];//Add card to hand
state->deckCount[player]--;
state->handCount[player]++;//Increment hand count
}
else{
int count = state->handCount[player];//Get current hand count for player
int deckCounter;
if (DEBUG){//Debug statements
printf("Current hand count: %d ", count);
}
deckCounter = state->deckCount[player];//Create holder for the deck count
state->hand[player][count] = state->deck[player][deckCounter - 1];//Add card to the hand
state->deckCount[player]--;
state->handCount[player]++;//Increment hand count
}
return 0;
}
int getCost(int cardNumber)
{
switch( cardNumber )
{
case curse:
return 0;
case estate:
return 2;
case duchy:
return 5;
case province:
return 8;
case copper:
return 0;
case silver:
return 3;
case gold:
return 6;
case adventurer:
return 6;
case council_room:
return 5;
case feast:
return 4;
case gardens:
return 4;
case mine:
return 5;
case remodel:
return 4;
case smithy:
return 4;
case village:
return 3;
case baron:
return 4;
case great_hall:
return 3;
case minion:
return 5;
case steward:
return 3;
case tribute:
return 5;
case ambassador:
return 3;
case cutpurse:
return 4;
case embargo:
return 2;
case outpost:
return 5;
case salvager:
return 4;
case sea_hag:
return 4;
case treasure_map:
return 4;
}
return -1;
}
int cardEffect(int card, int choice1, int choice2, int choice3, struct gameState *state, int handPos, int *bonus)
{
int i;
int j;
int k;
int x;
int index;
int currentPlayer = whoseTurn(state);
int nextPlayer = currentPlayer + 1;
int tributeRevealedCards[2] = {-1, -1};
int temphand[MAX_HAND];// moved above the if statement
int drawntreasure=0;
int cardDrawn;
int z = 0;// this is the counter for the temp hand
if (nextPlayer > (state->numPlayers - 1)){
nextPlayer = 0;
}
//uses switch to select card and perform actions
switch( card )
{
case adventurer:
while(drawntreasure<2){
if (state->deckCount[currentPlayer] <1){//if the deck is empty we need to shuffle discard and add to deck
shuffle(currentPlayer, state);
}
drawCard(currentPlayer, state);
cardDrawn = state->hand[currentPlayer][state->handCount[currentPlayer]-1];//top card of hand is most recently drawn card.
if (cardDrawn == copper || cardDrawn == silver || cardDrawn == gold)
drawntreasure++;
else{
temphand[z]=cardDrawn;
state->handCount[currentPlayer]--; //this should just remove the top card (the most recently drawn one).
z++;
}
}
while(z-1>=0){
state->discard[currentPlayer][state->discardCount[currentPlayer]++]=temphand[z-1]; // discard all cards in play that have been drawn
z=z-1;
}
return 0;
case council_room:
//+4 Cards
for (i = 0; i < 4; i++)
{
drawCard(currentPlayer, state);
}
//+1 Buy
state->numBuys++;
//Each other player draws a card
for (i = 0; i < state->numPlayers; i++)
{
if ( i != currentPlayer )
{
drawCard(i, state);
}
}
//put played card in played card pile
discardCard(handPos, currentPlayer, state, 0);
return 0;
case feast:
//gain card with cost up to 5
//Backup hand
for (i = 0; i <= state->handCount[currentPlayer]; i++){
temphand[i] = state->hand[currentPlayer][i];//Backup card
state->hand[currentPlayer][i] = -1;//Set to nothing
}
//Backup hand
//Update Coins for Buy
updateCoins(currentPlayer, state, 5);
x = 1;//Condition to loop on
while( x == 1) {//Buy one card
if (supplyCount(choice1, state) <= 0){
if (DEBUG)
printf("None of that card left, sorry! ");
if (DEBUG){
printf("Cards Left: %d ", supplyCount(choice1, state));
}
}
else if (state->coins < getCost(choice1)){
printf("That card is too expensive! ");
if (DEBUG){
printf("Coins: %d < %d ", state->coins, getCost(choice1));
}
}
else{
if (DEBUG){
printf("Deck Count: %d ", state->handCount[currentPlayer] + state->deckCount[currentPlayer] + state->discardCount[currentPlayer]);
}
gainCard(choice1, state, 0, currentPlayer);//Gain the card
x = 0;//No more buying cards
if (DEBUG){
printf("Deck Count: %d ", state->handCount[currentPlayer] + state->deckCount[currentPlayer] + state->discardCount[currentPlayer]);
}
}
}
//Reset Hand
for (i = 0; i <= state->handCount[currentPlayer]; i++){
state->hand[currentPlayer][i] = temphand[i];
temphand[i] = -1;
}
//Reset Hand
return 0;
case gardens:
return -1;
case mine:
j = state->hand[currentPlayer][choice1]; //store card we will trash
if (state->hand[currentPlayer][choice1] < copper || state->hand[currentPlayer][choice1] > gold)
{
return -1;
}
if (choice2 > treasure_map || choice2 < curse)
{
return -1;
}
if ( (getCost(state->hand[currentPlayer][choice1]) + 3) > getCost(choice2) )
{
return -1;
}
gainCard(choice2, state, 2, currentPlayer);
//discard card from hand
discardCard(handPos, currentPlayer, state, 0);
//discard trashed card
for (i = 0; i < state->handCount[currentPlayer]; i++)
{
if (state->hand[currentPlayer][i] == j)
{
discardCard(i, currentPlayer, state, 0);
break;
}
}
return 0;
case remodel:
j = state->hand[currentPlayer][choice1]; //store card we will trash
if ( (getCost(state->hand[currentPlayer][choice1]) + 2) > getCost(choice2) )
{
return -1;
}
gainCard(choice2, state, 0, currentPlayer);
//discard card from hand
discardCard(handPos, currentPlayer, state, 0);
//discard trashed card
for (i = 0; i < state->handCount[currentPlayer]; i++)
{
if (state->hand[currentPlayer][i] == j)
{
discardCard(i, currentPlayer, state, 0);
break;
}
}
return 0;
case smithy:
//+3 Cards
for (i = 0; i < 3; i++)
{
drawCard(currentPlayer, state);
}
//discard card from hand
discardCard(handPos, currentPlayer, state, 0);
return 0;
case village:
//+1 Card
drawCard(currentPlayer, state);
//+2 Actions
state->numActions = state->numActions + 2;
//discard played card from hand
discardCard(handPos, currentPlayer, state, 0);
return 0;
case baron:
state->numBuys++;//Increase buys by 1!
if (choice1 > 0){//Boolean true or going to discard an estate
int p = 0;//Iterator for hand!
int card_not_discarded = 1;//Flag for discard set!
while(card_not_discarded){
if (state->hand[currentPlayer][p] == estate){//Found an estate card!
state->coins += 4;//Add 4 coins to the amount of coins
state->discard[currentPlayer][state->discardCount[currentPlayer]] = state->hand[currentPlayer][p];
state->discardCount[currentPlayer]++;
for (;p < state->handCount[currentPlayer]; p++){
state->hand[currentPlayer][p] = state->hand[currentPlayer][p+1];
}
state->hand[currentPlayer][state->handCount[currentPlayer]] = -1;
state->handCount[currentPlayer]--;
card_not_discarded = 0;//Exit the loop
}
else if (p > state->handCount[currentPlayer]){
if(DEBUG) {
printf("No estate cards in your hand, invalid choice ");
printf("Must gain an estate if there are any ");
}
if (supplyCount(estate, state) > 0){
gainCard(estate, state, 0, currentPlayer);
state->supplyCount[estate]--;//Decrement estates
if (supplyCount(estate, state) == 0){
isGameOver(state);
}
}
card_not_discarded = 0;//Exit the loop
}
else{
p++;//Next card
}
}
}
else{
if (supplyCount(estate, state) > 0){
gainCard(estate, state, 0, currentPlayer);//Gain an estate
state->supplyCount[estate]--;//Decrement Estates
if (supplyCount(estate, state) == 0){
isGameOver(state);
}
}
}
return 0;
case great_hall:
//+1 Card
drawCard(currentPlayer, state);
//+1 Actions
state->numActions++;
//discard card from hand
discardCard(handPos, currentPlayer, state, 0);
return 0;
case minion:
//+1 action
state->numActions++;
//discard card from hand
discardCard(handPos, currentPlayer, state, 0);
if (choice1) //+2 coins
{
state->coins = state->coins + 2;
}
else if (choice2) //discard hand, redraw 4, other players with 5+ cards discard hand and draw 4
{
//discard hand
while(numHandCards(state) > 0)
{
discardCard(handPos, currentPlayer, state, 0);
}
//draw 4
for (i = 0; i < 4; i++)
{
drawCard(currentPlayer, state);
}
//other players discard hand and redraw if hand size > 4
for (i = 0; i < state->numPlayers; i++)
{
if (i != currentPlayer)
{
if ( state->handCount[i] > 4 )
{
//discard hand
while( state->handCount[i] > 0 )
{
discardCard(handPos, i, state, 0);
}
//draw 4
for (j = 0; j < 4; j++)
{
drawCard(i, state);
}
}
}
}
}
return 0;
case steward:
if (choice1 == 1)
{
//+2 cards
drawCard(currentPlayer, state);
drawCard(currentPlayer, state);
}
else if (choice1 == 2)
{
//+2 coins
state->coins = state->coins + 2;
}
else
{
//trash 2 cards in hand
discardCard(choice2, currentPlayer, state, 1);
discardCard(choice3, currentPlayer, state, 1);
}
//discard card from hand
discardCard(handPos, currentPlayer, state, 0);
return 0;
case tribute:
if ((state->discardCount[nextPlayer] + state->deckCount[nextPlayer]) <= 1){
if (state->deckCount[nextPlayer] > 0){
tributeRevealedCards[0] = state->deck[nextPlayer][state->deckCount[nextPlayer]-1];
state->deckCount[nextPlayer]--;
}
else if (state->discardCount[nextPlayer] > 0){
tributeRevealedCards[0] = state->discard[nextPlayer][state->discardCount[nextPlayer]-1];
state->discardCount[nextPlayer]--;
}
else{
//No Card to Reveal
if (DEBUG){
printf("No cards to reveal ");
}
}
}
else{
if (state->deckCount[nextPlayer] == 0){
for (i = 0; i < state->discardCount[nextPlayer]; i++){
state->deck[nextPlayer][i] = state->discard[nextPlayer][i];//Move to deck
state->deckCount[nextPlayer]++;
state->discard[nextPlayer][i] = -1;
state->discardCount[nextPlayer]--;
}
shuffle(nextPlayer,state);//Shuffle the deck
}
tributeRevealedCards[0] = state->deck[nextPlayer][state->deckCount[nextPlayer]-1];
state->deck[nextPlayer][state->deckCount[nextPlayer]--] = -1;
state->deckCount[nextPlayer]--;
tributeRevealedCards[1] = state->deck[nextPlayer][state->deckCount[nextPlayer]-1];
state->deck[nextPlayer][state->deckCount[nextPlayer]--] = -1;
state->deckCount[nextPlayer]--;
}
if (tributeRevealedCards[0] == tributeRevealedCards[1]){//If we have a duplicate card, just drop one
state->playedCards[state->playedCardCount] = tributeRevealedCards[1];
state->playedCardCount++;
tributeRevealedCards[1] = -1;
}
for (i = 0; i <= 2; i ++){
if (tributeRevealedCards[i] == copper || tributeRevealedCards[i] == silver || tributeRevealedCards[i] == gold){//Treasure cards
state->coins += 2;
}
else if (tributeRevealedCards[i] == estate || tributeRevealedCards[i] == duchy || tributeRevealedCards[i] == province || tributeRevealedCards[i] == gardens || tributeRevealedCards[i] == great_hall){//Victory Card Found
drawCard(currentPlayer, state);
drawCard(currentPlayer, state);
}
else{//Action Card
state->numActions = state->numActions + 2;
}
}
return 0;
case ambassador:
j = 0; //used to check if player has enough cards to discard
if (choice2 > 2 || choice2 < 0)
{
return -1;
}
if (choice1 == handPos)
{
return -1;
}
for (i = 0; i < state->handCount[currentPlayer]; i++)
{
if (i != handPos && i == state->hand[currentPlayer][choice1] && i != choice1)
{
j++;
}
}
if (j < choice2)
{
return -1;
}
if (DEBUG)
printf("Player %d reveals card number: %d ", currentPlayer, state->hand[currentPlayer][choice1]);
//increase supply count for choosen card by amount being discarded
state->supplyCount[state->hand[currentPlayer][choice1]] += choice2;
//each other player gains a copy of revealed card
for (i = 0; i < state->numPlayers; i++)
{
if (i != currentPlayer)
{
gainCard(state->hand[currentPlayer][choice1], state, 0, i);
}
}
//discard played card from hand
discardCard(handPos, currentPlayer, state, 0);
//trash copies of cards returned to supply
for (j = 0; j < choice2; j++)
{
for (i = 0; i < state->handCount[currentPlayer]; i++)
{
if (state->hand[currentPlayer][i] == state->hand[currentPlayer][choice1])
{
discardCard(i, currentPlayer, state, 1);
break;
}
}
}
return 0;
case cutpurse:
updateCoins(currentPlayer, state, 2);
for (i = 0; i < state->numPlayers; i++)
{
if (i != currentPlayer)
{
for (j = 0; j < state->handCount[i]; j++)
{
if (state->hand[i][j] == copper)
{
discardCard(j, i, state, 0);
break;
}
if (j == state->handCount[i])
{
for (k = 0; k < state->handCount[i]; k++)
{
if (DEBUG)
printf("Player %d reveals card number %d ", i, state->hand[i][k]);
}
break;
}
}
}
}
//discard played card from hand
discardCard(handPos, currentPlayer, state, 0);
return 0;
case embargo:
//+2 Coins
state->coins = state->coins + 2;
//see if selected pile is in play
if ( state->supplyCount[choice1] == -1 )
{
return -1;
}
//add embargo token to selected supply pile
state->embargoTokens[choice1]++;
//trash card
discardCard(handPos, currentPlayer, state, 1);
return 0;
case outpost:
//set outpost flag
state->outpostPlayed++;
//discard card
discardCard(handPos, currentPlayer, state, 0);
return 0;
case salvager:
//+1 buy
state->numBuys++;
if (choice1)
{
//gain coins equal to trashed card
state->coins = state->coins + getCost( handCard(choice1, state) );
//trash card
discardCard(choice1, currentPlayer, state, 1);
}
//discard card
discardCard(handPos, currentPlayer, state, 0);
return 0;
case sea_hag:
for (i = 0; i < state->numPlayers; i++){
if (i != currentPlayer){
state->discard[i][state->discardCount[i]] = state->deck[i][state->deckCount[i]--]; state->deckCount[i]--;
state->discardCount[i]++;
state->deck[i][state->deckCount[i]--] = curse;//Top card now a curse
}
}
return 0;
case treasure_map:
//search hand for another treasure_map
index = -1;
for (i = 0; i < state->handCount[currentPlayer]; i++)
{
if (state->hand[currentPlayer][i] == treasure_map && i != handPos)
{
index = i;
break;
}
}
if (index > -1)
{
//trash both treasure cards
discardCard(handPos, currentPlayer, state, 1);
discardCard(index, currentPlayer, state, 1);
//gain 4 Gold cards
for (i = 0; i < 4; i++)
{
gainCard(gold, state, 1, currentPlayer);
}
//return success
return 1;
}
//no second treasure_map found in hand
return -1;
}
return -1;
}
int discardCard(int handPos, int currentPlayer, struct gameState *state, int trashFlag)
{
//if card is not trashed, added to Played pile
if (trashFlag < 1)
{
//add card to played pile
state->playedCards[state->playedCardCount] = state->hand[currentPlayer][handPos];
state->playedCardCount++;
}
//set played card to -1
state->hand[currentPlayer][handPos] = -1;
//remove card from player's hand
if ( handPos == (state->handCount[currentPlayer] - 1) ) //last card in hand array is played
{
//reduce number of cards in hand
state->handCount[currentPlayer]--;
}
else if ( state->handCount[currentPlayer] == 1 ) //only one card in hand
{
//reduce number of cards in hand
state->handCount[currentPlayer]--;
}
else
{
//replace discarded card with last card in hand
state->hand[currentPlayer][handPos] = state->hand[currentPlayer][ (state->handCount[currentPlayer] - 1)];
//set last card to -1
state->hand[currentPlayer][state->handCount[currentPlayer] - 1] = -1;
//reduce number of cards in hand
state->handCount[currentPlayer]--;
}
return 0;
}
int gainCard(int supplyPos, struct gameState *state, int toFlag, int player)
{
//Note: supplyPos is enum of choosen card
//check if supply pile is empty (0) or card is not used in game (-1)
if ( supplyCount(supplyPos, state) < 1 )
{
return -1;
}
//added card for [whoseTurn] current player:
// toFlag = 0 : add to discard
// toFlag = 1 : add to deck
// toFlag = 2 : add to hand
if (toFlag == 1)
{
state->deck[ player ][ state->deckCount[player] ] = supplyPos;
state->deckCount[player]++;
}
else if (toFlag == 2)
{
state->hand[ player ][ state->handCount[player] ] = supplyPos;
state->handCount[player]++;
}
else
{
state->discard[player][ state->discardCount[player] ] = supplyPos;
state->discardCount[player]++;
}
//decrease number in supply pile
state->supplyCount[supplyPos]--;
return 0;
}
int updateCoins(int player, struct gameState *state, int bonus)
{
int i;
//reset coin count
state->coins = 0;
//add coins for each Treasure card in player's hand
for (i = 0; i < state->handCount[player]; i++)
{
if (state->hand[player][i] == copper)
{
state->coins += 1;
}
else if (state->hand[player][i] == silver)
{
state->coins += 2;
}
else if (state->hand[player][i] == gold)
{
state->coins += 3;
}
}
//add bonus
state->coins += bonus;
return 0;
}
//end of dominion.c
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.