/* This is one of the cipher files for the cipher interface written ** by wart@ugcs.caltech.edu ** ** Please don't steal my code without my permission. ** */ #include #include #include #include "term.h" #include "types.h" #include "ctypes.h" homophonic::homophonic(){ valid_chars = "1234567890"; length = 0; period = 4; key.init(4); best_fits.init(4); } int homophonic::execute_option(char option){ int valid = TRUE; switch(option){ case SUBSTITUTE: substitute(); break; case UNDO: undo(); break; case ALPHFIT: alphfit(); break; default: valid = base_exec_option(option); break; } return valid; } void homophonic::init_cipher(){ int i; /* Convert the character array to an array of numbers that are easier ** to deal with. */ for(i = 0; i < length/2; i++){ sscanf(cipher + (i*2), "%2d", ocipher+i); hist[ocipher[i]/25][ocipher[i]%25]++; } length /= 2; /* Calculate the best fits right away. Then when the user wants ** to find the best fit, we already know what it is. */ for(i = 0; i < 4; i++){ best_fits.alter(fit_hist(hist[i])+'a', i); } } void homophonic::substitute(){ int number; char tmp_str[STRINGLENGTH]; char pt_letter; prompt("What is the number? "); read_line(tmp_str); if(sscanf(tmp_str, "%d", &number) != 1) msgerror("Bad input."); if(number < 0 || number > 99) msgerror("Bad position."); else{ prompt("What is the new letter? "); pt_letter = get_char(); if(!isalpha(pt_letter)) msgerror("Bad letter."); else{ sub_letter(number, pt_letter); } } } void homophonic::alphfit(){ char tmp_str[STRINGLENGTH]; int row; prompt("Fit which row? (* for all) "); read_line(tmp_str); if(*tmp_str == '*'){ best_fits.duplicate(&key); } else if(sscanf(tmp_str, "%d", &row) != 1){ msgerror("Bad column."); } else if(row < 1 || row > 4){ msgerror("Column out of range."); } else{ key.alter(best_fits.val(row-1), row-1); } } void homophonic::undo(){ int column; char temp_str[STRINGLENGTH]; prompt("Which number? (* for all) "); read_line(temp_str); if(*temp_str == '*'){ key.clearkey(); } else if(sscanf(temp_str, "%d", &column) != 1 || column < 0 || column > 99){ msgerror("Bad number."); } else{ key.clearkey(column/25); } } void homophonic::show_menu(){ menu(1, "Options: (S)ubstitute (A)pply frequency fit (U)ndo column (W)rite (Q)uit"); } void homophonic::show_cipher(){ int i, npl; npl = (int) (SCREENWIDTH * .8) / 3; for(i = 0; i < length; i++){ /* First the number... */ msgprint((i%npl)*3, (i/npl)*2 + 3, " %02d", ocipher[i]); /* Now the letter... */ msgprint((i%npl)*3, (i/npl)*2 + 2, " %c", get_pt(ocipher[i])); } } void homophonic::show_key(){ int i; msgprint(0, 16, "Key:"); for(i = 0; i < 4; i++){ if(key.val(i) == BLANK) put_char('.', 3*i + 7, 16); else put_char(toupper(get_pt(i*25+1)), 3*i + 7, 16); } } char homophonic::get_pt(int num){ char pt; /* 00 is a special case. It really means 100. */ if(num == 0) num = 100; /* Now look at the key to see what kind of shift we need to put on it. */ if(key.val((num-1)/25) != BLANK){ pt = (num-1 + key.val((num-1)/25)-'a')%25 + 'a'; if(pt > 'i') pt++; if(pt > 'z') pt -= 26; } else pt = BLANK; return pt; } void homophonic::sub_letter(int number, char letter){ /* First convert the letter to a number */ letter -= 'a'; letter = (letter > 9)?letter-1:letter; /* Now shift it by the proper amount */ key.alter((letter - number + 1 + 100)%25+'a', (number-1)/25); } int homophonic::fit_hist(int newhist[25]){ int i, k, fweights[26]; static int weights[] = { 1863, 954, 1477, 1644, 2114, 1447, 1204, 1544, 1869, /* j was here */ 477, 1544, 1398, 1892, 1869, 1431, 477, 1887, 1799, 1969, 1431, 1114, 1204, 699, 1279, 0 }; int maxweight=0, maxpos=0; for(i = 0; i < 25; i++) fweights[i] = 0; /* Rotate through the 25 possible combinations */ for(k = 0; k < 25; k++){ /* Loop through the 25 histogram entries and add up the weights */ for(i = 0; i < 25; i++){ fweights[k] += newhist[i] * weights[(k+i)%25]; } } /* Find the largest weight and return the corresponding offset. */ for(i = 0; i < 25; i++){ if(maxweight < fweights[i]){ maxweight = fweights[i]; maxpos = i; } } return maxpos+1; } void homophonic::decipher(char *string){ int i=0; while(i < length){ *string++ = get_pt(ocipher[i]); i++; } *string = (char) NULL; }