/* 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" nisub::nisub(){ valid_chars = "1234567890"; length = 0; } int nisub::execute_option(char option){ int valid = TRUE; switch(option){ case SUBSTITUTE: substitute(); break; case UNDO: undo(); break; default: valid = base_exec_option(option); break; } return valid; } int nisub::set_period(int newperiod){ return TRUE; } void nisub::init_cipher(){ int i; /* Convert the character array to an array of numbers that are easier ** to deal with. */ for(i = 0; i < length; i++){ sscanf(cipher + (i*3), "%d", ocipher+i); hist[ocipher[i]/25][ocipher[i]%25]++; } } void nisub::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 nisub::alphfit(){ char tmp_str[STRINGLENGTH]; int i, row; prompt("Fit which row? (* for all) "); read_line(tmp_str); if(*tmp_str == '*'){ for(i = 0; i < 4; i++){ key[i] = fit_hist(hist[i]); } } else if(sscanf(tmp_str, "%d", &row) != 1){ msgerror("Bad column."); } else if(row < 1 || row > 4){ msgerror("Column out of range."); } else{ key[row-1] = fit_hist(hist[row-1]); } } void nisub::undo(){ int column, i; prompt("Which number? (* for all) "); column = get_char(); if(column == '*'){ for(i = 0; i < period; i++) key[i] = UNCHANGED; } else{ key[column - '1'] = UNCHANGED; } } void nisub::show_menu(){ menu(1, "Options: (S)ubstitute (A)pply frequency fit (U)ndo column (W)rite (Q)uit"); } void nisub::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 nisub::show_key(){ int i; msgprint(0, 16, "Key:"); for(i = 0; i < 4; i++){ if(key[i] == UNCHANGED) put_char('.', 3*i + 7, 16); else put_char(toupper(get_pt(i*25+1)), 3*i + 7, 16); } } char nisub::get_pt(int num){ char pt; /* 00 is a special case. It really means 100. */ if(num == 0) num = 99; /* Now look at the key to see what kind of shift we need to put on it. */ if(key[(num-1)/25] != UNCHANGED){ pt = (num-1 + key[(num-1)/25])%25 + 'a'; if(pt > 'i') pt++; if(pt > 'z') pt -= 26; } else pt = BLANK; return pt; } void nisub::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[(number-1)/25] = (letter - number + 1 + 100)%25; } int nisub::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 26 possible combinations */ for(k = 0; k < 25; k++){ /* Loop through the 26 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 < 26; i++){ if(maxweight < fweights[i]){ maxweight = fweights[i]; maxpos = i; } } return maxpos+1; } void nisub::decipher(char *string){ int i=0; while(i < length){ *string++ = get_pt(ocipher[i]); i++; } *string = (char) NULL; }