Az S. 11. feladat (2005. október) |
S. 11. A világ dolgait szeretjük különböző tulajdonságok szerint csoportosítani, és a tulajdonságok között összefüggéseket keresni. Írjunk programot, amely tulajdonságok között von le logikai következtetéseket.
A program bemenetének, amit a billentyűzetről (a standard bemenetről) olvas, minden sora egy-egy állítást vagy kérdést tartalmaz; ezekre egy-egy sorban kell válaszolnia a képernyőre (a standard kimenetre).
Az állítások és kérdések különböző tulajdonságokra vonatkoznak. Az elemi tulajdonságok egyetlen szóból állnak, pl. kicsi, piros. A NINCS, LÉTEZIK, ÉS, VAGY, NEM, HA, AKKOR szavak tiltottak, de minden más szót elemi tulajdonságnak tekintünk.
Az elemi tulajdonságok tagadását úgy képezzük, hogy eléjük írjuk, hogy NEM. Például a piros tagadása az, hogy NEM piros.
Az összetett tulajdonságokat úgy képezzük, hogy néhány elemi tulajdonságot vagy elemi tulajdonságok tagadásait összekapcsoljuk az ÉS vagy a VAGY szavakkal, pl. kicsi ÉS NEM piros. A kétféle összekapcsolás kombinálását (pl. nagy ÉS piros VAGY kék) nem engedjük meg.
Háromféle állítást engedünk meg. Ezek szintaxisa:
LÉTEZIK (tulajdonság)
NINCS (tulajdonság)
HA (tulajdonság) AKKOR (tulajdonság)
Kérdést úgy képezünk, hogy egy állítás végére kérdőjelet írunk.
Az állításokra a program a következőket válaszolhatja:
ÉRTEM ha új információt kapott
TUDOM ha az állítás következik a korábbiakból \
EZ ELLENTMOND A KORÁBBIAKNAK (ilyenkor figyelmen kívül hagyja)
NEM ÉRTEM ha szintaktikusan helytelen az input
Hasonlóan a kérdésekre adható válaszok:
IGEN, illetve NINCS ha a kérdés igaz állításra vonatkozott
NEM, illetve DE IGEN ha a kérdés hamis állításra vonatkozott
NEM TUDOM ha a válasz igaz és hamis is lehet
A program addig fusson, amíg a felhasználó le nem állítja. Feltételezhetjük, hogy az elemi tulajdonságok száma legfeljebb 8, és az input legfeljebb 10000 sorból áll. A kis- és nagybetűket tekintsük azonosnak. Minden olyan karaktert, ami nem betű vagy kérdőjel, tekintsünk a szóközzel azonosnak.
Példa (dőlt betűvel szedtük a számítógép válaszait):
HA kutya VAGY macska VAGY ló AKKOR szőrös ÉS négylábú ÉRTEM HA tacskó VAGY foxi AKKOR kutya ÉRTEM HA foxi AKKOR négylábú TUDOM HA szúnyog AKKOR hatlábú ÉRTEM HA tacskó AKKOR szőrös? IGEN LÉTEZIK tacskó? NEM TUDOM LÉTEZIK tacskó ÉRTEM NINCS szőrös ÉS kutya? DE IGEN HA négylábú AKKOR NEM hatlábú ÉRTEM LÉTEZIK ló ÉS szúnyog? NEM NINCS hatlábú ÉS tacskó? NINCS LÉTEZIK négylábú VAGY hatlábú ÉS NEM szőrös? NEM ÉRTEM |
Beküldendő a program forráskódja (s11.pas, s11.c, ...)
(10 pont)
A beküldési határidő 2005. november 15-én LEJÁRT.
Megoldás. Először is megjegyezzük, hogy a feladatbeli példában kilencféle elemi tulajdonság szerepel. A rugalmasság kedvéért a programunkat úgy valósítjuk meg, hogy az elemi tulajdonságok maximális számát egy makróban definiáljuk.
A program működési elve
A programban 10-féle elemi tulajdonságot engedünk meg. Egy tetszőleges dologra, objektumra mindegyik tulajdonság vagy teljesül, vagy pedig nem teljesül; ebből a szempontból egy objektum legfeljebb 210=1024-féle lehet. Ezért definiálunk 1024-féle tulajdonság atomot, amelyek megfelelnek az elemi tulajdonságok részhalmazainak. Minden elemi és összetett tulajdonságot az atomok egy részhalmazaként képzelünk el. A részhalmazban szereplő elemi tulajdonságok igazak az adott atomra, a részhalmazon kívüli elemi tulajdonságok pedig nem teljesülnek rá.
A HA-AKKOR és a NINCS alakú állítások bizonyos atomokról azt állítják, hogy olyan tulajdonságú dolog nincs. Ezek az állítások tehát a lehetséges atomok halmazát szűkítik; az ilyen állításokat szűkítésnek fogjuk nevezni. A LÉTEZIK állítások pedig atomok halmazairól állítják, hogy legalább az egyikük létezik. Ezek az egzisztencia állítások.
A program tárolja a lehetséges atomok halmazát, és ezt minden egyes elfogadott szűkítéskor módosítja. Azokat a nem üres halmazokat pedig, amelyekről valamelyik LÉTEZIK állításból tudjuk, hogy nem lehetnek üresek, külön-külön eltároljuk. Szűkítéskor a nem üres halmazokból is töröljük a meg nem engedett elemeket.
A szűkítések ellenőrzése két részből áll. A szűkítés mindig azt állítja, hogy atomok csak egy bizonyos A halmazban lehetnek. Ha az A halmaz diszjunkt valamelyik nem üres B halmazzal, az ellentmondás. Az ilyen szűkítés nem megengedett, illetve kérdés esetén a válasz NEM. Az ellenőrzés második részeként ellenőrizzük a megengedett atomok M halmazát. Ha MA, akkor a szűkítés nem jelent új információt; a válasz IGEN, illetve TUDOM. Ha a szűkítés új információt jelent, akkor M-et és az összes nem üres halmazt elmetsszük A-val.
Az egzisztencia állítások ellenőrzése szintén két részből áll. Egy egzisztencia állítás azt mondja, hogy egy bizonyos A halmaz nem üres. Ha A diszjunkt a megengedett atomok halmazával, akkor ez ellentmondás. Ha pedig valamelyik korábbi nem üres halmaz részhalmaza A-nak, akkor az információ nem új.
A program felépítése
A példaprogramot C++-ban írtuk, és Linux alatt, GCC 3.3.3 fordítóval fordítottuk.
A program elején az ETN makróban definiáltuk az elemi tulajdonságok maximális számát, az ATN makróban pedig az atomokét.
Az atomokat megszámozzuk 0-tól 1023-ig. A tulajdonságokat egészekből álló halmazokkal reprezentáljuk:
typedef std::set<int> Tulajdonsag;
Az uresHalmaz és a teljesHalmaz változókat a részletszámolásoknál használjuk; az egyik halmaz üres, a másik a teljes {0,1,2,...,1023} halmaz.
A tulajdonságok legfontosabb műveleteit és relációit a * (metszet), + (unió), - (különbség, illetve komplementer), << és >> (részhalmaz) operátorok valósítják meg.
Az elemi tulajdonságokat is kódolnunk kell. A tulajdonsagKod függvény egy tulajdonságnevet alakít számmá; a visszaadott számok a 2-hatványok (1,2,4,8,...). Az elemiTulajdonsag függvény pedig tulajdonságnevet tulajdonsággá konvertál; a visszadott halmaz azokat az atomokat tartalmazza, amelyek sorszáma tartalmazza a tulajdonságkódnak megfelelő bitet, pl. a 2 kódú tulajdonsághoz tartozó halmaz: {2,3,6,7,10,11,...}
A lehetsegesHalmaz változó tartalmazza azokat az atomokat, amelyeket egyik szűkítés sem zárt még ki; értéke kezdetben a teljes halmaz. A nemUresHalmazok vektorban pedig azokat a halmazokat soroljuk fel, amelyek valamelyik egzisztencia állítás alapján nem lehetnek üresek.
A SzukitesEllenorzes ellenőrzi, hogy egy szűkítő állítás a korábbiak alapján igaz, hamis vagy új információ. A függvény paramétere azon atomok halmaza, amiket az állítás megenged. A SzukitesBejegyzes az új szűkítő információ bejegyzésére szolgál; az új megengedett halmazzal elmetszi a lehetsegesHalmaz-t és a nemUresHalmazok mindegyik elemét.
A Nincs és a HaAkkor függvények értelemszerűen a NINCS, illetve HA-AKKOR alakú állításokat és kérdéseket dolgozzák fel. Mindkét függvényben a kerdes argumentum mondja meg, hogy új állításról, vagy csak kérdésről van szó. Mindkét program meghívja a SzukitesEllenorzes függvényt, szükség esetén a Szukitesbejegyzes-t, és kiírja a képernyőre a választ.
Hasonlóan, az EgzisztenciaEllenorzes, EgzisztenciaBejegyzes és Letezik függvények dolgozzák fel a LETEZIK állátásokat és kérdéseket.
Az állítások és kérdések interpretációját további részekre bontottuk. A programban nem használtunk kivételeket (excpetionöket); helyette a voltHiba változóban jelezzük, ha az interpretáció nem sikerült.
Az osszetettTulajdonsag függvény szavak egy sorozatát alakítja atomok halmazává. A szavakat a szavak vektorban kapjuk, az átalakítandó tartomány első és utolsó elemének indexe elso, illetvet utso. Ez a függvény kezeli a NEM, az ÉS és a VAGY relációkat.
A SzavakraTordeles függvény egy stringet bont szavakra. A kérdőjel önálló szó.
Végül az EgySorFeldolgozasa függvény egy stringet szavakra bont, megvizsgálja az első szót és hogy az utolsó szó kérdőjel-e, és meghívja a HaAkkor, Nincs vagy a Letezik függvényt.
A sorok beolvasása végtelen ciklusban a main függvényben történik.
// S. 10. // Mekk Elek 11. o. t. // Nekeresd, Ezermesterképző Intézet // kaposzta@nekeresd.hu // Ezt a programot Linux alatt, GCC 3.3.3 fordítóval teszteltük. // -------------------------------------------------------------------- #include <iostream> #include <string> #include <map> #include <set> #include <vector> #define ETN 10 // Az elemi tulajdonságok maximális száma #define ATN (1 << 10) // Az atomi tulajdonságok max. száma // ==================================================================== // Összetett tulajdonságok kezelése. Az összetett tulajdonságok // tulajdonságatomok halmazai. Az atomokat megszámozzuk, az összetett // tulajdonságokat reprezentáló "Tulajdonsag" tipus ezért egészek egy // halmaza lesz. typedef std::set<int> Tulajdonsag; Tulajdonsag uresHalmaz; Tulajdonsag teljesHalmaz; // Az összes atom halmaza. Értéket a main-ben kap // -------------------------------------------------------------------- // VAGY művelet -- két tulajdonsághalmaz uniója Tulajdonsag operator + ( const Tulajdonsag &A, const Tulajdonsag &B ) { Tulajdonsag C; std::set_union( A.begin(), A.end(), B.begin(), B.end(), std::inserter( C, C.begin() )); return C; } // -------------------------------------------------------------------- // ÉS művelet -- két tulajdonsághalmaz metszete Tulajdonsag operator * ( const Tulajdonsag &A, const Tulajdonsag &B ) { Tulajdonsag C; std::set_intersection( A.begin(), A.end(), B.begin(), B.end(), std::inserter( C, C.begin() )); return C; } // -------------------------------------------------------------------- // Különbséghalmaz Tulajdonsag operator - ( const Tulajdonsag &A, const Tulajdonsag &B ) { Tulajdonsag C; std::set_difference( A.begin(), A.end(), B.begin(), B.end(), std::inserter( C, C.begin() )); return C; } // -------------------------------------------------------------------- // Tagadás -- komplementum képzés Tulajdonsag operator - ( const Tulajdonsag &A ) { return teljesHalmaz - A; } // -------------------------------------------------------------------- // Részhalmaz ellenőrzése bool operator << ( const Tulajdonsag &A, const Tulajdonsag &B ) { return ( (A-B).size() == 0 ); } bool operator >> ( const Tulajdonsag &A, const Tulajdonsag &B ) { return ( B << A ); } // ==================================================================== // Elemi tulajdonságok kezelése // Tulajdonság kódjának kikeresése. A függvény egy elemi tulajdonság // nevét kapja, és visszaadja a kódot. Ha a tulajdonság még nem // szerepelt, a következő szabad kódot kapja. Ha az elemi // tulajdonságok száma túl nagy, kilép a programból. int tulajdonsagKod( const std::string nev ) { // A korábbi név-kód párok static std::map<std::string,int> kodTabla; // Kikeressük a nevet a táblázatból std::map<std::string,int>::const_iterator it; it = kodTabla.find( nev ); // Ha szerepel a táblázatban, akkor megvan a kód if (it != kodTabla.end()) { return it->second; } // Nem szerepel a táblázatban. Ellenőrizzük, tele-e a táblázat if ( kodTabla.size() >= ETN ) { std::cout << "Túl sok elemi tulajdonság!" << std::endl; exit( 1 ); } // A kód a tábla mérete-edik 2-hatvány int kod = 1 << kodTabla.size(); kodTabla.insert( std::make_pair( nev, kod )); return kod; } // -------------------------------------------------------------------- // Elemi tulajdonság (szó) tulajdonsággá konvertálása Tulajdonsag elemiTulajdonsag( const std::string &nev ) { int kod = tulajdonsagKod( nev ); // A tulajdonság kódja int i; Tulajdonsag T; for (i=0; i<ATN; i++) { if ( i & kod ) T.insert( i ); } return T; } // ==================================================================== // A felhasználó által adott információk feldolgozása, tárolása. Tulajdonsag lehetsegesHalmaz; // Azok az atomok, amik létezhetnek (amikről senki // sem mondta, hogy nem léteznek) std::vector<Tulajdonsag> nemUresHalmazok; // Azon tulajdonságok felsorolása, // amiknek a kapott információ // alapján létezniük kell. // -------------------------------------------------------------------- // Szűkítő jellegű állítások és kérdések (HA .. AKKOR, NINCS) // ellenőrzése és feldolgozása. Egy szűkítés azt állítja vagy kérdezi, // hogy atomok csak egy bizonyos halmazban vannak(-e). Pl. a "NINCS A" // azt állítja, hogy csak az A tulajdonságban felsorolt atomok // létezhetnek. // A függvény bemenete tehát egy tulajdonság, és az a kérdés, hogy // létezik-e ezen kívül atom. Az eredmény háromféle lehet: // 0 = az eddigi információ alapján nem tudjuk // 1 = biztosan nem létezik -- az új állítás a korábbiakból következik // 2 = biztosan létezik -- az új állítás a korábbiaknak ellentmond int SzukitesEllenorzes( const Tulajdonsag &A ) { uint i; // Ha valamelyik biztosan nem üres halmazzal diszjunkt, akkor // ellentmond az eddigi információnak for (i=0; i<nemUresHalmazok.size(); i++) if (nemUresHalmazok[i] * A == uresHalmaz) return 2; // Ellenőrizzük, hogy az A-ban minden lehetséges atom szerepel-e if (lehetsegesHalmaz << A) return 1; else return 0; } // --------------------------------------------------------------------- // A szűkítés bejegyzése az adatbzázisba void SzukitesBejegyzes( const Tulajdonsag &A ) { uint i; // Szűkítjük a lehetséges atomok halmazát lehetsegesHalmaz = lehetsegesHalmaz * A; // Szűkítjüka biztosan létező halmazokat is for (i=0; i<nemUresHalmazok.size(); i++) nemUresHalmazok[i] = nemUresHalmazok[i] * A; } // --------------------------------------------------------------------- // "NINCS A" feldolgozása. Ha csak kérdés, akkor kerdes=true. A // függvény kiírja a választ a képernyőre, és nem ad vissza semmit void Nincs( const Tulajdonsag &A, bool kerdes ) { Tulajdonsag B = -A; switch (SzukitesEllenorzes( B )) { case 0: // Új információ if (kerdes) std::cout << "NEM TUDOM" << std::endl; else { SzukitesBejegyzes( B ); std::cout << "ÉRTEM" << std::endl; } break; case 1: // Következik a korábbiakból if (kerdes) std::cout << "NINCS" << std::endl; else std::cout << "TUDOM" << std::endl; break; case 2: // Ellentmond a korábbiaknak if (kerdes) std::cout << "DE IGEN" << std::endl; else std::cout << "EZ ELLENTMOND A KORÁBBIAKNAK" << std::endl; break; } } // --------------------------------------------------------------------- // "HA A AKKOR B" feldolgozása void HaAkkor( const Tulajdonsag &A, const Tulajdonsag &B, bool kerdes ) { Tulajdonsag C = -A + B; // A C halmaz az, amire szűkít switch (SzukitesEllenorzes( C )) { case 0: // Új információ if (kerdes) std::cout << "NEM TUDOM" << std::endl; else { SzukitesBejegyzes( C ); std::cout << "ÉRTEM" << std::endl; } break; case 1: // Következik a korábbiakból if (kerdes) std::cout << "IGEN" << std::endl; else std::cout << "TUDOM" << std::endl; break; case 2: // ellentmond a korábbiaknak if (kerdes) std::cout << "NEM" << std::endl; else std::cout << "EZ ELLENTMOND A KORÁBBIAKNAK" << std::endl; break; } } // --------------------------------------------------------------------- // Egzisztencia állítások (LÉTEZIK) ellenőrzése és feldolgozása. A // függvény bemenete ismét egy tulajdonság, amiről azt // állítjuk/kérdezzük, hogy az eddigi információ alapján van-e benne // létező atom. A lehetséges válaszok: // 0 = az eddigi információ alapján nem tudjuk // 1 = biztosan létezik -- a korábbiakból következik, hogy a halmaz // nem üres // 2 = biztosan nem létezik -- a halmaz a korábbiak alapján üres int EgzisztenciaEllenorzes( const Tulajdonsag &A ) { uint i; // Ellenőrizzük, hogy a halmazban csupa nemlétező atom van-e if (lehetsegesHalmaz * A == uresHalmaz) return 2; // Ha a halmaz tartalmazz valamelyik korábbi, semmiképpen sem üres // halmazt, akkor a halmaz biztosan nem üres for (i=0; i<nemUresHalmazok.size(); i++) if (A >> nemUresHalmazok[i]) return 1; return 0; } // --------------------------------------------------------------------- // Egzisztencia állítás bejegyzése void EgzisztenciaBejegyzes( const Tulajdonsag &A ) { // Az újabb nem üres halmazt hozzávesszük a listához nemUresHalmazok.push_back( A * lehetsegesHalmaz ); } // --------------------------------------------------------------------- // "LÉTEZIK A" feldolgozása. Ha kerdes=true, akkor csak kérdezzük void Letezik( const Tulajdonsag &A, bool kerdes ) { switch (EgzisztenciaEllenorzes( A )) { case 0: // Új információ if (kerdes) std::cout << "NEM TUDOM" << std::endl; else { EgzisztenciaBejegyzes( A ); std::cout << "ÉRTEM" << std::endl; } break; case 1: // Következik a korábbiakból if (kerdes) std::cout << "IGEN" << std::endl; else std::cout << "TUDOM" << std::endl; break; case 2: // Ellentmond a korábbiaknak if (kerdes) std::cout << "NEM" << std::endl; else std::cout << "EZ ELLENTMOND A KORÁBBIAKNAK" << std::endl; break; } } // ==================================================================== // Az input sorok interpretálása. // Ha valamikor hiba volt (pl. az ÉS és VAGY keverése), itt jelezzük bool voltHiba; // -------------------------------------------------------------------- // Szavak egy sorozatának tulajdonsággá konvertálása. A szavak tömbb // elso-edik szavától az utso-adik szaváig Tulajdonsag osszetettTulajdonsag( const std::vector<std::string> &szavak, int elso, int utso ) { Tulajdonsag osszeg; int tipus = 0; // 1 = a tagok VAGY-gyal vannak kapcsolva. // 2 = ÉS-sel. 0 = Még nem tudjuk int i; // A tulajdonságnak legalább egy szóból kell állnia if (elso > utso) { voltHiba=true; return uresHalmaz; } // Sorban megyünk a tagokon i=elso; while (i<=utso) { // Ha ez nem az első tag, relációjelnek kell következnie. if (i>elso) { if (szavak[i]=="VAGY") { // Ha már volt ÉS, az hiba if (tipus == 2) { voltHiba = true; return uresHalmaz; } tipus = 1; } else if (szavak[i]=="ÉS") { // Ha már volt VAGY, az hiba if (tipus == 1) { voltHiba = true; return uresHalmaz; } tipus = 2; } else { voltHiba = true; return uresHalmaz; } // Nem relációjel :-( ++i; // feldolgoztuk a relációjelet } // Ellenőrizzük, a végére értünk-e if (i>utso) { voltHiba=true; return uresHalmaz; } // A következő tag ami csak XXX vagy NEM XXX alakú lehet int tagadjuk=0; if (szavak[i]=="NEM") { tagadjuk=1; ++i; if (i>utso) { voltHiba=true; return uresHalmaz; } } // A tulajdonság neve nem lehet védett szó if ( szavak[i]=="NEM" || szavak[i]=="VAGY" || szavak[i]=="ÉS" || szavak[i]=="HA" || szavak[i]=="AKKOR" || szavak[i]=="VAGY" || szavak[i]=="LÉTEZIK" || szavak[i]=="NINCS" || szavak[i]=="?" ) { voltHiba = true; return uresHalmaz; } // Az új tag kiszámítása és hozzáadása az öüsszeghez Tulajdonsag ujTag = tagadjuk ? - elemiTulajdonsag( szavak[i] ) : elemiTulajdonsag( szavak[i] ); switch (tipus) { case 0: osszeg = ujTag; break; case 1: osszeg = osszeg + ujTag; break; case 2: osszeg = osszeg * ujTag; break; } ++ i; } return osszeg; } // --------------------------------------------------------------------- // Egy teljes sor szavakra tördelése. A kérdőjel önálló szó std::vector<std::string> szavakraTordeles( const std::string &sor ) { std::vector<std::string> eredmeny; std::string ujSzo; int i,n; n = sor.length(); for (i=0; i<n; i++) { char c = toupper( sor[i] ); // A következő karakter, nagybetűvé konvertálva if (!isalpha(c) && c!='?') c = ' '; // Ha nem betű vagy kérdőjel, akkor szóköz if (c=='?') { // Ha kérdőjel, akkor az előző szónak is vége if (ujSzo!="") { eredmeny.push_back( ujSzo ); ujSzo = ""; } eredmeny.push_back( "?" ); } else if (c==' ') { if (ujSzo!="") { eredmeny.push_back( ujSzo ); ujSzo = ""; } } else ujSzo += c; } if (ujSzo!="") eredmeny.push_back( ujSzo ); return eredmeny; } // --------------------------------------------------------------------- // Egy sor feldolgozása, megválaszolása void EgySorFeldolgozasa( const std::string &sor ) { std::vector<std::string> szavak = szavakraTordeles( sor ); int n = szavak.size(); bool kerdes; voltHiba = false; // Üres sorokat nem értünk if (n==0) { std::cout << "NEM ÉRTEM" << std::endl; return; } // Ha az utolsó szó egy kérdőjel, akkor kérdés if (szavak[n-1]!="?") kerdes = false; else { kerdes = true; --n; } if (szavak[0]=="HA") { // Megkeressük az AKKOR szót int k=0; while (k<n && szavak[k]!="AKKOR") ++k; Tulajdonsag A = osszetettTulajdonsag( szavak, 1, k-1 ); // A HA és AKKOR közötti rész Tulajdonsag B = osszetettTulajdonsag( szavak, k+1, n-1 ); // Az AKKOR utáni rész if (voltHiba) std::cout << "NEM ÉRTEM" << std::endl; else HaAkkor( A, B, kerdes ); } else if (szavak[0]=="NINCS") { Tulajdonsag A = osszetettTulajdonsag( szavak, 1, n-1 ); if (voltHiba) std::cout << "NEM ÉRTEM" << std::endl; else Nincs( A, kerdes ); } else if (szavak[0]=="LÉTEZIK") { Tulajdonsag A = osszetettTulajdonsag( szavak, 1, n-1 ); if (voltHiba) std::cout << "NEM ÉRTEM" << std::endl; else Letezik( A, kerdes ); } else // Az első szó valami más... std::cout << "NEM ÉRTEM" << std::endl; } // --------------------------------------------------------------------- int main( int argc, char **argv ) { setlocale( LC_ALL, "hu_HU" ); // Inicializáljuk a teljesHalmaz és a lehetsegesHalmaz változókat int i; for (i=0; i<=ATN; i++) teljesHalmaz.insert( i ); lehetsegesHalmaz = teljesHalmaz; // Végtelen ciklusban olvasunk és értelmezünk while (1) { std::string sor; std::getline( std::cin, sor ); if (sor=="") break; EgySorFeldolgozasa( sor ); } } // ==================================================================== |
A dolgozatok tanulságai
A hibátlanul működő programokra 7 pont járt, a dokumentációra pedig legfeljebb a programra kapott pontszám fele, így gyűlhetett össze a maximális 7+3 pont.
A dokumentáció hiányosságai
Továbbra is nagyon hiányosak a programok dokumentációi. Ennek egyik oka talán az is lehet, hogy az elvárásaink nem elég világosak. Ezért most újra szeretnénk összefoglalni, hogy az S-jelű feladatok esetében egy jó leírás milyen részekből állhat. Mindenekelőtt a legfontosabb cél, hogy a javító vagy akárki más -- akár maga a program írója bizonyos idő elteltével -- könnyen megérthesse a program működését, és akár a programban előforduló hibákat is kijavíthassa.
- Az algoritmus működési elve. Elmagyarázzuk, hogy a program mit csinál, és miért működik. Az algoritmust többnyire érdemes külön fájlban leírni; a dokumentációnak ez a része egyrészt terjedelemesebb, másrészt olyan eszközöket (képletek, ábrák) is tartalmazhat, amiket a program szövegében nehéz elhelyezni.
- Áttekintés a program megvalósításáról. Ebben szerepel, hogy milyen programnyelven használtok, milyen operációs rendszeren és milyen fordítóval fordítottátok, a program milyen fontosabb részekből áll, és a használatához milyen esetleges változtatások szükségesek stb. Ez szerepelhet a forráskód elején is.
- A fontosabb változók és eljárások jelentése. Ez egy fontos összekötő kapocs az algoritmus leírása és a programkód között; elmagyarázza, hogy az adott változó vagy eljárás az algoritmus melyik részét valósítja meg. Ez részben a program áttekintésében, részben a forráskódban érdemes leírni.
- A forráskódban elhelyezett kommentek. Ezek célja a közvetlen forráskód megértése; ha valamelyik részlet értelme nem derülne ki azonnal az olvasó számára, akkor teszünk mellé egy rövid megjegyzést.
A legtöbb dolgozatból teljesen hiányzott az algoritmus és a program áttekintése. A kódban elhelyezett kommentek pedig csak egy-egy részletet próbáltak megmagyarázni, a program globális bemutatása nélkül. Így pedig nagyon nehéz megérteni, hogy a program maga hogyan működik.
Típushibák
Több versenyző nem bontotta az elemi tulajdonságokat atomokra. Emiatt a programjuk nem is működhetett helyesen. Ha a programjuk erre a leegyszerűsített esetre hibátlanul működött volna, 2+1 pontot kaphattak ... volna.
Az ékezetes karakterek kezelésa sajnos nagyon szorosan kapcsolódik az operációs rendszer által használt karakterkódoláshoz, és nagyon nehéz lenne a programot úgy megírni, hogy minden gépen egyformán jól működjön. A kódolásból származó problémákat nem tekintettük hibának, nem vontunk le érte pontot. Azokat a programokat, amiknél az ékezetes betűk kezelése gondot okozott, a forráskód módosításával, ékezetes betűk nélkül teszteltük.
Sajnos többeknél érzékelhető volt, hogy nem hagytak maguknak elegendő időt a feladat megoldására. Leginkább ez az oka a sok 0 pontos dolgozatnak. Pedig egy ilyen összetett feladat esetében a program tesztelésére és dokumentálására is időt kell hagyni.
Letölthető fájlok
C++ forráskód: s11.cpp
Tesztadatok: s11teszt.zip
Kós Géza
Statisztika:
13 dolgozat érkezett. 9 pontot kapott: Grósz Dániel. 6 pontot kapott: 1 versenyző. 5 pontot kapott: 1 versenyző. 2 pontot kapott: 1 versenyző. 0 pontot kapott: 9 versenyző.
A KöMaL 2005. októberi informatika feladatai