ana.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. #include <ctype.h>
  13. #define NULL ((void *)0)
  14. #define WORD_LIST "/sys/games/lib/anawords"
  15. #define VOWELS "aeiouy"
  16. #define ALPHAS 26
  17. #define LENLIMIT 64
  18. #define talloc(t) salloc(sizeof (t))
  19. #define MAP(c) ((c) - 'a')
  20. enum
  21. {
  22. in_fd,
  23. out_fd,
  24. err_fd,
  25. };
  26. typedef struct word word;
  27. struct word
  28. {
  29. char *text;
  30. int length;
  31. uint32_t mask;
  32. word *next;
  33. };
  34. typedef word *set[LENLIMIT];
  35. typedef struct
  36. {
  37. int count[ALPHAS];
  38. int length;
  39. uint32_t mask;
  40. }
  41. target;
  42. int fixed;
  43. int maxwords;
  44. set words;
  45. word *list[LENLIMIT];
  46. void
  47. error(char *s)
  48. {
  49. fprint(err_fd, "fatal error: %s\n", s);
  50. exits("fatal error");
  51. }
  52. void *
  53. salloc(uint32_t z)
  54. {
  55. void *p;
  56. if ((p = malloc(z)) == NULL)
  57. error("ran out of memory");
  58. return p;
  59. }
  60. void
  61. clean_word(char *s)
  62. {
  63. while (*s && *s != '\n')
  64. {
  65. if (isupper(*s))
  66. *s = tolower(*s);
  67. s++;
  68. }
  69. if (*s == '\n')
  70. *s = 0;
  71. }
  72. int
  73. word_ok(word *w)
  74. {
  75. char *s;
  76. int vowel;
  77. if (w->length == 0 || w->length >= LENLIMIT)
  78. return 0;
  79. if (w->length == 1)
  80. return strchr("aio", w->text[0]) != NULL;
  81. vowel = 0;
  82. s = w->text;
  83. while (*s != '\0')
  84. {
  85. if (!isalpha(*s))
  86. return 0;
  87. switch (*s)
  88. {
  89. case 'a':
  90. case 'e':
  91. case 'i':
  92. case 'o':
  93. case 'u':
  94. case 'y':
  95. vowel = 1;
  96. }
  97. s++;
  98. }
  99. return vowel;
  100. }
  101. uint32_t
  102. str_to_mask(char *s)
  103. {
  104. uint32_t m;
  105. m = 0;
  106. while (*s != '\0')
  107. m |= 1 << MAP(*s++);
  108. return m;
  109. }
  110. word *
  111. get_word(Biobuf *bp)
  112. {
  113. char *s;
  114. word *w;
  115. retry:
  116. if ((s = Brdline(bp, '\n')) == NULL)
  117. return NULL;
  118. clean_word(s);
  119. w = talloc(word);
  120. w->length = strlen(s);
  121. w->text = strcpy(salloc(w->length+1), s);
  122. w->mask = str_to_mask(s);
  123. if (!word_ok(w))
  124. {
  125. free(w->text);
  126. free(w);
  127. goto retry;
  128. }
  129. return w;
  130. }
  131. void
  132. build_wordlist(void)
  133. {
  134. Biobuf *bp;
  135. word *w;
  136. word **p;
  137. bp = Bopen(WORD_LIST, OREAD);
  138. if (!bp)
  139. {
  140. perror(WORD_LIST);
  141. exits(WORD_LIST);
  142. }
  143. while ((w = get_word(bp)) != NULL)
  144. {
  145. p = &words[w->length];
  146. w->next = *p;
  147. *p = w;
  148. }
  149. }
  150. void
  151. count_letters(target *t, char *s)
  152. {
  153. int i;
  154. for (i = 0; i < ALPHAS; i++)
  155. t->count[i] = 0;
  156. t->length = 0;
  157. while (*s != '\0')
  158. {
  159. t->count[MAP(*s++)]++;
  160. t->length++;
  161. }
  162. }
  163. int
  164. contained(word *i, target *t)
  165. {
  166. int n;
  167. char *v;
  168. target it;
  169. if ((i->mask & t->mask) != i->mask)
  170. return 0;
  171. count_letters(&it, i->text);
  172. for (n = 0; n < ALPHAS; n++)
  173. {
  174. if (it.count[n] > t->count[n])
  175. return 0;
  176. }
  177. if (it.length == t->length)
  178. return 1;
  179. for (v = VOWELS; *v != '\0'; v++)
  180. {
  181. if (t->count[MAP(*v)] > it.count[MAP(*v)])
  182. return 1;
  183. }
  184. return 0;
  185. }
  186. int
  187. prune(set in, int m, target *filter, set out)
  188. {
  189. word *i, *o, *t;
  190. int n;
  191. int nz;
  192. nz = 0;
  193. for (n = 1; n < LENLIMIT; n++)
  194. {
  195. if (n > m)
  196. {
  197. out[n] = NULL;
  198. continue;
  199. }
  200. o = NULL;
  201. for (i = in[n]; i != NULL; i = i->next)
  202. {
  203. if (contained(i, filter))
  204. {
  205. t = talloc(word);
  206. *t = *i;
  207. t->next = o;
  208. o = t;
  209. nz = 1;
  210. }
  211. }
  212. out[n] = o;
  213. }
  214. return nz;
  215. }
  216. void
  217. print_set(set s)
  218. {
  219. word *w;
  220. int n;
  221. for (n = 1; n < LENLIMIT; n++)
  222. {
  223. for (w = s[n]; w != NULL; w = w->next)
  224. fprint(out_fd, "%s\n", w->text);
  225. }
  226. }
  227. uint32_t
  228. target_mask(int c[])
  229. {
  230. uint32_t m;
  231. int i;
  232. m = 0;
  233. for (i = 0; i < ALPHAS; i++)
  234. {
  235. if (c[i] != 0)
  236. m |= 1 << i;
  237. }
  238. return m;
  239. }
  240. void
  241. dump_list(word **e)
  242. {
  243. word **p;
  244. fprint(out_fd, "%d", (int)(e - list + 1));
  245. for (p = list; p <= e; p++)
  246. fprint(out_fd, " %s", (*p)->text);
  247. fprint(out_fd, "\n");
  248. }
  249. void
  250. free_set(set s)
  251. {
  252. int i;
  253. word *p, *q;
  254. for (i = 1; i < LENLIMIT; i++)
  255. {
  256. for (p = s[i]; p != NULL; p = q)
  257. {
  258. q = p->next;
  259. free(p);
  260. }
  261. }
  262. }
  263. void
  264. enumerate(word **p, target *i, set c)
  265. {
  266. target t;
  267. set o;
  268. word *w, *h;
  269. char *s;
  270. int l, m, b;
  271. l = p - list;
  272. b = (i->length + (maxwords - l - 1)) / (maxwords - l);
  273. for (m = i->length; m >= b; m--)
  274. {
  275. h = c[m];
  276. for (w = h; w != NULL; w = w->next)
  277. {
  278. if (i->length == m)
  279. {
  280. *p = w;
  281. dump_list(p);
  282. continue;
  283. }
  284. if (l == maxwords - 1)
  285. continue;
  286. t = *i;
  287. t.length -= m;
  288. for (s = w->text; *s != '\0'; s++)
  289. t.count[MAP(*s)]--;
  290. t.mask = target_mask(t.count);
  291. c[m] = w->next;
  292. if (prune(c, m, &t, o))
  293. {
  294. *p = w;
  295. enumerate(p + 1, &t, o);
  296. free_set(o);
  297. }
  298. }
  299. c[m] = h;
  300. }
  301. }
  302. void
  303. clean(char *s)
  304. {
  305. char *p, *q;
  306. for (p = s, q = s; *p != '\0'; p++)
  307. {
  308. if (islower(*p))
  309. *q++ = *p;
  310. else if (isupper(*p))
  311. *q++ = tolower(*p);
  312. }
  313. *q = '\0';
  314. }
  315. void
  316. anagramulate(char *s)
  317. {
  318. target t;
  319. set subjects;
  320. clean(s);
  321. if (fixed)
  322. maxwords = fixed;
  323. else if ((maxwords = strlen(s) / 4) < 3)
  324. maxwords = 3;
  325. fprint(out_fd, "%s:\n", s);
  326. t.mask = str_to_mask(s);
  327. count_letters(&t, s);
  328. if (!prune(words,t.length, &t, subjects))
  329. return;
  330. enumerate(&list[0], &t, subjects);
  331. }
  332. void
  333. set_fixed(char *s)
  334. {
  335. if ((fixed = atoi(s)) < 1)
  336. fixed = 1;
  337. }
  338. void
  339. read_words(void)
  340. {
  341. char *s;
  342. Biobuf b;
  343. Binit(&b, in_fd, OREAD);
  344. while ((s = Brdline(&b, '\n')) != NULL)
  345. {
  346. s[Blinelen(&b)-1] = '\0';
  347. if (isdigit(s[0]))
  348. {
  349. set_fixed(s);
  350. fprint(out_fd, "Fixed = %d.\n", fixed);
  351. }
  352. else
  353. {
  354. anagramulate(s);
  355. fprint(out_fd, "Done.\n");
  356. }
  357. }
  358. }
  359. void
  360. main(int argc, char **argv)
  361. {
  362. build_wordlist();
  363. if (argc > 1)
  364. set_fixed(argv[1]);
  365. read_words();
  366. exits(0);
  367. }