MAKENSIS = "C:\Program Files (x86)\NSIS\makensis.exe"
TMPDIR =$(OUTDIR)\Objects
+TSTDIR =$(OUTDIR)\TestObjects
CC =$(CC) -nologo
LD =$(LINK) -nologo
-CFLAGS =$(CFLAGS) -W3 -YX -Fp$(TMPDIR)^\
+CFLAGS =$(CFLAGS) -W3
INC =-I$(SDLDIR)/include
DEFS =-DWIN32 -DHAVE_OPENGL -Dmain=SDL_main
LIBS =-libpath:$(SDLDIR)/lib SDLmain.lib SDL.lib SDL_mixer.lib kernel32.lib
OBJS = \
$(TMPDIR)\ag.obj \
+ $(TMPDIR)\ag_core.obj \
$(TMPDIR)\dlb.obj \
$(TMPDIR)\linked.obj \
$(TMPDIR)\sprite.obj \
.PHONY: all ag release
+#-------------------------------------------------------------------------
+
+tests: test_agcore test_dlb test_linked
+test_ag: setup $(OUTDIR)\test_ag.exe
+test_dlb: setup $(OUTDIR)\test_dlb.exe
+test_agcore: setup $(OUTDIR)\test_agcore.exe
+test_linked: setup $(OUTDIR)\test_linked.exe
+
+$(OUTDIR)\test_ag.exe: $(SRCDIR)/ag_test.c
+ $(CC) $(CFLAGS) $(INC) -DUNIT_TEST -Fo$(TSTDIR)\ $** -link $(LDFLAGS) -subsystem:console -out:$@
+
+$(OUTDIR)\test_agcore.exe: $(SRCDIR)/ag_core.c $(TMPDIR)\dlb.obj $(TMPDIR)\linked.obj
+ $(CC) $(CFLAGS) $(INC) -DUNIT_TEST -Fo$(TSTDIR)\ $** -link $(LDFLAGS) -subsystem:console -out:$@
+
+$(OUTDIR)\test_linked.exe: $(SRCDIR)/linked.c
+ $(CC) $(CFLAGS) $(INC) -DUNIT_TEST -Fo$(TSTDIR)\ $** -link $(LDFLAGS) -subsystem:console -out:$@
+
+$(OUTDIR)\test_dlb.exe: $(SRCDIR)/dlb.c
+ $(CC) $(CFLAGS) $(INC) -DUNIT_TEST -Fo$(TSTDIR)\ $** -link $(LDFLAGS) -subsystem:console -out:$@
+
+
#-------------------------------------------------------------------------
setup:
@if not exist $(OUTDIR) mkdir $(OUTDIR)
@if not exist $(TMPDIR) mkdir $(TMPDIR)
+ @if not exist $(TSTDIR) mkdir $(TSTDIR)
clean:
@if exist $(TMPDIR)\NUL $(RMDIR) $(TMPDIR) >NUL
* -------------------------------------------------------------------
*/
-#include <sys/types.h>
-#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define snprintf _snprintf
#endif
+/* functions from ag_code.c */
+void ag(struct node **head, struct dlb_node *dlbHead,
+ const char *guess, const char *remain);
+void getRandomWord(char *output, size_t length);
+int nextBlank(const char *string);
+
+
+
/* module level variables for game control */
char shuffle[8] = SPACE_FILLED_CHARS;
char answer[8] = SPACE_FILLED_CHARS;
char language[64];
char txt[50];
-char* rootWord;
+char rootWord[9];
int updateAnswers = 0;
int startNewGame = 0;
int solvePuzzle = 0;
}
}
-/***********************************************************
-synopsis: determine the next blank space in a string
- blanks are indicated by pound not space
-
-inputs: pointer the string to check
-
-outputs: returns position of next blank (1 is first character)
- or 0 if no blanks found
-***********************************************************/
-static int
-nextBlank(const char *string)
-{
- const char *p = strchr(string, SPACE_CHAR);
- if (p)
- return 1 + (p - string);
- return 0;
-}
-
-
-/***********************************************************
-synopsis: shift a string of characters 1 character to the left
- truncating the leftmost character
-
-inputs: pointer to string to shift
-
-outputs: pointer to the shifted string
-***********************************************************/
-static char *
-shiftLeftKill(const char *string)
-{
- return strdup(string + 1);
-}
-
-/***********************************************************
-synopsis: shift a string of characters 1 character to the left
- move the first character to the end of the string
- so it wraps around
-
-inputs: pointer to string to shift
-
-outputs: pointer to the shifted string
-***********************************************************/
-static char *
-shiftLeft(char *string)
-{
- char c = *string;
- char *p = string, *q = string+1;
- for (; p && *p && q && *q; ) {
- *p++ = *q++;
- }
- *p = c;
- return string;
-}
-
-/***********************************************************
-synopsis: Generate all possible combinations of the root word
- the initial letter is fixed, so to work out all
- anagrams of a word, prefix with space.
-
-inputs: head - pointer to the answers list
- dlbHead - pointer to the dictionary
- guess - pointer to the current guess
- remain - pointer to the remaining letters
-
-outputs: all parameters are in/out
-***********************************************************/
-static void
-ag(struct node** head, struct dlb_node* dlbHead,
- const char* guess, const char* remain)
-{
- char* newGuess;
- char* newRemain;
- int totalLen=0, guessLen=0, remainLen=0;
-
- /* allocate space for our working variables */
- guessLen = strlen(guess);
- remainLen = strlen(remain);
- totalLen = guessLen + remainLen;
-
- newGuess = malloc(sizeof(char) * (totalLen+1));
- newRemain = malloc(sizeof(char) * (totalLen+1));
-
- /* move last remaining letter to end of guess */
- strcpy(newGuess, guess);
- strcpy(newRemain, remain);
- newGuess[guessLen] = newRemain[remainLen-1];
- newGuess[guessLen+1] = '\0';
- newRemain[remainLen-1] = '\0';
-
- if (strlen(newGuess) > 3){
- char *str = shiftLeftKill(newGuess);
- if (dlb_lookup(dlbHead, str)) {
- push(head, str);
- }
- free(str);
- }
-
- if (strlen(newRemain)) {
- size_t i;
- ag(head, dlbHead, newGuess, newRemain);
-
- for (i = totalLen-1; i > 0; i--) {
- if (strlen(newRemain) > i){
- newRemain = shiftLeft(newRemain);
- ag(head, dlbHead, newGuess, newRemain);
- }
- }
- }
- /* free the space */
- free(newGuess);
- free(newRemain);
-}
-
-/***********************************************************
-synopsis: update all of the answers to "found"
-
-inputs: head - pointer to the answers linked list
-
-outputs: n/a
-***********************************************************/
-static void
-solveIt(struct node *head)
-{
- struct node* current = head;
-
- while (current != NULL){
- current->found = 1;
- current = current->next;
- }
-}
/***********************************************************
synopsis: load the named image to position x,y onto the
}
+/***********************************************************
+synopsis: update all of the answers to "found"
+
+inputs: head - pointer to the answers linked list
+
+outputs: n/a
+***********************************************************/
+static void
+solveIt(struct node *head)
+{
+ struct node* current = head;
+
+ while (current != NULL){
+ current->found = 1;
+ current = current->next;
+ }
+}
+
/***********************************************************
-/***********************************************************
-synopsis: spin the word file to a random location and then
- loop until a 7 or 8 letter word is found
- this is quite a weak way to get a random word
- considering we've got a nice dbl Dictionary to
- hand - but it works for now.
-
-inputs: n/a
-
-outputs: a random word
-***********************************************************/
-static void
-getRandomWord(char *output, size_t length)
-{
- FILE *fp;
- struct stat statbuf;
- char buffer[64];
-
- assert(length == 9);
-
- strcpy(txt,language);
- strcat(txt,"wordlist.txt");
- fp = fopen(txt,"r");
-
- stat(txt, &statbuf);
- fseek(fp, (rand() % statbuf.st_size), SEEK_SET);
- if (fscanf(fp, "%63s", buffer) == EOF)
- fseek(fp, 0, SEEK_SET);
-
- /* ok random location reached */
- while (strlen(buffer) != 7) {
- if (fscanf(fp, "%63s", buffer) == EOF) {
- /* go back to the start of the file */
- int i;
- fseek(fp, 0L, SEEK_SET);
- i = fscanf(fp, "%63s", buffer);
- assert(i != EOF);
- }
- }
-
- fclose(fp);
-
- /* add in our space character */
- strcpy(output, buffer);
- strcat(output, " ");
- return;
-}
-
/***********************************************************
synopsis: replace characters randomly
outputs: n/a
***********************************************************/
static void
-shuffleAvailableLetters(char** thisWord, struct sprite** letters)
+shuffleAvailableLetters(char *word, struct sprite **letters)
{
struct sprite *thisLetter = *letters;
int from, to;
char swap, posSwap;
- char* shuffleChars;
- char* shufflePos;
- int i=0;
+ char shuffleChars[8];
+ char shufflePos[8];
+ int i = 0;
int numSwaps;
- shuffleChars = malloc(sizeof(char) * 8);
- shufflePos = malloc(sizeof(char) * 8);
-
- for(i=0;i<7;i++){
- shufflePos[i]=i+1;
+ for (i = 0; i < 7; i++) {
+ shufflePos[i] = i + 1;
}
shufflePos[7] = '\0';
- strcpy(shuffleChars, *thisWord);
-
+ strcpy(shuffleChars, word);
numSwaps = rand()%10+20;
- for (i=0;i<numSwaps;i++){
+ for (i = 0; i < numSwaps; i++) {
from = rand()%7;
to = rand()%7;
shufflePos[to] = posSwap;
}
- while(thisLetter != NULL){
- if (thisLetter->box == SHUFFLE){
+ while (thisLetter != NULL) {
+ if (thisLetter->box == SHUFFLE) {
thisLetter->toX = (whereinstr(shufflePos, (char)(thisLetter->index+1)) * (GAME_LETTER_WIDTH + GAME_LETTER_SPACE)) + BOX_START_X;
thisLetter->index = whereinstr(shufflePos, (char)(thisLetter->index+1));
}
thisLetter = thisLetter->next;
}
- strcpy(*thisWord, shuffleChars);
-
- free(shuffleChars);
- free(shufflePos);
+ strcpy(word, shuffleChars);
}
newGame(struct node** head, struct dlb_node* dlbHead,
SDL_Surface* screen, struct sprite** letters)
{
- char* guess;
- char* remain;
+ char guess[8];
+ char remain[8];
int happy = 0; /* we don't want any more than ones with 66 answers */
/* - that's all we can show... */
int i;
destroyLetters(letters);
assert(*letters == NULL);
- guess = malloc(sizeof(char)*50);
- remain = malloc(sizeof(char)*50);
-
while (!happy) {
char buffer[9];
getRandomWord(buffer, sizeof(buffer));
strcpy(guess,"");
strcpy(rootWord, buffer);
bigWordLen = strlen(rootWord)-1;
- strcpy(remain,rootWord);
+ strcpy(remain, rootWord);
rootWord[bigWordLen] = '\0';
/* generate anagrams from random word */
ag(head, dlbHead, guess, remain);
- sort(head);
-
answersSought = Length(*head);
happy = ((answersSought <= 77) && (answersSought >= 6));
#ifdef DEBUG
printf("Selected word: %s, answers: %i\n", rootWord, answersSought);
#endif
+
/* now we have a good set of words - sort them alphabetically */
- //sort(head);
+ sort(head);
for (i = bigWordLen; i < 7; i++){
remain[i] = SPACE_CHAR;
}
-
remain[7] = '\0';
-
remain[bigWordLen]='\0';
shuffleWord(remain);
strcpy(shuffle, remain);
- free(guess);
- free(remain);
-
strcpy(answer, SPACE_FILLED_STRING);
/* build up the letter sprites */
gameTime = timeNow;
updateTime(screen);
}
- }
- else{
+ } else {
if (!stopTheClock){
stopTheClock = 1;
solvePuzzle = 1;
updateAnswers = 0;
}
- if(startNewGame){
+ if (startNewGame) {
/* move letters back down again */
if (!gotBigWord){
totalScore = 0;
startNewGame = 0;
}
- if(updateTheScore){
+ if (updateTheScore) {
updateScore(screen);
-
updateTheScore = 0;
}
- if (shuffleRemaining){
+ if (shuffleRemaining) {
/* shuffle up the shuffle box */
- char *shuffler;
- shuffler = malloc(sizeof(char) * 8);
+ char shuffler[8];
strcpy(shuffler, shuffle);
- shuffleAvailableLetters(&shuffler, letters);
+ shuffleAvailableLetters(shuffler, letters);
strcpy(shuffle, shuffler);
- free(shuffler);
- /* clearLetters(screen); */
- /* displayLetters(screen); */
-
shuffleRemaining = 0;
}
- if (clearGuess){
+ if (clearGuess) {
/* clear the guess; */
- if (clearWord(letters) > 0)
+ if (clearWord(letters) > 0) {
Mix_PlayChannel(-1, getSound("clear"),0);
-
+ }
clearGuess = 0;
}
- if (quitGame){
- done=1;
+ if (quitGame) {
+ done = 1;
}
- while (SDL_WaitEvent(&event))
- {
+ while (SDL_WaitEvent(&event)) {
if (event.type == SDL_USEREVENT) {
timer_delay = anySpritesMoving(letters) ? 10 : 100;
moveSprites(&screen, letters, letterSpeed);
strcpy(txt, language);
numberBank = SDL_LoadBMP(strcat(txt,"images/numberBank.bmp"));
- rootWord = malloc(sizeof(char)*9);
newGame(&head, dlbHead, screen, &letters);
gameLoop(&head, dlbHead, screen, &letters);
/* tidy up and exit */
- free(rootWord);
Mix_CloseAudio();
clearSoundBuffer(&soundCache);
dlb_free(dlbHead);
--- /dev/null
+/*
+ * This file contains all the anagram handling code so that the
+ * validity of the anagram management can be tested independently of
+ * the SDL graphical management code.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include "dlb.h"
+#include "linked.h"
+#include "ag.h"
+
+extern char txt[50];
+extern char language[64];
+
+/***********************************************************
+synopsis: determine the next blank space in a string
+ blanks are indicated by pound not space
+
+inputs: pointer the string to check
+
+outputs: returns position of next blank (1 is first character)
+ or 0 if no blanks found
+***********************************************************/
+int
+nextBlank(const char *string)
+{
+ const char *p = strchr(string, SPACE_CHAR);
+ if (p)
+ return 1 + (p - string);
+ return 0;
+}
+
+
+/***********************************************************
+synopsis: shift a string of characters 1 character to the left
+ truncating the leftmost character
+
+inputs: pointer to string to shift
+
+outputs: pointer to the shifted string
+***********************************************************/
+static char *
+shiftLeftKill(const char *string)
+{
+ return strdup(string + 1);
+}
+
+/***********************************************************
+synopsis: shift a string of characters 1 character to the left
+ move the first character to the end of the string
+ so it wraps around
+
+inputs: pointer to string to shift
+
+outputs: pointer to the shifted string
+***********************************************************/
+static char *
+shiftLeft(char *string)
+{
+ char c = *string;
+ char *p = string, *q = string+1;
+ for (; p && *p && q && *q; ) {
+ *p++ = *q++;
+ }
+ *p = c;
+ return string;
+}
+
+/***********************************************************
+synopsis: Generate all possible combinations of the root word
+ the initial letter is fixed, so to work out all
+ anagrams of a word, prefix with space.
+
+inputs: head - pointer to the answers list
+ dlbHead - pointer to the dictionary
+ guess - pointer to the current guess
+ remain - pointer to the remaining letters
+
+outputs: all parameters are in/out
+***********************************************************/
+void
+ag(struct node** head, struct dlb_node* dlbHead,
+ const char* guess, const char* remain)
+{
+ char* newGuess;
+ char* newRemain;
+ int totalLen=0, guessLen=0, remainLen=0;
+
+ /* allocate space for our working variables */
+ guessLen = strlen(guess);
+ remainLen = strlen(remain);
+ totalLen = guessLen + remainLen;
+
+ newGuess = malloc(sizeof(char) * (totalLen+1));
+ newRemain = malloc(sizeof(char) * (totalLen+1));
+
+ /* move last remaining letter to end of guess */
+ strcpy(newGuess, guess);
+ strcpy(newRemain, remain);
+ newGuess[guessLen] = newRemain[remainLen-1];
+ newGuess[guessLen+1] = '\0';
+ newRemain[remainLen-1] = '\0';
+
+ if (strlen(newGuess) > 3){
+ char *str = shiftLeftKill(newGuess);
+ if (dlb_lookup(dlbHead, str)) {
+ push(head, str);
+ }
+ free(str);
+ }
+
+ if (strlen(newRemain)) {
+ size_t i;
+ ag(head, dlbHead, newGuess, newRemain);
+
+ for (i = totalLen-1; i > 0; i--) {
+ if (strlen(newRemain) > i){
+ newRemain = shiftLeft(newRemain);
+ ag(head, dlbHead, newGuess, newRemain);
+ }
+ }
+ }
+ /* free the space */
+ free(newGuess);
+ free(newRemain);
+}
+
+/* checkGuess - needs to return a sound to play */
+
+/***********************************************************
+synopsis: spin the word file to a random location and then
+ loop until a 7 or 8 letter word is found
+ this is quite a weak way to get a random word
+ considering we've got a nice dbl Dictionary to
+ hand - but it works for now.
+
+inputs: n/a
+
+outputs: a random word
+***********************************************************/
+void
+getRandomWord(char *output, size_t length)
+{
+ FILE *fp;
+ struct stat statbuf;
+ char buffer[64];
+
+ assert(length == 9);
+
+ strcpy(txt,language);
+ strcat(txt,"wordlist.txt");
+ fp = fopen(txt,"r");
+
+ stat(txt, &statbuf);
+ fseek(fp, (rand() % statbuf.st_size), SEEK_SET);
+ if (fscanf(fp, "%63s", buffer) == EOF)
+ fseek(fp, 0, SEEK_SET);
+
+ /* ok random location reached */
+ while (strlen(buffer) != 7) {
+ if (fscanf(fp, "%63s", buffer) == EOF) {
+ /* go back to the start of the file */
+ int i;
+ fseek(fp, 0L, SEEK_SET);
+ i = fscanf(fp, "%63s", buffer);
+ assert(i != EOF);
+ }
+ }
+
+ fclose(fp);
+
+ /* add in our space character */
+ strcpy(output, buffer);
+ strcat(output, " ");
+ return;
+}
+
+#ifdef UNIT_TEST
+#include "unittest.h"
+
+char txt[50];
+char language[64];
+
+static int test_nextBlank(void *cd)
+{
+ char a[7] = {'a','b',SPACE_CHAR,'c',SPACE_CHAR,'d', 0};
+ test_equals_int("nextBlank", 3, nextBlank(a));
+ test_equals_int("nextBlank substr", 2, nextBlank(a+3));
+ test_equals_int("nextBlank no-blanks", 0, nextBlank("abcdef"));
+ test_equals_int("nextBlank zero-length", 0, nextBlank(""));
+ return 0;
+}
+
+static int test_shiftLeftKill(void *cd)
+{
+ char a[7] = { 'a','b','c','d','e','f', 0 };
+ char *s = shiftLeftKill(a);
+ test_equals_str("shiftLeftKill", "bcdef", s);
+ free(s);
+ s = shiftLeftKill("abcdef");
+ test_equals_str("shiftLeftKill const str", "bcdef", s);
+ free(s);
+ return 0;
+}
+
+static int test_shiftLeft(void *cd)
+{
+ char a[7] = { 'a','b','c','d','e','f', 0 };
+ char b[2] = { 'a', 0 };
+ test_equals_str("shiftLeft string", "bcdefa", shiftLeft(a));
+ test_equals_str("shiftLeft short string", "a", shiftLeft(b));
+ return 0;
+}
+
+static int test_getRandomWord()
+{
+ char buffer[9];
+ strcpy(language, "i18n/en_GB/");
+ getRandomWord(buffer, sizeof(buffer));
+ test_equals_int("randword last char is space", ' ', buffer[7]);
+ return 0;
+}
+
+static int test_anagram(void *cd)
+{
+ char lexicon[255];
+ char buffer[9];
+ int n, count = 0;
+ struct dlb_node *tree = NULL;
+ struct node *list = NULL;
+
+ strcpy(language, "i18n/en_GB/");
+ for (n = 0; n < 10; ++n) {
+ getRandomWord(buffer, sizeof(buffer));
+ if (strlen(buffer) == 8) ++count;
+ }
+ test_equals_int("check random words", 10, count);
+
+ strcpy(lexicon, language);
+ strcat(lexicon, "wordlist.txt");
+ dlb_create(&tree, lexicon);
+ ag(&list, tree, "", "zipper ");
+ test_equals_int("check anagrams of anagram", 14, Length(list));
+ destroyAnswers(&list);
+ dlb_free(tree);
+
+ return 0;
+}
+
+struct unit_test_t unit_tests[] = {
+ {NULL, test_shiftLeftKill, NULL},
+ {NULL, test_shiftLeft, NULL},
+ {NULL, test_nextBlank, NULL},
+ {NULL, test_getRandomWord, NULL},
+ {NULL, test_anagram, NULL}
+};
+
+int
+main(void)
+{
+ run_tests(unit_tests);
+ return 0;
+}
+#endif /* UNIT_TEST */
#include "ag.c"
#undef main
-static int test_nextBlank()
-{
- char a[7] = {'a','b',SPACE_CHAR,'c',SPACE_CHAR,'d', 0};
- test_equals_int("nextBlank", 3, nextBlank(a));
- test_equals_int("nextBlank substr", 2, nextBlank(a+3));
- test_equals_int("nextBlank no-blanks", 0, nextBlank("abcdef"));
- test_equals_int("nextBlank zero-length", 0, nextBlank(""));
- return 0;
-}
-
-static int test_shiftLeftKill()
-{
- char a[7] = { 'a','b','c','d','e','f', 0 };
- char *s = shiftLeftKill(a);
- test_equals_str("shiftLeftKill", "bcdef", s);
- free(s);
- s = shiftLeftKill("abcdef");
- test_equals_str("shiftLeftKill const str", "bcdef", s);
- free(s);
- return 0;
-}
-
-static int test_shiftLeft()
-{
- char a[7] = { 'a','b','c','d','e','f', 0 };
- char b[2] = { 'a', 0 };
- test_equals_str("shiftLeft string", "bcdefa", shiftLeft(a));
- test_equals_str("shiftLeft short string", "a", shiftLeft(b));
- return 0;
-}
-
static int test_whereinstr()
{
test_equals_int("where is b", 1, whereinstr("abcdef",'b'));
return 0;
}
-static int test_getRandomWord()
-{
- char buffer[9];
- strcpy(language, "i18n/en_GB/");
- getRandomWord(buffer, sizeof(buffer));
- test_equals_int("randword last char is space", ' ', buffer[7]);
- return 0;
-}
-
struct unit_test_t unit_tests[] = {
- {NULL, test_shiftLeftKill, NULL},
- {NULL, test_shiftLeft, NULL},
- {NULL, test_nextBlank, NULL},
{NULL, test_whereinstr, NULL},
- {NULL, test_getRandomWord, NULL},
};
int
#ifdef UNIT_TEST
#include "unittest.h"
-static int test_dlb()
+static int test_dlb(void *clientData)
{
struct dlb_node *head = NULL;
test_equals_int("check code for bad file", 0,
#ifdef UNIT_TEST
#include "unittest.h"
-static int test_list_creation()
+static int test_list_creation(void *clientData)
{
struct node *head = NULL, *node = NULL;
const char *words[] = {"one", "two", "three", "four", "five" };
for (node = head, n = word_count; node; --n, node = node->next) {
if (strcmp(words[n-1], node->anagram) != 0)
test_fail("incorrect node value");
- if (strlen(words[n-1]) != node->length)
+ if (strlen(words[n-1]) != (size_t)node->length)
test_fail("incorrect node value length");
}
#define RUN(what) printf("\t%s\n", what); test_count++;
+static void test_pass(const char *what)
+{
+ RUN(what);
+}
static void test_fail(const char *what)
{
printf("\tFAIL: %s\n", what);