/* * scramble.c, by Kimmo Kulovesi , 2004-05-02 * * This reads text from stdin and scrambles each word (composed of * alphabetic characters as detected by "isalpha()") so that the first * and last letter stay in place and all letters in between are * moved around randomly. * * * The point was to test the idea behind the following piece of text that * has been circulating around the Internet in various incarnations: * * Aoccdrnig to a rscheearch at Cmabrigde Uinervtisy, it deosn't mttaer * in waht oredr the ltteers in a wrod are, the olny iprmoetnt tihng is * taht the frist and lsat ltteer be at the rghit pclae. The rset can be * a toatl mses and you can sitll raed it wouthit porbelm. Tihs is * bcuseae the huamn mnid deos not raed ervey lteter by istlef, but the * wrod as a wlohe. * * That is: * * According to a researcher at Cambridge University, it doesn't matter * in what order the letters in a word are, the only important thing is * that the first and last letter be at the right place. The rest can be * a total mess and you can still read it without problem. This is * because the human mind does not read every letter by itself, but the * word as a whole. * * (The part about Cambridge University etc is almost certainly false.) * * NOTE! This program is the result of one Sunday afternoon of boredom * and is not very well planned or checked for errors. Use freely at your * own risk only, and distribute as you will. */ #include #include #include #include #include #define MAX_LENGTH_OF_WORD 15 /* Maximum length of word to buffer */ #define MAX_DISTANCE 3 /* Maximum distance of letters to swap */ #define MAX_RETRIES 8 /* Maximum retries for failed swaps */ /* * MAX_LENGTH_OF_WORD doesn't need to be excessively large - words * longer than that are simply scrambled in smaller parts, which * just prevents scrambling from occurring over the boundary of * such parts, and causes each part to have a non-scrambling first * and last letter. * * MAX_DISTANCE tries to make the scrambled text easier to read by * not swapping letters too far away from their original position in case * of really long words. However, MAX_DISTANCE is not strictly enforced - * repeated swapping can make letters end up further and further away. * * MAX_RETRIES is the maximum number of times to retry swapping letters * when scrambling has failed. Setting this larger increases the * likelihood of scrambling the word from its original order, but also * makes the program run slower. */ static int swap(char *const, const unsigned int, const unsigned int); static void scramble(char *const, const unsigned int); int main(void) { char word[MAX_LENGTH_OF_WORD + 1]; char *p; /* Pointer to position in buffer */ int bufleft; /* Room left in the buffer */ int c; /* Last character read */ (void) srand(time(NULL)); p = word; bufleft = sizeof(word) - 1; while ((c = getchar()) != EOF) { /* * Consider only "words" formed by alphabetic characters: */ if (bufleft > 0 && isalpha(c)) { *p++ = c; bufleft--; continue; /* !!!! */ } /* * If there is a word in the buffer, scramble and print it: */ if (p != word) { *p = '\0'; scramble(word, p - word); (void) fputs(word, stdout); p = word; bufleft = sizeof(word) - 1; } /* * Print non-alphabetic characters as they are, without buffering: */ (void) putchar(c); } /* * Handle any word still in buffer at the end of input: */ if (p != word) { *p = '\0'; scramble(word, p - word); (void) fputs(word, stdout); } return EXIT_SUCCESS; } static void scramble(char *const word, const unsigned int length) { assert(word != NULL); if (length > 3) { int i; /* Index in word buffer */ int swaps; /* Number of letters swapped */ int remaining; /* Letters remaining to scramble */ int retries; /* Retries remaining in case of failure */ for (retries = MAX_RETRIES, swaps = 0; swaps == 0 && retries > 0; --retries) { for (remaining = length - 2, i = 1; remaining > 1; --remaining, ++i) { if (remaining > MAX_DISTANCE) swaps += swap(word, i, i + rand() % MAX_DISTANCE); else swaps += swap(word, i, i + rand() % remaining); } } } } static int swap(char *const buf, const unsigned int a, const unsigned int b) { char tmp; assert(buf != NULL); if (a == b || buf[a] == buf[b]) return 0; tmp = buf[a]; buf[a] = buf[b]; buf[b] = tmp; return 1; }