mirror of
https://github.com/caperren/school_archives.git
synced 2025-11-09 21:51:15 +00:00
1432 lines
34 KiB
C
1432 lines
34 KiB
C
#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...\n");
|
|
}
|
|
|
|
// 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\n");
|
|
return -1;
|
|
}
|
|
else if (supplyCount(supplyPos, state) <1)
|
|
{
|
|
if (DEBUG)
|
|
printf("There are not any of that type of card left\n");
|
|
return -1;
|
|
}
|
|
else if (state->coins < getCost(supplyPos))
|
|
{
|
|
if (DEBUG)
|
|
printf("You do not have enough money to buy that. You have %d coins.\n", 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.\n", 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\n", 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\n", 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\n", 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;
|
|
}
|
|
|
|
//NOTE: THIS VERSION HAS ADDED BUGS IN THE 4 FUNCTIONS BELOW
|
|
int playAdventurer(int drawntreasure, struct gameState *state, int currentPlayer, int temphand[MAX_HAND], int z)
|
|
{
|
|
//Reveal cards from your deck until you reveal 2 Treasure cards.
|
|
//Put those Treasure cards into your hand and discard the other revealed cards.
|
|
int cardDrawn;
|
|
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;
|
|
}
|
|
|
|
int playSmithy(struct gameState *state, int handPos, int currentPlayer)
|
|
{
|
|
//+3 Cards
|
|
int i;
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
drawCard(currentPlayer, state);
|
|
}
|
|
|
|
//discard card from hand
|
|
discardCard(handPos, currentPlayer, state, 0);
|
|
return 0;
|
|
}
|
|
|
|
int playVillage(int currentPlayer, struct gameState *state, int handPos)
|
|
{
|
|
//+1 Card and +2 Actions
|
|
//+1 Card
|
|
drawCard(currentPlayer, state);
|
|
|
|
//+2 Actions
|
|
state->numActions = state->numActions + 2;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int playMine(struct gameState *state, int currentPlayer, int choice1, int choice2, int handPos)
|
|
{
|
|
//You may trash a Treasure from your hand. Gain a Treasure to your hand costing
|
|
//up to 3 coins more than it.
|
|
//Usage: play 5 0 3
|
|
//Where 5 is the mine card in hand, 0 is copper card in had, and 3 is silver card
|
|
//in the supply
|
|
|
|
int j = state->hand[currentPlayer][choice1]; //store card we will trash
|
|
int i;
|
|
|
|
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]) + 6) > 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;
|
|
}
|
|
|
|
int playEmbargo(struct gameState *state, int choice1, int handPos, int currentPlayer)
|
|
{
|
|
//+2 Coins. Trash this card. Put an Embargo token on top of a Supply pile.
|
|
// When a player buys a card, he gains a Curse card per Embargo token on that pile.
|
|
|
|
//NOTE: The program has a bug already where Player0 starts with a different number
|
|
// of VP than Player1. Regardless, I didn't mess with the VP counter.
|
|
|
|
//+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;
|
|
}
|
|
|
|
//NOT USED: DON'T CHECK THESE FOR BUGS
|
|
int playGreat_hall(int currentPlayer, struct gameState *state, int handPos)
|
|
{
|
|
//+1 Card
|
|
drawCard(currentPlayer, state);
|
|
|
|
//+1 Actions
|
|
state->numActions++;
|
|
|
|
//discard card from hand
|
|
discardCard(handPos, currentPlayer, state, 0);
|
|
return 0;
|
|
}
|
|
|
|
//NOT USED: DON'T CHECK THESE FOR BUGS
|
|
int playSteward(int choice1, int choice2, int choice3, int currentPlayer, struct gameState *state, int handPos)
|
|
{
|
|
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;
|
|
}
|
|
|
|
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:
|
|
return playAdventurer(drawntreasure, state, currentPlayer, temphand, z);
|
|
|
|
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:
|
|
|
|
return playMine(state, currentPlayer, choice1, choice2, handPos);
|
|
|
|
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
|
|
return playSmithy(state, handPos, currentPlayer);
|
|
|
|
case village:
|
|
|
|
return playVillage(currentPlayer, state, handPos);
|
|
|
|
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:
|
|
|
|
return playGreat_hall(currentPlayer, state, handPos);
|
|
|
|
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:
|
|
|
|
return playSteward(choice1, choice2, choice3, currentPlayer, state, handPos);
|
|
|
|
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:
|
|
|
|
return playEmbargo(state, choice1, handPos, currentPlayer);
|
|
|
|
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
|