void testDeckShuffle(struct gameState* G){ int deckCount; int player= G->whoseTurn; int empty_deck[MAX_DECK]; int i; for (i = 0; i < MAX_DECK; i++) { empty_deck[i]=""; } int j; G->discardCount[player]=G->deckCount[player]; for(j=0;j<G->discardCount[player]; j++){ G->discard[player][j]= j; } printf("Test 1) Testing when deck is empty, discard pile is shuffled, then added to deck\npreconditions: deck is empty, discard is full of unique cards (to check shuffle)\npostconditions: deck has cards\n"); deckCount=G->deckCount[player]; //deck count stored G->deckCount[player]=0; // deck count in state set to zero G->hand[player][0]=7; // adventurer card put in player's hand at pos zero memcpy(G->deck[player], empty_deck, sizeof(int) * deckCount); // player's deck is emptied printf("\n(before function call, to compare with deck cards post function call)\n"); printDiscard(player,G); printf("\n(deckCount before calling play_adventurer: %d)\n",G->deckCount[player]); printf("results: \n"); play_adventurer(player,G,0); //takes player, game ptr, and hand position of adventurer card printf("(deck count after calling play_adventurer)\n - Expected: at least 1 Actual: %d\n\n", G->deckCount[player]); printf("(Visual check to see that new cards in deck are shuffled)\n"); printDeck(player,G); }
int main() { int newCards = 2; int discarded = 0; // no discard in play_adventurer card int xtraCoins = 0; int newTreas1, newTreas2; int G_totalcount, testG_totalcount; int pass_count=0, fail_count=0; int tcc_hand, tcc_deck, tcc_discard, tcc_total; //tcc = treasure card count int i, r; int temphand[MAX_HAND];// moved above the if statement int drawntreasure=0; int cardDrawn=0; int seed = 1000; int numPlayers = 2; int thisPlayer = 0; struct gameState G, testG; int NUMCARDS = 27; int NUMCARDS_IN_PLAY = 17; int TOT_KCARDS = 20; int KCARD_FIRSTINDEX = adventurer; int MAX_KCARDS = 10; int MIN_STARTING_CARDS = 2; int MAX_STARTING_CARDS = 15; int k[MAX_KCARDS]; // array storing 10 cards to use in a single game int NUMTREASURECARDS = 3; int TREASURE_FIRSTINDEX = copper; // list of cards char* card[] = {"curse", "estate", "duchy", "province", "copper", "silver", "gold", "adventurer", "council_room", "feast", "gardens", "mine", "remodel", "smithy", "village", "baron", "great_hall", "minion", "steward", "tribute", "ambassador", "cutpurse", "embargo", "outpost", "salvager", "sea_hag", "treasure_map"}; // declare random test variables int rand_kcard[MAX_KCARDS]; // adventurer and 9 other randomly selected kingdom cards int rand_numhandcards; // starting number of cards in hand from 2 to 10 int rand_numdeckcards; // starting number of cards in deck from 2 to 10 int rand_numdiscards; // starting number of cards in discard from 2 to 10 int rand_thiscard; // 1 of 17 cardtypes in play (1 curse, 3 victory 3 treasure, 10 kingdom) int rand_isTreasure; // boolean determining whether a card is a Treasure card int cardtype[NUMCARDS]; // counts of each card type in deck and discard (potential discards) int kcardcount = 0; // count of numnber of kcards types established int repeat_flag; // true if repeat was found printf("\t----------------- Random Testing Card: %s ----------------\n", TESTCARD); printf("\t***BUG FOUND: play_adventurer does not discard original adventurer card -- disregarding discard***\n"); printf("\t***BUG FOUND: play_adventurer does not update coins -- disregarding coin update***\n"); printf("\t >> Initial tests perform as expected; continue only exception reporting <<\n"); for (i=0; i<NUMCARDS; i++) { cardtype[i] = 0; } for (r=0; r<NUM_RUNS; r++) { kcardcount = 0; tcc_hand=0; tcc_deck=0; tcc_discard=0; tcc_total=0; // establish parameters of a single test case // establish 10 kingdom cards to use for this game rand_kcard[0] = adventurer; kcardcount++; while (kcardcount < MAX_KCARDS) { repeat_flag = FALSE; rand_kcard[kcardcount] = (rand() % TOT_KCARDS) + KCARD_FIRSTINDEX; for (i=0; i<kcardcount; i++) { if (rand_kcard[kcardcount] == rand_kcard[i]) repeat_flag = TRUE; } if (!repeat_flag) kcardcount++; } for (i=0; i<MAX_KCARDS; i++) k[i] = rand_kcard[i]; //for (i=0; i<MAX_KCARDS; i++) printf("\trand_kcard[%d] = %s\n", i, card[k[i]]); printf("\n"); //for (i=0; i<MAX_KCARDS; i++) printf("\trand_kcard[%d] = %s\n", i, card[rand_kcard[i]]); printf("\n"); // initialize a game state and player cards initializeGame(numPlayers, k, seed, &G); // establish number of cards in hand from 2 to 10 rand_numhandcards = (rand() % (MAX_STARTING_CARDS - MIN_STARTING_CARDS + 1)) + MIN_STARTING_CARDS; //printf("\tstarting cards in hand: %d\n", rand_numhandcards); G.handCount[thisPlayer] = rand_numhandcards; G.hand[thisPlayer][0] = adventurer; // establish number of cards in deck from 2 to 10 rand_numdeckcards = (rand() % (MAX_STARTING_CARDS - MIN_STARTING_CARDS + 1)) + MIN_STARTING_CARDS; //printf("\tstarting cards in deck: %d\n", rand_numdeckcards); G.deckCount[thisPlayer] = rand_numdeckcards; // establish number of cards in discard from 2 to 10 rand_numdiscards = (rand() % (MAX_STARTING_CARDS - MIN_STARTING_CARDS + 1)) + MIN_STARTING_CARDS; //printf("\tstarting cards in discard: %d\n", rand_numdiscards); G.discardCount[thisPlayer] = rand_numdiscards; // establish each card // cards in hand G.hand[thisPlayer][0] = adventurer; for (i=1; i<rand_numhandcards; i++) { rand_isTreasure = rand() % 2; if (rand_isTreasure) { G.hand[thisPlayer][i] = (rand() % NUMTREASURECARDS) + TREASURE_FIRSTINDEX; tcc_hand++; } else { rand_thiscard = rand() % (NUMCARDS_IN_PLAY - NUMTREASURECARDS); if (rand_thiscard < TREASURE_FIRSTINDEX) G.hand[thisPlayer][i] = rand_thiscard; else { G.hand[thisPlayer][i] = k[rand_thiscard - TREASURE_FIRSTINDEX]; } } } //for (i=0; i<rand_numhandcards; i++) printf("\t\thandcard[%d] = %s\n", i, card[G.hand[thisPlayer][i]]); // cards in deck for (i=0; i<rand_numdeckcards; i++) { rand_isTreasure = rand() % 2; if (rand_isTreasure) { G.deck[thisPlayer][i] = (rand() % NUMTREASURECARDS) + TREASURE_FIRSTINDEX; tcc_deck++; } else { rand_thiscard = rand() % (NUMCARDS_IN_PLAY - NUMTREASURECARDS); if (rand_thiscard < TREASURE_FIRSTINDEX) G.deck[thisPlayer][i] = rand_thiscard; else G.deck[thisPlayer][i] = k[rand_thiscard - TREASURE_FIRSTINDEX]; } } for (i=0; i<rand_numdeckcards; i++) cardtype[G.deck[thisPlayer][i]]++; //for (i=0; i<rand_numdeckcards; i++) printf("\t\tdeckcard[%d] = %s\n", i, card[G.deck[thisPlayer][i]]); // cards in discard for (i=0; i<rand_numdiscards; i++) { rand_isTreasure = rand() % 2; if (rand_isTreasure) { G.discard[thisPlayer][i] = (rand() % NUMTREASURECARDS) + TREASURE_FIRSTINDEX; tcc_discard++; } else { rand_thiscard = rand() % (NUMCARDS_IN_PLAY - NUMTREASURECARDS); if (rand_thiscard < TREASURE_FIRSTINDEX) G.discard[thisPlayer][i] = rand_thiscard; else G.discard[thisPlayer][i] = k[rand_thiscard - TREASURE_FIRSTINDEX]; } } for (i=0; i<rand_numdiscards; i++) cardtype[G.discard[thisPlayer][i]]++; //for (i=0; i<rand_numdiscards; i++) printf("\t\tdiscard[%d] = %s\n", i, card[G.deck[thisPlayer][i]]); tcc_total = tcc_hand + tcc_deck + tcc_discard; // -------- TEST: execute a single test case --------------- // copy the game state to a test case memcpy(&testG, &G, sizeof(struct gameState)); play_adventurer(thisPlayer, drawntreasure, cardDrawn, temphand, &testG); G_totalcount = G.handCount[thisPlayer] + G.deckCount[thisPlayer] + G.discardCount[thisPlayer]; testG_totalcount = testG.handCount[thisPlayer] + testG.deckCount[thisPlayer] + testG.discardCount[thisPlayer]; newTreas1 = testG.hand[thisPlayer][testG.handCount[thisPlayer]-1]; newTreas2 = testG.hand[thisPlayer][testG.handCount[thisPlayer]-2]; discarded = 0; // modifying because BUG FOUND - play adventurer does not discard orig adventurer xtraCoins = 0; // modifying because BUG FOUND - play_adventurer does not update coins. newCards = (tcc_deck + tcc_discard >= 2)? 2: tcc_deck + tcc_discard; // lower of 2 or #Treasures in deck+discard if (testG.handCount[thisPlayer] != G.handCount[thisPlayer] + newCards - discarded) { fail_count++; printf("\n\tTEST %d: orig {handcount, deckcount, discardcount, total} = {%d, %d, %d, %d}\n", r, G.handCount[thisPlayer], G.deckCount[thisPlayer], G.discardCount[thisPlayer], G_totalcount); printf("\tnew {handcount, deckcount, discardcount, total} = {%d, %d, %d, %d}\n", testG.handCount[thisPlayer], testG.deckCount[thisPlayer], testG.discardCount[thisPlayer], testG_totalcount); printf("\torig treasure card count {handcount, deckcount, discardcount, total} = {%d, %d, %d, %d}\n", tcc_hand, tcc_deck, tcc_discard, tcc_total); printf("\thand count = %d, expected = %d\n", testG.handCount[thisPlayer], G.handCount[thisPlayer] + newCards - discarded); printf("\torig last 2 card: %s, %s\n", card[G.hand[thisPlayer][G.handCount[thisPlayer]-1]], card[G.hand[thisPlayer][G.handCount[thisPlayer]-2]]); printf("\tnew last 2 cards: %s, %s\n", card[newTreas1], card[newTreas2]); printf("\tCoin before: %d, Coin after: %d\n", G.coins, testG.coins); //printf("\t\tdeck count = %d, expected = %d\n", testG.deckCount[thisPlayer], G.deckCount[thisPlayer] - newCards + shuffledCards); //printf("\t\tcoins = %d, expected = %d\n\n", testG.coins, G.coins + xtraCoins); //assert(testG.handCount[thisPlayer] == G.handCount[thisPlayer] + newCards - discarded); //assert(testG.deckCount[thisPlayer] == G.deckCount[thisPlayer] - newCards + shuffledCards); //assert(testG.coins == G.coins + xtraCoins); } else pass_count++; } // output the counts of initialized deck and discard cards printf("\n\tNumber of test cases: %d. PASS=%d FAIL=%d\n\n", NUM_RUNS, pass_count, fail_count); for (i=0; i<NUMCARDS; i++) printf("\tcard %-15s==> # times in either deck or discard count: %d\n", card[i], cardtype[i]); return 0; }
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: play_adventurer(¤tPlayer, state, &cardDrawn, drawntreasure, &z, temphand); 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!\n"); if (DEBUG){ printf("Cards Left: %d\n", supplyCount(choice1, state)); } } else if (state->coins < getCost(choice1)){ printf("That card is too expensive!\n"); if (DEBUG){ printf("Coins: %d < %d\n", state->coins, getCost(choice1)); } } else{ if (DEBUG){ printf("Deck Count: %d\n", 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\n", 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: play_smithy(¤tPlayer, state, &handPos); return 0; case village: play_village(¤tPlayer, state, &handPos); 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\n"); printf("Must gain an estate if there are any\n"); } 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: play_great_hall(¤tPlayer, state, &handPos); 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\n"); } } } 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\n", 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\n", 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: play_sea_hag(state, ¤tPlayer); 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; }