Advertisement
Guest User

cipher.c

a guest
Jun 26th, 2015
737
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.41 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdbool.h>
  4. #include <string.h>
  5. #include <ctype.h>
  6. #include <assert.h>
  7.  
  8. typedef struct dict {
  9.     char *bufz;
  10.     unsigned bufz_size;
  11.     unsigned count;
  12.     unsigned words[];
  13. } dict;
  14.  
  15. static const char *dict_target;
  16. static int
  17. dict_cmp(const void *a, const void *b)
  18. {
  19.     unsigned ai = *(unsigned *)a;
  20.     unsigned bi = *(unsigned *)b;
  21.     return strcmp(&dict_target[ai], &dict_target[bi]);
  22. }
  23.  
  24. void
  25. dict_sort(dict *d)
  26. {
  27.     dict_target = d->bufz;
  28.     qsort(d->words, d->count, sizeof(d->words[0]), dict_cmp);
  29. }
  30.  
  31. static bool
  32. word_is_valid(const char *word)
  33. {
  34.     for (const char *p = word; *p; p++)
  35.         if (!islower(*p) && !ispunct(*p))
  36.             return false;
  37.     return true;
  38. }
  39.  
  40. dict *
  41. dict_create(const char *file)
  42. {
  43.     unsigned max_words = 256;
  44.     dict *d = malloc(sizeof(*d) + sizeof(unsigned) * max_words);
  45.     d->count = 0;
  46.     d->bufz_size = 4096;
  47.     d->bufz = malloc(d->bufz_size);
  48.     unsigned p = 0;
  49.     FILE *in = fopen(file, "r");
  50.     int last = ' ';
  51.     int c;
  52.     while ((c = fgetc(in)) != EOF) {
  53.         if (!isspace(c)) {
  54.             if (isspace(last))
  55.                 d->words[d->count++] = p;
  56.             d->bufz[p++] = c;
  57.         } else {
  58.             if (!isspace(last)) {
  59.                 d->bufz[p++] = '\0';
  60.                 char *word = d->bufz + d->words[d->count - 1];
  61.                 if (!word_is_valid(word)) {
  62.                     d->count--;
  63.                     p = d->words[d->count];
  64.                 }
  65.             }
  66.         }
  67.         last = c;
  68.         if (p == d->bufz_size) {
  69.             d->bufz_size *= 2;
  70.             d->bufz = realloc(d->bufz, d->bufz_size);
  71.         }
  72.         if (d->count == max_words) {
  73.             max_words *= 2;
  74.             d = realloc(d, sizeof(*d) + sizeof(unsigned) * max_words);
  75.         }
  76.     }
  77.     fclose(in);
  78.     if (d->bufz[p] != '\0')
  79.         d->bufz[p++] = '\0';
  80.     dict_sort(d);
  81.     d->bufz_size = p;
  82.     d->bufz = realloc(d->bufz, d->bufz_size + 64);  // trim
  83.     return realloc(d, sizeof(*d) + sizeof(unsigned) * d->count); // trim
  84. }
  85.  
  86. void
  87. dict_free(dict *d)
  88. {
  89.     free(d->bufz);
  90.     free(d);
  91. }
  92.  
  93. bool
  94. dict_check(dict *d, const char *word)
  95. {
  96.     dict_target = d->bufz;
  97.     strcpy(d->bufz + d->bufz_size, word);
  98.     unsigned i = d->bufz_size;
  99.     return bsearch(&i, d->words, d->count, sizeof(d->words[0]), dict_cmp)
  100.         != NULL;
  101. }
  102.  
  103. typedef struct cipher {
  104.     char line[1024];
  105.     char *words[256];
  106.     int sub[26];
  107.     int rev[26];
  108. } cipher;
  109.  
  110. void
  111. cipher_setsub(cipher *c, char from, char to)
  112. {
  113.     assert(isupper(from));
  114.     assert(islower(to));
  115.     c->sub[from - 'A'] = to   - 'a';
  116.     c->rev[to   - 'a'] = from - 'A';
  117. }
  118.  
  119. void
  120. cipher_clearsub(cipher *c, char from)
  121. {
  122.     assert(isupper(from));
  123.     char to = c->sub[from - 'A'] + 'a';
  124.     assert(islower(to));
  125.     c->sub[from - 'A'] = -1;
  126.     c->rev[to - 'a'] = -1;
  127. }
  128.  
  129. bool
  130. cipher_has_sub(cipher *c, char x)
  131. {
  132.     if (islower(x))
  133.         return c->rev[x - 'a'] != -1;
  134.     else if (isupper(x))
  135.         return c->sub[x - 'A'] != -1;
  136.     assert("invalid character");
  137.     return false;
  138. }
  139.  
  140. void
  141. cipher_load(cipher *c)
  142. {
  143.     for (int i = 0; i < 26; i++) {
  144.         c->sub[i] = -1;
  145.         c->rev[i] = -1;
  146.     }
  147.     fgets(c->line, sizeof(c->line), stdin);
  148.     int wordcount = 0;
  149.     for (char *p = c->line; *p; p++) {
  150.         if (!isspace(*p)) {
  151.             c->words[wordcount++] = p;
  152.             while (*p && !isspace(*p))
  153.                 p++;
  154.             p--;
  155.         } else {
  156.             *p = '\0';
  157.         }
  158.     }
  159.     c->words[wordcount] = NULL;
  160.     int pairs;
  161.     scanf("%d", &pairs);
  162.     for (int i = 0; i < pairs; i++) {
  163.         char pair[3];
  164.         scanf("%2s", pair);
  165.         c->sub[pair[1] - 'A'] = pair[0] - 'a';
  166.         c->rev[pair[0] - 'a'] = pair[1] - 'A';
  167.     }
  168. }
  169.  
  170. void
  171. cipher_decode_word(const cipher *c, char *word)
  172. {
  173.     for (int i = 0; word[i]; i++)
  174.         if (isupper(word[i]))
  175.             word[i] = c->sub[word[i] - 'A'] + 'a';
  176. }
  177.  
  178. void
  179. cipher_decode_print_all(const cipher *c)
  180. {
  181.     for (char **p = (char **)c->words; *p; p++) {
  182.         char word[strlen(*p) + 1];
  183.         strcpy(word, *p);
  184.         cipher_decode_word(c, word);
  185.         printf("%s ", word);
  186.     }
  187.     printf("\n");
  188. }
  189.  
  190. static void
  191. cipher_solve(cipher *c, dict *dict, int word, int p)
  192. {
  193.     char *w = c->words[word];
  194.     if (w == NULL) {
  195.         /* Valid decoding! */
  196.         cipher_decode_print_all(c);
  197.         return;
  198.     }
  199.     /* Find next substitution. */
  200.     for (; w[p]; p++)
  201.         if (isupper(w[p]) && !cipher_has_sub(c, w[p]))
  202.             break;
  203.     if (w[p]) {
  204.         /* Try all possible substitutions. */
  205.         for (int i = 0; i < 26; i++) {
  206.             char r = i + 'a';
  207.             if (!cipher_has_sub(c, r)) {
  208.                 cipher_setsub(c, w[p], r);
  209.                 cipher_solve(c, dict, word, p + 1);
  210.                 cipher_clearsub(c, w[p]);
  211.             }
  212.         }
  213.     } else {
  214.         /* Check if this word decodes into a dictionary word. */
  215.         char test[strlen(w) + 1];
  216.         strcpy(test, w);
  217.         cipher_decode_word(c, test);
  218.         if (dict_check(dict, test))
  219.             cipher_solve(c, dict, word + 1, 0);
  220.     }
  221. }
  222.  
  223. int
  224. main(void)
  225. {
  226.     dict *dict = dict_create("/usr/share/dict/words");
  227.     cipher cipher;
  228.     cipher_load(&cipher);
  229.     cipher_solve(&cipher, dict, 0, 0);
  230.     dict_free(dict);
  231.     return 0;
  232. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement