initial commit

This commit is contained in:
2018-08-18 15:47:12 +01:00
commit 77fe861eb9
20 changed files with 1171 additions and 0 deletions

3
src/STYLE.md Normal file
View File

@@ -0,0 +1,3 @@
Indented using:
astyle --style=java

37
src/dir.c Normal file
View File

@@ -0,0 +1,37 @@
#include "dir.h"
#include "rnd.h"
int directions[] = {
DIRECTION_N,
DIRECTION_NE,
DIRECTION_E,
DIRECTION_SE,
DIRECTION_S,
DIRECTION_SW,
DIRECTION_W,
DIRECTION_NW
};
int get_direction(int simple) {
if (simple) {
if (random_number(0, 1) == 0) {
return DIRECTION_E;
} else {
return DIRECTION_S;
}
} else {
return directions[random_number(0, NUM_DIRECTIONS)];
}
}
#ifdef DEBUG_DIR_MAIN
#include <stdio.h>
int main() {
int n = 32;
while (--n > 0) {
printf("%d\n", get_direction(1));
}
return 0;
}
#endif

19
src/dir.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef WORDSEARCH_DIR
#define WORDSEARCH_DIR
enum direction {
DIRECTION_N,
DIRECTION_NE,
DIRECTION_E,
DIRECTION_SE,
DIRECTION_S,
DIRECTION_SW,
DIRECTION_W,
DIRECTION_NW
};
#define NUM_DIRECTIONS 8
int get_direction(int simple);
#endif

232
src/grid.c Normal file
View File

@@ -0,0 +1,232 @@
// #define DEBUG
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include "rnd.h"
#include "dir.h"
#include "grid.h"
enum exitcodes {
EXIT_WORDTOOLONG,
};
bounds *get_bounds(int height, int width, enum direction direction, int length) {
#ifdef DEBUG
printf("get_bounds(height=%d, width=%d, direction=%d, length=%d) -> ", height, width, direction, length);
#endif
if (length > height || length > width) {
return NULL;
}
length--;
bounds *b = (bounds *) malloc(sizeof(bounds));
b->min_x = 0;
b->max_x = width-1;
b->min_y = 0;
b->max_y = height-1;
if (direction == DIRECTION_N ||
direction == DIRECTION_NE || direction == DIRECTION_NW) {
b->min_y = length;
}
if (direction == DIRECTION_W ||
direction == DIRECTION_NW || direction == DIRECTION_SW) {
b->min_x = length;
}
if (direction == DIRECTION_E ||
direction == DIRECTION_NE || direction == DIRECTION_SE) {
b->max_x = width - length - 1;
}
if (direction == DIRECTION_S ||
direction == DIRECTION_SW || direction == DIRECTION_SE) {
b->max_y = height - length - 1;
}
#ifdef DEBUG
printf("%d <= x <= %d & %d <= y <= %d\n", b->min_x, b->max_x, b->min_y, b->max_y);
#endif
return b;
}
int move_x(int x, enum direction d) {
if(
d == DIRECTION_E ||
d == DIRECTION_NE ||
d == DIRECTION_SE
) {
x++;
} else if (
d == DIRECTION_W ||
d == DIRECTION_NW ||
d == DIRECTION_SW
) {
x--;
}
return x;
}
int move_y(int y, enum direction d) {
if(
d == DIRECTION_N ||
d == DIRECTION_NE ||
d == DIRECTION_NW
) {
y--;
} else if (
d == DIRECTION_S ||
d == DIRECTION_SE ||
d == DIRECTION_SW
) {
y++;
}
return y;
}
char **make_grid(char **words, int height, int width, int simple, int count) {
char **grid = init_grid(NULL, height, width);
#ifdef INITCHECK
free_grid(grid, height);
exit(0);
#endif
for(int i=0; i<count; i++) {
#ifdef DEBUG
printf("Placing word %d: %s\n", i, words[i]);
#endif
int tries = 0;
int placed = 0;
while(tries++ < WORDSEARCH_MAXTRIES && placed == 0) {
char **g = place_word(words[i], grid, height, width, simple);
if(g) {
placed = 1;
grid = g;
}
}
#ifdef DEBUG
print_grid(grid, height);
#endif
}
#ifndef DONOTFILL
/* Now the words are done, we need to fill in the blanks */
for (int x=0; x<height; x++) {
for (int y=0; y<width; y++) {
if(grid[x][y] == '_') {
grid[x][y] = get_random_letter();
}
}
}
#endif
return grid;
}
char** place_word(char *word, char **grid, int height, int width, int simple) {
int dir = get_direction(simple);
bounds *b;
#ifdef DEBUG
printf("place_word(%s, ...), direction=%d\n", word, dir);
#endif
b = get_bounds(height, width, dir, strlen(word));
if (b) {
/* word will probably fit... */
int x, y;
x = random_number(b->min_x, b->max_x);
y = random_number(b->min_y, b->max_y);
#ifdef DEBUG
printf("Attempting to place word `%s' starting @ %d,%d going %d\n", word, x, y, dir);
#endif
char** tempgrid = init_grid(grid, height, width);
/* Now we have two copies of the grid, try to place the word... */
int i;
for(i=0; i<strlen(word); i++) {
if(!isalpha(word[i])) continue;
if(tempgrid[y][x] != '_') {
#ifdef DEBUG
printf("Checking (%d,%d)\n", x, y);
#endif
if(tempgrid[y][x] != word[i]) {
/* Failed to place word */
free_grid(tempgrid, height);
free(b);
return 0;
} else {
/* word crossed ok! */
}
} else {
tempgrid[y][x] = word[i];
}
x = move_x(x, dir);
y = move_y(y, dir);
}
#ifdef DEBUG
printf("Placed word %s\n", word);
print_grid(tempgrid, height);
printf("Swapping references...\n");
#endif
free_grid(grid, height);
free(b);
grid = tempgrid;
#ifdef DEBUG
printf("Dumping current grid:\n");
print_grid(grid, height);
#endif
return grid;
} else {
/* word can't fit */
printf("[ERR] Word too long to place in this grid: %s\n", word);
exit(EXIT_WORDTOOLONG);
}
}
/* Clones or creates an empty grid - pass NULL in as old to get an empty grid */
char **init_grid(char** old, int height, int width) {
int row, cell;
char **new = malloc(height * sizeof(char*));
for (row=0; row < height; row++) {
new[row] = malloc(width * sizeof(char));
for (cell=0; cell < width; cell++) {
if(old) {
new[row][cell] = old[row][cell];
} else {
new[row][cell] = '_';
}
}
}
return new;
}
void free_grid(char** grid, int height) {
for (int i=0; i<height; i++) {
free(grid[i]);
}
free(grid);
}
void print_grid(char** grid, int height) {
// printf("print_grid(): \n");
for(int i=0; i<height; i++) {
if(grid[i] == NULL) {
printf("row error (i=%d)\n", i);
} else {
printf("%s\n", grid[i]);
}
}
}

27
src/grid.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef WORDSEARCH_GRID
#define WORDSEARCH_GRID
#include "dir.h"
#define WORDSEARCH_MAXTRIES 500
char **make_grid(char **words, int height, int width, int simple, int count);
typedef struct bounds {
int min_y;
int max_y;
int min_x;
int max_x;
} bounds;
/* returns NULL if cannot fit word; caller needs to free() the response */
bounds *get_bounds(int height, int width, enum direction direction, int length);
char** place_word(char *word, char **grid, int height, int width, int simple);
char **init_grid(char** old, int height, int width);
void free_grid(char** grid, int height);
int move_x(int x, enum direction d);
int move_y(int y, enum direction d);
void print_grid(char** grid, int height);
#endif

121
src/rnd.c Normal file
View File

@@ -0,0 +1,121 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include "rnd.h"
/* https://www.math.cornell.edu/~mec/2003-2004/cryptography/subs/frequencies.html */
#define ALPHABET_SIZE 26
#define RND_MAXINT 10000
struct letter_frequency {
int p; /* pegged to 10000 rather than 1 */
char c;
} letter_frequencies[] = {
{
7, 'Z'
}, {
10, 'J'
}, {
11, 'Q'
}, {
17, 'X'
}, {
69, 'K'
}, {
111, 'V'
}, {
149, 'B'
}, {
182, 'P'
}, {
203, 'G'
}, {
209, 'W'
}, {
211, 'Y'
}, {
230, 'F'
}, {
261, 'M'
}, {
271, 'C'
}, {
288, 'U'
}, {
398, 'L'
}, {
432, 'D'
}, {
592, 'H'
}, {
602, 'R'
}, {
628, 'S'
}, {
695, 'N'
}, {
731, 'I'
}, {
768, 'O'
}, {
812, 'A'
}, {
910, 'T'
}, {
1202, 'E'
},
};
/* from http://stackoverflow.com/questions/822323/how-to-generate-a-random-number-in-c */
int random_number(int min_num, int max_num) {
static int initialised = 0;
int result = 0;
int low_num = 0;
int hi_num = 0;
if (min_num < max_num) {
low_num = min_num;
hi_num = max_num + 1; // this is done to include max_num in output.
} else {
low_num = max_num + 1; // this is done to include max_num in output.
hi_num = min_num;
}
if (!initialised) {
struct timeval tv;
gettimeofday(&tv, NULL);
// srand(time(NULL));
srand(tv.tv_usec);
initialised = 1;
}
result = (rand() % (hi_num - low_num)) + low_num;
return result;
}
char get_random_letter() {
int rnd = random_number(0, RND_MAXINT);
for (int i = 0; i < ALPHABET_SIZE; i++) {
if (rnd < letter_frequencies[i].p) {
return letter_frequencies[i].c;
}
rnd -= letter_frequencies[i].p;
}
return '\0';
}
#ifdef DEBUG_RND_MAIN
#include <stdio.h>
#include <assert.h>
int main() {
int n = 10000;
while (--n > 0) {
// printf("%c", get_random_letter());
int r = random_number(0,10);
assert(r >= 0);
assert(r <= 10);
}
return 0;
}
#endif

7
src/rnd.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef WORDSEARCH_RND
#define WORDSEARCH_RND
char get_random_letter();
int random_number(int min_num, int max_num);
#endif

19
src/tags Normal file
View File

@@ -0,0 +1,19 @@
Mdir dir.c /^int main() {$/
Mrnd rnd.c /^int main() {$/
Mwordsearch wordsearch.c /^int main(int argc, char **argv) {$/
bounds grid.h /^} bounds;$/
direction dir.h /^enum direction {$/
exitcodes grid.c /^enum exitcodes {$/
free_grid grid.c /^void free_grid(char** grid, int height) {$/
get_bounds grid.c /^bounds *get_bounds(int height, int width, enum dir/
get_direction dir.c /^int get_direction(int simple) {$/
get_random_letter rnd.c /^char get_random_letter() {$/
init_grid grid.c /^char **init_grid(char** old, int height, int width/
letter_frequency rnd.c /^struct letter_frequency {$/
make_grid grid.c /^char **make_grid(char **words, int height, int wid/
move_x grid.c /^int move_x(int x, enum direction d) {$/
move_y grid.c /^int move_y(int y, enum direction d) {$/
place_word grid.c /^char** place_word(char *word, char **grid, int hei/
print_grid grid.c /^void print_grid(char** grid, int height) {$/
random_number rnd.c /^int random_number(int min_num, int max_num) {$/
strtoupper wordsearch.c /^#define strtoupper(X) for(char* c=X; *c=toupper(*c/

46
src/wordsearch.c Normal file
View File

@@ -0,0 +1,46 @@
/*
============================================================================
Name : wordsearch.c
Author : Matthew Slowe
Version :
Copyright : MIT
Description : Hello World in C, Ansi-style
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "grid.h"
#include <ctype.h>
#define strtoupper(X) for(char* c=X; *c=toupper(*c); ++c)
int main(int argc, char **argv) {
// Reading parameters
if(argc < 3) {
fprintf(stderr, "Usage: %s <height> <width> [ words ... ]\n", argv[0]);
exit(1);
}
int width, height;
height = atoi(argv[1]);
width = atoi(argv[2]);
char *words[argc-3];
int words_count = argc-3;
for(int i=0; i<words_count; i++) {
words[i] = malloc(strlen(argv[i+3]));
strcpy(words[i], argv[i+3]);
strtoupper(words[i]);
}
// if(argc > 2) {
//
// } else {
// char *words[4] = { "test", "word", "longer", "verylong" };
// }
char **grid = make_grid(words, height, width, 0, words_count);
print_grid(grid, height);
free_grid(grid, height);
}