Before playing the game, it must be installed and compiled. There are a few requirements to do this:
files from below this userguide, and save them into the same directory. Then you need to use
and pressing return - after that it should launch and you can go ahead and move on to the next section of this guide.
From this menu, you have three options. Simply press the coloured letter to select that option. In this case, pressing
will quit the game. It doesn't mater if the letter you press is uppercase or lowercase when you select it - the game is case-insensitive.
It's also worth noting that all menus in this game work the same way. When you are presented with a selection, your options will have a bolded letter and pressing that letter on the keyboard will select that option.
When you begin a new game by selecting the new game option from the main menu, you need to think of one of the animals the game knows. The game will then ask you questions in an attempt to determine which animal you have selected in your mind:
Answer the questions, and when it has reached a conclusion, it will guess the animal you have thought of:
If it fails to reach a conclusion, then you have tricked the game (or cheated!) and the game will admit defeat:
file contains a list of animals and their attributes. The format of this file is controlled by several parameters in the source of
, but the default format is quite simple. There is one animal per line. The line begins with the name of the animal, followed by it's attributes (space-separated). There is a single colon (:) separating the animal's name from it's attributes. This results in the database file shown towards the bottom of this page.
This file allows the game to be expanded to additional animals without needing to be recompiled. Only certain attributes are recognised by the game at this time. These include:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <regex.h>
/* Animal database setup */
// In the DB file, this separates the animal from it's attributes.
#define S_DBFILE_KEY_DELIM ":"
// This separates each attribute from the others.
#define S_DBFILE_FLAG_DELIM " "
// This separates each entry containing attributes and animals.
#define S_DBFILE_ENTRY_DELIM "\n"
/*
Under default settings, the DB file would look like:
animal1:attribute1 attribute2
animal2:attribute2 attribute3
[..etc..]
*/
// The path to the DB file itself.
#define P_DBFILE "./animals.db"
// You can download the default file from:
// http://kevinsnet.com/subsites/uni/IntroComputing/animals.db
// The number of entries in the DB file. The default file has 30.
#define I_TOTAL_ANIMALS 30;
/* Game setup */
// The name of the game.
#define S_NAME "20 Questions"
// The version of the game.
#define S_VERSION "0.1c"
// Enable debug mode?
#define I_DEBUG 0
/* Debug mode, when set to 1, outputs extra information about
* the data loaded from the database at startup and the process
* of deducting the impossible answers during gameplay. Enable it
* to see this information.
/*
/* Output setup */
// Prefix status output with this:
#define S_STATUS "-\e[97;1m:\e[0m- "
// Prefix informational output with this:
#define S_INFO "-\e[94;1mi\e[0m- "
// Prefix error output with this:
#define S_ERROR "-\e[91;1m!\e[0m- "
// Prefix requests for input from the user with this:
#define S_QUESTION "-\e[93;1m?\e[0m- "
// Prefix win-notices with this:
#define S_WINNER "-\e[92;1m$\e[0m- "
// Prefix lose-notices with this:
#define S_LOSER "-\e[93;1m|\e[0m- "
// ANSI code to clear the screen:
#define A_CLEAR "\e[2J"
// ANSI code for bold text:
#define A_BOLD "\e[93;1m"
/* Note: ANSI bolded text doesn't look right on all the systems
* tested on, so instead I'm colouring it yellow. It seems to work
* better than bolding it on some terminals, plus, it looks nice.
*/
// ANSI code to reset output to normal:
#define A_NORM "\e[0m"
/* End of configuration */
// Declare the functions we're gonna make later.
int unbufGetc
();
void startGame
();
void quitGame
();
void listAnimals
();
void doMainMenu
();
int getUserAnswer
();
void endGame
();
// The following variables are defined in a global context,
// because these won't always pass between function correctly.
// Their data is actually defined in the configuration section above.
int totalAnimals = I_TOTAL_ANIMALS;
int debugMode = I_DEBUG;
// The main subroutine.
int main
( void ){
// Variable declaration. These are all variables we're gonna use in main().
FILE *dbHandle;
char *stringBuffer;
char fileBuffer
[128];
char strAnimalList
[1024] =
"";
char tmpBuffer
[128] =
"";
char dbAnimals
[totalAnimals
][128];
char dbFlags
[totalAnimals
][128];
int lineCount =
0;
int cycleCount =
0;
int phaseCount =
0;
int loopCount =
0;
int tmpInt =
0;
fpos_t dbPosition;
printf("%s%s%s v%s starting up...\n", A_CLEAR, S_STATUS, S_NAME, S_VERSION
);
// Open the DB file for reading, or prompt the user to download it if it can't be read.
if((dbHandle = fopen
(P_DBFILE,
"r")) ==
NULL){
printf("%sCannot open the DB file. Enter the following URL in a web browser,\n", S_ERROR
);
printf("%sand save the resulting file into the directory you're currently in:\n", S_ERROR
);
printf("%shttp://kevinsnet.com/subsites/uni/IntroComputing/animals.db\n", S_ERROR
);
// We output our error, so exit with an error code.
exit
(1);
}
// Set &dbPosition to the beginning of the file, so that we can read some data from it, and then
// set it back to this position to re-read some of it.
fgetpos
(dbHandle, &dbPosition
);
// While we're not at the end of the DB file,
while(!feof
(dbHandle
)){
if(fgets
(fileBuffer,
126, dbHandle
)){
// increase the linecount by one if it's not null.
lineCount++;
}
}
// And now we put ourself back at the beginning of the DB file.
fsetpos
(dbHandle, &dbPosition
);
// Set some counters to zero.
cycleCount =
0;
phaseCount =
0;
// While we're not at the end of the DB file,
while(!feof
(dbHandle
)){
// read some of the data into fileBuffer
if(fgets
(fileBuffer,
126, dbHandle
)){
// then use strtok to split it by the entry delimiter defined above
stringBuffer = strtok
(fileBuffer, S_DBFILE_KEY_DELIM
);
// and if the result's not empty,
while(stringBuffer !=
NULL){
// and the phase counter is zero
if(phaseCount ==
0){
// then we have an animal name. store it in the array.
strcpy
(dbAnimals
[cycleCount
], stringBuffer
);
// and toggle the phase for the next strtok operation.
phaseCount =
1;
// but if the phase count isn't zero
}else{
// then we have attribute flags. store it in the flags array.
strcpy
(dbFlags
[cycleCount
], stringBuffer
);
// and toggle the phase for the next strtok operation.
phaseCount =
0;
}
// repeat strtok til we've read in all the entries in the DB.
stringBuffer = strtok
(NULL, S_DBFILE_ENTRY_DELIM
);
}
// and increase the cycleCount.
cycleCount++;
}
}
// when we're done, we close the DB file.
fclose
(dbHandle
);
// more counters go back to zero.
tmpInt =
0;
phaseCount =
0;
loopCount =
0;
// while the loop counter is less than the number of lines in the file,
while(loopCount < lineCount
){
// print an animal and it's attributes, but only if debug mode is on.
printf(debugMode>
0?
"%sAnimal '%s' with attributes '%s' loaded.\n":
"",
S_STATUS, dbAnimals
[loopCount
], dbFlags
[loopCount
]);
// if this isn't the first iteration of the loop,
if(loopCount >
0){
// and the phase counter is more than one
if(phaseCount >
1){
// enter a newline and a tab into a temporary buffer.
strcpy
(tmpBuffer,
"\n\t");
// then set the phase counter back to zero.
phaseCount =
0;
// but if the phase counter isn't more than one,
}else{
// check the temporary integer (which should contain a strlen)
// if it's more than seven,
if(tmpInt >
7){
// enter a single tab in the temporary buffer.
strcpy
(tmpBuffer,
"\t");
// if it's less than seven
}else{
// enter two tabs in the temporary buffer.
strcpy
(tmpBuffer,
"\t\t");
}
// then increase the phase counter by one.
phaseCount++;
}
// otherwise, if it is the first iteration of the loop,
}else{
// enter a single tab in the temporary buffer.
strcpy
(tmpBuffer,
"\t");
}
// set the temporary integer to the length of the name of the current iteration numbered animal
tmpInt = strlen
(dbAnimals
[loopCount
]);
// and add that animal's name to the temporary buffer.
strcat
(tmpBuffer, dbAnimals
[loopCount
]);
// then put the contents of the temporary buffer into the animal list
strcat
(strAnimalList, tmpBuffer
);
// and increase the loop count by one.
loopCount++;
}
/* This whole while loop results in the animal list
* string containing a nice, evenly formatted,
* three-column list of all the animals in the DB file.
* the strlen is used to calculate the amount of space
* needed between animal names to space the columns easily.
*/
if(cycleCount <
1 || strlen
(dbAnimals
[0]) ==
0 || strlen
(dbFlags
[0]) ==
0){
printf("%sThe DB file is corrupt. Enter the following URL in a web browser,\n", S_ERROR
);
printf("%sand save the resulting file into the directory you're currently in:\n", S_ERROR
);
printf("%shttp://kevinsnet.com/subsites/uni/IntroComputing/animals.db\n", S_ERROR
);
exit
(1);
}
// Display the number of animals loaded.
printf("%s%u of %u animals loaded from the database.\n", S_STATUS, cycleCount, lineCount
);
// And call the function to output the nicely formatted list.
listAnimals
(strAnimalList
);
// Then just print out some help information.
printf("\n%sTIP: At any menu, press the bolded key to select that option.\n", S_INFO
);
// And show them the main menu, passing it some useful information needed to generate the menu.
doMainMenu
(lineCount, dbAnimals, dbFlags, strAnimalList
);
return 0;
}
// This function generates the main menu. It should never return, because it should always be there somewhere.
// It takes an integer containing the number of DB entries, an array of animals, an array of flags, and
// the stringed animal list as parameters.
void doMainMenu
(int lineCount,
char dbAnimals
[totalAnimals
][128],
char dbFlags
[totalAnimals
][128],
char strAnimalList
[1024]) {
// Give us an empty integer please.
int keypress =
0;
// Infinite loop. Really, if this exists, then maths as *I* know it has come to an end.
while(1 ==
1){
// Print the menu, nicely formatted please.
printf("\n%s[GAME MENU] %sN%sew game, %sQ%suit, %sL%sist known animals.\n",
S_QUESTION, A_BOLD, A_NORM, A_BOLD, A_NORM, A_BOLD, A_NORM
);
// Get the user's selection from the standard input using unbufGetc().
// unbufGetc is a custom function for getting input.
keypress = unbufGetc
(stdin
);
// If the keypress is...
switch(keypress
) {
// .. lowercase n
case 78:
// start the game, pass it some useful parameters.
startGame
(lineCount, dbAnimals, dbFlags
);
break;
// .. uppercase n
case 110:
// start the game, pass it some useful parameters.
startGame
(lineCount, dbAnimals, dbFlags
);
break;
// .. lowercase q
case 81:
// go to where we exit the application.
quitGame
();
break;
// .. uppercase q
case 113:
// go to where we exit the application.
quitGame
();
break;
// .. lowercase l
case 76:
// list the animals, pass it our animal list string
listAnimals
(strAnimalList
);
break;
// .. uppercase l
case 108:
// list the animals, pass it our animal list string
listAnimals
(strAnimalList
);
break;
}
}
}
// This function quits the game with a successful exit code.
// It returns nothing and requires no parameters -- THERE IS NO RETURN.
void quitGame
() {
// Let the user know that they wanted to exit.
// We'll try to make them feel bad about leaving, but it's really too late.
printf("\n%sUser is exiting... Please don't leave ;_;\n", S_STATUS
);
// Exit, successfully, since there were no errors.
exit
(0);
}
// This function actually runs the game. It takes a couple parameters -- the number of files in the DB
// and the arrays of animals and flags. It returns nothing, as when it returns, the game ended somehow
// (either the user ended it or someone won/lost) and it returns to the main menu.
void startGame
(int lineCount,
char dbAnimals
[totalAnimals
][128],
char dbFlags
[totalAnimals
][128]) {
// Setup our variables.
// For the most part, these are integers or empty strings/arrays we need.
int userResponse =
0;
// stateInt is special. We start this at 11, see below for the reasoning.
int stateInt =
11;
int oldInt =
0;
int loopCount =
0;
int possibleCount =
0;
int tmpCount =
0;
int questionCount =
0;
// This is a multidimensional array. Each state will have it's own entry of
// totalAnimals entries in the array. See below for information about the states.
char possibleAnimals
[99][totalAnimals
][128];
char possibleFlags
[99][totalAnimals
][128];
// Also declare regex and regmatch pointers. These are used for the regexing.
// .. I'll explain a below.
regex_t *regex;
regmatch_t *matches;
/* Information:
* A lot happens below. For a start, there's going to be a series of while loops based
* around an integer, stateInt. Originally this was just a way to control the asking of
* questions, to allow us to just loop through a question until we got some kind of valid
* input, and the integers were just gonna be sequential from 0 up.
* In the end, it was decided that the state integer could also be used to prevent
* contradicting questions from being asked, so, questions in similar "groups" will have
* a similar digits in the tens-place (ie, transportation method - swimming/flying/underground
* all have a 1 in the tens-place) and then the question number is in the ones place.
* This makes it easier to keep track of.
* Since, as a result of this state numbering system, the tens place can go up to 9, the
* animals and flags arrays declared above require 99 arrays rather than the just-under-20
* that would otherwise be required.
* In addition, I decided to switch from using strtok() to parse up the parameters to
* using regexes. strtok() requires a lot of repetition and there is simply nothing better
* than a good cup of regexes when you're sifting through strings.
*/
// While the state is 11,
while(stateInt ==
11){
// get the user's response to the question using a custom function, getUserAnswer().
userResponse = getUserAnswer
("Can your animal swim?");
// If their answer was ...
switch(userResponse
){
// ... yes,
case 1:
// zero some counters,
possibleCount =
0;
loopCount =
0;
// then loop through the lines in the db, and for each one,
while(loopCount < lineCount
){
// compile a simple regex: /swimming/
regcomp
(regex,
"swimming",
0);
// if the regex matches
if(regexec
(regex, dbFlags
[loopCount
],
0, matches,
0) ==
0){
// and the entry is blank,
if(strlen
(dbAnimals
[loopCount
]) ==
0){
// skip this cycle
break;
};
// but if it matches and it's not blank, print out some debug info if we want,
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, dbAnimals
[loopCount
]);
// and then copy the animal and it's flags into the new arrays.
strcpy
(possibleAnimals
[stateInt
][possibleCount
], dbAnimals
[loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], dbFlags
[loopCount
]);
possibleCount++;
}
// and the loop counter goes up one.
loopCount++;
}
// if there are no animals that match at all,
if(possibleCount ==
0){
// we lose
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
// print some stats
endGame
(questionCount
);
// and go back to the main menu.
return;
}
// if there's one possible match,
if(possibleCount ==
1){
// we won!
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
// print some stats
endGame
(questionCount
);
// and go back to the main menu.
return;
}
// set oldInt to our current state integer,
oldInt = stateInt;
// increase our question count, and then set the state integer to the next state.
questionCount++;
stateInt =
21;
break;
// ... no,
case 2:
// zero some counters
possibleCount =
0;
loopCount =
0;
// loop through each DB entry,
while(loopCount < lineCount
){
// compile a simple regex: /swimming/
regcomp
(regex,
"swimming",
0);
// and then if it DOESN'T match,
if(regexec
(regex, dbFlags
[loopCount
],
0, matches,
0) !=
0){
// and it's blank,
if(strlen
(dbAnimals
[loopCount
]) ==
0){
// skip this one.
break;
};
// but if it's not blank, spit out some debug info,
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, dbAnimals
[loopCount
]);
// and then copy it to the new arrays.
strcpy
(possibleAnimals
[stateInt
][possibleCount
], dbAnimals
[loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], dbFlags
[loopCount
]);
possibleCount++;
}
// loop counter goes up.
loopCount++;
}
// we lose again...
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
// we win again...
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
// oldInt is set to our state.
oldInt = stateInt;
// question counter goes up.
questionCount++;
// change state.
stateInt =
12;
break;
// ... quit,
case 3:
// then quit back to the main menu
return;
break;
}
}
// We're going to repeat this for each state, using new flags, and we're going to regex it
// against the results in the arrays from the last state, rather than the array with the animals
// from the DB. This results in the arrays getting smaller and smaller, resulting in a win or a
// lose through the process of elimination.
while(stateInt ==
12){
userResponse = getUserAnswer
("Can your animal fly?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"flying",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
21;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"flying",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
13;
break;
case 3:
return;
break;
}
}
// And again.
while(stateInt ==
13){
userResponse = getUserAnswer
("Does your animal live underground?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"underground",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
21;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"underground",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
21;
break;
case 3:
return;
break;
}
}
// .... aaaand again.
while(stateInt ==
21){
userResponse = getUserAnswer
("Is your animal a feline?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"feline",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
31;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"feline",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
22;
break;
case 3:
return;
break;
}
}
// ... Guess what we're doing again!?
while(stateInt ==
22){
userResponse = getUserAnswer
("Is your animal an arachnid?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"arachnid",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
31;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"arachnid",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
23;
break;
case 3:
return;
break;
}
}
// Third time's a charm, but hey, we're well past our third run.
while(stateInt ==
23){
userResponse = getUserAnswer
("Is your animal an insect?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"insect",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
31;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"insect",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
24;
break;
case 3:
return;
break;
}
}
// Again and again, and again and again.
while(stateInt ==
24){
userResponse = getUserAnswer
("Is your animal a canine?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"canine",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
31;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"canine",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
31;
break;
case 3:
return;
break;
}
}
// Do it again, do it again! -- these are song lyrics, just so you know.
while(stateInt ==
31){
userResponse = getUserAnswer
("Can your animal be found in a jungle?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"jungle",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
91;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"jungle",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
32;
break;
case 3:
return;
break;
}
}
// It's called "Again and again".
while(stateInt ==
32){
userResponse = getUserAnswer
("Can your animal be found on a farm?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"farm",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
91;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"farm",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
33;
break;
case 3:
return;
break;
}
}
// "Again and again" which is by The Bird and the Bee.
while(stateInt ==
33){
userResponse = getUserAnswer
("Can your animal be found in the desert?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"desert",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
91;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"desert",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
91;
break;
case 3:
return;
break;
}
}
// The song was used in a popular Mac music video. Oddly enough, it's called "Again and again"
while(stateInt ==
91){
userResponse = getUserAnswer
("Is your animal a herbivore?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"herbivore",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
92;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"herbivore",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
92;
break;
case 3:
return;
break;
}
}
// Look it up on YouTube -- search for "Again and again".
while(stateInt ==
92){
userResponse = getUserAnswer
("Can your animal be domesticated?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"domesticated",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
93;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"domesticated",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
93;
break;
case 3:
return;
break;
}
}
// In fact, I've done it for you -- "Again and again": http://uk.youtube.com/watch?v=6kxDxLAjkO8
while(stateInt ==
93){
userResponse = getUserAnswer
("Does your animal lay eggs?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"eggs",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
94;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"eggs",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
94;
break;
case 3:
return;
break;
}
}
// You can also buy the song on iTunes -- it's called "Again and again"
while(stateInt ==
94){
userResponse = getUserAnswer
("Can your animal camouflage itself?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"camouflage",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
95;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"camouflage",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
95;
break;
case 3:
return;
break;
}
}
// This is the last one. That's good, cause I'm running out of witty commentary.
while(stateInt ==
95){
userResponse = getUserAnswer
("Can you get milk from your animal?");
switch(userResponse
){
case 1:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"milk",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) ==
0){
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
100;
break;
case 2:
possibleCount =
0;
loopCount =
0;
while(loopCount < lineCount
){
regcomp
(regex,
"milk",
0);
if(regexec
(regex, possibleFlags
[oldInt
][loopCount
],
0, matches,
0) !=
0){
if(strlen
(possibleAnimals
[oldInt
][loopCount
]) ==
0){
break;
};
printf(debugMode>
0?
"%sIt could be '%s'.\n":
"", S_INFO, possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleAnimals
[stateInt
][possibleCount
], possibleAnimals
[oldInt
][loopCount
]);
strcpy
(possibleFlags
[stateInt
][possibleCount
], possibleFlags
[oldInt
][loopCount
]);
possibleCount++;
}
loopCount++;
}
if(possibleCount ==
0){
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
return;
}
if(possibleCount ==
1){
printf("%sYour animal is: %s!\n", S_WINNER, possibleAnimals
[stateInt
][0]);
endGame
(questionCount
);
return;
}
oldInt = stateInt;
questionCount++;
stateInt =
100;
break;
case 3:
return;
break;
}
}
// Using the default animals.db, there should be no way to get this far. But if you did, we admit defeat.
printf("%sNope, I can't guess your animal. You outsmarted me...this time!\n", S_LOSER
);
endGame
(questionCount
);
// And then we go back to the main menu so you can defeat us again. Cheater.
return;
}
// This function generates and generates some statistics about the game played.
// It takes the question count as a paramter and returns nothing.
void endGame
(int questionCount
) {
printf("%sYou answered %u questions.\n", S_INFO,
(questionCount +
1));
return;
}
// And this function takes our nicely formatted list of animals we made when the game
// first started as a parameter, and prints the list of animals. Then it returns nothing.
void listAnimals
(char strAnimalList
[1024]) {
printf("%sI know the following animals:\n%s\n", S_INFO, strAnimalList
);
return;
}
// This displays the question (passed as parameter) we're asking the user, and their choices.
// It returns 1 if they selected YES, 2 if they selected NO, 3 if they selected QUIT, or
// 0 if the button they pressed didn't match any of the available selections.
int getUserAnswer
(char *userQuestion
) {
// Output the question & choices.
printf("%s[MENU] %s %sY%ses/%sN%so/%sQ%suit to menu\n",
S_QUESTION, userQuestion, A_BOLD, A_NORM, A_BOLD, A_NORM, A_BOLD, A_NORM
);
// Set the integer keypress to the number identifying the button the user pressed.
// Call our own unbufGetc to do this, and get it from the standard input.
int keypress = unbufGetc
(stdin
);
// If the user pressed...
switch(keypress
){
// .. lowercase y
case 89:
// we give a 1.
return 1;
break;
// .. capital y
case 121:
// we give a 1.
return 1;
break;
// .. lowercase n
case 78:
// we give a 2.
return 2;
break;
// .. capital n
case 110:
// we give a 2.
return 2;
break;
// .. lowercase q
case 81:
// and a 3...
return 3;
break;
// .. capital q
case 113:
// and a 3...
return 3;
break;
// or, if the user can't follow directions...
default:
// they get NOTHING.
return 0;
break;
}
// if we get this far, switch() broke, so we'll give you nothing.
return 0;
}
// and the function you heard so much about before, unbufGetc.
// this takes a file point as a parameter (it'll usually be stdin)
// and returns a keypress code. it's a little more complicated though.
int unbufGetc
(FILE *getcHandle
) {
// this function is why I included termios.h...
// make two structs to hold terminal data in.
struct termios termIOold;
struct termios termIOnew;
// store the current terminal atrributes in one of those structs.
tcgetattr
(0, &termIOold
);
// and make the other struct match the first.
termIOnew = termIOold;
// now we're going to change some of the terminals parameters so that
// when the user presses a button, it is directly passed to us without
// waiting for them to press return/enter to pass it to us.
// (this is what the unbuf means, it's an unbuffered input.)
termIOnew.
c_lflag &= ~
(ICANON|ECHO
);
tcsetattr
(0, TCSANOW, &termIOnew
);
// get the keypress! it'll only be a single one since we're not buffering
// keypresses at this point.
int keypress = getc
(getcHandle
);
// put the terminal back to normal.
tcsetattr
(0, TCSANOW, &termIOold
);
/* we could just leave the terminal in an unbuffered state for the duration of
* the execution and set it back to normal on exit, but if we do that then we
* risk the user having a cocked up terminal if they stop execution uncleanly
* (for example by pressing ^C or killing our PID)... so changing it back and
* forth several dozen times is a slightly more friendly way to do it.
*/
// and return the keypress as an integer.
return keypress;
}