Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions workshop1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Workshop 1 - Конзолно приложение за шифриране/дешифриране
*Преди да започнем, учтиво искаме да ви помолим да **изключите** копилоти, ако използвате такива при писане на код, както и да **не използвате** чат асистенти.*

*Не възнаграждаваме с точки за успешно решение - целта е сами да се пробвате да помислите и напишете кода на програмата, за да има максимална полза за вас.*

## Backstory

[Цезаровият шифър](https://bg.wikipedia.org/wiki/%D0%A6%D0%B5%D0%B7%D0%B0%D1%80%D0%BE%D0%B2_%D1%88%D0%B8%D1%84%D1%8A%D1%80) е един от най-старите и най-прости методи за криптиране на текст. Той се основава на заместване на всяка буква в текста с друга буква, която се намира на фиксиран брой позиции по-надясно (при криптиране) или по-наляво (при декриптиране) в дадена азбука.

**"Ключ"** (key) наричаме този фиксиран брой позиции. Например, ако използваме ключ 3 с английската азбука при криптиране, буквата 'A' ще бъде заменена с 'D', буквата 'B' с 'E', и така нататък.
* Ако стигнем до края на азбуката, продължаваме от началото (т.е. 'Z' с ключ 3 става 'C').
* Ако някой символ не е от азбуката (пунктуация, цифри, чужди букви, т.н.), той остава непроменен.

## Функционалности
Вашата задача е да довършите файла `cipher.py` по такъв начин, че да може да бъде изпълняван от командния ред (дадена ви е помощна имплементация за това с `argparse`), като поддържа следния синтаксис и функционалности:

```shell
python cipher.py <MODE> [<TEXT>] -k <KEY> [-a <ALPHABET_NAME>]
```

където:
* `<MODE>` е или `encrypt`, или `decrypt`. Указва в коя посока да се извърши трансформацията.
* При `encrypt` всяка буква се измества с ключа надясно (прибавя се стойността на ключа към поредността на буквата).
* При `decrypt` всяка буква се измества с ключа наляво (изважда се стойността на ключа от поредността на буквата).
* Запазва се вида на буквите (главни/малки).
* Символи извън указаната азбука не се променят (букви от чужда азбука, цифри, пунктуация, др. символи).
* `<TEXT>` е текстов низ (str), който може да съдържа букви, цифри, пунктуация и други символи. Той трябва да бъде обработен според зададения режим и ключ.
* Този аргумент може да бъде пропуснат. В такъв случай програмата трябва да изчака вход от потребителя (чрез вградената функция `input()`), за да получи текста за обработка.
* `-k <KEY>` е цяло число, което указва ключът. Валидни стойности са от 1 до дължината на азбуката минус едно.
* Да се изведе подходяща грешка при невалиден ключ.
* Специално за ключ 0 или ключ равен на дължината на азбуката, да се изведе съобщение `Key results in no change.` и програмата да приключи без да прави нищо останало.
* `-a <ALPHABET_NAME>` е аргумент по желание, който указва коя азбука да се използва. Ако не е подаден, по подразбиране се използва `en` - английската азбука (A-Z с 26 букви). Възможни стойности:
* `en`: английска (`ABCDEFGHIJKLMNOPQRSTUVWXYZ`)
* `bg`: българска (`АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯ`)
* `ru`: руска (`АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ`)
* `de`: немска (`ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜß`)
* `tr`: турска (`ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ`)
* `gr`: гръцка (`ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ`)
* ... (можете да добавите и други азбуки по ваше желание)
* Потребителят може да подаде само едно име на азбука.
* Потребителят трябва да може да подаде името на азбуката с малки букви, главни букви или смесено.
* При подаване на име на азбука, която не е от изброените горе, да се изведе съобщение `Unrecognized alphabet {alphabet_name}. Supported values are: {list_of_supported_alphabets}` и програмата да приключи. В съобщението `{alphabet_name}` се замества с подаденото от потребителя име, а в `{list_of_supported_alphabets}` се изреждат всички поддържани азбуки, разделени със запетая и интервал.
* Пример: `Unrecognized alphabet foo. Supported values are: en, bg, ru, de, tr, gr`.

## Примери

```shell
$ python cipher.py encrypt xyzabc -k 3

abcdef
```

```shell
$ python cipher.py encrypt "Hello, world!" -k 3

Khoor, zruog!
```

```shell
$ python cipher.py decrypt "Khoor, zruog!" -k 3

Hello, world!
```

```shell
$ python cipher.py encrypt -k 16
Here the program waits for the user to input text
Xuhu jxu fhewhqc mqyji veh jxu kiuh je ydfkj junj
```

```shell
$ python cipher.py encrypt "Я виж, можем и на български." -k 2 -a bg

Б дки, оризо к пв гюневтумк.
```

```shell
$ python cipher.py encrypt "Я виж, можем и на български." -k 2

Я виж, можем и на български.
```

```shell
$ python cipher.py encrypt whatever -k 666

Invalid key 666. Key must be between 1 and 25.
```

```shell
$ python cipher.py encrypt whatever -k 0

Key results in no change.
```

```shell
$ python cipher.py encrypt whatever -k 3 -a foo

Unrecognized alphabet foo. Supported values are: en, bg, ru, de, tr, gr.
```

## Помощ
* За намиране на индекс на символ (или substring) в низ, може да използвате [str.find()](https://docs.python.org/3/library/stdtypes.html#str.find).
* За проверка дали даден символ е главна буква, може да използвате `str.isupper()`.
* За преждевременен изход от програмата, може да използвате `sys.exit()`.
* Може да проверите дали работи коректно програмата ви с някой специализиран за това сайт, например този: https://cryptii.com/pipes/caesar-cipher
20 changes: 20 additions & 0 deletions workshop1/cipher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import argparse


parser = argparse.ArgumentParser()
parser.add_argument("mode", choices=["encrypt", "decrypt"], help="Mode of operation (encrypt or decrypt)")
parser.add_argument("text", nargs="?", help="Text to be processed")
parser.add_argument("-k", "--key", type=int, required=True, help="Key for encryption/decryption")
parser.add_argument("-a", "--alphabet", default="en", help="Alphabet to use")
args = parser.parse_args()

mode = args.mode
text = args.text
key = args.key
alphabet = args.alphabet

# print(f"Helpful debug info: {mode=}, {key=}, {alphabet=}, {text=}")


# свободни сте да пишете и променяте кода във файла както сметнете за най-удачно
# употребата на функции е препоръчителна