initial commit

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

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
Debug/wordsearch
Release/wordsearch
*.o
*.d
*.swp
.cproject
.project
.settings

44
Debug/makefile Normal file
View File

@ -0,0 +1,44 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
-include ../makefile.init
RM := rm -rf
# All of the sources participating in the build are defined here
-include sources.mk
-include src/subdir.mk
-include subdir.mk
-include objects.mk
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(C_DEPS)),)
-include $(C_DEPS)
endif
endif
-include ../makefile.defs
# Add inputs and outputs from these tool invocations to the build variables
# All Target
all: wordsearch
# Tool invocations
wordsearch: $(OBJS) $(USER_OBJS)
@echo 'Building target: $@'
@echo 'Invoking: GCC C Linker'
gcc -o "wordsearch" $(OBJS) $(USER_OBJS) $(LIBS)
@echo 'Finished building target: $@'
@echo ' '
# Other Targets
clean:
-$(RM) $(EXECUTABLES)$(OBJS)$(C_DEPS) wordsearch
-@echo ' '
.PHONY: all clean dependents
.SECONDARY:
-include ../makefile.targets

8
Debug/objects.mk Normal file
View File

@ -0,0 +1,8 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
USER_OBJS :=
LIBS :=

17
Debug/sources.mk Normal file
View File

@ -0,0 +1,17 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
OBJ_SRCS :=
ASM_SRCS :=
C_SRCS :=
O_SRCS :=
S_UPPER_SRCS :=
EXECUTABLES :=
OBJS :=
C_DEPS :=
# Every subdirectory with source files must be described here
SUBDIRS := \
src \

33
Debug/src/subdir.mk Normal file
View File

@ -0,0 +1,33 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
# Add inputs and outputs from these tool invocations to the build variables
C_SRCS += \
../src/dir.c \
../src/grid.c \
../src/rnd.c \
../src/wordsearch.c
OBJS += \
./src/dir.o \
./src/grid.o \
./src/rnd.o \
./src/wordsearch.o
C_DEPS += \
./src/dir.d \
./src/grid.d \
./src/rnd.d \
./src/wordsearch.d
# Each subdirectory must supply rules for building sources it contributes
src/%.o: ../src/%.c
@echo 'Building file: $<'
@echo 'Invoking: GCC C Compiler'
gcc -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<"
@echo 'Finished building: $<'
@echo ' '

44
Release/makefile Normal file
View File

@ -0,0 +1,44 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
-include ../makefile.init
RM := rm -rf
# All of the sources participating in the build are defined here
-include sources.mk
-include src/subdir.mk
-include subdir.mk
-include objects.mk
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(C_DEPS)),)
-include $(C_DEPS)
endif
endif
-include ../makefile.defs
# Add inputs and outputs from these tool invocations to the build variables
# All Target
all: wordsearch
# Tool invocations
wordsearch: $(OBJS) $(USER_OBJS)
@echo 'Building target: $@'
@echo 'Invoking: GCC C Linker'
gcc -o "wordsearch" $(OBJS) $(USER_OBJS) $(LIBS)
@echo 'Finished building target: $@'
@echo ' '
# Other Targets
clean:
-$(RM) $(EXECUTABLES)$(OBJS)$(C_DEPS) wordsearch
-@echo ' '
.PHONY: all clean dependents
.SECONDARY:
-include ../makefile.targets

8
Release/objects.mk Normal file
View File

@ -0,0 +1,8 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
USER_OBJS :=
LIBS :=

17
Release/sources.mk Normal file
View File

@ -0,0 +1,17 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
OBJ_SRCS :=
ASM_SRCS :=
C_SRCS :=
O_SRCS :=
S_UPPER_SRCS :=
EXECUTABLES :=
OBJS :=
C_DEPS :=
# Every subdirectory with source files must be described here
SUBDIRS := \
src \

33
Release/src/subdir.mk Normal file
View File

@ -0,0 +1,33 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
# Add inputs and outputs from these tool invocations to the build variables
C_SRCS += \
../src/dir.c \
../src/grid.c \
../src/rnd.c \
../src/wordsearch.c
OBJS += \
./src/dir.o \
./src/grid.o \
./src/rnd.o \
./src/wordsearch.o
C_DEPS += \
./src/dir.d \
./src/grid.d \
./src/rnd.d \
./src/wordsearch.d
# Each subdirectory must supply rules for building sources it contributes
src/%.o: ../src/%.c
@echo 'Building file: $<'
@echo 'Invoking: GCC C Compiler'
gcc -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<"
@echo 'Finished building: $<'
@echo ' '

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);
}

439
tests/words-long.in Normal file
View File

@ -0,0 +1,439 @@
gaping
panicky
lock
purple
geese
massive
judge
hateful
helpless
uppity
public
cheat
head
scare
fax
adhesive
laugh
fancy
whip
strong
lethal
scintillating
decision
match
route
steadfast
drip
ossified
rail
trade
dock
sweet
wrap
stew
jewel
penitent
finger
tearful
cold
dayostage
instinctive
birds
kill
kettle
welcome
plough
dolls
telling
alleged
chemical
provide
roll
seat
knotty
hospital
white
cup
battle
straight
wandering
gate
holistic
freezing
nine
rat
head
accept
fretful
box
theory
apparel
duck
skip
judge
amount
file
sail
develop
eminent
used
sore
upbeat
jelly
cough
incandescent
point
person
laugh
squeak
ink
skirt
cellar
talk
youthful
tame
knowledgeable
pull
bat
launch
deer
jumpy
holiday
horses
last
punish
muddle
occur
bomb
delicious
unaccountable
mitten
quilt
smile
market
childlike
ignore
puzzled
trip
coal
spiritual
chop
flower
harmonious
thaw
teeth
drink
natural
six
skin
replace
beg
cheerful
conscious
spectacular
sassy
contain
existence
blink
tawdry
ladybug
suit
grandiose
pack
border
act
warlike
overt
husky
page
mess up
unnatural
snails
shaky
bird
abhorrent
bucket
label
healthy
approval
grass
pale
faithful
pump
neck
passenger
rinse
zip
imagine
pot
board
outgoing
plot
green
machine
descriptive
advice
kick
guarded
massive
sail
furtive
bouncy
continue
precede
mindless
pleasant
obeisant
present
huge
produce
quaint
refuse
shrill
woozy
flawless
excellent
list
witty
sofa
open
tin
hug
gaze
empty
disarm
wrong
lethal
agreeable
superb
sigh
dock
supreme
soothe
cracker
flimsy
chin
overjoyed
spot
exotic
synonymous
fat
acceptable
naughty
dam
regret
spark
toy
tap
apologise
entertain
open
concern
striped
abusive
tan
hammer
bright
bless
spy
spoon
paper
stitch
arch
seed
slippery
air
troubled
materialistic
pleasant
stitch
ugliest
bulb
leg
dependent
spill
number
spot
toad
rhetorical
marvelous
earsplitting
redundant
multiply
title
wealthy
detail
queen
hum
bat
combative
rough
muddled
snore
rainstorm
assorted
hungry
temporary
wash
compare
person
tense
parcel
use
man
hang
bubble
sleepy
scarf
teeny-tiny
excellent
used
invincible
abstracted
unusual
hideous
gifted
rob
homely
aspiring
health
friends
baby
political
mammoth
miss
pump
throat
haircut
delightful
side
x-ray
arithmetic
plant
brass
knot
panoramic
pig
sort
rake
second
thaw
comparison
whistle
female
hurt
shade
delirious
reminiscent
fog
confuse
question
flawless
fat
chess
efficacious
grape
bitter
nation
necessary
grumpy
vase
resonant
gaping
force
smiling
stir
improve
interrupt
cowardly
sturdy
wave
concentrate
giant
follow
reject
fire
cure
hill
nail
ice
psychotic
vacation
serious
simplistic
kitty
quiet
agreeable
avoid
elderly
cattle
add
doubtful
quill
try
zinc
icicle
jam
wink
muddle
hellish
month
thirsty
paltry
pick
sponge
hobbies
productive
truck
toys
taste
tin
territory
meat
discovery
romantic
pointless
quixotic
free
stupid
selection
advice
grade
road
brief
evasive
tenuous
challenge
plausible
reflect
axiomatic
look
irritate
damaging
uninterested
pathetic
coat
kneel
step
spy
group
unadvised
trousers
window
nerve
fit
preach
name
toy
screeching
box
type
kettle
head
nauseating
excuse
amuse
hammer
cars
mug

9
tests/words.in Normal file
View File

@ -0,0 +1,9 @@
Kitchen
Lounge
Study
Ballroom
Conservatory
Billiard Room
Library
Hall
Dining Room