xref: /csrg-svn/games/caesar/caesar.c (revision 60756)
139003Sbostic /*
2*60756Sbostic  * Copyright (c) 1989, 1993
3*60756Sbostic  *	The Regents of the University of California.  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  *
1342569Sbostic  * %sccs.include.redist.c%
1439003Sbostic  */
1539003Sbostic 
1639004Sbostic #ifndef lint
17*60756Sbostic static char copyright[] =
18*60756Sbostic "@(#) Copyright (c) 1989, 1993\n\
19*60756Sbostic 	The Regents of the University of California.  All rights reserved.\n";
2039004Sbostic #endif /* not lint */
2139003Sbostic 
2239004Sbostic #ifndef lint
23*60756Sbostic static char sccsid[] = "@(#)caesar.c	8.1 (Berkeley) 05/31/93";
2439004Sbostic #endif /* not lint */
2539004Sbostic 
2639004Sbostic #include <math.h>
2739003Sbostic #include <stdio.h>
2839003Sbostic #include <ctype.h>
2939006Sbostic #include <unistd.h>
3039003Sbostic 
3139004Sbostic #define	LINELENGTH	2048
3239004Sbostic #define	ROTATE(ch, perm) \
3339006Sbostic 	isupper(ch) ? ('A' + (ch - 'A' + perm) % 26) : \
3439004Sbostic 	    islower(ch) ? ('a' + (ch - 'a' + perm) % 26) : ch
3539004Sbostic 
3639006Sbostic /*
3739006Sbostic  * letter frequencies (taken from some unix(tm) documentation)
3839006Sbostic  * (unix is a trademark of Bell Laboratories)
3939006Sbostic  */
4039006Sbostic double stdf[26] = {
4139006Sbostic 	7.97, 1.35, 3.61, 4.78, 12.37, 2.01, 1.46, 4.49, 6.39, 0.04,
4239006Sbostic 	0.42, 3.81, 2.69, 5.92,  6.96, 2.91, 0.08, 6.63, 8.77, 9.68,
4339006Sbostic 	2.62, 0.81, 1.88, 0.23,  2.07, 0.06,
4439006Sbostic };
4539006Sbostic 
main(argc,argv)4639003Sbostic main(argc, argv)
4739004Sbostic 	int argc;
4839004Sbostic 	char **argv;
4939003Sbostic {
5039006Sbostic 	extern int errno;
5139006Sbostic 	register int ch, dot, i, nread, winnerdot;
5239004Sbostic 	register char *inbuf;
5339006Sbostic 	int obs[26], try, winner;
5439006Sbostic 	char *malloc(), *strerror();
5539003Sbostic 
5639006Sbostic 	if (argc > 1)
5739006Sbostic 		printit(argv[1]);
5839003Sbostic 
5939004Sbostic 	if (!(inbuf = malloc(LINELENGTH))) {
6039004Sbostic 		(void)fprintf(stderr, "caesar: out of memory.\n");
6139004Sbostic 		exit(1);
6239003Sbostic 	}
6339003Sbostic 
6439004Sbostic 	/* adjust frequency table to weight low probs REAL low */
6539004Sbostic 	for (i = 0; i < 26; ++i)
6639004Sbostic 		stdf[i] = log(stdf[i]) + log(26.0 / 100.0);
6739003Sbostic 
6839006Sbostic 	/* zero out observation table */
6939006Sbostic 	bzero(obs, 26 * sizeof(int));
7039004Sbostic 
7139006Sbostic 	if ((nread = read(STDIN_FILENO, inbuf, LINELENGTH)) < 0) {
7239006Sbostic 		(void)fprintf(stderr, "caesar: %s\n", strerror(errno));
7339006Sbostic 		exit(1);
7439006Sbostic 	}
7539006Sbostic 	for (i = nread; i--;) {
7639006Sbostic 		ch = inbuf[i];
7739006Sbostic 		if (islower(ch))
7839006Sbostic 			++obs[ch - 'a'];
7939006Sbostic 		else if (isupper(ch))
8039006Sbostic 			++obs[ch - 'A'];
8139006Sbostic 	}
8239003Sbostic 
8339006Sbostic 	/*
8439006Sbostic 	 * now "dot" the freqs with the observed letter freqs
8539006Sbostic 	 * and keep track of best fit
8639006Sbostic 	 */
8739006Sbostic 	for (try = winner = 0; try < 26; ++try) { /* += 13) { */
8839006Sbostic 		dot = 0;
8939006Sbostic 		for (i = 0; i < 26; i++)
9039006Sbostic 			dot += obs[i] * stdf[(i + try) % 26];
9139006Sbostic 		/* initialize winning score */
9239006Sbostic 		if (try == 0)
9339006Sbostic 			winnerdot = dot;
9439006Sbostic 		if (dot > winnerdot) {
9539006Sbostic 			/* got a new winner! */
9639006Sbostic 			winner = try;
9739006Sbostic 			winnerdot = dot;
9839003Sbostic 		}
9939006Sbostic 	}
10039003Sbostic 
10139006Sbostic 	for (;;) {
10239006Sbostic 		for (i = 0; i < nread; ++i) {
10339006Sbostic 			ch = inbuf[i];
10439004Sbostic 			putchar(ROTATE(ch, winner));
10539004Sbostic 		}
10639006Sbostic 		if (nread < LINELENGTH)
10739006Sbostic 			break;
10839006Sbostic 		if ((nread = read(STDIN_FILENO, inbuf, LINELENGTH)) < 0) {
10939006Sbostic 			(void)fprintf(stderr, "caesar: %s\n", strerror(errno));
11039006Sbostic 			exit(1);
11139006Sbostic 		}
11239003Sbostic 	}
11339006Sbostic 	exit(0);
11439004Sbostic }
11539003Sbostic 
printit(arg)11639006Sbostic printit(arg)
11739006Sbostic 	char *arg;
11839004Sbostic {
11939006Sbostic 	register int ch, rot;
12039003Sbostic 
12139006Sbostic 	if ((rot = atoi(arg)) < 0) {
12239006Sbostic 		(void)fprintf(stderr, "caesar: bad rotation value.\n");
12339006Sbostic 		exit(1);
12439006Sbostic 	}
12539004Sbostic 	while ((ch = getchar()) != EOF)
12639004Sbostic 		putchar(ROTATE(ch, rot));
12739006Sbostic 	exit(0);
12839003Sbostic }
129