MENSA triangle riddle

Simon F said:
cristic said:
I remember this puzzle, it was part of a Prolog assignment... 8)

Which'd probably mean it was about 20~30 lines of code :)

Ah, memories, that made me dig up that old homework... :)
Actually the riddle was not the same, but a similiar one:


On a street, there are five houses. There is a man living in each house. They all have different nationalities, different pets, different color, smoking and drinking preferences. What we know is:

* the Englishman lives in the red house
* the man living in the green house drinks coffee
* the Italian drinks tea
* the man living in the yellow house smokes Kent
* the man drinking milk lives in the middle house
* the Russian lives in the leftmost house
* the man smoking Marlboro lives next to the man having a fox
* the man smoking Kent lives next to the man having a horse
* the man drinking juice smokes Pall Mall
* the Japanese smokes Assos
* the Russian lives next to the blue house
* the Spanish has a dog
* the man having a snake smokes Camel
* the grey house lies near the green house
* the man having a cat and the man drinking vodka live in the lateral houses

You are invited to manually find an answer to the following question: "Find a suitable distribution of nationalities, pets, colors, cigarettes and drinks, so that all the above requirements are satisfied".


And the grand solution was a little bit longer than 20-30 lines of code... though I wouldn't know how to make it more concise. :|

Code:
solve(S) :-
	S = [_,_,_,_,_],
	nationality(O1,englishman),color(O1,red),member(O1,S),
	color(O2,green),drink(O2,coffee),member(O2,S),
	nationality(O3,italian),drink(O3,tea),member(O3,S),
	color(O4,yellow),cigarette(O4,kent),member(O4,S),
	drink(O5,milk),middle(O5,S),
	nationality(O6,russian),leftmost(O6,S),
	cigarette(OA7,marlboro),pet(OB7,fox),near(OA7,OB7,S),
	cigarette(OA8,kent),pet(OB8,horse),near(OA8,OB8,S),
	drink(O9,juice),cigarette(O9,pall_mall),member(O9,S),
	nationality(O10,japanese),cigarette(O10,assos),member(O10,S),
	nationality(OA11,russian),color(OB11,blue),near(OA11,OB11,S),
	nationality(O12,spanish),pet(O12,dog),member(O12,S),
	pet(O13,snake),cigarette(O13,camel),member(O13,S),
	color(OA14,grey),color(OB14,green),near(OA14,OB14,S),
	pet(OA15,cat),drink(OB15,vodka),lateral(OA15,S),lateral(OB15,S).

color([Color,_,_,_,_],Color).

nationality([_,Nationality,_,_,_],Nationality).

drink([_,_,Drink,_,_],Drink).

cigarette([_,_,_,Cigarette,_],Cigarette).

pet([_,_,_,_,Pet],Pet).

leftmost(X,[X,_,_,_,_]).

middle(X,[_,_,X,_,_]).

lateral(X,[X,_,_,_,_]).
lateral(X,[_,_,_,_,X]).

left(A,B,S) :-
	append(_,[A,B|_],S).

near(A,B,S) :-
	left(A,B,S).
near(A,B,S) :-
	left(B,A,S).

Now you can ask the inference machine this query and it'll give you an answer:

Code:
?- solve(S).

S = [[yellow,russian,vodka,kent,fox], [blue,italian,tea,marlboro,horse], [red,englishman,milk,camel,snake], [grey,spanish,juice,pall_mall,dog], [green,japanese,coffee,assos,cat]] ;

No
 
OK, I guess there has gone long enough to give a C-solution without any hiding. So here's the C-hack version of cristic's quiz (Oooh, 15 nested loops this time).
Code:
#include <stdio.h>

char*   unknown = "?";
#define Known(X) ((X)!=unknown)

#define CheckAll(I, P1, V1, P2, V2) \
  for(I=0; I<5; I++) {\
    char **p1=&P1[I], **p2=&P2[I];\
    if(Known(*p1)) continue; \
    if(Known(*p2)) continue; \
    *p1=V1; *p2=V2;

#define CheckDist(I, I0, D, P1, V1) \
  for(I=I0-D; I<=I0+D; I+=2*D) {\
    char **p1=&P1[I], **p2=&P1[I];\
    if(I<0 || I>4) continue; \
    if(Known(*p1)) continue; \
    *p1=V1;

#define EndCheck() \
  *p1 = *p2 = unknown; }

int main(int argc, char* argv[])
{
  int i,i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14;
  char *nat[5], *col[5], *dri[5], *cig[5], *pet[5];

  for(i=0; i<5; i++) 
    nat[i] = col[i] = dri[i] = cig[i] = pet[i] = unknown;

  nat[0] = "Russian";
  col[1] = "Blue";
  dri[2] = "Milk";

  CheckAll (i1,  nat,"Englishman",  col,"Red")
  CheckAll (i2,  nat,"Italian",     dri,"Tea")
  CheckAll (i3,  nat,"Japanese",    cig,"Assos")
  CheckAll (i4,  nat,"Spanish",     pet,"Dog")
  CheckAll (i5,  col,"Green",       dri,"Coffee")
  CheckDist(i6,  i5,1,              col,"Grey")
  CheckAll (i7,  cig,"Kent",        col,"Yellow")
  CheckDist(i8,  i7,1,              pet,"Horse")
  CheckAll (i9,  cig,"Marlboro",    cig,"Marlboro")
  CheckDist(i10, i9,1,              pet,"Fox")
  CheckAll (i11, dri,"Juice",       cig,"Pall Mall")
  CheckAll (i12, pet,"Snake",       cig,"Camel")
  CheckAll (i13, pet,"Cat",         pet,"Cat")
  CheckDist(i14, i13,4,             dri,"Vodka")
  
  printf("--------\n");
  for(i=0; i<5; i++) {
    printf("%-10s  %-6s  %-6s  %-9s  %-5s\n",
           nat[i], col[i], dri[i], cig[i], pet[i]);
  }

  EndCheck() EndCheck() EndCheck() EndCheck() EndCheck()
  EndCheck() EndCheck() EndCheck() EndCheck() EndCheck()
  EndCheck() EndCheck() EndCheck() EndCheck() 
  return 0;
}
I won't take responsibillity for the humiliation you'll be put to if you use that coding style. For instance, writing unbalanced gull-wings in macros is something that warrants a serious slapping with a dead trout. But hey, it made it easy to write it. :D

Btw, Simon what was your approach?

[Edit]
Removed some unnecessary stuff in the code.
 
Code:
#include <stdio.h>

/*
  Russian      leftmost
  Russian   +- blue 
  milk         middle

  Englishman   red 
  Italian      tea
  Japanese     Assos
  Spanish      dog

  green        coffee
  green     +- grey        // "near"

  Kent         yellow
  Kent      +- horse

  Marlboro  +- fox
  juice        Pall Mall
  snake        Camel
  cat      +-4 vodka       // "lateral"
*/

char* sNat[6] = {"Englishman", "Italian", "Russian", "Japanese", "Spanish", "?"};
char* sCol[6] = {"Red", "Green", "Yellow", "Blue", "grey", "?"};
char* sDri[6] = {"Coffee", "Tea", "Milk", "Juice", "Vodka", "?"};
char* sCig[6] = {"Kent", "Marlboro", "Pall Mall", "Assos", "Camel", "?"};
char* sPet[6] = {"Fox", "Horse", "Dog", "Snake", "Cat", "?"};

enum {Englishman, Italian, Russian, Japanese, Spanish};
enum {Red, Green, Yellow, Blue, Grey};
enum {Coffee, Tea, Milk, Juice, Vodka};
enum {Kent, Marlboro, Pall_Mall, Assos, Camel};
enum {Fox, Horse, Dog, Snake, Cat};

#define unknown (5)
#define Known(X) (X!=unknown)

#define FOR(I)   for(I=0;I<5;I++)

#define CheckAll(I, P1, V1, P2, V2) \
  FOR(I) {\
    int *p1=&P1[I], *p2=&P2[I];\
    if(Known(*p1)) continue; \
    if(Known(*p2)) continue; \
    *p1=V1; *p2=V2;

#define CheckDist(I, I0, D, P1, V1) \
  for(I=I0-D;I<=I0+D;I+=2*D) {\
    int *p1=&P1[I], *p2=&P1[I];\
    if(I<0 || I>4) continue; \
    if(Known(*p1)) continue; \
    *p1=V1;

#define EndCheck() \
  *p1 = *p2 = unknown; }

int main(int argc, char* argv[])
{
  int i;
  int i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14;
  int nat[5], col[5], dri[5], cig[5], pet[5];

  FOR(i) { nat[i] = col[i] = dri[i] = cig[i] = pet[i] = unknown; }

  nat[0] = Russian;
  col[1] = Blue;
  dri[2] = Milk;

  CheckAll (i1,  nat,Englishman,  col,Red)
  CheckAll (i2,  nat,Italian,     dri,Tea)
  CheckAll (i3,  nat,Japanese,    cig,Assos)
  CheckAll (i4,  nat,Spanish,     pet,Dog)
  CheckAll (i5,  col,Green,       dri,Coffee)
  CheckDist(i6,  i5,1,            col,Grey)
  CheckAll (i7,  cig,Kent,        col,Yellow)
  CheckDist(i8,  i7,1,            pet,Horse)
  CheckAll (i9,  cig,Marlboro,    cig,Marlboro)
  CheckDist(i10, i9,1,            pet,Fox)
  CheckAll (i11, dri,Juice,       cig,Pall_Mall)
  CheckAll (i12, pet,Snake,       cig,Camel)
  CheckAll (i13, pet,Cat,         pet,Cat)
  CheckDist(i14, i13,4,           dri,Vodka)
 
  printf("--------\n");
  FOR(i) {
    //printf("%d  %d  %d  %d  %d    ", nat[i], col[i], dri[i], cig[i], pet[i]);
    printf("%-10s  %-6s  %-6s  %-9s  %-5s\n",
           sNat[nat[i]],
           sCol[col[i]],
           sDri[dri[i]],
           sCig[cig[i]],
           sPet[pet[i]]);
  }

  EndCheck() EndCheck() EndCheck() EndCheck()
  EndCheck() EndCheck() EndCheck() EndCheck()
  EndCheck() EndCheck() EndCheck() EndCheck()
  EndCheck() EndCheck()
  return 0;
}

Why is the solution more difficult than the question?
 
Actually it's not :)

I also cheated once for a puzzle, it's also an old one. I don't remember the exact numbers, but it's about several people crossing a bridge at night. There are only one lamp and the bridge is so small, so there can be only two people crossing the bridge at once, and one person must come back to bring the lamp for others. The walking speed of those people are all different, and you have to make all four persons cross the bridge under a specific time. When two people walking across the bridge, the faster one must slows down to match the slow one. And they are all fat, so they can't go on each other's back :)

In one example, the speeds are: 1 minutes (to cross the bridge), 2 minutes, 5 minutes, and 6 minutes. The time requirement is 13 minutes. It's different from the numbers in the puzzle I saw, but the idea is the same.

When I saw that puzzle, I tried for several minutes and got impatient, so I wrote a small C program to solve it. When I saw the answer the program produced, I thought "Ah! Of course!" That's one of a few moment when I think computer is smarter than I :p
 
TekkenMaster said:
Why is the solution more difficult than the question?
The C code includes both the question and a explicit method to solve it, of course it's longer than just the question written in english. I suppose you dont know C, so of course it will also look more difficult, since it's written in a language you don't know.

[Edit]
I'm sorry, that might have sounded condescending, and I didn't mean to.
And now I see that I used one unnecessary indirection level in the code. I'll change that above.
 
I suppose you dont know C

Wrong presupposition.

Oh, and please don't write code in a post without code-tags

Wasn't aware Courier New has become a standard font for writing codes, but if it means you'll stop lamenting like your Xbox power cord was set ablazed, I've taken the time and effort to review and edit my previous post.
 
Oops, I didn't edit that quick enough.

I removed my request for code-tags when I saw that you put them there. It was certainly not ment like you bold-faced it. It was meant as a polite request.

Courier New might not be standard, but using a non-proportional font definitely is.

The reason I thought you didn't know C, was that if you'd been programming you wouldn't ask that question. You'd know the answer already.
 
Simon F said:
Crisidelm said:
Well, I think that Einstein (if he really did say that anyway) meant that only 2% of world population can solve it without using paper and pen (or any other "aid" alike), that is, mentally only.

Are you sure? I can't imagine even 2% of the population could keep more than 8 facts in their short term memory at a time.

yes, I do think so, then again, was Einstein wrong about the 2%? Probably so, but who knows. Definitively there are people who can solve it mentally, how many, I don't know. I'm not one of them for sure :)
 
Basic said:
Btw, Simon what was your approach?
.

The approach I took is the same way I solve them by hand (more or less). You have a big grid of possibilities (i.e. potential facts) and immediately mark in those permitted by the rules and those that are ruled-out. This then reveals new facts (which can cancel out other possibilities). You keep going until the solution is left.

This particular puzzle differs from many that are published in that there is a fair amount of "implicit" information in the facts.



Well, before releasing the code, I was thinking about making it more generic so that it could "parse" a problem file rather than having the conditions hardwired in, but I guess I'm not going to get time to do that : -)

BTW: This is hacked code, so it's not very pretty.

Code:
#include <stdio.h>
#include <stdlib.h>

/*
// Define the number of elements
*/
#define NUM_ITEMS (5)

/*
// Define the number of properties each item has
*/
#define NUM_PROPERTIES (6)

/*
// Define the names of the properties
*/
const char * PropertyTypes[NUM_PROPERTIES] =
{
	"number",
	"colour",
	"nationality",
	"drink",
	"cigar",
	"pet"
};
/*
// For convience, also give these numeric codes
*/
enum
{
	NUMBERS,
	COLOURS,
	NATIONALITY,
	DRINKS,
	CIGARS,
	PETS
} Properties;

/*
// Define all the things (they must be unique).
// They can be in any order (as long as they are grouped correctly!)
// (well the house numbers should be in the correct order!)
*/
const char *Everything[NUM_PROPERTIES * NUM_ITEMS]=
{
		"house 1",
		"house 2",
		"house 3",
		"house 4",
		"house 5",

		"red",
		"green",
		"blue",
		"white",
		"yellow",


		"swede",
		"brit",
		"dane",
		"norwegian",
		"german",


		"tea",
		"coffee",
		"milk",
		"beer",
		"water",		


		"dunhill",
		"blend",
		"bluemaster",
		"prince",
		"pallmall",

		"dogs",
		"cats",
		"horse",
		"birds",
		"fish",
};


/*
// Define the way we represent facts
*/
#define YES (1)
#define NO	(-1)
#define NOT_DECIDED (-2)

/*
// Define a big array containing all the known facts
// (note there is redundacy, but it makes it much easier to program)
*/
int Facts[NUM_PROPERTIES * NUM_ITEMS][NUM_PROPERTIES * NUM_ITEMS];

/*
// Routines
*/
static void InitialiseFacts();

static void AddTheSame(char const *Item1, char const *Item2);

static void AddNotTheSame(char const *Item1, char const *Item2, int verbose);

/*
// Search for a new fact as revealed by a process of elimination.
// return non-zero if a new fact was found.
*/
static int DoNewFactSearch(char const **NewEquiv1, char const **NewEquiv2);


/*
// Asks if we know what is what. Returns a NON zero value (and the index for 
// the string) if we know.
*/
static int WhatIs(char const *Item, 
				  char const *AskedProperty, 
				  int *EquivalentIndex);


/*
// returns TRUE if we know for certain that Item1 != Item2
*/
static int DefinitelyNot(char const *Item1, char const *Item2);


/*
// Bit of a special routine for this puzzle
// 
*/
static void AddNeighbours(char const *Item1, char const *Item2);



/*
// main routine
*/
void main(void)
{
	int answer, Index, i;
	char const *NewFact1,  *NewFact2;

	/*
	// Intialise the facts structure
	*/
	InitialiseFacts();


	/*
	// Add all the basic, really straightforward facts
	*/
	AddTheSame("brit", "red");
	AddTheSame("swede", "dogs");
	AddTheSame("dane", "tea");

	AddNotTheSame("green", "house 5", 1);
	AddNotTheSame("white", "house 1", 1);

	AddTheSame("green", "coffee");
	AddTheSame("pallmall", "birds");
	AddTheSame("yellow", "dunhill");

	AddTheSame("house 3", "milk");
	AddTheSame("norwegian", "house 1");

	AddNotTheSame("blend", "cats",    1);
	AddNotTheSame("horse", "dunhill", 1);

	AddTheSame("bluemaster", "beer");
	AddTheSame("german", "prince");
	
	AddNotTheSame("norwegian", "blue", 1);
	AddNotTheSame("blend", "water",    1);


	printf("Added initial,  easy facts.......\n\n");

	/*
	// keep looping until we know who the hell owns the fish :-)
	*/
	while(WhatIs("fish", "nationality", &answer) == 0)
	{
		/*		
		// Cross reference all the facts we've got so far.
		*/
		printf("\nDoing Elimination Search....\n");
		while(DoNewFactSearch(&NewFact1, &NewFact2))
		{
			printf("Discovered that %s == %s\n", NewFact1, NewFact2);

			AddTheSame(NewFact1, NewFact2);

			printf("\n");
		}
		printf("\n");


		/*
		// Do the tricky rules.
		//
		// Add the less precise neighbour information
		*/
		AddNeighbours("blend", "cats");
		AddNeighbours("horse", "dunhill");
		AddNeighbours("norwegian", "blue");
		AddNeighbours("blend", "water");


		
		/*
		// Now for the nasty one.
		//
		//    green to left of white
		//
		// if we know green's number AND white's number, then don't bother
		*/
		if( WhatIs("green", "number", &Index) && 
			WhatIs("white", "number", &Index))
		{
			/*do nothing more*/
		}
		/*
		// Else if we know where at least one of them is...
		*/
		else if( WhatIs("green", "number", &Index))
		{
			AddTheSame("white", Everything[Index+1]);
		}
		else if(WhatIs("white", "number", &Index))
		{
			AddTheSame("green", Everything[Index-1]);
		}
		/*
		// else we don't know which is which but...
		//
		//  if we know green is NOT house N, then white is NOT house N+1
		*/
		else
		{
			/*
			// step through the possible houses
			*/
			for(i = 0; i < 4; i++)
			{
				if(DefinitelyNot("green", Everything[i+ NUMBERS* NUM_ITEMS]))
				{
					AddNotTheSame("white", 
								 Everything[i+1+NUMBERS* NUM_ITEMS], 0);
				}
			}
			for(i = 1; i < 5; i++)
			{
				if(DefinitelyNot("white", Everything[i+ NUMBERS* NUM_ITEMS]))
				{
					AddNotTheSame("green", 
								  Everything[i-1+NUMBERS* NUM_ITEMS], 0);
				}
			}
		}/*end else... handling green and white*/


	}
	printf("\n\nThe fish is owned by the %s\n", Everything[answer]);
	
}



/******************************************************************/
/******************************************************************/
/******************************************************************/
/* The guts......*/

static void AddNeighbours(const char *Item1, const char *Item2)
{
	int Index;
	int ThisHouse;
	int i;


	/*
	// If we already know where both houses are, then just do a sanity
	// check
	*/
	if(WhatIs(Item1, "number", &Index) && WhatIs(Item2, "number", &i))
	{
		if(abs(Index - i) != 1)
		{
			printf("Error %s and %s are supposed to be neighbours!\n",
						  Item1, Item2);

			exit(1);
		}


		return;

	}

	printf("Trying to add %s and %s as neighbours.. \n", Item1, Item2);

	/*
	// If we know Item1's number...
	*/
	if(WhatIs(Item1, "number", &Index))
	{
		/*
		// mark any houses that are not neighbours
		*/
		for(i = 0; i < 5; i++)
		{
			ThisHouse = i+NUMBERS*NUM_ITEMS;
	
			/*
			// if this house is not a neighbour
			*/
			if((ThisHouse != Index-1) && (ThisHouse != Index+1))
			{
				AddNotTheSame(Item2, Everything[ThisHouse], 0);
			}
		}
	}
	else if(WhatIs(Item2, "number", &Index))
	{
		/*
		// mark any houses that are not neighbours
		*/
		for(i = 0; i < 5; i++)
		{
			ThisHouse = i+NUMBERS*NUM_ITEMS;
	
			/*
			// if this house is not a neighbour
			*/
			if((ThisHouse != Index-1) && (ThisHouse != Index+1))
			{
				AddNotTheSame(Item1, Everything[ThisHouse], 0);
			}
		}
	}
}

/******************************************************************/
/******************************************************************/
/******************************************************************/

static void InitialiseFacts()
{
	int i, j, k;
	int Base;
	/*
	// Clear everything out
	*/
	for(i = 0; i < NUM_ITEMS * NUM_PROPERTIES; i++)
	{
		for(j = 0; j < NUM_ITEMS * NUM_PROPERTIES; j++)
		{
			Facts[i][j] = NOT_DECIDED;
		}
	}
	/*
	// Now put in the "bleeding obvious... i.e. X==X
	*/
	for(k = 0; k < NUM_PROPERTIES; k++)
	{
		Base = k * NUM_ITEMS;

		for(i = 0; i < NUM_ITEMS; i++)
		{
			for(j = 0; j < NUM_ITEMS; j++)
			{
				Facts[Base+i][Base+j] = NO;
			}

			/*
			// Just fix the main diagonal i.e. X==X
			*/
			Facts[Base+i][Base+i] = YES;
		}
	}
}


static void AddTheSame(char const *Item1, char const *Item2)
{
	int Index1, Index2;
	int i;

	printf("Adding %s == %s \n", Item1, Item2);
	/*
	// Find the two items
	*/
	for(Index1 = 0; Index1 < NUM_PROPERTIES * NUM_ITEMS; Index1++)
	{
		if(strcmp(Everything[Index1], Item1) == 0)
		{
			break;
		}
	}
	if(Index1 == NUM_PROPERTIES * NUM_ITEMS)
	{
		printf("Error. Couldn't find %s in AddTheSame(%s, %s)\n",
						Item1,  Item1, Item2);

		exit(1);
	}

	for(Index2 = 0; Index2 < NUM_PROPERTIES * NUM_ITEMS; Index2++)
	{
		if(strcmp(Everything[Index2], Item2) == 0)
		{
			break;
		}
	}
	if(Index2 == NUM_PROPERTIES * NUM_ITEMS)
	{
		printf("Error. Couldn't find %s in AddTheSame(%s, %s)\n",
						Item2,  Item1, Item2);
		exit(1);
	}


	/*
	// fill in the details: Cross reference the information
	// These two items are identical, and so each can share the other's
	// information.
	*/
	for(i = 0; i < NUM_PROPERTIES * NUM_ITEMS; i++)
	{
		/*
		// Do rows
		*/
		if( (Facts[Index1][i] == NO) || (Facts[Index2][i] == NO))
		{
			/*
			//Do a sanity check
			*/
			if((Facts[Index1][i] == YES) || (Facts[Index2][i] == YES))
			{
				printf("Error. %s and %s disagree about %s!\n",
						Item1,  Item2, Everything[i]);
			}

			/*
			// Update the info
			*/
			Facts[Index1][i] = NO;
			Facts[Index2][i] = NO;
		}/*end if*/

#if 0
		else if( (Facts[Index1][i] == YES) || (Facts[Index2][i] == YES))
		{
			/*
			// Update the info
			*/
			Facts[Index1][i] = YES;
			Facts[Index2][i] = YES;
		}
#endif
		/*
		// Do columns
		*/
		if( (Facts[i][Index1] == NO) || (Facts[i][Index2] == NO) )
		{
			/*
			//Do a sanity check
			*/
			if((Facts[i][Index1] == YES) || (Facts[i][Index2] == YES))
			{
				printf( "Error. %s and %s disagree about %s!\n",
						Item1,  Item2, Everything[i]);
			}

			/*
			// Update the info
			*/
			Facts[i][Index1] = NO;
			Facts[i][Index2] = NO;
		}
#if 0
		else if( (Facts[i][Index1] == YES) || (Facts[i][Index2] == YES))
		{
			/*
			// Update the info
			*/
			Facts[i][Index1] = YES;
			Facts[i][Index2] = YES;
		}
#endif

	}/*end for*/


	Facts[Index1][Index2] = YES;
	Facts[Index2][Index1] = YES;
}


static void AddNotTheSame(char const *Item1, char const *Item2, int Verbose)
{
	int Index1, Index2;

	if(Verbose)
	{
		printf("Adding %s != %s \n", Item1, Item2);
	}
	/*
	// Find the two items
	*/
	for(Index1 = 0; Index1 < NUM_PROPERTIES * NUM_ITEMS; Index1++)
	{
		if(strcmp(Everything[Index1], Item1) == 0)
		{
			break;
		}
	}
	if(Index1 == NUM_PROPERTIES * NUM_ITEMS)
	{
		printf("Error. Couldn't find %s in AddNotTheSame(%s, %s)\n",
						Item1,  Item1, Item2);

		exit(1);
	}

	for(Index2 = 0; Index2 < NUM_PROPERTIES * NUM_ITEMS; Index2++)
	{
		if(strcmp(Everything[Index2], Item2) == 0)
		{
			break;
		}
	}
	if(Index2 == NUM_PROPERTIES * NUM_ITEMS)
	{
		printf("Error. Couldn't find %s in AddNotTheSame(%s, %s)\n",
						Item2,  Item1, Item2);
		exit(1);
	}

	/*
	// Do a quick sanity check
	*/
	if((Facts[Index1][Index2] == YES) || (Facts[Index2][Index1] == YES))
	{
		printf("Error. %s and %s are supposed to be the same!\n",
						Item1,  Item2);
		exit(1);
	}

	/*
	// fill in the details
	*/
	Facts[Index1][Index2] = NO;
	Facts[Index2][Index1] = NO;
}



static int DefinitelyNot(char const *Item1, char const *Item2)
{
	int Index1, Index2;

	/*
	// Find the two items
	*/
	for(Index1 = 0; Index1 < NUM_PROPERTIES * NUM_ITEMS; Index1++)
	{
		if(strcmp(Everything[Index1], Item1) == 0)
		{
			break;
		}
	}
	if(Index1 == NUM_PROPERTIES * NUM_ITEMS)
	{
		printf("Error. Couldn't find %s in AddNotTheSame(%s, %s)\n",
						Item1,  Item1, Item2);

		exit(1);
	}

	for(Index2 = 0; Index2 < NUM_PROPERTIES * NUM_ITEMS; Index2++)
	{
		if(strcmp(Everything[Index2], Item2) == 0)
		{
			break;
		}
	}
	if(Index2 == NUM_PROPERTIES * NUM_ITEMS)
	{
		printf("Error. Couldn't find %s in AddNotTheSame(%s, %s)\n",
						Item2,  Item1, Item2);
		exit(1);
	}


	return(Facts[Index1][Index2] == NO);
}



/*
// Search for new facts.
// return non-zero if a new fact was found.
*/
static int DoNewFactSearch(char const **NewEquiv1, char const **NewEquiv2)
{
	int RowToCheck, Property, i;
	int NoCount, UnknownCount, YesCount;
	int Base;
	int LastUnknown;

	for(RowToCheck = 0; RowToCheck < NUM_PROPERTIES * NUM_ITEMS; RowToCheck++)
	{
		/*
		// Scan through it in blocks of properties. If we find that all
		// bar one is set as NO, then it's a new fact
		*/
		for(Property = 0; Property < NUM_PROPERTIES; Property++)
		{
			Base = Property * NUM_ITEMS;
			NoCount = 0;
			YesCount= 0;
			UnknownCount = 0;

			for(i = 0; i < NUM_ITEMS; i++)
			{
				if(Facts[RowToCheck][i+Base] == NO)
				{
					NoCount++;
				}
				else if(Facts[RowToCheck][i+Base] == YES)
				{
					YesCount++;
				}
				else if(Facts[RowToCheck][i+Base] == NOT_DECIDED)
				{
					UnknownCount++;

					LastUnknown = i+Base;
				}
			}/*end for i*/


			/*
			// If there is only one possibility left
			*/
			if((UnknownCount == 1) && (NoCount == (NUM_ITEMS-1)))
			{

				*NewEquiv1 = Everything[RowToCheck];
				*NewEquiv2 = Everything[LastUnknown];

				return 1;
			}
			/*
			// Else do some sanity checks...
			*/
			else if(NoCount == NUM_ITEMS)
			{
				printf("Error. %s doesn't have a %s available!\n",
						Everything[RowToCheck], PropertyTypes[Property]);
				exit(1);
			}
			else if(YesCount > 1)
			{
				printf("Error. %s IS MAPPED TO TWO %s !!!\n",
						Everything[RowToCheck], PropertyTypes[Property]);
				exit(1);
			}
			else if(UnknownCount + YesCount + NoCount != NUM_ITEMS)
			{
				printf("Error. %s has error in %s (%d %d %d)!!!\n",
						Everything[RowToCheck], PropertyTypes[Property],
						UnknownCount, YesCount, NoCount);
				exit(1);
			}
		}
	}

	/*
	// no luck
	*/
	return 0;
}



/*
// Asks if we know what is what. Returns a NON zero value (and the index for 
// the string) if we know.
*/
static int WhatIs(char const *Item, 
				  char const *AskedProperty, 
				  int *pEquivalentIndex)
{
	int Index, Property;
	int i;
	int Base;

	/*
	// Find the item
	*/
	for(Index = 0; Index < NUM_PROPERTIES * NUM_ITEMS; Index++)
	{
		if(strcmp(Everything[Index], Item) == 0)
		{
			break;
		}
	}

	if(Index == NUM_PROPERTIES * NUM_ITEMS)
	{
		fprintf(stderr, "Error. Couldn't find %s in Whatis(%s, %s)\n",
						Item,  Item, AskedProperty);

		exit(1);
	}

	/*
	// Find the property
	*/
	for(Property = 0; Property < NUM_PROPERTIES;  Property++)
	{
		if(strcmp(PropertyTypes[Property], AskedProperty) == 0)
		{
			break;
		}
	}

	if(Property == NUM_PROPERTIES)
	{
		fprintf(stderr, "Error. Couldn't find %s in Whatis(%s, %s)\n",
						AskedProperty,  Item, AskedProperty);

		exit(1);
	}

	/*
	// Search through the area looking for a yes
	*/
	Base = Property * NUM_ITEMS;

	for(i = Base; i < Base + NUM_ITEMS; i++)
	{
		if(Facts[Index][i] == YES)
		{					
			*pEquivalentIndex = i;
			return 1;
		}
	}
	
	/*
	// Else no luck
	*/
	*pEquivalentIndex = -100000;
	return 0;

}

/*
// END OF FILE
*/
 
I didn't get it, but I got close. Then I read the answers :( When I saw the flash movie, I did see the "hypotenuse" bend. The "hypotenuse" doesn't look exactly the same in those 2 pictures. I couldn't figure out why, until I read the answer. :(
 
Back
Top