De Special Operations Executive1 — afgekort SOE — was een van de zeven geheime diensten die door de Britse regering werden opgericht tijdens de Tweede Wereldoorlog. Deze organisatie maakte gebruik van poëzie om in het geheim te communiceren met haar spionnen in vijandelijke gebieden. Daarbij spraken afzender en ontvanger op voorhand af welk gedicht ze zouden gebruiken. Door de opeenvolgende letters van het gedicht te nummeren, ontstond een eenvoudige sleutel die kon gebruikt worden om berichten te coderen en decoderen. Omdat beide partijen het gedicht van buiten konden leren, was er ook geen codeboek dat verloren kon geraken. Toch konden de nazi's de code vrij makkelijk breken, vooral als het om een bekend gedicht ging.
Toen SOE-officier Leo Marks2 dit begon door te hebben, introduceerde hij een aantal zelfgeschreven gedichten. Deze gaf hij in maart 1944 aan de Franse agente Violette Szabo3:
The life that I have is all that I have,
And the life that I have is yours.
The love that I have of the life that I have
Is yours and yours and yours.A sleep I shall have, a rest I shall have,
Yet death will be but a pause.
For the peace of my years in the long green grass
Will be yours and yours and yours.
Marks had het drie maanden daarvoor geschreven, ter nagedachtenis aan zijn vriendin Ruth die in Canada was omgekomen bij een vliegtuigongeluk. Het gedicht werd wereldberoemd toen het werd voorgelezen in de film Carve Her Name with Pride4 uit 1958, over de exploten van Szabo in de oorlog. Helaas werd Szabo zelf gevangen genomen, gemarteld en vermoord voordat ze berichten naar elkaar konden verzenden.
De sleutel van een SOE-code wordt bepaald aan de hand van de tekst van een gedicht, door daarin alle opeenvolgende letters te nummeren vanaf één. Daarbij worden karakters die geen letter zijn genegeerd. Gevraagd wordt:
Schrijf een functie versleutel waaraan de locatie (str) moet doorgegeven worden van een tekstbestand dat de tekst van een gedicht bevat. De functie moet een dictionary (dict) teruggeven waarvan de sleutels gevormd worden door alle letters (str) die in het gedicht voorkomen. De dictionary moet elke letter afbeelden op een verzameling (set) van alle volgnummers (int) van die letter in de sleutel van de SOE-code. Hierbij wordt geen onderscheid gemaakt tussen hoofdletters en kleine letters, en worden hoofdletters gebruikt als sleutel van de dictionary.
Schrijf een functie reconstrueer waaraan de sleutel van een SOE-code (dict) moet doorgegeven worden, zoals die wordt teruggegeven door de functie versleutel. De functie moet een string (str) teruggeven met de opeenvolgende letters van het gedicht waarmee de sleutel werd opgesteld (in hoofdletters).
Schrijf een functie codeer waaraan twee argumenten moeten doorgegeven worden: i) een bericht $$m$$ (str) en ii) een sleutel van een SOE-code (dict) zoals die wordt teruggegeven door de functie versleutel. De functie moet de gecodeerde versie van $$m$$ teruggeven, voorgesteld als een lijst (list) van volgnummers (int) die bekomen wordt door elke letter van $$m$$ te vervangen door een willekeurig gekozen volgnummer van die letter in de sleutel van de SOE-code. Bij het vervangen van de letters uit $$m$$ mag geen onderscheid gemaakt worden tussen hoofdletters en kleine letters, en moeten alle karakters die geen letter zijn genegeerd worden. Als een letter uit $$m$$ niet voorkomt in de gegeven sleutel, dan moet die vervangen worden door volgnummer 0.
Schrijf een functie decodeer waaraan twee argumenten moeten doorgegeven worden: i) een bericht $$m$$ (str) dat gecodeerd werd volgens een SOE-code (cfr. functie codeer) en ii) de sleutel van de gebruikte SOE-code (dict) zoals die wordt teruggegeven door de functie versleutel. De functie moet een string (str) met de opeenvolgende letters uit het oorspronkelijke bericht teruggeven (in hoofdletters). Hierbij moet volgnummer 0 gedecodeerd worden als een vraagteken (?).
In onderstaande voorbeeldsessie gaan we ervan uit dat het tekstbestand gedicht.txt5 zich in de huidige directory bevindt.
>>> sleutel = versleutel('gedicht.txt6')
>>> sleutel['C']
{177}
>>> sleutel['A']
{10, 14, 19, 24, 28, 31, 43, 47, 66, 70, 84, 88, 98, 106, 114, 123, 127, 130, 138, 142, 150, 162, 164, 176, 185, 204, 218, 226}
>>> sleutel['R']
{55, 96, 104, 112, 131, 170, 186, 198, 203, 216, 224, 232}
>>> sleutel['K']
Traceback (most recent call last):
KeyError: 'K'
>>> reconstrueer(sleutel)
'THELIFETHATIHAVEISALLTHATIHAVEANDTHELIFETHATIHAVEISYOURSTHELOVETHATIHAVEOFTHELIFETHATIHAVEISYOURSANDYOURSANDYOURSASLEEPISHALLHAVEARESTISHALLHAVEYETDEATHWILLBEBUTAPAUSEFORTHEPEACEOFMYYEARSINTHELONGGREENGRASSWILLBEYOURSANDYOURSANDYOURS'
>>> codeer('Carve Her Name With Pride', sleutel)
[177, 176, 198, 128, 132, 9, 200, 55, 99, 47, 181, 77, 153, 26, 41, 9, 163, 232, 188, 108, 184]
>>> codeer('Carve Her Name With Pride', sleutel)
[177, 123, 112, 29, 173, 76, 16, 232, 195, 204, 181, 40, 153, 26, 11, 76, 119, 104, 120, 228, 173]
>>> codeer('The Wind That Shakes the Barley', sleutel)
[190, 42, 175, 153, 68, 227, 220, 75, 69, 19, 34, 51, 9, 164, 0, 118, 18, 41, 65, 144, 211, 130, 112, 78, 59, 93]
>>> decodeer([177, 176, 198, 128, 132, 9, 200, 55, 99, 47, 181, 77, 153, 26, 41, 9, 163, 232, 188, 108, 184], sleutel)
'CARVEHERNAMEWITHPRIDE'
>>> decodeer([177, 123, 112, 29, 173, 76, 16, 232, 195, 204, 181, 40, 153, 26, 11, 76, 119, 104, 120, 228, 173], sleutel)
'CARVEHERNAMEWITHPRIDE'
>>> decodeer([190, 42, 175, 153, 68, 227, 220, 75, 69, 19, 34, 51, 9, 164, 0, 118, 18, 41, 65, 144, 211, 130, 112, 78, 59, 93], sleutel)
'THEWINDTHATSHA?ESTHEBARLEY'