예제 #1
0
void Renderer::MoveBlockRight()
{
    // don't do anything if game is NULL
    if(m_game == NULL)
    {
        return;
    }
    m_game->moveRight();
    copyGameState();            //update for network, and draw
    update();                   //actually draw
}
예제 #2
0
void Renderer::Tick()
{
    // don't do anything if the game is NULL
    if(m_game == NULL)
    {
        return;
    }
    m_game->tick();
    copyGameState();            //update for network, and draw
    update();                   // actually draw
}
예제 #3
0
void Renderer::RotateBlockCCW()
{
    // don't do anything if game is  NULL
    if(m_game == NULL)
    {
        return;
    }
    m_game->rotateCCW();
    copyGameState();            //update for network, and draw
    update();                   //actually draw
}
예제 #4
0
void Renderer::CreateNewGame()
{
    // if null initialize otherwise reset it
    if(m_game == NULL)
    {
        m_game = new Game(10, 24);
    }
    else
    {
        m_game->reset();
    }
    // copy the game state to send it through the network and to draw
    copyGameState();
}
예제 #5
0
void Renderer::DropPiece()
{
    // don't do anything if game is NULL
    if(m_game == NULL)
    {
        return;
    }

    if(m_game->drop())
    {
        copyGameState();        // if dropped successfully update for network, and draw
        update();               // actually draw
    }
}
예제 #6
0
/*******************************************************************************
** Function: test
** Description: execute tests (see above).
** Parameters:
**		expected: bool, the expected outcome
**		pre: gameState before card effect execution
**		post: gameState after card effect execution
**		passes: count of tests passed
**		failures: count of tests failed
** Pre-Conditions:
**		pre and post are pointers to valid gameState structs
**		passes and failures are pointers to valid integer accumulators
** Post-Conditions: passes and failures are incremented per test results
*******************************************************************************/
void test(int expected, struct gameState* pre, struct gameState* post, int* passes, int* failures)
{
	int result;

	/* retain a copy the initial game state for post-comparison */
	copyGameState(post, pre);
	/* execute function */
	result = TESTFUNC(post);
	/* 1) return value */
	if (OUTPUTLEVEL > 1) printf(
		"Result: %s, expected %s. ",
		result ? "true" : "false",
		expected ? "true" : "false");
	if (expected) updateTestResult(result, passes, failures);
	else updateTestResult(!result, passes, failures);
	/* 2) gameState unchanged */
	result = gameStateChanged(pre, post);
	if (OUTPUTLEVEL > 1)
	{
		if (result == FALSE) printf("Result: gameState unchanged. ");
		else printf("Result: gameState changed. ");
	}
	updateTestResult(result == FALSE, passes, failures);
}
int main()
{
	//check player deck before drawing
	//check player deck after drawing
	//make sure that the number of cards in the deck decreases and the number of discards increases
	//
	//check the state of other players prior to playing of smithy
	//check the state of other players after playing smithy
	//
	//check the state of the victory piles (estate 1, duchy 2, province 3)
	//check the state of the kingdom piles (get the indices from the chosen kingdom cards in the init)
	//

	srand(time(NULL));
	int handPos, randPlayerIdx, initSuccess, i, j, randNumPlayers, randCardIdx;
	int seed = 1000;
	int kingCards[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse, great_hall, tribute, smithy};
	//int randNumPlayers = 2;
	struct gameState game1, game2;
	int caseSuccess = 0;
	int otherPlayerIDX;
	int testCase = 0;
	int numSuccess = 0;
	int playerCompSuccess = 0;
	int supplySuccess = 0;
	int r;

	printf(">>>>>>    ADVENTURER TESTING    <<<<<<\n");



	//start of random testing
	int caseCounter = 0;
	while(caseCounter <= 100)
	{
		//randomize number of players
		//randomize the current player from within the set of available players
		//randomize the hand index at which the adventurer is stored		//	
		//make sure to take note of the index where the adventurer card is at
		//
		//test the conditions mentioned above
		randNumPlayers = 2 + (rand() % 3);
		randPlayerIdx = rand() % (randNumPlayers);
		randCardIdx = rand() % 6;

		supplySuccess = 0;
		playerCompSuccess = 0;
		caseSuccess = 0;
		initSuccess = initializeGame(randNumPlayers, kingCards, seed, &game1);
		
		game1.hand[randPlayerIdx][randCardIdx] = adventurer;
		

		//The for loop below fills the discard pile so that when the deck appears to be empty it has cards to reshuffle
		for(r = 0; r < 5; r++)
		{
			game1.discard[randPlayerIdx][r] = rand() % 26;
			game1.discardCount[randPlayerIdx]++;
		}
		game1.deckCount[randPlayerIdx] = rand() % 2;	//randomize the deck count available
		//game1.deckCount[randPlayerIdx] = 0;	//testing the deck count to step into the desired reshuffle conditional
		//game1.hand[randPlayerIdx][game1.handCount[randPlayerIdx]-1] = 4 + (rand() % 5);
		
		copyGameState(&game1,&game2);	//copy the initial gamestate  for comparison later
		

		//now play adventurer
		//
		adventurer_action(&game1, randCardIdx, randPlayerIdx);

		//check that 2 additional cards are drawn meaning the number of cards currently in the hand should be larger by 1
		if((game2.handCount[randPlayerIdx] + 1 ) == (game1.handCount[randPlayerIdx]))
		{
			caseSuccess++;
			printf("adventurer_action(): PASS for handCount\n");
		}
		else
			printf("adventurer_action(): FAIL for handCount\n");
		if(game2.deckCount[randPlayerIdx] > game1.deckCount[randPlayerIdx])
		{
			caseSuccess++;
			printf("adventurer_action(): PASS for deckCount\n");

		}
		else
			printf("adventurer_action(): FAIL for deckCount\n");

		//check that discard increases
		
		//check to make sure the supplies don't change
		for(i = 0; i < (treasure_map + 1); i++)
		{
			if(game2.supplyCount[i] == game1.supplyCount[i])
			{
				supplySuccess++;
				//printf("supplySuccess: %d\n", supplySuccess);

			}
			else
				printf("adventurer_action(): FAIL for supply\n");

		}
		if(supplySuccess ==  treasure_map + 1)
		{
			printf("adventurer_action(): PASS for supply\n");
			caseSuccess++;
		}
		//compare other players states
		for(j = 0; j < randNumPlayers; j++)
		{
			//printf("j: %d\n", j);
			//printf("randNumPlayers: %d\n", randNumPlayers);
			if((j != randPlayerIdx) && (randNumPlayers > 1))
			{

				if(comparePlayerState(&game1, &game2, j) > 0)
					printf("adventurer_action(): FAIL for external player comparison\n");
				else
					playerCompSuccess += 1;
			}
			else
				playerCompSuccess += 1;
		}
		if(playerCompSuccess > 0)
		{
			caseSuccess++;
			printf("adventurer_action(): PASS for external player comparison\n");
		}
		
		//printf("caseSuccess: %d\n", caseSuccess);
		if(caseSuccess >= 4)
			numSuccess++;
		testCase++;
		caseCounter++;
	}

	printf("%d PASSED test cases out of %d\n", numSuccess, testCase);
	printf("%d FAILED test cases out of %d\n", testCase-numSuccess, testCase);

	if((testCase-numSuccess) == 0)
		printf(">>>>>>    TEST SUCCESS    <<<<<<\n");
	else
		printf(">>>>>>    TEST FAILURE    <<<<<<\n");



	printf(">>>>>>    ADVENTURER TEST COMPLETE    <<<<<<\n");

	//printf("The number of players in this game is: %d\n", game1.randNumPlayers);
	//game1.randNumPlayers = 100;
	//printf("The number of players in this game is: %d\n", game1.randNumPlayers);

	return 0;
}
예제 #8
0
/*******************************************************************************
** Function: main
** Description: entrypoint for unit test.
** Parameters: None
** Pre-Conditions: None
** Post-Conditions: Exit code 0 if all tests succeeded, otherwise 1.
*******************************************************************************/
int main()
{
	int players;
	int player;

	/* game states */
	struct gameState pre;
	struct gameState post;
	struct gameState state;

	int i;
	int pile1, pile2, pile3;
	int card;
	int expected;

	int passes = 0; /* tests passed */
	int failures = 0; /* tests failed */

	if (OUTPUTLEVEL > 0) printf("\n*** BEGIN " FILENAME " (unit test for " xstr(TESTFUNC) ") ***\n");

	/* test games with each allowed number of players */
	for (players = 2; players <= MAX_PLAYERS; players++)
	{
		/* initialize a standard game, using a pre-defined set of kingdom cards and random seed */
		initializeGame(players, Kingdom, SEED, &state);

		/* reset all players' hands and decks */
		for (player = 0; player < players; player++)
		{
			state.deckCount[player] += state.handCount[player];
			state.handCount[player] = 0;
		}

		/* ensure ALL supply piles have at least 1 card */
		for (i = 0; i <= treasure_map; i++)
		{
			if (state.supplyCount[i] < 1) state.supplyCount[i] = 1;
		}

		/* test each player */
		for (player = 0; player < players; player++)
		{
			if (OUTPUTLEVEL > 1) printf("\nState: %d players, player index %d.\n", players, player);

			/* 1) No cards (all piles empty), return true */
			/* get a fresh copy of the base gamestate */
			copyGameState(&pre, &state);
			if (OUTPUTLEVEL > 1) printf("Test Condition: all supply piles empty.\n");
			/* set card configuration */
			for (i = 0; i <= treasure_map; i++) pre.supplyCount[i] = 0;
			test(TRUE, &pre, &post, &passes, &failures);

			/* 2) Newly initialized game (all piles > 0, return false */
			/* get a fresh copy of the base gamestate */
			copyGameState(&pre, &state);
			if (OUTPUTLEVEL > 1) printf("Test Condition: all supply piles > 0 cards.\n");
			test(FALSE, &pre, &post, &passes, &failures);

			/* 3) Newly initialized game, for each supply pile, empty just that pile */
			/*    return false except for emptied provinces pile which returns true */
			if (OUTPUTLEVEL > 1) printf("\nTest single empty supply piles (others > 0)...\n");

			for (card = 0; card <= treasure_map; card++)
			{
				/* get a fresh copy of the base gamestate */
				copyGameState(&pre, &state);
				if (OUTPUTLEVEL > 1) printf("\nEmpty pile: %d\n", card);
				/* set card configuration */
				pre.supplyCount[card] = 0;
				expected = FALSE;
				if (card == province) expected = TRUE;
				test(expected, &pre, &post, &passes, &failures);
			}

			/*	4) Newly initialized game, empty all combinations of 3 piles */
			/*     all combinations of 3 should return true */
			if (OUTPUTLEVEL > 1) printf("\nTest all combinations of empty supply piles (others > 0)...\n");

			for (pile1 = 0; pile1 <= treasure_map; pile1++)
			{
				for (pile2 = pile1; pile2 <= treasure_map; pile2++)
				{
					for (pile3 = pile2; pile3 <= treasure_map; pile3++)
					{
						if (pile1 == pile2 ||
							pile1 == pile3 ||
							pile2 == pile3) continue; /* only want 3 distinct piles */

						/* get a fresh copy of the base gamestate */
						copyGameState(&pre, &state);
						if (OUTPUTLEVEL > 1) printf("\nEmpty piles: %d, %d, %d\n", pile1, pile2, pile3);
						/* set card configuration */
						pre.supplyCount[pile1] = 0;
						pre.supplyCount[pile2] = 0;
						pre.supplyCount[pile3] = 0;
						expected = TRUE;
						test(expected, &pre, &post, &passes, &failures);
					}
				}
			}
		}
	}

	if (OUTPUTLEVEL > 0)
	{
		if (OUTPUTLEVEL > 1) printf("\n");
		printf("SUMMARY for " FILENAME " (" xstr(TESTFUNC) "): ");
		if (failures == 0) printf("passed all %d tests.\nTesting Outcome: SUCCESS!\n", passes);
		else
		{
			printf("failed %d of %d tests.\n", failures, passes + failures);
			printf("Testing Outcome: FAILED!\n");
			if (OUTPUTLEVEL > 1) printf("See results output above.\n");
		}
		if (OUTPUTLEVEL > 0) printf("*** END " FILENAME " (unit test for " xstr(TESTFUNC) ") ***\n");
	}

	return failures != 0 ? 1 : 0;
}
예제 #9
0
int main()
{
	srand(time(NULL));
	int randCardIdx, randPlayerIdx, initSuccess, i, j, u, q;
	int seed = 1000;
	int kingCards[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse, great_hall, tribute, smithy};
	int randNumPlayers;
	struct gameState game1, game2;
	int caseSuccess = 0;
	int otherPlayerIDX;
	int testCase = 0;
	int numSuccess = 0;
	int playerCompSuccess = 0;
	int supplySuccess = 0;

	printf(">>>>>>    VILLAGE RANDOM TESTING    <<<<<<\n");
	int caseCounter = 0;

	//Implement fixed loop to give a wide variety of random test cases
	while(caseCounter <= 1000)
	{
		randNumPlayers = 2 + (rand() % 3);			//randomizing the number of players in the game
		randPlayerIdx = rand() % (randNumPlayers );	//randomizing the player index
		randCardIdx = rand() % 6;					//randomizing the placement of the card

		supplySuccess = 0;
		playerCompSuccess = 0;
		caseSuccess = 0;
		initSuccess = initializeGame(randNumPlayers, kingCards, seed, &game1);	//initialize gamestate
		
		game1.hand[randPlayerIdx][randCardIdx] = great_hall;	//place the card in the chosen random location


		copyGameState(&game1,&game2);	//copy the initial gamestate  for comparison to gamestate modified by the function
		
		village_action(&game1, randCardIdx, randPlayerIdx);	//Play the village card by passing in gamestate by reference
		
		//check that 1 additional cards are drawn meaning the number of cards currently in the hand should be larger by 0
		if((game2.handCount[randPlayerIdx]  ) == (game1.handCount[randPlayerIdx]))
		{
			caseSuccess++;
			printf("village_action(): PASS for handCount\n");
		}
		else
			printf("village_action(): FAIL for handCount\n");


		//Check that the deckCount has decreased by one after drawing a new card
		if((game2.deckCount[randPlayerIdx] - 1) == game1.deckCount[randPlayerIdx])
		{
			caseSuccess++;
			printf("village_action(): PASS for deckCount\n");

		}
		else
			printf("village_action(): FAIL for deckCount\n");

		//check that discard increases
		
		//check to make sure the supplies don't change
		for(i = 0; i < (treasure_map + 1); i++)
		{
			if(game2.supplyCount[i] == game1.supplyCount[i])
			{
				supplySuccess++;
				//printf("supplySuccess: %d\n", supplySuccess);

			}
			else
				printf("village_action(): FAIL for supply\n");

		}
		if(supplySuccess ==  treasure_map + 1)
		{
			printf("village_action(): PASS for supply\n");
			caseSuccess++;
		}

		//compare other players states
		for(j = 0; j < randNumPlayers; j++)
		{
			if((j != randPlayerIdx) && (randNumPlayers > 1))
			{
				if(comparePlayerState(&game1, &game2, j) > 0)
					printf("village_action(): FAIL for external player comparison\n");
				else
					playerCompSuccess += 1;
			}
			else
				playerCompSuccess += 1;
		}
		if(playerCompSuccess > 0)
		{
			caseSuccess++;
			printf("village_action(): PASS for external player comparison\n");

		}
		

		//check to see the increase in the number of actions given to the player who played the card
		if((game2.numActions + 2) == game1.numActions)
		{
			caseSuccess++;
			printf("village_action(): PASS for additional action added\n");

		}
		else
			printf("village_action(): FAIL for additional action added\n");


		if(caseSuccess >= 5)
			numSuccess++;
		testCase++;

		caseCounter++;
	}


	printf("%d PASSED test cases out of %d\n", numSuccess, testCase);
	printf("%d FAILED test cases out of %d\n", testCase-numSuccess, testCase);

	if((testCase-numSuccess) == 0)
		printf(">>>>>>    TEST SUCCESS    <<<<<<\n");
	else
		printf(">>>>>>    TEST FAILURE    <<<<<<\n");


	printf(">>>>>>    VILLAGE RANDOM TESTING COMPLETE    <<<<<<\n");
	

	//printf("The number of players in this game is: %d\n", game1.randNumPlayers);
	//game1.randNumPlayers = 100;
	//printf("The number of players in this game is: %d\n", game1.randNumPlayers);

	return 0;
}
예제 #10
0
int main()
{
	srand(time(NULL));
	int randCardIdx, randPlayerIdx, initSuccess, i, j, u, q;
	int seed = 1000;
	int kingCards[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse, great_hall, tribute, smithy};
	int randNumPlayers;
	struct gameState game1, game2;
	int caseSuccess = 0;
	int otherPlayerIDX;
	int testCase = 0;
	int numSuccess = 0;
	int playerCompSuccess = 0;
	int supplySuccess = 0;
	int bonus = 0;

	printf(">>>>>>    GREAT HALL TESTING    <<<<<<\n");
	int caseCounter = 0;
	while(caseCounter <= 1000)
	{
		randNumPlayers = 2 + (rand() % 3);			//randomize the number of players
		randPlayerIdx = rand() % (randNumPlayers );	//randomize which player is playing the card
		randCardIdx = rand() % 6;					//randomize the placement of the card under test in the players hand

		supplySuccess = 0;
		playerCompSuccess = 0;
		caseSuccess = 0;
		initSuccess = initializeGame(randNumPlayers, kingCards, seed, &game1);
		
		game1.hand[randPlayerIdx][randCardIdx] = great_hall;
		game1.whoseTurn = randPlayerIdx;
		copyGameState(&game1,&game2);	//copy the initial gamestate  for comparison later
		

		//great_hall_action(&game1, randPlayerIdx, randCardIdx);	//play great hall card passing in the inital gamestate to be modified
		cardEffect(great_hall, 0, 0, 0, &game1, randCardIdx, &bonus);

		//check that 1 additional cards are drawn meaning the number of cards currently in the hand should be larger by 0
		if((game2.handCount[randPlayerIdx]  ) == (game1.handCount[randPlayerIdx]))
		{
			caseSuccess++;
			printf("great_hall_action(): PASS for handCount\n");
		}
		else
			printf("great_hall_action(): FAIL for handCount\n");

		//check that the new deck count is larger 
		if((game2.deckCount[randPlayerIdx] - 1) == game1.deckCount[randPlayerIdx])
		{
			caseSuccess++;
			printf("great_hall_action(): PASS for deckCount\n");

		}
		else
			printf("great_hall_action(): FAIL for deckCount\n");

		//check that discard increases
		
		//check to make sure the supplies don't change
		for(i = 0; i < (treasure_map + 1); i++)
		{
			if(game2.supplyCount[i] == game1.supplyCount[i])
			{
				supplySuccess++;
				//printf("supplySuccess: %d\n", supplySuccess);

			}
			else
				printf("great_hall_action(): FAIL for supply\n");

		}
		if(supplySuccess ==  treasure_map + 1)
		{
			printf("great_hall_action(): PASS for supply\n");
			caseSuccess++;
		}

		//compare other players states
		for(j = 0; j < randNumPlayers; j++)
		{
			if((j != randPlayerIdx) && (randNumPlayers > 1))
			{
				//printf("Other player %d comparison\n", j);
				//printf("random player index: %d\n\n", randPlayerIdx);
				if(comparePlayerState(&game1, &game2, j) > 0)
					printf("great_hall_action(): FAIL for external player comparison\n");
				else
					playerCompSuccess += 1;
			}
			else
				playerCompSuccess += 1;
		}
		if(playerCompSuccess > 0)
		{
			caseSuccess++;
			printf("great_hall_action(): PASS for external player comparison\n");

		}
		
		//test for additional action allowed
		if((game2.numActions + 1) == game1.numActions)
		{
			caseSuccess++;
			printf("great_hall_action(): PASS for additional action added\n");

		}
		else
			printf("great_hall_action(): FAIL for additional action added\n");


		if(caseSuccess >= 5)
			numSuccess++;
		testCase++;

		caseCounter++;
	}


	printf("%d PASSED test cases out of %d\n", numSuccess, testCase);
	printf("%d FAILED test cases out of %d\n", testCase-numSuccess, testCase);

	if((testCase-numSuccess) == 0)
		printf(">>>>>>    TEST SUCCESS    <<<<<<\n");
	else
		printf(">>>>>>    TEST FAILURE    <<<<<<\n");


	printf(">>>>>>    GREAT HALL TESTING COMPLETE    <<<<<<\n");
	

	//printf("The number of players in this game is: %d\n", game1.randNumPlayers);
	//game1.randNumPlayers = 100;
	//printf("The number of players in this game is: %d\n", game1.randNumPlayers);

	return 0;
}
예제 #11
0
파일: c2.c 프로젝트: chriskonnertz/c2-chess
/**
* Ermittelt den besten Zug aus der uebergebenen Stellung.
*
* from = Poistionsindex des Start des Zugs, to = Ziel
* bestEval = die beste ermittelte Bewertung
* bestEvalAdding = zusätzliche Bewertung die genutzt werden kann, um gleichbewertete Zuege zu priorisieren
* depth = die aktuelle Zugtiefe
*/
void aiDeepSearch(struct GameState *gameState, char *from, char *to, int *bestEval, int *bestEvalAdding, char depth) {
	short movesCounter;
	char moves[28 * 16 * 2]; // keine Initialiserung!
	struct GameState gs;

	if (depth == 0 && autoMode) printBoard((*gameState).board, 0, 0);

	// Erzeuge lokale Kopie des GameState der beliebig veraendert werden kann:
	copyGameState(gameState, &gs); 

	// Erzeuge Zuege:
	generateMoves(&gs, moves, &movesCounter);

	// Zunaechst alle Zuege auf Gueltigkeit (Schach) untersuchen.
	// Ungueltige Zuege aussortieren.
	short move;
	short found = 0; // gefundene gueltige Zuege
	int eval = 0;
	int evalAdding = 0;
	*bestEval = -valueCheckMate; // valueCheckMate bedeutet: Der bewertende Spieler ist Schachmatt/Patt
	//*bestEvalAdding = 0;
	for (move = 0; move < movesCounter; move += 2) {
		short pieceFrom = gs.board[moves[move]];
		short pieceTo = gs.board[moves[move + 1]];

		// Testzug machen:
		//printDev("Betrachte Zug %i  von %i (%i) nach %i (%i).\n", move, moves[move], pieceFrom, moves[move+1], pieceTo);
		doMovePartial(&gs, moves[move], moves[move + 1]);

		if (isCheck(&gs)) { // Eigener Koenig unter Schach?
			//printDev("Ausortierter Zug %i von %i nach %i da Schachgebot von: %i\n", move, moves[move], moves[move+1], isCheck(&gs));
			// derzeit: nichts tun
		} else {
			found++;

			if (depth >= maxDepth) {
				eval = evaluateBoard(gs.board);
				evalAdding = 0;
				if (gs.turnNumber % 2 == 1) eval *= -1; // ist der Spieler, der am Zug ist, schwarz, die Bewertung umdrehen (da sie immer aus Sicht von Weiss erfolgt)
				//printDev("Betrachte Zug %i von %i nach %i. Bewertung: %i\n", move, moves[move], moves[move+1], eval);
			} else {
				gs.turnNumber++; // Zugnummer erhoehen damit der naechste Spieler am Zug ist
				char rfrom = 0; // der Wert wird nicht benoetigt
				char rto = 0;
				aiDeepSearch(&gs, &rfrom, &rto, &eval, &evalAdding, depth + 1);		

				eval *= -1; // NegaMax-Algorithmus: Die Bewertung umdrehen. Aus der Sicht des Spielers, der in dieser Funktion gerade berechnet wird, ist der andere Spieler der Gegner und ein gutes Ergebnis von ihm fuer ihn selber schlecht.
				evalAdding *= -1;
				gs.turnNumber--;

				if (debugMode && depth == 0) {
					if (pieceTo == 0) {
						printDev("[%3.0f%%] Deep Search: Zug mit %c von %i nach %i. Bewertung: %6i\n", ((double) move / (double) movesCounter) * 100, getPieceSymbolAsChar(pieceFrom), moves[move], moves[move+1], eval);
					} else {
						printDev("[%3.0f%%] Deep Search: Zug mit %c von %i nach %i und schlaegt %c. Bewertung: %6i\n", ((double) move / (double) movesCounter) * 100, getPieceSymbolAsChar(pieceFrom), moves[move], moves[move+1], getPieceSymbolAsChar(pieceTo), eval);
					}
				}
			}

			// Schlagzuege unterhalb der tiefsten Ebene (Evaluationsebene) werden minimal vorteilhaft bewertet.
			// Der Grund dafuer ist, dass es sonst zu Situationen kommen kann, in denen die KI zwar schlagen kann,
			// was auch vorteilhat waere im Sinne der Bewertung, es aber nicht tut.
			// Warum nicht? Weil in diesen Situationen die KI sieht, dass die eine Figur sicher schlagen kann, und zwar
			// innerhalb ihres ganzen Horizonts. Es ist dann aus Sicht der KI egal, ob sie die Figur diese oder naechste Runde schlaegt.
			// Aber es kann sein, dass die KI die Situation in der naechsten Runde wiede so bewertet und das Schlagen
			// immer auf einen zukuenftigen Zeitpunkt verschiebt. Deshalb wird das schlagen minimal positiv bewertet.
			if (pieceTo != 0) evalAdding += pow(2, maxDepth + 1 - depth);

			if (eval > *bestEval || (eval == *bestEval && evalAdding > *bestEvalAdding)) {
				if (debugMode && depth == 0) printDev("Dieser Zug hat nun die beste Bewertung.\n");
				*bestEval = eval;
				*bestEvalAdding = evalAdding;
				*from = moves[move];
				*to = moves[move + 1];
			}
		}

		// Zug rueckgaengig machen:
		gs.board[moves[move]] = pieceFrom;
		gs.board[moves[move + 1]] = pieceTo;

		//if (eval > valueCheckMate) {
		//	printDev("Checkmate-Cutoff!\n");
		//	break;
		//} 
	}

	// Wenn ich keine gueltigen Zuege habe, bin ich schachmatt oder patt.
	// Daher auf Schach pruefen: Besteht kein Schach, dann bin ich patt.
	// In diesem Fall gebe ich anstatt -valueCheckMate (=Schachmatt) als Bewertung 0 zurueck.
	// Damit weiss der Spieler, der vor mir am Zug ist, zwar nicht genau, dass es ein Patt ist.
	// Das ist aber irrelevant.
	if (found == 0) {
		if (isCheck(&gs) == 0) *bestEval = 0;
	}
}
예제 #12
0
파일: c2.c 프로젝트: chriskonnertz/c2-chess
/**
* Hauptmethode
*/
int main(int argc, char *argv[]) {
	hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	char o;
	char boardMode = 0; // 0/1
	char fullScreen = 1;
	char from[] = "??";
	char to[] = "??";
	char filename[255];
	char moves[28 * 16 * 2]; // keine Initialiserung!
	short movesCounter = 0;
	short board[120];
	int eval;
	int okay;
	int i;

	struct GameState gameState;
	struct GameState gameStateCopy;
	createStartBoard(board);
	setGameState(&gameState, board, 0, 3, 4);

	srand((unsigned int) time(NULL));  // Zufallsgenerator initialisieren

	if (fullScreen) system("cls");

	do {
		printf("\nSpieler: %i, Halbzug: %i\n", gameState.turnNumber % 2, gameState.turnNumber);
		printBoard(gameState.board, 0, boardMode);

		COLOR(128);
		printf("\n> Kommando:");
		COLOR(COLOR_DEFAULT);
		printf(" ");
        scanf("%c", &o); // Auf Char scannen
        fflush(stdin);

        if (fullScreen && o != 'm') system("cls");

        switch (o) {
        	case 'x':
        		// "magic" move - alles ist moeglich. Auch, Fehler zu produzieren.
        	case 'm':
        		printf("Zug von: ");
        		scanf("%s", from);
        		fflush(stdin);

        		printf("Zug nach: ");
        		scanf("%s", to);
        		fflush(stdin);

        		if (strlen(from) != 2 || strlen(to) != 2) {
        			printError("Ungueltige Koordinaten!\n");
        		} else {
        			autoSave(&gameState);
        			if (o == 'x') {
						doMovePartial(&gameState, convertCoordToIndex(from), convertCoordToIndex(to));
						doMoveFinal(&gameState, convertCoordToIndex(from), convertCoordToIndex(to));
        			} else {
        				if (doUserMove(&gameState, convertCoordToIndex(from), convertCoordToIndex(to))) system("cls");
        			}
        		}
        		break;
        	case 'n':
        		gameState.turnNumber--;
				printInfo("Zug zurueck.\n");
        		break;
        	case 'a':
        		do {
        			autoSave(&gameState);
        			okay = aiMove(&gameState, 0);
        		} while (autoMode && okay && ((gameState.turnNumber % 2 == 0 && gameState.ai0) || (gameState.turnNumber % 2 == 1 && gameState.ai1)));
        		break;
        	case 'c':
        		printInfo("Schach: %i\n", isCheck(&gameState));
        		break;
        	case 'h':
        		printHistory();
        		break;
        	case 'g':
        		generateMoves(&gameState, moves, &movesCounter);
        		printInfo("%i moegliche Zuege (ohne Beruecksichtigung von Schach).\n", movesCounter / 2);
				for (i = 0; i < movesCounter; i += 2) {
					printf("Zug mit %i von %i nach %i.\n", gameState.board[moves[i]], moves[i], moves[i + 1]);
				}
        		break;
        	case 'v':
        		eval = evaluateBoard(gameState.board);
        		printInfo("Evaluation (aus Sicht von weiss): %i\n", eval);
        		break;
        	case 't':
        		copyGameState(&gameState, &gameStateCopy);
    			okay = aiMove(&gameStateCopy, 3);
        		break;
        	case 'o':
        		okay = loadOpeningBookMove(&gameState, from, to);
        		if (okay) {
        			printInfo("Zugvorschlag aus dem Eroeffnungsbuch: mit %c von %s nach %s", getPieceSymbolAsChar(gameState.board[convertCoordToIndex(from)]), from, to);
        		} else {
        			printInfo("Das Eroeffnungsbuch enthaelt keinen passenden Zug!");
        		}
        		break;
        	case 's':
        		saveGame(&gameState, "quicksave", 1);
        		break;
        	case 'r':
				loadGame(&gameState, "quicksave");
        		break;
        	case 'l':
        		system("dir savegames\\*.sav /B");
				printf("\nLade Datei (Endung nicht angeben):\n");
				scanf("%s", filename);
				fflush(stdin);

				loadGame(&gameState, filename);
        		break;
        	case 'u':
        		loadAutoSave(&gameState);
        		break;
        	case 'b':
        		boardMode = (1 - boardMode);
        		printInfo("Brettdarstellung gewechselt auf: %i\n", boardMode);
        		break;
        	case 'd':
        		debugMode = (1 - debugMode);
        		printInfo("Debugmodus gewechselt auf: %i\n", debugMode);
        		break;
        	case '?':
        		printf("m (move)\tEinen Zug durchfuehren.\n");
        		printf("n (next)\tDen Spieler wechseln (ohne Zug, regelwidrig!)\n");
        		printf("a (ai)\t\tKI einen Zug durchfuehren lassen.\n");
        		printf("h (history)\tDen Spielverlauf anzeigen.\n");
        		printf("c (check)\tStellung auf Schach pruefen.\n");
        		printf("g (generate)\tMoegliche Zuege anzeigen lassen.\n");
        		printf("v (value)\tBewertung der Stellung anzeigen lassen.\n");
        		printf("t (tip)\t\tDie KI einen Zug-Tip anzeigen lassen.\n");
        		printf("s (save)\tQuicksave-Spielstand anlegen.\n");
        		printf("r (reload)\tQuicksave-Spielstand laden.\n");
        		printf("l (load)\tSpielstand laden (Dateiname angeben).\n");
        		printf("u (undo)\tLetzten Zug zuruecknehmen.\n");
        		printf("b (board)\tBrettdarstellung wechseln (fuer Debuggging).\n");
        		printf("d (open)\tDebugausgaben aktivieren/deaktivieren.\n");
        		printf("? (help)\tDiese Hilfe zu den Kommandos anzeigen lassen.\n");
        		printf("e (exit)\tDas Programm beenden.\n");
        		break;
        	case 'e':
        		// do nothing
        		break;
        	case '\n':
        		// do nothing
        		break;
        	default:
        		printError("Unbekannter Operator: %c\n", o);
        		break;
        }
        fflush(stdin);
	} while (o != 'e');

	return 0;
}
예제 #13
0
/*******************************************************************************
** Function: main
** Description: entrypoint for unit test.
** Parameters: None
** Pre-Conditions: None
** Post-Conditions: Exit code 0 if all tests succeeded, otherwise 1.
*******************************************************************************/
int main()
{
	int players;
	int player;
	int handpos, deckpos;
	int bonus;
	struct gameState pre;
	struct gameState post;
	struct gameState state;

	int i;
	int result;
	int treasures;
	int handDeltas[treasure_map + 1]; /* array of all card types */
	int discardDeltas[treasure_map + 1]; /* array of all card types */

	int passes = 0; /* tests passed */
	int failures = 0; /* tests failed */

	if (OUTPUTLEVEL > 0) printf("\n*** BEGIN " FILENAME " (cardEffect unit test for " xstr(CARDUNDERTEST) ") ***\n");

	/* test games with each allowed number of players */
	for (players = 2; players <= MAX_PLAYERS; players++)
	{
		/* initialize a standard game, using a pre-defined set of kingdom cards and random seed */
		initializeGame(players, Kingdom, SEED, &state);

		/* reset all players' hands and decks */
		for (player = 0; player < players; player++)
		{
			state.deckCount[player] += state.handCount[player];
			state.handCount[player] = 0;
		}

		/* test each player */
		for (player = 0; player < players; player++)
		{
			/* 1) Ensure that card effect picks gold from revealed cards */

			/* get a fresh copy of the base gamestate */
			copyGameState(&pre, &state);

			/* stack the current player's hand with the card under test and set current player */
			pre.handCount[player] = HANDCOUNT;
			for (handpos = 0; handpos < pre.handCount[player]; handpos++) pre.hand[player][handpos] = CARDUNDERTEST;
			pre.whoseTurn = player;

			/* deck: 3 gold cards, discard : empty */
			pre.discardCount[player] = 0;
			pre.deckCount[player] = 3;
			for (deckpos = 0; deckpos < pre.deckCount[player]; deckpos++) pre.deck[player][deckpos] = gold;
			if (OUTPUTLEVEL > 1) printf("Card Configuration: deck 3 gold cards, discard empty.\n");

			/* test several hand positions */
			for (handpos = 0; handpos < pre.handCount[player]; handpos++)
			{
				/* test hand positions at either end of the hand and in the middle, skip others */
				if (
					!(handpos == 0 ||
						handpos == pre.handCount[player] / 2 ||
						handpos == (pre.handCount[player] - 1))
					) continue;

				/* retain a copy the initial game state for post-comparison */
				copyGameState(&post, &pre);

				/* perform the card effect */
				bonus = 0;
				cardEffect(CARDUNDERTEST, 0, 0, 0, &post, handpos, &bonus);

				if (OUTPUTLEVEL > 1) printf("Test Standard Conditions\n");
				testStandardConditions(players, player, handpos, &pre, &post, &passes, &failures);

				if (OUTPUTLEVEL > 1) printf("Test Extra Conditions\n");

				/* verify exactly 2 gold treasures drawn */
				if (OUTPUTLEVEL > 1) printf("Test: Exactly 2 golds added to hand...\n");
				deltaPlayerCardTypesInHand(&pre, &post, player, handDeltas);
				result = TRUE;
				for (i = 0; i <= treasure_map; i++)
				{
					if (i == gold)
					{
						if (handDeltas[i] != 2) result = FALSE;
					}
					else if (i == CARDUNDERTEST) /* card that was played */
					{
						if (handDeltas[i] != -1) result = FALSE;
					}
					else
					{
						if (handDeltas[i] != 0) result = FALSE;
					}
				}
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == TRUE, &passes, &failures);

				/* verify discard state is unchanged */
				if (OUTPUTLEVEL > 1) printf("Test: Player discard state unchanged...\n");
				result = deltaPlayerDiscardCount(&pre, &post, player);
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == 0, &passes, &failures);
			}

			/* 2) Ensure that card effect picks silver from revealed cards */

			/* get a fresh copy of the base gamestate */
			copyGameState(&pre, &state);

			/* stack the current player's hand with the card under test and set current player */
			pre.handCount[player] = HANDCOUNT;
			for (handpos = 0; handpos < pre.handCount[player]; handpos++) pre.hand[player][handpos] = CARDUNDERTEST;
			pre.whoseTurn = player;

			/* deck: 3 silver cards, discard : empty */
			pre.deckCount[player] = 3;
			pre.discardCount[player] = 0;
			for (deckpos = 0; deckpos < pre.deckCount[player]; deckpos++) pre.deck[player][deckpos] = silver;
			if (OUTPUTLEVEL > 1) printf("Card Configuration: deck 3 silver cards, discard empty.\n");

			/* test several hand positions */
			for (handpos = 0; handpos < pre.handCount[player]; handpos++)
			{
				/* test hand positions at either end of the hand and in the middle, skip others */
				if (
					!(handpos == 0 ||
						handpos == pre.handCount[player] / 2 ||
						handpos == (pre.handCount[player] - 1))
					) continue;

				/* retain a copy the initial game state for post-comparison */
				copyGameState(&post, &pre);

				/* perform the card effect */
				bonus = 0;
				cardEffect(CARDUNDERTEST, 0, 0, 0, &post, handpos, &bonus);

				if (OUTPUTLEVEL > 1) printf("Test Standard Conditions\n");
				testStandardConditions(players, player, handpos, &pre, &post, &passes, &failures);

				if (OUTPUTLEVEL > 1) printf("Test Extra Conditions\n");

				/* verify exactly 2 silver treasures drawn */
				if (OUTPUTLEVEL > 1) printf("Test: Exactly 2 silvers added to hand...\n");
				deltaPlayerCardTypesInHand(&pre, &post, player, handDeltas);
				result = TRUE;
				for (i = 0; i <= treasure_map; i++)
				{
					if (i == silver)
					{
						if (handDeltas[i] != 2) result = FALSE;
					}
					else if (i == CARDUNDERTEST) /* card that was played */
					{
						if (handDeltas[i] != -1) result = FALSE;
					}
					else
					{
						if (handDeltas[i] != 0) result = FALSE;
					}
				}
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == TRUE, &passes, &failures);

				/* verify discard state is unchanged */
				if (OUTPUTLEVEL > 1) printf("Test: Player discard state unchanged...\n");
				result = deltaPlayerDiscardCount(&pre, &post, player);
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == 0, &passes, &failures);
			}

			/* 3) Ensure that card effect picks copper from revealed cards */

			/* get a fresh copy of the base gamestate */
			copyGameState(&pre, &state);

			/* stack the current player's hand with the card under test and set current player */
			pre.handCount[player] = HANDCOUNT;
			for (handpos = 0; handpos < pre.handCount[player]; handpos++) pre.hand[player][handpos] = CARDUNDERTEST;
			pre.whoseTurn = player;

			/* deck: 3 copper cards, discard : empty */
			pre.discardCount[player] = 0;
			pre.deckCount[player] = 3;
			for (deckpos = 0; deckpos < pre.deckCount[player]; deckpos++) pre.deck[player][deckpos] = copper;
			if (OUTPUTLEVEL > 1) printf("Card Configuration: deck 3 copper cards, discard empty.\n");

			/* test several hand positions */
			for (handpos = 0; handpos < pre.handCount[player]; handpos++)
			{
				/* test hand positions at either end of the hand and in the middle, skip others */
				if (
					!(handpos == 0 ||
						handpos == pre.handCount[player] / 2 ||
						handpos == (pre.handCount[player] - 1))
					) continue;

				/* retain a copy the initial game state for post-comparison */
				copyGameState(&post, &pre);

				/* perform the card effect */
				bonus = 0;
				cardEffect(CARDUNDERTEST, 0, 0, 0, &post, handpos, &bonus);

				if (OUTPUTLEVEL > 1) printf("Test Standard Conditions\n");
				testStandardConditions(players, player, handpos, &pre, &post, &passes, &failures);

				if (OUTPUTLEVEL > 1) printf("Test Extra Conditions\n");

				/* verify exactly 2 copper treasures drawn */
				if (OUTPUTLEVEL > 1) printf("Test: Exactly 2 coppers added to hand...\n");
				deltaPlayerCardTypesInHand(&pre, &post, player, handDeltas);
				result = TRUE;
				for (i = 0; i <= treasure_map; i++)
				{
					if (i == copper)
					{
						if (handDeltas[i] != 2) result = FALSE;
					}
					else if (i == CARDUNDERTEST) /* card that was played */
					{
						if (handDeltas[i] != -1) result = FALSE;
					}
					else
					{
						if (handDeltas[i] != 0) result = FALSE;
					}
				}
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == TRUE, &passes, &failures);

				/* verify discard state is unchanged */
				if (OUTPUTLEVEL > 1) printf("Test: Player discard state unchanged...\n");
				result = deltaPlayerDiscardCount(&pre, &post, player);
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == 0, &passes, &failures);
			}

			/* 
			 * 4) Ensure that card effect picks only treasure cards when mixed
			 *    with non-treasure cards; also, does not skip treasure cards
			 */

			/* get a fresh copy of the base gamestate */
			copyGameState(&pre, &state);

			/* stack the current player's hand with the card under test and set current player */
			pre.handCount[player] = HANDCOUNT;
			for (handpos = 0; handpos < pre.handCount[player]; handpos++) pre.hand[player][handpos] = CARDUNDERTEST;
			pre.whoseTurn = player;

			/* deck: 1 estate on top, followed by gold, estate, silver, estate, copper, estate; discard: empty */
			pre.discardCount[player] = 0;
			pre.deckCount[player] = 7;
			pre.deck[player][6] = estate; /* top of deck */
			pre.deck[player][5] = gold;
			pre.deck[player][4] = estate;
			pre.deck[player][3] = silver;
			pre.deck[player][2] = estate;
			pre.deck[player][1] = copper;
			pre.deck[player][0] = estate;

			if (OUTPUTLEVEL > 1) printf("Card Configuration: 1 estate on top, followed by gold, estate, silver, estate, copper, estate; discard: empty.\n");

			/* test several hand positions */
			for (handpos = 0; handpos < pre.handCount[player]; handpos++)
			{
				/* test hand positions at either end of the hand and in the middle, skip others */
				if (
					!(handpos == 0 ||
						handpos == pre.handCount[player] / 2 ||
						handpos == (pre.handCount[player] - 1))
					) continue;

				/* retain a copy the initial game state for post-comparison */
				copyGameState(&post, &pre);

				/* perform the card effect */
				bonus = 0;
				cardEffect(CARDUNDERTEST, 0, 0, 0, &post, handpos, &bonus);

				if (OUTPUTLEVEL > 1) printf("Test Standard Conditions\n");
				testStandardConditions(players, player, handpos, &pre, &post, &passes, &failures);

				if (OUTPUTLEVEL > 1) printf("Test Extra Conditions\n");

				/* verify discard contains only 1 estate card */
				if (OUTPUTLEVEL > 1) printf("Test: Added 1 estate to discard...\n");
				deltaPlayerCardTypesInDiscard(&pre, &post, player, discardDeltas);
				result = TRUE;
				for (i = 0; i <= treasure_map; i++)
				{
					if (i == estate)
					{
						if (discardDeltas[i] != 1) result = FALSE;
					}
					else
					{
						if (discardDeltas[i] != 0) result = FALSE;
					}
				}
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == TRUE, &passes, &failures);

				/* verify hand added 1 gold, 1 silver card */
				if (OUTPUTLEVEL > 1) printf("Test: Added 1 gold, 1 silver to hand...\n");
				deltaPlayerCardTypesInHand(&pre, &post, player, handDeltas);
				result = TRUE;
				for (i = 0; i <= treasure_map; i++)
				{
					if (i == silver)
					{
						if (handDeltas[i] != 1) result = FALSE;
					}
					else if (i == gold)
					{
						if (handDeltas[i] != 1) result = FALSE;
					}
					else if (i == CARDUNDERTEST) /* card that was played */
					{
						if (handDeltas[i] != -1) result = FALSE;
					}
					else
					{
						if (handDeltas[i] != 0) result = FALSE;
					}
				}
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == TRUE, &passes, &failures);
			}


			/*
			* 5) Ensure that card effect picks only treasure cards when mixed
			*    with non-treasure cards; also, does not skip treasure cards
			*/

			/* get a fresh copy of the base gamestate */
			copyGameState(&pre, &state);

			/* stack the current player's hand with the card under test and set current player */
			pre.handCount[player] = HANDCOUNT;
			for (handpos = 0; handpos < pre.handCount[player]; handpos++) pre.hand[player][handpos] = CARDUNDERTEST;
			pre.whoseTurn = player;

			/* deck: 1 estate on top, followed by copper, estate, silver, estate, gold, estate; discard: empty */
			pre.discardCount[player] = 0;
			pre.deckCount[player] = 7;
			pre.deck[player][6] = estate; /* top of deck */
			pre.deck[player][5] = copper;
			pre.deck[player][4] = estate;
			pre.deck[player][3] = silver;
			pre.deck[player][2] = estate;
			pre.deck[player][1] = gold;
			pre.deck[player][0] = estate;

			if (OUTPUTLEVEL > 1) printf("Card Configuration: 1 estate on top, followed by copper, estate, silver, estate, gold, estate; discard: empty.\n");

			/* test several hand positions */
			for (handpos = 0; handpos < pre.handCount[player]; handpos++)
			{
				/* test hand positions at either end of the hand and in the middle, skip others */
				if (
					!(handpos == 0 ||
						handpos == pre.handCount[player] / 2 ||
						handpos == (pre.handCount[player] - 1))
					) continue;

				/* retain a copy the initial game state for post-comparison */
				copyGameState(&post, &pre);

				/* perform the card effect */
				bonus = 0;
				cardEffect(CARDUNDERTEST, 0, 0, 0, &post, handpos, &bonus);

				if (OUTPUTLEVEL > 1) printf("Test Standard Conditions\n");
				testStandardConditions(players, player, handpos, &pre, &post, &passes, &failures);

				if (OUTPUTLEVEL > 1) printf("Test Extra Conditions\n");

				/* verify discard contains only 1 estate card */
				if (OUTPUTLEVEL > 1) printf("Test: Added 1 estate to discard...\n");
				deltaPlayerCardTypesInDiscard(&pre, &post, player, discardDeltas);
				result = TRUE;
				for (i = 0; i <= treasure_map; i++)
				{
					if (i == estate)
					{
						if (discardDeltas[i] != 1) result = FALSE;
					}
					else
					{
						if (discardDeltas[i] != 0) result = FALSE;
					}
				}
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == TRUE, &passes, &failures);

				/* verify hand added 1 copper, 1 silver card */
				if (OUTPUTLEVEL > 1) printf("Test: Added 1 copper, 1 silver to hand...\n");
				deltaPlayerCardTypesInHand(&pre, &post, player, handDeltas);
				result = TRUE;
				for (i = 0; i <= treasure_map; i++)
				{
					if (i == copper)
					{
						if (handDeltas[i] != 1) result = FALSE;
					}
					else if (i == silver)
					{
						if (handDeltas[i] != 1) result = FALSE;
					}
					else if (i == CARDUNDERTEST) /* card that was played */
					{
						if (handDeltas[i] != -1) result = FALSE;
					}
					else
					{
						if (handDeltas[i] != 0) result = FALSE;
					}
				}
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == TRUE, &passes, &failures);
			}

			/* 6) Ensure card effect causes deck to be reshuffled when cards run out */

			/* get a fresh copy of the base gamestate */
			copyGameState(&pre, &state);

			/* stack the current player's hand with the card under test and set current player */
			pre.handCount[player] = HANDCOUNT;
			for (handpos = 0; handpos < pre.handCount[player]; handpos++) pre.hand[player][handpos] = CARDUNDERTEST;
			pre.whoseTurn = player;

			/* deck: empty, discard 1 gold, 1 silver, 1 copper */
			pre.deckCount[player] = 0;
			pre.discardCount[player] = 3;
			pre.discard[player][2] = gold;
			pre.discard[player][1] = silver;
			pre.discard[player][0] = copper;

			if (OUTPUTLEVEL > 1) printf("Card Configuration: deck empty, discard contains 1 gold, 1 silver, 1 copper.\n");

			/* test several hand positions */
			for (handpos = 0; handpos < pre.handCount[player]; handpos++)
			{
				/* test hand positions at either end of the hand and in the middle, skip others */
				if (
					!(handpos == 0 ||
						handpos == pre.handCount[player] / 2 ||
						handpos == (pre.handCount[player] - 1))
					) continue;

				/* retain a copy the initial game state for post-comparison */
				copyGameState(&post, &pre);

				/* perform the card effect */
				bonus = 0;
				cardEffect(CARDUNDERTEST, 0, 0, 0, &post, handpos, &bonus);

				if (OUTPUTLEVEL > 1) printf("Test Standard Conditions\n");
				testStandardConditions(players, player, handpos, &pre, &post, &passes, &failures);

				if (OUTPUTLEVEL > 1) printf("Test Extra Conditions\n");

				/* verify discard is empty */
				if (OUTPUTLEVEL > 1) printf("Test: Discard is empty...\n");
				result = post.discardCount[player];
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == 0, &passes, &failures);

				/* verify 2 treasures in hand */
				if (OUTPUTLEVEL > 1) printf("Test: 2 treasure cards added to hand...\n");
				deltaPlayerCardTypesInHand(&pre, &post, player, handDeltas);
				result = TRUE;
				treasures = 0;
				for (i = 0; i <= treasure_map; i++)
				{
					if (i == copper || i == silver || i == gold)
					{
						if (handDeltas[i] < 0) result = FALSE;
						treasures += handDeltas[i];
					}
					else if (i == CARDUNDERTEST) /* card that was played */
					{
						if (handDeltas[i] != -1) result = FALSE;
					}
					else
					{
						if (handDeltas[i] != 0) result = FALSE;
					}
				}
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == TRUE && treasures == 2, &passes, &failures);
			}

			/* 7) Ensure card effect will draw a single treasure card */
			/* get a fresh copy of the base gamestate */
			copyGameState(&pre, &state);

			/* stack the current player's hand with the card under test and set current player */
			pre.handCount[player] = HANDCOUNT;
			for (handpos = 0; handpos < pre.handCount[player]; handpos++) pre.hand[player][handpos] = CARDUNDERTEST;
			pre.whoseTurn = player;

			/* deck: 1 gold; discard: empty */
			pre.discardCount[player] = 0;
			pre.deckCount[player] = 1;
			pre.deck[player][0] = gold;

			if (OUTPUTLEVEL > 1) printf("Card Configuration: deck 1 gold, discard empty.\n");

			/* test several hand positions */
			for (handpos = 0; handpos < pre.handCount[player]; handpos++)
			{
				/* test hand positions at either end of the hand and in the middle, skip others */
				if (
					!(handpos == 0 ||
						handpos == pre.handCount[player] / 2 ||
						handpos == (pre.handCount[player] - 1))
					) continue;

				/* retain a copy the initial game state for post-comparison */
				copyGameState(&post, &pre);

				/* perform the card effect */
				bonus = 0;
				cardEffect(CARDUNDERTEST, 0, 0, 0, &post, handpos, &bonus);

				if (OUTPUTLEVEL > 1) printf("Test Standard Conditions\n");
				testStandardConditions(players, player, handpos, &pre, &post, &passes, &failures);

				if (OUTPUTLEVEL > 1) printf("Test Extra Conditions\n");

				/* verify discard is empty */
				if (OUTPUTLEVEL > 1) printf("Test: Discard is empty...\n");
				result = post.discardCount[player];
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == 0, &passes, &failures);

				/* verify exactly 1 gold in hand */
				if (OUTPUTLEVEL > 1) printf("Test: 1 gold card added to hand...\n");
				deltaPlayerCardTypesInHand(&pre, &post, player, handDeltas);
				result = TRUE;
				for (i = 0; i <= treasure_map; i++)
				{
					if (i == gold)
					{
						if (handDeltas[i] != 1) result = FALSE;
					}
					else if (i == CARDUNDERTEST) /* card that was played */
					{
						if (handDeltas[i] != -1) result = FALSE;
					}
					else
					{
						if (handDeltas[i] != 0) result = FALSE;
					}
				}
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == TRUE, &passes, &failures);
			}

			/* 8) Ensure card effect will draw a single treasure card */
			/* get a fresh copy of the base gamestate */
			copyGameState(&pre, &state);

			/* stack the current player's hand with the card under test and set current player */
			pre.handCount[player] = HANDCOUNT;
			for (handpos = 0; handpos < pre.handCount[player]; handpos++) pre.hand[player][handpos] = CARDUNDERTEST;
			pre.whoseTurn = player;

			/* deck: 1 silver; discard: empty */
			pre.discardCount[player] = 0;
			pre.deckCount[player] = 1;
			pre.deck[player][0] = silver;

			if (OUTPUTLEVEL > 1) printf("Card Configuration: deck 1 silver, discard empty.\n");

			/* test several hand positions */
			for (handpos = 0; handpos < pre.handCount[player]; handpos++)
			{
				/* test hand positions at either end of the hand and in the middle, skip others */
				if (
					!(handpos == 0 ||
						handpos == pre.handCount[player] / 2 ||
						handpos == (pre.handCount[player] - 1))
					) continue;

				/* retain a copy the initial game state for post-comparison */
				copyGameState(&post, &pre);

				/* perform the card effect */
				bonus = 0;
				cardEffect(CARDUNDERTEST, 0, 0, 0, &post, handpos, &bonus);

				if (OUTPUTLEVEL > 1) printf("Test Standard Conditions\n");
				testStandardConditions(players, player, handpos, &pre, &post, &passes, &failures);

				if (OUTPUTLEVEL > 1) printf("Test Extra Conditions\n");

				/* verify discard is empty */
				if (OUTPUTLEVEL > 1) printf("Test: Discard is empty...\n");
				result = post.discardCount[player];
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == 0, &passes, &failures);

				/* verify exactly 1 silver in hand */
				if (OUTPUTLEVEL > 1) printf("Test: 1 silver card added to hand...\n");
				deltaPlayerCardTypesInHand(&pre, &post, player, handDeltas);
				result = TRUE;
				for (i = 0; i <= treasure_map; i++)
				{
					if (i == silver)
					{
						if (handDeltas[i] != 1) result = FALSE;
					}
					else if (i == CARDUNDERTEST) /* card that was played */
					{
						if (handDeltas[i] != -1) result = FALSE;
					}
					else
					{
						if (handDeltas[i] != 0) result = FALSE;
					}
				}
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == TRUE, &passes, &failures);
			}

			/* 9) Ensure card effect will draw a single treasure card */
			/* get a fresh copy of the base gamestate */
			copyGameState(&pre, &state);

			/* stack the current player's hand with the card under test and set current player */
			pre.handCount[player] = HANDCOUNT;
			for (handpos = 0; handpos < pre.handCount[player]; handpos++) pre.hand[player][handpos] = CARDUNDERTEST;
			pre.whoseTurn = player;

			/* deck: 1 copper; discard: empty */
			pre.discardCount[player] = 0;
			pre.deckCount[player] = 1;
			pre.deck[player][0] = copper;

			if (OUTPUTLEVEL > 1) printf("Card Configuration: deck 1 copper, discard empty.\n");

			/* test several hand positions */
			for (handpos = 0; handpos < pre.handCount[player]; handpos++)
			{
				/* test hand positions at either end of the hand and in the middle, skip others */
				if (
					!(handpos == 0 ||
						handpos == pre.handCount[player] / 2 ||
						handpos == (pre.handCount[player] - 1))
					) continue;

				/* retain a copy the initial game state for post-comparison */
				copyGameState(&post, &pre);

				/* perform the card effect */
				bonus = 0;
				cardEffect(CARDUNDERTEST, 0, 0, 0, &post, handpos, &bonus);

				if (OUTPUTLEVEL > 1) printf("Test Standard Conditions\n");
				testStandardConditions(players, player, handpos, &pre, &post, &passes, &failures);

				if (OUTPUTLEVEL > 1) printf("Test Extra Conditions\n");

				/* verify discard is empty */
				if (OUTPUTLEVEL > 1) printf("Test: Discard is empty...\n");
				result = post.discardCount[player];
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == 0, &passes, &failures);

				/* verify exactly 1 copper in hand */
				if (OUTPUTLEVEL > 1) printf("Test: 1 copper card added to hand...\n");
				deltaPlayerCardTypesInHand(&pre, &post, player, handDeltas);
				result = TRUE;
				for (i = 0; i <= treasure_map; i++)
				{
					if (i == copper)
					{
						if (handDeltas[i] != 1) result = FALSE;
					}
					else if (i == CARDUNDERTEST) /* card that was played */
					{
						if (handDeltas[i] != -1) result = FALSE;
					}
					else
					{
						if (handDeltas[i] != 0) result = FALSE;
					}
				}
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == TRUE, &passes, &failures);
			}

			/* Ensure card effect will draw no cards if no treasures are available */
			/* get a fresh copy of the base gamestate */
			copyGameState(&pre, &state);

			/* stack the current player's hand with the card under test and set current player */
			pre.handCount[player] = HANDCOUNT;
			for (handpos = 0; handpos < pre.handCount[player]; handpos++) pre.hand[player][handpos] = CARDUNDERTEST;
			pre.whoseTurn = player;

			/* deck: 5 estates, 0 treasures; discard: empty */
			pre.discardCount[player] = 0;
			pre.deckCount[player] = 5;
			for (deckpos = 0; deckpos < pre.deckCount[player]; deckpos++) pre.deck[player][deckpos] = estate;

			if (OUTPUTLEVEL > 1) printf("Card Configuration: deck 5 estates, discard empty.\n");

			/* test several hand positions */
			for (handpos = 0; handpos < pre.handCount[player]; handpos++)
			{
				/* test hand positions at either end of the hand and in the middle, skip others */
				if (
					!(handpos == 0 ||
						handpos == pre.handCount[player] / 2 ||
						handpos == (pre.handCount[player] - 1))
					) continue;

				/* retain a copy the initial game state for post-comparison */
				copyGameState(&post, &pre);

				/* perform the card effect */
				bonus = 0;
				cardEffect(CARDUNDERTEST, 0, 0, 0, &post, handpos, &bonus);

				if (OUTPUTLEVEL > 1) printf("Test Standard Conditions\n");
				testStandardConditions(players, player, handpos, &pre, &post, &passes, &failures);

				if (OUTPUTLEVEL > 1) printf("Test Extra Conditions\n");

				/* verify 0 treasures added to hand */
				if (OUTPUTLEVEL > 1) printf("Test: 0 treasure cards added to hand...\n");
				deltaPlayerCardTypesInHand(&pre, &post, player, handDeltas);
				result = TRUE;
				for (i = 0; i <= treasure_map; i++)
				{
					if (i == CARDUNDERTEST) /* card that was played */
					{
						if (handDeltas[i] != -1) result = FALSE;
					}
					else
					{
						if (handDeltas[i] != 0) result = FALSE;
					}
				}
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == TRUE, &passes, &failures);

				/* verify discard contains 5 estates */
				if (OUTPUTLEVEL > 1) printf("Test: 5 estates in discard...\n");
				deltaPlayerCardTypesInDiscard(&pre, &post, player, discardDeltas);
				result = TRUE;
				for (i = 0; i <= treasure_map; i++)
				{
					if (i == estate)
					{
						if (discardDeltas[i] != 5) result = FALSE;
					}
					else if (i == CARDUNDERTEST) /* card that was played */
					{
						if (discardDeltas[i] != -1) result = FALSE;
					}
					else
					{
						if (discardDeltas[i] != 0) result = FALSE;
					}
				}
				if (OUTPUTLEVEL > 1) printf("Result: ");
				updateTestResult(result == TRUE, &passes, &failures);
			}
		}
	}

	if (OUTPUTLEVEL > 0)
	{
		if (OUTPUTLEVEL > 1) printf("\n");
		printf("SUMMARY for " FILENAME " (" xstr(CARDUNDERTEST) "): ");
		if (failures == 0) printf("passed all %d tests.\nTesting Outcome: SUCCESS!\n", passes);
		else
		{
			printf("failed %d of %d tests.\n", failures, passes + failures);
			printf("Testing Outcome: FAILED!\n");
			if (OUTPUTLEVEL > 1) printf("See results output above.\n");
		}
		printf("*** END " FILENAME " (cardEffect unit test for " xstr(CARDUNDERTEST) ") ***\n");
	}

	return failures != 0 ? 1 : 0;
}