Question
I need some help. We are working on code that will simulate the card game Dominion. I have provided the relevant code I believe. Please
I 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
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started