(P) Firma

Tavoite: Harjoittelen lukemaan toisen henkilön kirjoittamaa ohjelmakoodia ja tutustun ohjelman modulaarisuuteen.

Harjoittelen lisää rekursiota, osoittimien käyttämistä ja dynaamista muistinhallintaa. Myös ohjelman jakamista osiin funktioita käyttäen on syytä pohtia.

Ohjeita: Hae ohjelmakoodipohja: templates/07/company2/ -> student/07/company2/.

Tärkeää

Ennen kuin aloitat, lue huolellisesti koko tehtävänanto. Huomaa erityisesti kohdat Ohjelman toteuttaminen osissa (vaaditut commitit) sekä Erityisvaatimukset.

Kohdasta Arviointi huomaa erityisesti, että ohjelman pitää ensin läpäistä kaikki automaattitestit. Muuten työ ei mene assistenttien arvioitavaksi, eikä siitä saa pisteitä.

Huomautus

Tämän projektin saa (mutta ei ole pakko) tehdä parityönä. Paripalautusta varten tulee muodostaa ryhmä palauttamalla lomake, joka löytyy vasemman puolen valikosta otsikolla “Luo uusi ryhmä”. Lisäksi tämän sivun alaosan palautuslaatikkossa on näkyvissä kaksi vaihtoehtoa: “Palauta yksin” / “Palauta ryhmässä”. Ole tarkkana, että valitset oikean vaihtoehdon, koska valintaa ei voi myöhemmin perua. Palautuslaatikkoon tulee vain jommankumman jäsenen Git-repositorion osoite. Kirjoittakaa kooditiedoston kommentteihin molempien nimet ym. muut tiedot.

Ryhmää voi etsiä Kooditorion Discord-linkin kautta (ks. Aikataulu & linkit).

Toteuta moduuli Company ohjelmaan, joka lukee käynnistyessään firman tietoja käyttäjän antamasta syötetiedostosta, ja antaa käyttäjälle mahdollisuuden tehdä firman henkilösuhteisiin liittyviä hakuja.

Ongelman yksinkertaistamiseksi rajataan pois testitapauksista sellaiset tilanteet, joissa henkilösuhteet muodostaisivat ns. mahdottomia silmukoita. Esimerkiksi jos A on B:n pomo, B ei voi olla A:n pomo. Testaamme ohjelmaa vain järkevillä testitapauksilla. Halutessasi haastetta tehtävään, saat toki toteuttaa ohjelmaasi tarkastuksia kummallistenkin tilanteiden varalle.

Automaattitesteissä olennainen “vaikea” testitapaus on esimerkiksi sellainen, että firmassa on henkilö, jolla ei ole pomoa (tai se ei ole tiedossa). Ohjelma saa kaatua tähän, vaan sen pitää kyetä ilmoittamaan, että kyseisen henkilön tiedoissa ei ole pomo(j)a.

Alkukommentti ja palautteen kieli

Samoin kuin aikaisemmin, tässäkin projektissa vaaditaan alkukommentti. Tällä kertaa sitä ei ole annettu, vaan sinun pitää kirjoittaa se itse. Mallia voit katsoa ensimmäisen projektin tehtävänannosta. Kirjoita alkukommentti tiedostoon main.cpp.

Alkukommentista pitää käydä ilmi ainakin seuraavat asiat:

  • ohjelman lyhyt kuvaus

  • tekijän nimi

  • opiskelijanumero

  • käyttäjätunnus (Git-repositorion hakemiston nimi)

  • sähköpostiosoite

  • lyhyt kuvaus käytetyistä tietorakenteista ja toteutetuista komennoista

  • perusteluita toteutusvalinnoille (pakollinen).

Jos teette parityötä, muistakaa lisätä molempien tiedot.

Toisin kuin ensimmäisessä projektissa, nyt kooditiedostoja on enemmän. Huomaa otsikkotiedostojen alussa olevat kommentit, joissa kuvataan kyseinen luokka/moduuli. Päivitä niitä tarvittaessa.

Kuten edellisessä projektissa palautteen kieli valitaan palautuslaatikossa (tämän sivun lopussa). Kielivalinta määräytyy ainoastaan sen perusteella, minkä kielivalinnan olet tehnyt viimeisimmän palautuksen palautuslaatikossa.

Ohjelman moduulit

Ohjelma koostuu neljästä eri moduulista: main, Cli, Utils ja Company. Moduulit main, Cli ja Utils on annettu valmiiksi pohjakoodissa. Tehtäväksesi jää moduulin Company loppuun toteuttaminen.

  • Moduuli main vastaa ohjelman käynnistämisestä. Se pyytää käyttäjältä syötetiedoston ja hoitaa syötetiedoston käsittelyn.

  • Moduuli Cli sisältää ohjelman komentotulkin. Se tunnistaa komennot käyttäjän syötteistä.

  • Moduuli Utils sisältää joitakin yleiskäyttöisiä funktioita. Se on myös nimiavaruus.

  • Moduuli Company toteuttaa tietorakenteen, johon tallennetaan työntekijöitä ja heidän välisiään suhteita. Luokan julkiselle puolelle (public) ei saa tehdä muutoksia, mutta yksityiselle puolelle (private) saa laittaa esimerkiksi tarvittavia apufunktioita.

Valmiiksi toteutettuja moduuleita ei tarvitse muokata. Komentotulkkimoduulin toimintaa ei ole myöskään välttämätön ymmärtää. Kun kierroksen aiheena on modulaarisuus, on tämä ohjelma kuitenkin hyvä esimerkki tutkittavaksi kokonaisuudessaan.

Tiedostossa main.cpp riveillä 149-162 on poikkeusten käsittelyyn liittyvää koodia, jossa tarkistetaan syötteiden oikeellisuus. Poikkeusten käsittely ei kuulu tämän kurssin sisältöön, joten kyseiseen koodikohtaan ei kannata liikaa kiinnittää huomiota, eikä sitä tarvitse ymmärtää.

Ohjelman toiminta

Ohjelmalle syötetään aluksi CSV-tiedosto, josta data luetaan. Ohjelma jäsentää datan ja syöttää ne opiskelijan toteuttamalle Company-moduulille. Tämän jälkeen avataan komentotulkki, jolla voidaan hakea tietoja firmasta. Kirjainten koot eivät vaikuta komentojen nimissä. Sen sijaan parametrina annettavissa tunnisteissa (ID) koolla on merkitystä. Parametrina annetut tunnisteet voi myös rajata lainausmerkeillä.

  • QUIT - Sulkee ohjelman.

  • PRINT - Tulostaa kaikki ohjelmaan tallennetut työntekijät.

  • COLLEAGUES <ID> - Tulostaa ID:n kollegat (eli muut työntekijät, joilla on sama lähin esihenkilö).

  • BOSSES <ID> <N> - Tulostaa ID:n pomot tasolle N asti, eli N:n arvolla 1 tulostetaan ID:n lähin esihenkilö, N:n arvolla 2 lisäksi myös lähimmän esihenkilön lähin esihenkilö jne.

  • SUBORDINATES <ID> <N> - Tulostaa ID:n alaiset tasolle N asti, eli N:n arvolla 1 tulostetaan ID:n suorat alaiset, N:n arvolla 2 lisäksi myös alaisten suorat alaiset jne.

  • LONGEST <ID> - Tulostaa pisimpään palvelleen työntekijän, kun tarkastelu aloitetaan henkilöstä ID ja otetaan huomioon myös ID:n kaikki alaiset.

  • SHORTEST <ID> - Tulostaa lyhyimmän ajan palvelleen työntekijän, kun tarkastelu aloitetaan henkilöstä ID ja otetaan huomioon myös ID:n kaikki alaiset.

Moduulin Company toiminta

Tiedostossa company.hh on valmiiksi määriteltynä tietue (struct) yhden työntekijän tietojen tallentamiseen. Toteutettavassa tietorakenteessa jokaisen työntekijän tiedot talletetaan tällaiseen tietueeseen. Tietueille varataan muistia dynaamisesti, ja tietueet linkitetään toisiinsa osoittimilla, jotka kuvaavat esihenkilö-alaissuhteita. Aloita tehtävään perehtyminen tutustumalla tietueen määrittelyyn.

Tietorakennetta toteuttaessasi saat valita itse, mitä STL:n säiliöitä käytät tietueosoittimien tallentamiseen, mutta tietueiden pitää olla linkitettyinä toisiinsa edellä esitetyllä tavalla.

Yleisiä asioita ja virhetulosteita:

  • Kaikki listatut työntekijät tulostetaan omille riveillensä järjestyksessä, jota kutsumme aakkosjärjestykseksi. Tämä järjestys on muuten kuten aakkosjärjestys, mutta kaikki isot kirjaimet edeltävät kaikkia pieniä kirjaimia eli: A ... Z a ... z. (Tämä on järjestys, jota merkkijonojen vertailut < ja > käyttävät.)

  • Jos henkilön lisäyksessä yritetään lisätä samaa henkilöä kahdesti, tulostetaan:

    Error. Employee already added.
    
  • Tehtävän helpottamiseksi: Esihenkilö-alaissuhteiden lisäyksessä ei tarvitse huomioida mahdollisten duplikaattien aiheuttamia ongelmia.

  • Voit olettaa etteivät esihenkilö-alaissuhteet muodosta silmukoita.

  • Jos komennon kohteena olevaa työntekijää ei löydy, tulostetaan:

    Error. <ID> not found.
    
  • Jos työntekijään kohdistuvalla komennolla ei löydy tulostettavia henkilöitä, tulostetaan:

    <ID> has no <tulostettava ryhmä>.
    

    missä <tulostettava ryhmä> voi olla esimerkiksi alaiset, pomot tai kollegat.

  • Komennoissa SUBORDINATES ja BOSSES: Jos N < 1, tulostetaan:

    Error. Level can't be less than 1.
    

Lyhyet kuvaukset metodien toiminnasta:

  • addNewEmployee - Luo annettujen tietojen perusteella uuden työntekijän, joka tallennetaan tietorakenteeseen. Huomaa, että tässä kohdassa ei vielä lisätä alaisia tai esihenkilöitä.

  • addRelation - Täydentää olemassa oleville työntekijöille esihenkilö-alaissuhteen, eli linkittää tietueet toisiinsa osoittimia käyttäen. Jos parametrina annettua esihenkilöä ei ole olemassa, tilanne tulkitaan niin, että työntekijällä ei ole esihenkilöä. Tätä ei pidetä virheenä, eikä mitään virheilmoitusta anneta.

  • printEmployees - Tulostaa kaikki tietorakenteeseen tallennetut työntekijät aakkosjärjestykseen muodossa:

    <ID> <osasto> <työsuhteen pituus>
    
  • printColleagues - Tulostaa työntekijän kollegat (muut työntekijät, joilla on sama lähin esihenkilö) aakkosjärjestyksessä muodossa:

    <ID> has <lukumaara> colleagues:
    <ID1>
    <ID2>
    ...
    
  • printBossesN - Tulostaa annetun työntekijän esihenkilöt tasolle N asti muodossa:

    <ID> has <lukumäärä> of bosses:
    <ID1>
    <ID2>
    ...
    
  • printSubordinatesN - Tulostaa annetun työntekijän alaiset tasolle N asti muodossa:

    <ID> has <lukumäärä> of subordinates:
    <ID1>
    <ID2>
    ...
    
  • printLongestTimeInLineManagement - Tulostaa annetun työntekijän linjaorganisaatiosta pisimpään palvelleen työntekijän muodossa:

    With the time of <työsuhteen pituus>, <ID> is the longest-served employee in <ID>'s line management.
    

    tai jos annettu työntekijä on itse pisimpään palvellut:

    With the time of <työsuhteen pituus>, <ID> is the longest-served employee in their line management.
    

    Kahden yhtä pitkään palvelleen työntekijän kohdalla ei ole väliä, kumpi tulostetaan.

    Komento vertailee siis henkilön <ID> ja kaikkien hänen alaistensa työsuhteiden pituuksia (jolloin otetaan huomioon suorat ja epäsuorat alaiset eli alaisten alaiset niin pitkälle, kuin heitä riittää).

  • printShortestTimeInLineManagement - Tulostaa annetun työntekijän linjaorganisaatiosta lyhyimmän ajan palvelleen työntekijän muodossa:

    With the time of <työsuhteen pituus>, <ID> is the shortest-served employee in <ID>'s line management.
    

    tai jos annettu työntekijä on itse lyhyimmän ajan palvellut:

    With the time of <työsuhteen pituus>, <ID> is the shortest-served employee in their line management.
    

    Kahden yhtä pitkään palvelleen työntekijän kohdalla tulostetaan aakkosjärjestyksessä ensimmäinen (tai riittää myös, että ohjelmasi tulostaa kumman tahansa, jos vain ohjelmasi läpäisee automaattitestit).

    Komento vertailee siis henkilön <ID> ja kaikkien hänen alaistensa työsuhteiden pituuksia (jolloin otetaan huomioon suorat ja epäsuorat alaiset eli alaisten alaiset niin pitkälle, kuin heitä riittää).

Esimerkkidata:

#CSV-fields
#<ID>;<Department>;<Time in service>;<Boss>

Margit;TiTe;15;Terhi
Kari;TiTe;7;Timo
Timo;TiTe;10;big boss
big boss;administration;1;
secretary;administration;4;big boss
Antti;TiTe;5;Kari
Terhi;TiTe;18;Timo
Eliisa;TiTe;5;Terhi
Mika;TiTe;10;Terhi
Minna;TiTe;1;Margit
Eero;Math;10;big boss
Markus;Math;5;Eero
Manu;Math;4;Eero
Jarno;TiTe;5;
Mikko;TiTe;0.5;Jarno
Arttu;TiTe;0.5;Jarno
lonely rider;desert;5;

Esimerkkiajo:

Input file: data.txt
> print
Antti, TiTe, 5
Arttu, TiTe, 0.5
Eero, Math, 10
Eliisa, TiTe, 5
Jarno, TiTe, 5
Kari, TiTe, 7
Margit, TiTe, 15
Manu, Math, 4
Markus, Math, 5
Mika, TiTe, 10
Mikko, TiTe, 0.5
Minna, TiTe, 1
Terhi, TiTe, 18
Timo, TiTe, 10
big boss, administration, 1
lonely rider, desert, 5
secretary, administration, 4
> colleagues Margit
Margit has 2 colleagues:
Eliisa
Mika
> colleagues secretary
secretary has 2 colleagues:
Eero
Timo
> colleagues big boss
Error: Wrong amount of parameters.
> colleagues "big boss"
big boss has no colleagues.
> longest Timo
With the time of 18, Terhi is the longest-served employee in Timo's line management.
> longest Teri
Error. Teri not found.
> longest Terhi
With the time of 18, Terhi is the longest-served employee in their line management.
> subordinates Terhi 0
Error. Level can't be less than 1.
> subordinates Terhi 1
Terhi has 3 subordinates:
Eliisa
Margit
Mika
> subordinates Terhi 2
Terhi has 4 subordinates:
Eliisa
Margit
Mika
Minna
> subordinates Terhi 3
Terhi has 4 subordinates:
Eliisa
Margit
Mika
Minna
> bosses Margit 2
Margit has 2 bosses:
Terhi
Timo
> bosses Margit 7
Margit has 3 bosses:
Terhi
Timo
big boss
> bosses "big boss" 3
big boss has no bosses.
> colleagues Jarno
Jarno has no colleagues.
> bosses Jarno 1
Jarno has no bosses.
> subordinates Minna 1
Minna has no subordinates.
> subordinates "lonely rider" 5
lonely rider has no subordinates.
> bosses "lonely rider" 5
lonely rider has no bosses.
> quit

Vihjeitä

  • Jotkut funktiot tekevät enemmän tai vähemmän samaa asiaa (erityisesti printLongestTimeInLineManagement ja printShortestTimeInLineManagement). Kannattaa siis huolella miettiä, millaisia apufunktioita teet, että ohjelmakoodista ei tule toisteista.

  • Huomaa, että luokan sisäiset const-funktiot eivät voi kutsua funktioita, joista puuttuu sana const. Sanan const puuttuminen aiheuttaa kääntäjässä [-fpermissive]-virheen. Eli funktio, jota on kielletty muuttamasta olion tilaa, ei saa kutsua funktioita, jotka voivat muokata olion tilaa.

  • Muista, että oletuksena ohjelma käännetään build-hakemistoon. Testaamista varten kannattaa siirtää syötetiedostot tähän samaan hakemistoon.

Ohjelman toteuttaminen osissa

Tehtävä on tarkoitettu toteutettavaksi useassa vaiheessa ja versionhallintaa hyödyntäen. Vähimmäisvaatimuksena on, että työstä löytyy useita loogisia committeja.

Voit toteuttaa ohjelman esimerkiksi seuraavassa järjestyksessä:

  • tietorakenteen valinta ja tiedoston lukeminen

  • työntekijöiden lisääminen tietorakenteeseen

  • työntekijäsuhteiden lisääminen tietorakenteeseen

  • varsinaiset komennot yksi kerrallaan

  • kommenttien ja tyylin viimeistely.

Erityisvaatimukset

Seuraavia vaatimuksia on noudatettava, jotta työ hyväksytään:

  • Työntekijöiden tiedot on talletettava annettua tietuetta (struct Employee) käyttäen. Se löytyy tiedostosta company.hh.

  • Työntekijä-tietueille varataan muistia dynaamisesti. Osoittimet näihin tietueisiin saavat olla talletettuna mihin tahansa, esim. valitsemaasi STL:n säiliöön.

    • Käytä dynaamiseen muistinhallintaan vain älykkäitä (jaettuja) osoittimia, äläkä esim. komentoja new tai delete.

  • Esihenkilö-alaissuhteet talletetaan linkittämällä työntekijä-tietueet toisiinsa osoittimia käytten.

  • Syötetiedoston saa avata luettavaksi vain kerran ohjelman suorituksen aikana. Tiedoston lukemisen aikana kaikki tarvittava tieto tulee siirtää ohjelman muistissa olevaan tietorakenteeseen.

  • Luokan Company julkista rajapintaa ei saa muuttaa. Yksityiseen osioon saa lisätä uusia apufunktioita ja tietorakenteita.

Arviointi

Jotta työ päätyisi assistenttien arvioitavaksi, sen pitää ensin läpäistä automaattitestit. Jos saat automaattitesteistä 0 pistettä, myös lopullinen pistemääräsi on 0, eikä työ mene assistenttien arvioitavaksi.

Assistentti arvioi ja pisteyttää automaattitestit läpäisseistä (= 1 p) sekä tehtävänannon erikoisvaatimukset täyttävistä töistä viimeisen määräajan puitteissa tehdyn commitin seuraavien arviointikriteerien mukaan:

  • Ratkaisun yleisperiaate: 0-20 pistettä:

    • Tehtävän osaamistavoitteet on saavutettu.

    • Ohjelmakoodi on jaettu funktioita, luokkia ja/tai metodeita käyttäen loogisiksi kokonaisuuksiksi, jotka ovat sopivan pituisia.

    • Jos luokkia ja olioita on käytetty, ne on toteutettu olio-ohjelmoinnin periaatteita noudattaen (ks. Olio-ohjelmoinnin tyyliseikkoja).

    • Tietorakenne ei sisällä toisteista eikä turhaa tietoa. Valittuja tietorakenteita on käytetty järkevästi.

    • Ohjelmakoodi ei sisällä turhaa toisteisuutta eikä muutakaan turhaa.

    • Ohjelmakoodi ei sisällä tarpeettomia rajoitteita tai oletuksia tai muita väkinäisiä ratkaisuita.

    • Ohjelmarakenteet on toteutettu helposti ymmärrettäviksi.

    • Ohjelmakoodissa ei ole käytetty globaaleja muuttujia (globaalit const-vakiot ovat OK).

    • Ohjelman toimintaa ei lopeteta exit-funktiota käyttäen.

    • Ohjelmassa on käytetty dynaamista muistinhallintaa, ja se on toteutettu älykkäillä osoittimilla (shared_ptr) eikä komennoilla new tai delete.

  • Ohjelmointityyli: 0-20 pistettä:

    • Huomaa molempien projektikierrosten Tyyliseikkoja-luvut.

    • Muuttujat ja funktiot nimetty selkeästi ja kuvaavasti. Nimeämisessä on käytetty vain yhtä kieltä, ei esim. suomea ja englantia sekaisin.

    • Ohjelmassa on käytetty nimettyjä vakioita taikalukujen sijasta.

    • Ohjelmakoodi on asemoitu siististi.

    • Koodirivien pituus on enintään 80 merkkiä.

    • Jokaisen (itse kirjoittamasi/editoimasi) tiedoston alussa on kommentti, josta käy ilmi tiedoston tarkoitus, työn tekijä(t) ja muut tarvittavat tiedot.

    • Jokaisen funktion/metodin alussa (otsikkotiedostossa jos sellainen on) on kommentti, joka kuvaa sen toiminnan, paluuarvon ja parametrit.

    • Kommentteja on muutenkin tarpeellisissa kohdissa.

    • Kommentit liittyvät toteutettuun ohjelmaan eivätkä johonkin sen vanhempaan versioon.

    • Kaikki kommentit on kirjoitettu samalla kielellä (fi/en), mutta kommentoinnissa saa käyttää eri kieltä kuin muuttujien ym. nimissä.

    • Kaikki muuttujat on alustettu.

    • Kääntäjä ei anna koodia käännettäessä varoituksia.

  • Versionhallinnan käyttö: 0-10 pistettä:

    • Committeja on riittävä määrä.

    • Commit-viestien sisältö on selkeä ja kuvaava.

Huomautus arvioinnista

Automaattitesteillä tarkistetaan, toimiiko ohjelma. Assistentit taas kiinnittävät huomiota tyyliseikkoihin ym. yllä lueteltuihin kriteereihin. Periaatteessa on siis mahdollista, että täysin toimivasta ohjelmasta saa nolla pistettä, jos ohjelma ei täytä yllä lueteltuja vaatimuksia.

Erityisesti tyylivaatimuksista on kerrottu tämän kierroksen aikaisemmassa materiaaliosiossa.

Huomautus arvosteltavan työn versiosta

Arvosteluun otetaan ohjelman se versio, josta on tehty viimeisin onnistunut Plussa-palautus (määräaikaan mennessä). Onnistuneella palautuksella tarkoitetaan palautusta, joka on läpäissyt automaattitestit.

Ensimmäisen onnistuneen Plussa-palautuksen jälkeen haluat todennäköisesti vielä korjailla koodisi tyyliä (esim. lisätä kommentteja), jos vain palautusaikaa on vielä jäljellä.

Muista lopuksi kuitenkin tämä: Kun olet palauttanut viimeisen version Gittiin, palauta se vielä kerran Plussaan.

A+ esittää tässä kohdassa tehtävän palautuslomakkeen.