Skip to content
Snippets Groups Projects
Select Git revision
  • 01427a246a9b44b6780bfe9c3761c63262c6e098
  • main default
  • frederik
  • Sondre
4 results

const.h

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    stoppesteder.cpp 13.37 KiB
    /**
     * Kode-fil for stoppesteder-klassen
     *
     * @file stoppesteder.cpp
     * @author Sondre Sand & Frederik Simonsen
     */
    #include <iomanip>
    #include <iostream>
    #include <string>
    #include <vector>
    #include <fstream>
    #include <algorithm> // any_of, transform
    #include "LesData3.h"
    #include "stoppested.h"
    #include "stoppesteder.h"
    using namespace std;
    
    /**
     * Sletter minne allokert med Stoppesteder
     */
    Stoppesteder::~Stoppesteder() {
        for (int i = 0; i < stopper.size(); i++)
            delete stopper[i]; // Sletter det tilpekte
        stopper.clear(); // Tømmer vektor for pekere
    }
    
    /**
     * Sjekker om en stoppesteds indeks finnes i vektoren
     *
     * @param nr - nr fra brukeren.
     * @return true - Hvis indeks finnes i vektoren
     * @return false - Hvis indeksen ikke finnes i vektoren
     */
    bool Stoppesteder::finnesIndeks(const int nr){
        // Sjekker om medsendt nr ikke er større enn vektorens størrelse:
        if (nr <= stopper.size()) {
            for (int i = 0; i < stopper.size(); i++) { // For hver stoppested:
                if (i == nr) //hopper ut hvis tall er funnet
                    return true; // Funn
            }
        }
        return false; // Ingen funn
    }
    
    /**
     * sjekker om en string inneholder tall.
     * 
     * @param nvn Streng fra bruker som skal sjekkes om inneholder tall
     * @return true Hvis tall i strengen
     * @return false Hvis ikke tall i strengen
     */
    bool Stoppesteder::ikkeHarTall(const string nvn){
        return any_of(nvn.begin(), nvn.end(), ::isdigit);
    }
    /**
     * Sjekker om Stoppesteder sin vektor er tom eller ei
     *
     * @return true Hvis vektor er tom
     * @return false Hvis vektor ikke er tom
     */
    bool Stoppesteder::tom() {
        return stopper.empty();
    }
    
    /**
     * Prøver å finne et stoppesteds navn vha dens indeks i vektoren
     *
     * @param nvn - Navn som skal sjekkes om finnes
     * @return i - Stoppestedets faktiske indeks ved funn
     * @return -1 - Har ikke funnet stoppestedets indeks (skal ikke skje)
     * @see Stoppested::hentStoppestedNavn()
     */
    int Stoppesteder::hentIndeksVhaNavn(const string nvn) {
        string navn; // Hjelpevariabel for å sammenligne navn
        for (int i = 0; i < stopper.size(); i++) { // For hvert stoppested:
            navn = stopper[i]->hentStoppestedNavn(); // Henter faktisk navn
            if(navn == nvn) { // Sammenligner faktisk navn med medsendt navn
                return i; // Funn, returnerer indeks
            }
        }
        return -1; // Ingen funn, skal ikke skje
    }
    
    /**
     * En funksjon som erstatter eventuelle æøåÆØÅ med eoaEOA i medsendt navn
     *
     * @param nvn - Et stoppesteds navn som skal få æøåÆØÅ byttet ut
     * @return string - En string uten æøåÆØÅ
     */
    string Stoppesteder::byttBokstaver(const string nvn) {
        string nyString; // Hjelpevariabel
    
        for (int i = 0; i < nvn.size(); i++) { // For hver bokstav i navnet:
            switch(int(nvn[i])) { // Caster om til intverdi:
                case -111: nyString += 'e'; break; // -111: æ, gjør om til e
                case 111: nyString += 'o'; break; // 111: ø, gjør om til o
                case -122: nyString += 'a'; break; // -122: å, gjør om til a
                case -110: nyString += 'E'; break; // -110: Æ, gjør om til E
                case 79: nyString += 'O'; break; // 79: Ø, gjør om til O
                case -113: nyString += 'A'; break; // -113: Å, gjør om til A
                default: nyString += nvn[i]; // Ingen av bokstavene over, beholder
            }                                // samme bokstav som opprinnelig
        }
        return nyString; // Returnerer string uten æøåÆØÅ
    }
    
    /**
     * Forsøker å finne et entydig stoppestedsnavn i datastrukturen
     *
     * @param nvn - Input fra bruker som skal sjekkes om matcher med et entydig
                    stoppesteds navn i datastrukturen
     * @return string - Et stoppesteds faktiske navn ved entydighet, evt. en tom
     *                  string hvis ikke entydig match funnet
     * @see Stoppested::hentStoppestedNavn()
     */
    string Stoppesteder::finnEntydig(string nvn) {
        string stortNavn, // Hjelpevariabler for å sjekke om navnematch
               tom; // Brukes for return av en tom string ved ikke funn
        int entydig = 0; // Hjelpevariabel for å returnere evt. korrekt navn
        vector <int> navneMatch; // En hjelpevektor for å mellomlagre eventuelle
                                 // indekser som matcher med medsendt navn
    
        // Gjør om medsendt navn til store bokstaver:
        transform(nvn.begin(), nvn.end(), nvn.begin(), ::toupper);
    
        for (int i = 0; i < stopper.size(); i++) { // For hvert stoppested:
            stortNavn = stopper[i]->hentStoppestedNavn(); // Henter dets navn
            transform(stortNavn.begin(), stortNavn.end(), // Gjør om til store
                      stortNavn.begin(), ::toupper);      // bokstaver
    
            if (stortNavn.compare(nvn) == 0) { // Hele navnet matcher
                navneMatch.push_back(i); // Legges indeks bakerst i hjelpevektor
                entydig = navneMatch[navneMatch.size()-1]; // Henter riktig indeks
                // Returnerer det faktiske navnet på stoppestedet vha. indeks:
                return stopper[entydig]->hentStoppestedNavn();
            }
                // Hvis deler av navnet matcher, men ikke full match:
            if (stortNavn.compare(0, nvn.size(), nvn) == 0) {
                navneMatch.push_back(i); // Legger indeks bakerst i hjelpevektor
            }
    
            if (navneMatch.size() > 1) // Hvis mer enn en navnematch funnet:
                return tom; // Early return, navn er ikke entydig
        }
    
        if (navneMatch.size() == 1) { // Hvis kun en delmatch på navn:
            entydig = navneMatch[0]; // Henter korrekt indeks
            return stopper[entydig]->hentStoppestedNavn();// Returnerer faktisk navn
        } else // Ingen registrerte navn som matcher
            return tom; // Returnerer en tom string
    }
    
    /**
     * Henter et stoppesteds navn ved hjelp av dens indeks i vektoren
     *
     * @param nr - Stoppestedets faktiske nummer
     * @return string - Stoppestedets faktiske navn
     * @see Stoppested::hentStoppestedNavn()
     */
    string Stoppesteder::hentNavnVhaIndeks(const int nr) {
        string navn; // Hjelpevariabel for å returnere faktiske navn
        // Henter stoppestedets faktiske navn vha. indeks (stoppestedets nr - 1)
        navn = stopper.at(nr-1)->hentStoppestedNavn();
        return navn; // Returnerer stoppestedets faktiske navn
    }
    
    /**
     * Forsøker å finne om et Stoppestedsnavn er duplikat
     *
     * @param nvn - Bruker innlest navn som skal sjekkes mot reelle Stoppestedsnavn
     * @return Hvis duplikat, returneres en peker til Stoppestedet med navnet
     * @return Hvis ikke duplikat, eller ingen stoppesteder i datastrukturen
     *         returneres nullptr
     * @see Stoppested::hentStoppestedNavn()
     */
    Stoppested* Stoppesteder::finnDuplikat(string nvn) {
        string sNavn; // Hjelpevariabel for å hente faktiske stoppestedets navn
    
        // Gjør om medsent navn til store bokstaver:
        transform(nvn.begin(), nvn.end(), nvn.begin(), ::toupper);
        if (!stopper.empty()) { // Hvis stoppesteder er registrert:
            for (int i = 0; i < stopper.size(); i++) { //  For hvert stoppested:
                // Henter faktisk navn på stoppested:
                sNavn = stopper[i]->hentStoppestedNavn();
                // Gjør om faktisk navn til store bokstaver:
                transform(sNavn.begin(), sNavn.end(), sNavn.begin(), ::toupper);
                if (sNavn == nvn) // Hvis medsendt matcher med faktisk navn
                    return stopper[i]; // Funn, returner peker til stoppestedet
            }
        }
        return nullptr; // Ingen stoppesteder i datastrukturen, eller
                        // fant ingen duplikater
    }
    
    /**
     * Funksjon som håndterer brukervalg ifm. Stoppestedermenyen
     *
     * @see Stoppesteder::skrivMeny()
     * @see Stoppesteder::nyStop()
     * @see Stoppesteder::skrivAlle()
     * @see Stoppesteder::skrivStopp()
     */
    void Stoppesteder::handling() {
        char valg;
    
        skrivMeny(); // Skriver ut menyvalgene til bruker
        valg = lesChar("\nKommando"); // Leser brukervalg
    
        switch (valg) {
            case 'N': nyStop(); break; // Legge til nytt stoppested
            case 'A': skrivAlle(); break; // Skriv alle stoppesteder
            case 'E': skrivStopp(); break; // Skriv alt om et stoppested
                            // Går tilbake til hovedmeny:
            default: cout << "\nUlovlig kommando!\n"; break;
        }
    }
    
    /**
     * Leser inn data om stoppesteder fra fil
     *
     * @see Stoppested::Stoppested(...)
     */
    void Stoppesteder::lesFraFil() {
        ifstream innfilS("Stoppesteder.dta"); // Åpner aktuell fil
        string navn; // Hjelpevariable for å lese navn og antall stoppesteder på fil:
        int antStopp;
    
        if (innfilS) { // Hvis filen funnet
            innfilS >> antStopp; innfilS.ignore(); // Leser antall stopp, kaster '\n'
            cout << "Leser " << antStopp
                 << " stoppesteder fra 'stoppested.dta'...\n";
            getline(innfilS, navn); // Forsøker å lese første post
            while (!innfilS.eof()) { // Så lenge ikke slutt på fil:
                // Oppretter nytt stoppested og legges bakerst i vector:
                stopper.push_back(new Stoppested(navn, innfilS));
                getline(innfilS, navn); // Forsøker å lese neste post:
            }
            innfilS.close(); // Lukker aktuell fil
        } else // Feilmelding, filen finnes ikke:
            cout << "\nFant ikke filen 'stoppested.dta'...\n\n";
    }
    
    /**
     * Legger til et nytt stoppested i datastrukturen, hvis mulig (ingen duplikat)
     *
     * @see Stoppesteder::ikkeHarTall(...)
     * @see Stoppesteder::byttBokstaver(...)
     * @see Stoppesteder::finnDuplikat(...)
     * @see Stoppested::Stoppested(...)
     */
    void Stoppesteder::nyStop() {
        Stoppested* nyStopp = nullptr;
        string navn;
        // TODO: Lag en funksjon som sørger for at et stoppesteds navn ikke
        // TODO: kun kan være tall!
        cout << "\nNavn på stoppested: "; getline(cin,navn); // Leser navn
        while (navn.size() < 2 || ikkeHarTall(navn)) { // Looper hvis navn er >2 tegn
            cout << "\nNavn kan ikke inneholde tall, og må være 2 tegn eller mer."
                 << " Prøv igjen: ";
            getline(cin, navn);
        }
    
        navn = byttBokstaver(navn); // fjerner evt. æøåÆØÅ i navn
    
        if (!stopper.empty()) // Hvis det finnes stoppesteder registrert:
            nyStopp = finnDuplikat(navn); // Sjekker for duplikat
    
        if (nyStopp == nullptr) { // Ingen duplikater funnet/stoppesteder registrert
            nyStopp = new Stoppested(navn); // Oppretter nytt stoppested
            stopper.push_back(nyStopp); // Legges bakerst i vektoren
            cout << "\nStoppested med navn: " << navn << " er nå lagt til.\n";
        } else // Duplikat navn:
            cout << "\nStedsnavnet finnes allerede.\n";
    }
    
    /**
     * Skriver ut navn og nummer om hvert stoppested i datastrukturen
     * Skriver ut 3 stoppesteder per linje i run-time
     * Forsøker å skrive formatert utskrift
     *
     * @see Stoppested::skrivData()
     */
    void Stoppesteder::skrivAlle() {
        int n = 0; // Indikator for å telle opp antall utskrifter
    
        if (!stopper.empty()) { // Hvis det finnes stoppesteder registrert:
            cout << "\nAlle stoppestedene i datastrukturen:\n";
            for (int i = 0; i < stopper.size(); i++) { // For hvert stoppested:
                cout << setw(4) << i+1 << ": "; // Skriver ut stoppestedets nummer
                stopper[i]->skrivData(); // Stopp skriver eget navn
                n++; // Teller opp indikator
                if (n % 3 == 0) { // Sørger for linjeskift for hver 3.stopp
                    cout << '\n';
                }
            }
        } else // Ingen stoppesteder registrert:
            cout << "\nIngen stoppesteder registrert i datastrukturen!\n";
    }
    
    /**
     * Skriver stoppestedsmenyens menyvalg til brukeren
     */
    void Stoppesteder::skrivMeny() {
        cout << "\nFølgende kommandoer er tilgjengelige:\n"
             << "\tN - Nytt stoppested\n"
             << "\tA - Skriv alle stoppesteder\n"
             << "\tE - Skriv alt om et stoppested\n";
    }
    
    /**
     * Skriver ut all informasjon om et stopp (navn, naboer og tid i mellom)
     *
     * @see Stoppesteder::finnDuplikat(...)
     * @see Stoppesteder::finnEntydig(...)
     * @see Stoppested::skrivNaboerOgTid()
     */
    void Stoppesteder::skrivStopp() {
        string navn, // Hjelpevariabler for å lese navn fra bruker og finne
               entydigNavn; // faktisk navn i datastrukturen.
        Stoppested* stoppestedet = nullptr;
    
        if (!stopper.empty()) { // Hvis det finnes stoppesteder i datastrukturen
            cout << "\nAlt om stoppestedet: "; getline(cin, navn);
    
            while (navn.size() < 1) { // Sørger for at navn være minst 1 tegn
                cout << "\nNavn må være 2 tegn eller mer. Prøv igjen: ";
                getline(cin, navn);
            }
    
            entydigNavn = finnEntydig(navn); // Forsøker å finne et reelt navn
    
            if (entydigNavn.size() > 0) { // Hvis det faktisk er et entydig navn:
                cout << '\n' << entydigNavn << " har forbindelser til:\n";
                // Henter det faktiske stoppestedets peker:
                stoppestedet = finnDuplikat(entydigNavn);
                stoppestedet->skrivNaboerOgTid(); // Skriver dens naboer og tid
            } else // Finner ingen match på navn fra bruker:
                cout << "\nNavnet finnes ikke, eller er ikke entydig!\n\n";
    
        } else // Ingen stoppesteder i datastrukturen:
            cout << "\nIngen stopper registrert i datastrukturen!\n";
    }
    
    
    /**
     * Skriver stoppestedenes data til fil
     *
     * @see Stoppested::skrivTilFil(...)
     */
    void Stoppesteder::skrivTilFil() {
        ofstream utfil("Stoppesteder.dt2"); // Åpner fil for skriving:
        cout << "\nSkriver til filen stoppesteder.dt2...\n";
        utfil << stopper.size() << '\n'; // Skriver antall stoppesteder
        for (int i = 0; i < stopper.size(); i++) { // For hvert stoppested:
            stopper[i]->skrivTilFil(utfil); // Stoppestedet skriver seg selv til fil
        }
        utfil.close(); // Lukker fil ved fullført skriving
    }