Select Git revision
stoppesteder.cpp
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
}