Собственно, буквально за несколько дней до того как Белокрылов
привел нам пример экспертной системы, которая угадывает слово
по принципу ответа да/нет, мой начальник на работе показал
мне очень похожую прогу, написанную им самим и предложенную как
альтернатива зачёту в одной из групп ИТМО. :)

Прога называется Cat :)
Принцип работы, как и реализация, очень прост:
Программа при старте спрашивает "Это кот?"
Если нет, то идет по вершинам дерева свойств предметов.
Если слово отгадано, то игра заканчивается,
если нет, то прости ввести само слово и его свойство.
Все изменения в дереве сохраняются.

Конечно это упрощенный вариант того о чем говорил Белокрылов,
но все же позволяет понять принцип её работы!

Exe-шник с небольшим деревом ответов
Инструкции:
набирать в консоли можно только буквами латиницей
положительный ответ "Y", отрицательный "N"

А вот исходный код:
(всего то ~200 строк кода :))

Код:
#define EE_MARK "ee"

struct TREE_ITEM
{
	char *question;
	TREE_ITEM *down, *next;
};



TREE_ITEM*
AllocateNode(const char *question)
{
	TREE_ITEM *pItem = (TREE_ITEM*)malloc(sizeof(TREE_ITEM));
	if (!pItem)
return NULL;

	pItem->down = pItem->next = NULL;
	pItem->question = strdup(question);
	return pItem;
}

void
FreeNode(TREE_ITEM *pNode)
{
	if (!pNode)
return;

	free(pNode->question);
	free(pNode);
}


void FreeTree(TREE_ITEM *pTree)
{
	if (!pTree)
return;

	FreeTree(pTree->next);
	FreeTree(pTree->down);
	FreeNode(pTree);
}

void SaveSubTree(FILE *fp, TREE_ITEM *pTree, INT n = 0)
{
	char *s = (char *)calloc(n + 1, 1);
	memset(s, ' ', n);
	if (!pTree)
	{
fprintf(fp, "%s%s\n", s, EE_MARK);
free(s);
return;
	}
    fprintf(fp, "%s%s\n", s, pTree->question);
	SaveSubTree(fp, pTree->next, n + 1);
	SaveSubTree(fp, pTree->down, n + 1);
	free(s);
}

void PrintTree(TREE_ITEM *pTree)
{
	puts("---------------------------------");
	SaveSubTree(stdout, pTree);
	puts("---------------------------------");
}

void SaveTree(TREE_ITEM *pTree)
{
	CopyFile("tree", "tree.old", FALSE);
	FILE *fp = fopen("tree", "wt");
	if (!fp)
return;
	SaveSubTree(fp, pTree);
	fclose(fp);
}

char *SkipSpaces(char *p)
{
	while (*p && (*p == ' '))
p++;
	return p;
}

TREE_ITEM* LoadSubTree(FILE *fp)
{
	char str[1024];
	fgets(str, sizeof(str), fp);
	if (str[strlen(str) - 1] == '\n')
str[strlen(str) - 1] = 0;
	char *p = SkipSpaces(str);
	if (!strcmp(p, EE_MARK))
return NULL;
	TREE_ITEM *pRet = AllocateNode(p);
	pRet->next = LoadSubTree(fp);
	pRet->down = LoadSubTree(fp);
	return pRet;
}

TREE_ITEM *LoadTree()
{
    FILE *fp = fopen("tree", "rt");
	if (!fp)
return NULL;
	TREE_ITEM *pRet = LoadSubTree(fp);
	fclose(fp);
	return pRet;
}

bool
YesNo()
{
	while (TRUE)
	{
char c = toupper(getchar());
getchar();
if (c == 'Y')
	return true;
else if (c == 'N')
	return false;
	}
}

void Run(TREE_ITEM *pRoot)
{
	TREE_ITEM *pCur = pRoot, *pPrev;
	while (pCur)
	{
printf("Eto %s? ", pCur->question);
if (YesNo())
{
	if (pCur->down)
Run(pCur->down);
	else
puts("Uraaaaaaaaaa!!!");
	return;
}
else
{
	pPrev = pCur;
	pCur = pCur->next;
}
	}
	puts("Chto eto?");
	char name[1024];
	gets(name);
	char dif[1024];
	printf("Chem otlichaetsia ot %s?\n", pPrev->question);
	gets(dif);
	pPrev->next = AllocateNode(dif);
	pPrev->next->down = AllocateNode(name);
}

int _tmain(int argc, _TCHAR* argv[])
{ 
	SetConsoleCP(1251);
	SetConsoleOutputCP(1251);
	TREE_ITEM *pRoot = LoadTree();
	if (!pRoot)
	{
pRoot = AllocateNode("Kot");
if (!pRoot)
	return -1;
	}
	PrintTree(pRoot);
	Run(pRoot);
	PrintTree(pRoot);
	SaveTree(pRoot);
	FreeTree(pRoot);
	puts("Press ENTER to exit");
	getchar();
	return 0;
}