Only in mastermind: client.log
Only in mastermind: mastermind2.patch
Only in mastermind: mastermind.patch
Only in mastermind: obj
Only in mastermind: server.log
diff -rup omastermind/mastermind/src/Bitarray.h mastermind/src/Bitarray.h
--- omastermind/mastermind/src/Bitarray.h	2013-10-27 15:20:55.000000000 +0100
+++ mastermind/src/Bitarray.h	2013-11-13 14:57:45.885436426 +0100
@@ -1,6 +1,6 @@
 #ifndef __BITARRAY_H
 #define __BITARRAY_H
-/** Bitarray. Think of a Bitarray as a very large word where you can do bit operations on.
+/** Bitarray. Think of a Bitarray as a very large word which you can do bit operations on.
  * @author Danny Milosavljevic (0826039)
  * @brief Array of bits
  * @date 2013-10-26
@@ -43,5 +43,4 @@ int Bitarray_getSetCount(struct Bitarray
 /** retrieves the bit with the given index */
 int Bitarray_get(struct Bitarray* self, unsigned int bitIndex);
 
-
-#endif /* ndef __BITSET_H */
+#endif /* ndef __BITARRAY_H */
diff -rup omastermind/mastermind/src/client.c mastermind/src/client.c
--- omastermind/mastermind/src/client.c	2013-11-11 15:24:35.000000000 +0100
+++ mastermind/src/client.c	2013-11-13 22:18:14.305975851 +0100
@@ -85,7 +85,7 @@ static void perror2(const char* text) {
  * @param portname name of the port to connect to
  * @return file descriptor of a connect()ed socket, or (-1) on error
  */
-static int connectToHost(const char* arg0, const char* hostname, const char* portname) {
+static int connectToHost(const char* hostname, const char* portname) {
 	int fd;
 	struct sockaddr_in addr;
 	struct hostent* hostent;
@@ -93,7 +93,7 @@ static int connectToHost(const char* arg
 	long int direct_port = 0;
 	fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 	if(fd == -1) {
-		(void) fprintf(stderr, "%s: Could not connect to \"%s:%s\"\n", arg0, hostname, portname);
+		(void) fprintf(stderr, "%s: Could not connect to \"%s:%s\"\n", progname, hostname, portname);
 		perror2("socket");
 		return(-1);
 	}
@@ -101,7 +101,7 @@ static int connectToHost(const char* arg
 	if(servent == NULL) {
 		direct_port = strtol(portname, NULL, 10);
 		if(direct_port < 0 || direct_port > 0xFFFF) {
-			(void) fprintf(stderr, "%s: Could not connect to \"%s:%s\": port was unknown.\n", arg0, hostname, portname);
+			(void) fprintf(stderr, "%s: Could not connect to \"%s:%s\": port was unknown.\n", progname, hostname, portname);
 			perror2("strtol");
 			(void) close(fd);
 			return(-1);
@@ -109,7 +109,7 @@ static int connectToHost(const char* arg
 	}
 	hostent = gethostbyname(hostname);
 	if(hostent == NULL) {
-		(void) fprintf(stderr, "%s: Could not connect to \"%s:%s\"\n", arg0, hostname, portname);
+		(void) fprintf(stderr, "%s: Could not connect to \"%s:%s\"\n", progname, hostname, portname);
 		herror("gethostbyname");
 		(void) close(fd);
 		return(-1);
@@ -117,7 +117,7 @@ static int connectToHost(const char* arg
 	addr.sin_family = AF_INET;
 	addr.sin_port = (servent != NULL) ? servent->s_port : htons(direct_port); /* s_port is already in network byte order */
 	if(sizeof(addr.sin_addr) < hostent->h_length) {
-		(void) fprintf(stderr, "%s: Could not connect to \"%s:%s\": no idea how to read the address\n", arg0, hostname, portname);
+		(void) fprintf(stderr, "%s: Could not connect to \"%s:%s\": no idea how to read the address\n", progname, hostname, portname);
 		(void) close(fd);
 		return(-1);
 	}
@@ -215,9 +215,6 @@ static int convertResponseStatus(int res
 				return(-1);
 }
 
-
-/*static void traverse_possibilities(const char* client_name, int fd, struct gamestate* state, int i_slot) {
-}*/
 /**
  * @brief play game
  * @param clientName client name
@@ -225,34 +222,51 @@ static int convertResponseStatus(int res
  * @param state game state
  * @return exit code
  */
-static int playGame(const char* clientName, int fd, struct Gamestate* state) {
+static int playGame(int fd, struct Gamestate* state) {
 	guess_t guess = {0};
 	int response;
-	int exitcode;
+	int exitcode = (-1);
 	int correctCount; /* of server's answer */
 	int opresentCount; /* of server's answer */
 	int i;
-	/* prepare initial guess */
-	for(i = 0; i < SLOTS; ++i) 
-		guess[i] = i % COLORS;
-	while(1 == 1) {
+	int preparedSlotCount = 0;
+	int preparedColorCount = 0;
+	assert(SLOTS > 0);
+	assert(COLORS > 0);
+	assert(COLORS < 15); /* it isn't worth prefiltering the colors otherwise */
+	while(exitcode != 0) {
 		Gamestate_startRound(state);
+		if(preparedSlotCount < SLOTS) {
+			for(i = 0; i < SLOTS; ++i)
+				guess[i] = preparedColorCount;
+		} else {
+			i = Gamestate_getBestMove(state, &guess);
+			if(!i)
+				abort();
+		}
 		response = sendGuess(fd, &guess);
 		exitcode = convertResponseStatus(response, &correctCount, &opresentCount);
 		if(exitcode != (-1))
 			return(exitcode);
 		if(correctCount == SLOTS) {
-			if(!printGuess(stdout, &guess) || 
-			   fputc('\n', stdout) == EOF)
-				abort();
-			return(0);
+			exitcode = 0;
+			continue;
 		}
 		Gamestate_removeDifferentlyScoredSecrets(state, &guess, correctCount, opresentCount);
-		i = Gamestate_getBestMove(state, &guess);
-		if(!i)
-			abort();
+		if(preparedSlotCount < SLOTS) {
+			if(correctCount > 0) {
+				for(i = 0; i < correctCount + opresentCount; ++i)
+					Gamestate_addPaletteEntry(state, guess[0]);
+			}
+			preparedSlotCount += correctCount + opresentCount;
+			++preparedColorCount;
+		}
 	}
-	return(-1);
+	assert(exitcode == 0);
+	if(!printGuess(stdout, &guess) || 
+	   fputc('\n', stdout) == EOF)
+		abort();
+	return(0);
 }
 
 /** 
@@ -274,12 +288,12 @@ int main(int argc, char* argv[]) {
 	}
 	server_hostname = argv[1];
 	server_port = argv[2];
-	fd = connectToHost(argv[0], server_hostname, server_port);
+	fd = connectToHost(server_hostname, server_port);
 	if(fd == -1)
 		return(EXIT_FAILURE);
 	state = alloca(Gamestate_getAllocation());
 	Gamestate_init(state);
-	status = playGame(argv[0], fd, state);
+	status = playGame(fd, state);
 	switch(status) {
 	case 0: /* guessed correctly */
 		(void) printf("%d\n", Gamestate_getRoundCount(state));
diff -rup omastermind/mastermind/src/Gamestate.c mastermind/src/Gamestate.c
--- omastermind/mastermind/src/Gamestate.c	2013-11-11 14:04:59.000000000 +0100
+++ mastermind/src/Gamestate.c	2013-11-13 23:51:38.473811068 +0100
@@ -26,6 +26,11 @@ struct Gamestate {
 	int eliminationCount; /**< current eliminationCount for getBestMove iterations. */
 	int correctCount; /**< number of correct colors at the correct places */
 	int opresentCount; /**< number of present colors at the wrong places */ 
+	int paletteCount; /**< number of colors in palette */
+	uint8_t palette[SLOTS]; /**< colors in palette */
+	unsigned int highestData;
+	int firstHighest;
+	int highestEliminationCount;
 };
 
 size_t Gamestate_getAllocation(void) {
@@ -47,6 +52,7 @@ void Gamestate_init(struct Gamestate* se
 	/* initially, all secrets are possible */
 	for(secretBitIndex = 0; secretBitIndex < capacity; ++secretBitIndex)
 		Bitarray_set(self->secrets, secretBitIndex, 1);
+	self->paletteCount = 0;
 }
 
 void Gamestate_deinit(struct Gamestate* self) {
@@ -109,6 +115,7 @@ static void storeGuess(void* userdata, u
 	guess_t* outGuess = (guess_t*) userdata;
 	unpackGuess(bitIndex, outGuess);
 }
+
 /** given a guess and a (possible) secret and score, if the secret would be removed because of it, increase self->eliminationCount */
 static void Gamestate_getEliminationCount_scoreSecret(void* userdata, unsigned int secretBitIndex) {
 	struct Gamestate* self = (struct Gamestate*) userdata;
@@ -155,6 +162,59 @@ static int Gamestate_getEliminationCount
 	return outEliminationCount;
 }
 
+/** helper function to permute entries by the Boothroyd method
+  * @param x the array to permute
+  * @param n number of elements after the current one (i.e. index of current element)
+  * @param nn number of elements in total
+  * @param callback callback to call for each permutation.
+  * @param userdata userdata to give to callback.
+  */
+static void boothroyd(uint8_t* x, int n, int nn, void (*callback)(void*, uint8_t*, int), void* userdata) {
+	int c = 0, i;
+	uint8_t t;
+	while (1) {
+		if (n > 2)
+			boothroyd(x, n - 1, nn, callback, userdata);
+		if (c >= n - 1)
+			return;
+		i = (n & 1) ? 0 : c;
+		c++;
+		t = x[n - 1], x[n - 1] = x[i], x[i] = t;
+		if (callback != NULL)
+			(*callback)(userdata, x, nn);
+	}
+}
+ 
+/** permute entries by the Boothroyd method
+  * @param x the array to permute
+  * @param n number of elements in x
+  * @param callback callback to call for each permutation.
+  * @param userdata userdata to give to callback.
+  */
+static void perm2(uint8_t* x, int n, void (*callback)(void* userdata, uint8_t*, int), void* userdata) {
+	if (callback != NULL)
+		(*callback)(userdata, x, n);
+	boothroyd(x, n, n, callback, userdata);
+}
+
+/** process one elimination */
+static void processElimination(void* userdata, uint8_t* guess, int guessCount) {
+	struct Gamestate* self = (struct Gamestate*) userdata;
+	guess_t xguess;
+	memcpy(&xguess, guess, sizeof(guess_t));
+	unsigned int data = packGuess(&xguess);
+	/** Calculate how many possibilities (secrets) we could (at least) eliminate.
+	  * Take the guess with the highest such value.
+	  */
+	int eliminationCount;
+	eliminationCount = Gamestate_getEliminationCount(self, data);
+	if(self->firstHighest || eliminationCount > self->highestEliminationCount) {
+		/* update maximum */
+		self->highestEliminationCount = eliminationCount;
+		self->highestData = data;
+		self->firstHighest = 0;
+	}
+}
 /** determines the next best move to make.
   * @param self game state so far
   * @param outGuess location to store the move in
@@ -169,10 +229,9 @@ int Gamestate_getBestMove(struct Gamesta
 	  *   Later on, we send that guess.
 	  */
 	int secretCount; /* number of set bits in secrets */
-	unsigned int data; /* possible guess */
-	unsigned int highestData = 0; /* for storing where the maximum is (i.e. which guess is best) */
-	int first = 1;
-	int highestEliminationCount = -1; /* for storing the maximum */
+	self->highestData = 0; /* for storing where the maximum is (i.e. which guess is best) */
+	self->firstHighest = 1;
+	self->highestEliminationCount = -1; /* for storing the maximum */
 	secretCount = Bitarray_getSetCount(self->secrets);
 	assert(secretCount > 0);
 	DEBUG("Getting best move...\n");
@@ -180,26 +239,17 @@ int Gamestate_getBestMove(struct Gamesta
 		Bitarray_iterateSet(self->secrets, storeGuess, outGuess);
 		return 1;
 	}
-	for(data = 0; data < pow(COLORS, SLOTS); ++data) { /* for all possible guesses */
-		/** Calculate how many possibilities (secrets) we could (at least) eliminate.
-		  * Take the guess with the highest such value.
-		  */
-		int eliminationCount;
-		eliminationCount = Gamestate_getEliminationCount(self, data);
-		if(eliminationCount > highestEliminationCount) {
-			/* update maximum */
-			highestEliminationCount = eliminationCount;
-			highestData = data;
-			first = 0;
-		}
-	}
-	unpackGuess(highestData, outGuess);
+	assert(SLOTS == 5);
+	assert(self->paletteCount == SLOTS);
+	perm2(self->palette, self->paletteCount, &processElimination, self);
+	unpackGuess(self->highestData, outGuess);
 	DEBUG("Done getting best move.\n");
-	return !first; // (highestEliminationCount > 0);
+	return !self->firstHighest; // (highestEliminationCount > 0);
 }
 
 /** given a score and a secret, returns whether it DOESN'T match the score. */
 static int differentlyScoredP(void* userdata, unsigned int secretBitIndex) {
+	/* this is NOT allowed to use palette. */
 	struct Gamestate* self = (struct Gamestate*) userdata;
 	int correctCount, opresentCount;
 	guess_t g1, g2;
@@ -221,12 +271,18 @@ int printGuess(FILE* destination, guess_
 }
 
 void Gamestate_removeDifferentlyScoredSecrets(struct Gamestate* self, guess_t* g1, int correctCount, int opresentCount) {
+	/* this is NOT allowed to use palette. */
 	/*(void) fprintf(stderr, "Guessing ");
 	printGuess(g1);*/
 	self->guess = packGuess(g1);
 	self->correctCount = correctCount; /* closure for unsetEach */
 	self->opresentCount = opresentCount; /* closure for unsetEach */
 	Bitarray_unsetEach(self->secrets, differentlyScoredP, self);
+	if(correctCount + opresentCount == 0) { /* no colors in there match anything. TODO is that worth it? */
+		int i;
+		for(i = 0; i < SLOTS; ++i)
+			Gamestate_disqualifyGuessesContainingColor(self, (*g1)[i]);
+	}
 	DEBUG("Removed differently scored secrets.\n");
 }
 void Gamestate_startRound(struct Gamestate* self) {
@@ -236,4 +292,39 @@ void Gamestate_startRound(struct Gamesta
 int Gamestate_getRoundCount(struct Gamestate* self) {
 	return self->roundCount;
 }
-
+uint8_t Gamestate_getPaletteEntry(struct Gamestate* self, int index) {
+	return self->palette[index];
+}
+int Gamestate_getPaletteEntryCount(struct Gamestate* self) {
+	return self->paletteCount;
+}
+void Gamestate_addPaletteEntry(struct Gamestate* self, uint8_t value) {
+	if(self->paletteCount >= SLOTS)
+		abort();
+	self->palette[self->paletteCount++] = value;
+}
+void Gamestate_disqualifyGuessesContainingColor(struct Gamestate* self, uint8_t value) {
+	/* since this is used when building up the palette, don't use it in here. */
+	guess_t guess;
+	assert(SLOTS == 5);
+	for(int s0i = 0; s0i < COLORS; ++s0i) {
+		guess[0] = s0i;
+		for(int s1i = 0; s1i < COLORS; ++s1i) {
+			guess[1] = s1i;
+			for(int s2i = 0; s2i < COLORS; ++s2i) {
+				guess[2] = s2i;
+				for(int s3i = 0; s3i < COLORS; ++s3i) {
+					guess[3] = s3i;
+					for(int s4i = 0; s4i < COLORS; ++s4i) {
+						guess[4] = s4i;
+						if(guess[0] == value || guess[1] == value || guess[2] == value || guess[3] == value || guess[4] == value) {
+							unsigned int data; /* possible guess */
+							data = packGuess(&guess);
+							Bitarray_set(self->secrets, data, 0);
+						}
+					}
+				}
+			}
+		}
+	}
+}
diff -rup omastermind/mastermind/src/Gamestate.h mastermind/src/Gamestate.h
--- omastermind/mastermind/src/Gamestate.h	2013-11-11 07:37:32.000000000 +0100
+++ mastermind/src/Gamestate.h	2013-11-13 20:54:32.390600068 +0100
@@ -69,10 +69,36 @@ int printGuess(FILE* destination, guess_
   */
 void Gamestate_removeDifferentlyScoredSecrets(struct Gamestate* self, guess_t* g1, int correctCount, int opresentCount);
 
+/** get the entry in the palette (of colors) with the given index.
+  * @param self game state.
+  * @param index index in palette. 0 is first.
+  * @return color
+  */
+uint8_t Gamestate_getPaletteEntry(struct Gamestate* self, int index);
+
+/** get the entry count in the palette. 
+  * @param self game state.
+  * @return entry count
+  */
+int Gamestate_getPaletteEntryCount(struct Gamestate* self);
+
+/** add entry to the palette. 
+  * @param self game state.
+  * @param value color.
+  */
+void Gamestate_addPaletteEntry(struct Gamestate* self, uint8_t value);
+
+/** disqualify any guesses that contain the given color. 
+  * @param self game state.
+  * @param value color (NOT using palette).
+  */ 
+void Gamestate_disqualifyGuessesContainingColor(struct Gamestate* self, uint8_t value);
+
 /** increase round count */
 void Gamestate_startRound(struct Gamestate* self);
 
 /** get round count */
 int Gamestate_getRoundCount(struct Gamestate* self);
 
+
 #endif
Only in mastermind: testClient
Only in mastermind: testServer
