xref: /csrg-svn/games/caesar/caesar.c (revision 39006)
139003Sbostic /*
239004Sbostic  * Copyright (c) 1989 The Regents of the University of California.
339004Sbostic  * All rights reserved.
439003Sbostic  *
539004Sbostic  * This code is derived from software contributed to Berkeley by
639004Sbostic  * Rick Adams.
739003Sbostic  *
839004Sbostic  * Authors:
939004Sbostic  *	Stan King, John Eldridge, based on algorithm suggested by
1039004Sbostic  *	Bob Morris
1139003Sbostic  * 29-Sep-82
1239003Sbostic  *
1339004Sbostic  * Redistribution and use in source and binary forms are permitted
1439004Sbostic  * provided that the above copyright notice and this paragraph are
1539004Sbostic  * duplicated in all such forms and that any documentation,
1639004Sbostic  * advertising materials, and other materials related to such
1739004Sbostic  * distribution and use acknowledge that the software was developed
1839004Sbostic  * by the University of California, Berkeley.  The name of the
1939004Sbostic  * University may not be used to endorse or promote products derived
2039004Sbostic  * from this software without specific prior written permission.
2139004Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
2239004Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
2339004Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2439003Sbostic  */
2539003Sbostic 
2639004Sbostic #ifndef lint
2739004Sbostic char copyright[] =
2839004Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
2939004Sbostic  All rights reserved.\n";
3039004Sbostic #endif /* not lint */
3139003Sbostic 
3239004Sbostic #ifndef lint
33*39006Sbostic static char sccsid[] = "@(#)caesar.c	5.3 (Berkeley) 09/05/89";
3439004Sbostic #endif /* not lint */
3539004Sbostic 
3639004Sbostic #include <math.h>
3739003Sbostic #include <stdio.h>
3839003Sbostic #include <ctype.h>
39*39006Sbostic #include <unistd.h>
4039003Sbostic 
4139004Sbostic #define	LINELENGTH	2048
4239004Sbostic #define	ROTATE(ch, perm) \
43*39006Sbostic 	isupper(ch) ? ('A' + (ch - 'A' + perm) % 26) : \
4439004Sbostic 	    islower(ch) ? ('a' + (ch - 'a' + perm) % 26) : ch
4539004Sbostic 
46*39006Sbostic /*
47*39006Sbostic  * letter frequencies (taken from some unix(tm) documentation)
48*39006Sbostic  * (unix is a trademark of Bell Laboratories)
49*39006Sbostic  */
50*39006Sbostic double stdf[26] = {
51*39006Sbostic 	7.97, 1.35, 3.61, 4.78, 12.37, 2.01, 1.46, 4.49, 6.39, 0.04,
52*39006Sbostic 	0.42, 3.81, 2.69, 5.92,  6.96, 2.91, 0.08, 6.63, 8.77, 9.68,
53*39006Sbostic 	2.62, 0.81, 1.88, 0.23,  2.07, 0.06,
54*39006Sbostic };
55*39006Sbostic 
5639003Sbostic main(argc, argv)
5739004Sbostic 	int argc;
5839004Sbostic 	char **argv;
5939003Sbostic {
60*39006Sbostic 	extern int errno;
61*39006Sbostic 	register int ch, dot, i, nread, winnerdot;
6239004Sbostic 	register char *inbuf;
63*39006Sbostic 	int obs[26], try, winner;
64*39006Sbostic 	char *malloc(), *strerror();
6539003Sbostic 
66*39006Sbostic 	if (argc > 1)
67*39006Sbostic 		printit(argv[1]);
6839003Sbostic 
6939004Sbostic 	if (!(inbuf = malloc(LINELENGTH))) {
7039004Sbostic 		(void)fprintf(stderr, "caesar: out of memory.\n");
7139004Sbostic 		exit(1);
7239003Sbostic 	}
7339003Sbostic 
7439004Sbostic 	/* adjust frequency table to weight low probs REAL low */
7539004Sbostic 	for (i = 0; i < 26; ++i)
7639004Sbostic 		stdf[i] = log(stdf[i]) + log(26.0 / 100.0);
7739003Sbostic 
78*39006Sbostic 	/* zero out observation table */
79*39006Sbostic 	bzero(obs, 26 * sizeof(int));
8039004Sbostic 
81*39006Sbostic 	if ((nread = read(STDIN_FILENO, inbuf, LINELENGTH)) < 0) {
82*39006Sbostic 		(void)fprintf(stderr, "caesar: %s\n", strerror(errno));
83*39006Sbostic 		exit(1);
84*39006Sbostic 	}
85*39006Sbostic 	for (i = nread; i--;) {
86*39006Sbostic 		ch = inbuf[i];
87*39006Sbostic 		if (islower(ch))
88*39006Sbostic 			++obs[ch - 'a'];
89*39006Sbostic 		else if (isupper(ch))
90*39006Sbostic 			++obs[ch - 'A'];
91*39006Sbostic 	}
9239003Sbostic 
93*39006Sbostic 	/*
94*39006Sbostic 	 * now "dot" the freqs with the observed letter freqs
95*39006Sbostic 	 * and keep track of best fit
96*39006Sbostic 	 */
97*39006Sbostic 	for (try = winner = 0; try < 26; ++try) { /* += 13) { */
98*39006Sbostic 		dot = 0;
99*39006Sbostic 		for (i = 0; i < 26; i++)
100*39006Sbostic 			dot += obs[i] * stdf[(i + try) % 26];
101*39006Sbostic 		/* initialize winning score */
102*39006Sbostic 		if (try == 0)
103*39006Sbostic 			winnerdot = dot;
104*39006Sbostic 		if (dot > winnerdot) {
105*39006Sbostic 			/* got a new winner! */
106*39006Sbostic 			winner = try;
107*39006Sbostic 			winnerdot = dot;
10839003Sbostic 		}
109*39006Sbostic 	}
11039003Sbostic 
111*39006Sbostic 	for (;;) {
112*39006Sbostic 		for (i = 0; i < nread; ++i) {
113*39006Sbostic 			ch = inbuf[i];
11439004Sbostic 			putchar(ROTATE(ch, winner));
11539004Sbostic 		}
116*39006Sbostic 		if (nread < LINELENGTH)
117*39006Sbostic 			break;
118*39006Sbostic 		if ((nread = read(STDIN_FILENO, inbuf, LINELENGTH)) < 0) {
119*39006Sbostic 			(void)fprintf(stderr, "caesar: %s\n", strerror(errno));
120*39006Sbostic 			exit(1);
121*39006Sbostic 		}
12239003Sbostic 	}
123*39006Sbostic 	exit(0);
12439004Sbostic }
12539003Sbostic 
126*39006Sbostic printit(arg)
127*39006Sbostic 	char *arg;
12839004Sbostic {
129*39006Sbostic 	register int ch, rot;
13039003Sbostic 
131*39006Sbostic 	if ((rot = atoi(arg)) < 0) {
132*39006Sbostic 		(void)fprintf(stderr, "caesar: bad rotation value.\n");
133*39006Sbostic 		exit(1);
134*39006Sbostic 	}
13539004Sbostic 	while ((ch = getchar()) != EOF)
13639004Sbostic 		putchar(ROTATE(ch, rot));
137*39006Sbostic 	exit(0);
13839003Sbostic }
139