Условие

Написать программу vigenere.c, которая шифрует сообщение с помощью шифра Виженера.

На вход программы подаем один аргумент командной строки: ключевое слово k, состоящее из букв английского алфавита. Если приложение запускается более чем с одним аргументом или с аргументом не входящим в алфавит, нужно вывести информацию об ошибке с завершением программы. То есть main будет возвращать 1 — в таком случае наши автоматические тесты поймут, что здесь всё хорошо, и это условие учтено. Если всё хорошо, программа должна перейти к запросу строки текста p, который мы и шифруем полученным выше ключом k, напечатать результат и завершить выполнение программы, возвратив значение 0

Уточнение

Нужно сделать так, чтобы в ключе k символы A и a обозначались как 0, B и b как 1, …, Z и z как 25. Программа должна применять шифр Виженера только к буквам текста p. Остальные символы (цифры, знаки препинания, пробелы) нужно вывести без изменений. Если алгоритм собирается применить j-й символ k к i-му символу p, не входящему в алфавит, применяем этот j-й символ ключа к следующему алфавитному символу в тексте; вы не можете просто оставить его и перейти к другому символу в k. Наконец, программа должна сохранить регистр каждой буквы в p

Не знаете, с чего начать?

Задание 2. Parlez-vous français? - 1

Вот вам несколько советов от Замайлы, ассистента курса CS50

К счастью, реализация этой задачки очень похожа на реализацию шифра Цезаря. Только в качестве ключа используется не целое число, а строка. Если вы успешно реализовали шифр имени римского правителя, он может стать прекрасным стартом для второго задания. Вы, вероятно, уже смекнули, что шифр Виженера с одной буквой в качестве ключа — это тот же шифр Цезаря. 

В алгоритме Виженера применяются те же шаги, что и в «Цезаре»: 

  1. Получить ключ
    • кодовое слово — это второй аргумент командной строки argv[1]
    • должен входить в алфавит: функция isalpha
  2. Получить текст
  3. Зашифровать
  4. Напечатать шифрованный текст

Итак, второй аргумент командной строки argv[1] проверим на принадлежность к алфавитным символам. Делаем это с помощью уже знакомой isalpha. Если ключ корректен, получаем от пользователя строку и начинаем шифровать. 

Формула шифра Виженера похожа на формулу шифра Цезаря. Каким образом вы преобразуете букву на соответствующее смещение шифра? Попробуйте сравнить значения по таблице ASCII. 

Задание 2. Parlez-vous français? - 2

Скорее всего, у вас получится отыскать закономерность между буквами и их алфавитными индексами, используя последовательности в таблице. Догадались, как отнять одну букву от другой, чтобы получить желаемый результат? Смещения для больших и малых букв неодинаковы, так что вам придется определить две похожие формулы для определения смещения для строчных и отдельно для прописных букв. 
Также не забудьте, что цикл прохода по тексту должен игнорировать символы, не входящие в английский алфавит. И не забудьте сохранить регистр букв.

Если посмотреть на формулу шифра: 

ci = (pi + kj) % 26

вы увидите две индексные переменные, i и j. Одна сохраняет позицию в исходном тексте, другая — в ключе. Если ваш текст длиннее ключа, индекс по ключу проходит с конца ключа снова в его начало.

Как это сделать? С помощью операции деления по модулю! Результат операции — остаток от деления двух чисел. Практическая польза этой операции в программировании просто огромна! 

Представьте, что многочисленную группу людей нужно разделить на три подгруппы. Один из способов это сделать — попросить их рассчитаться на первый-второй-третий. 

Задание 2. Parlez-vous français? - 3

То есть, первый человек относится к первой группе, второй — ко второй, третий — к третьей, четвертый — снова к первой и так далее. Вы можете использовать деление по модулю чтобы произвести эту же операцию. Пронумеруем те же три группы с нуля. Вот как это делается: 

Задание 2. Parlez-vous français? - 4

Если вы возьмете индекс и поделите его по модулю максимального значения, полученный результат никогда не будет больше или равен этому значению. 

Попробуйте применить этот принцип для возвращения ключевого слова в начало! Только вместо сортировки по группам вам нужен индекс ключевого слова, чтобы вы могли правильную букву для смещения, не выходя за длину ключа. 

Так как мы автоматизируем некоторые тесты вашего кода, программа должна вести себя так, как показано ниже:

jharvard@appliance (~/Dropbox/pset2): ./vigenere bacon
Meet me at the park at eleven am
Negh zf av huf pcfx bt gzrwep oz

Как еще можно протестировать программу, кроме ручного вычисления зашифрованного текста? Мы добрые: для этого мы написали программу devigenere. Она принимает один и только один аргумент командной строки (ключевое слово), а её работа заключается в том, чтобы принять зашифрованный текст в качестве входных данных и вернуть обычный.

Запустите её: 

~cs50/pset2/devigenere k

Где k — ключевое слово. 
Если вы хотите проверить правильность вашей программы с помощью check50, выполните:

check50 2015.fall.pset2.vigenere vigenere.c

А если хотите оценить нашу реализацию vigenere, наберите:

~cs50/pset2/vigenere