Programmeermethoden 2022
Tweede programmeeropgave: Pincode
De
tweede programmeeropgave van het vak
Programmeermethoden
in het najaar van 2022
heet
Pincode;
zie ook het
vierde werkcollege,
vijfde werkcollege
(de betreffende WWW-bladzijde bevat handige
tips)
en
zesde werkcollege,
en lees geregeld deze pagina op WWW.
We gaan een file coderen en decoderen met behulp van een eenvoudige pincode.
Maar de pincode kan tijdens het (de)coderen veranderen,
en wat doen trouwens die Lychrel-getallen in de invoerfile?
En als we de pincode niet meer weten?
Aan de gebruiker wordt gevraagd of het
om coderen of decoderen gaat en hoe de originele file en de
"doelfile" heten. De ge(de)codeerde invoerfile komt in deze doelfile terecht;
de invoerfile zelf blijft onveranderd.
Verder wordt de pincode
gevraagd, waarbij bij het decoderen
een optie is om aan te geven dat deze onbekend is,
bijvoorbeeld door als pincode -1 te geven;
het programma stopt meteen als de gebruiker
een getal groter dan 9999 of kleiner dan -1 invoert.
Stel eenvoudige vragen om deze gegevens van de gebruiker te
weten te komen.
Het programma leest dan eenmalig (uitzondering: (*)) de opgegeven invoerfile,
en schrijft de uitvoer symbool voor symbool weg naar de uitvoerfile.
Elk symbool uit de invoerfile mag en moet precies
één maal (met invoer.get (...)) gelezen worden.
De pincode is een geheel getal tussen 0 en 9999,
waarbij zo nodig voorloopnullen gebruikt worden. Zo wordt bijvoorbeeld
42 opgevat als 0042.
Als in de te coderen file een getal kleiner dan 10000
en ongelijk 0 gedetecteerd wordt,
wordt dit dynamisch de nieuwe pincode
(waarin weer vooraan begonnen wordt).
Let op: het eerste niet-cijfer na de nieuwe pincode wordt
nog met de oude pincode gecodeerd.
Hierbij letten we niet op voorloopnullen: 0000042 wordt dus opgevat als 42.
Na het (de)coderen worden nog afgedrukt het aantal regels en
het aantal karakters van de originele file.
Het coderen geschiedt regel voor regel, en gaat als volgt.
Neem even aan dat de pincode 4281 is. Het eerste karakter van de invoerfile
wordt dan gecodeerd als het 4 verderop in de ASCII-tabel gelegen karakter,
het tweede als het 2 verderop gelegen karakter, ..., het vijfde weer als het 4 verderop gelegen karakter, etcetera.
We nemen hierbij aan dat de invoerfile bestaat uit tabs, carriage returns, line feeds, en verder gewone karakters met ASCII-waarde tussen 32 en 126,
grenzen inbegrepen.
We rekenen verder modulo 95,
dus karakter 127 wordt karakter 32, etcetera.
Zo wordt Slaap zzzzz! met pincode 1289 gecodeerd als Tnijq"#${|#*.
Regelovergangen ('\n' en eventueel '\r') blijven onderanderd,
evenals tabs ('\t'). Na een regelovergang begin je
weer vooraan in de pincode.
Verder moet het programma van elk geheel getal ongelijk nul dat bij het coderen in de invoerfile
voorkomt controleren of dit wellicht een Lychrel-getal is (zie deze link voor een definitie).
Op het scherm wordt het desbetreffende getal afgedrukt, en daarnaast wat het aantal iteraties is om tot
een palindroom te komen (voor 545 is dit 0, voor 113 is dit 1), of het nummer van de iteratie waarvan het resultaat
boven INT_MAX (gebruik include <climits>) uitkomt
(voor 196 is dit (waarschijnlijk) 18). Als dit gebeurt, wordt dit erbij vermeld, bijvoorbeeld als "potentieel Lychrel-getal".
De tekst 123abcd-"qqq 5"+++uvw-77.088ddd//vb5656 bevat
de gehele getallen 123, 5, 77, 88 en 5656; deze moeten dus gecontroleerd worden.
Neem aan dat de getallen in de tekst zelf hooguit INT_MAX zijn.
Als we bij het decoderen de pincode niet weten,
moeten alle pincodes 0...9999 geprobeerd worden.
Een pincode waarbij het vaakst de lettercombinatie
"the" (hoofdletters of kleine letters,
bijvoorbeeld "tHe") in de decodering voorkomt
wordt als de juiste beschouwd, en de bijbehorende decodering wordt opgeleverd.
Als er meerdere pincodes even goed decoderen,
gebruiken we de kleinste.
Let op: hierbij moet 10000 maal gedecodeerd worden, en
wordt de invoerfile dus 10000 maal gelezen (*). Zorg ervoor
dat er in deze situatie niet naar een uitvoerfile wordt weggeschreven,
anders duurt het te lang!
Ter verdere inspiratie, zie het vijfde werkcollege, en een aantal voorbeelden:
- [eenvoudig]
Met pincode 1234 wordt simpel2022.txt
gecodeerd als simpel2022uit1.txt,
en met pincode 8692 als simpel2022uit2.txt
(let er in dat laatste geval op dat (bijvoorbeeld) de derde letter,
een z, als een $ wordt gecodeerd);
de file heeft 11 regels en 389 karakters, en
er staan geen cijfers of tabs in.
(Gaat het decoderen ook goed?)
- Met pincode 1234 wordt voorbeeld2022.txt
gecodeerd als voorbeeld2022uit.txt;
de file heeft 16 regels en 463 karakters,
en 9876 vergt 5 iteraties, en 196 verongelukt tijdens de 18de.
Er staan twee tabs in de file, en twee nieuwe pincodes.
- Met pincode 1234 wordt voorbeeld2022a.txt
gecodeerd als voorbeeld2022auit.txt.
Gaat het goed direct na de eerste nieuwe pincode?
- Wat is de pincode van geheim2022.txt?
Let op: kopiëren door met rechter muisknop
op de links te klikken, anders (met markeer-copy-paste) gaan spaties/tabs wellicht fout!
Opmerkingen
-
We nemen aan dat de gebruiker zo vriendelijk is verder geen
fouten te maken bij het invoeren van gegevens.
Als een getal gevraagd wordt, geeft hij/zij een getal.
-
Gebruik de regelstructuur: elke regelovergang in een bestand bestaat
uit een LineFeed
(\n) (in UNIX) of een CarriageReturn gevolgd door een LineFeed
(\r\n) (in Windows).
Normaal gesproken gaat dit "vanzelf" goed.
We nemen aan dat er voor het EndOfFile-symbool (wat dat ook moge zijn)
een regelovergang staat.
-
Alleen voor de namen van de files
mag een array (of string) gebruikt worden;
voor het lezen
en verwerken van de tekst is slechts het huidige karakter en
enige kennis over de voorgaande karakters nodig — zie boven.
Alleen de headerfiles iostream en fstream
mogen gebruikt worden (en string
voor de filenamen; denk in dat geval wellicht aan het gebruik
van c_str; en climits voor INT_MAX).
Uit een file mag alleen met invoer.get (...) gelezen
worden, vergelijk Hoofdstuk 3.7 uit het dictaat,
gedeelte "aantekeningen bij de hoorcolleges".
Binnen de hoofdloop van het programma staat bij voorkeur maar
één keer een get-opdracht,
vergelijk het voorbeeldprogramma uit dit hoofdstuk
(daar staat twee keer get, één maal
vóór de loop, uiteraard).
Karakters mogen niet worden teruggezet in de
oorspronkelijke file.
Schrijf zelf functies die testen of een karakter een cijfer is, etcetera. Er mogen geen andere functies dan die
uit fstream gebruikt worden, en wellicht c_str.
-
Denk aan het infoblokje dat aan begin
op het scherm verschijnt. Gebruik enkele geschikte functies,
bijvoorbeeld voor infoblokje, inlezen gegevens van de gebruiker,
omkeren van een getal, Lychrel-test, (zo mogelijk in één functie) coderen en decoderen van een file, en gokken;
zie de tips bij het vijfde werkcollege.
Globale variabelen zijn streng verboden.
Ruwe indicatie voor de lengte van het C++-programma: circa 250 regels.
Uiterste inleverdatum: maandag 17 oktober 2022, 17:00 uur.
Manier van inleveren:
- Digitaal de C++-code
inleveren: stuur een email naar
pm@liacs.leidenuniv.nl.
Stuur geen executable's,
lever alleen de C++-file digitaal in! Noem deze bij voorkeur zoiets als
kaagrutte2.cc, dit voor de tweede opdracht van het duo Rutte-van Kaag.
De laatst voor de deadline ingeleverde versie wordt nagekeken.
- En ook een papieren versie van het verslag
(inclusief de C++-code) deponeren
in de speciaal daarvoor bestemde doos "Programmeermethoden"
bij kamer 159 van het Snellius-gebouw.
Overal duidelijk datum en namen van de (maximaal twee) makers vermelden,
in het bijzonder als commentaar in de eerste regels van de C++-code.
Lees bij het
zesde werkcollege hoe het verslag
eruit moet zien en wat er in moet staan.
Te gebruiken compiler: als hij maar C++ vertaalt;
het programma moet in principe zowel op een Linux-machine
(met
g++) als onder Windows met Code::Blocks draaien.
Test dus in principe op beide systemen!
Normering: verslag 1; layout 1; commentaar 1;
overzichtelijkheid/modulariteit 2;
werking 5.
Eventuele aanvullingen en verbeteringen: lees deze WWW-bladzijde:
www.liacs.leidenuniv.nl/~kosterswa/pm/op2pm.php.