Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
rute.cpp 22.10 KiB
/**
* Kode-fil for rute-klassen
*
* @file rute.cpp
* @author Sondre Sand & Frederik Simonsen
*/
#include <algorithm> // all_of, sort
#include <iostream>
#include <iomanip>
#include <list>
#include <fstream>
#include "const.h"
#include "rute.h"
#include "stoppested.h"
#include "stoppesteder.h"
#include "LesData3.h"
using namespace std;
extern Stoppesteder gStoppestederBase;
//********STOPP FUNKSJONER*******************
/**
* Oppretter et nytt Stopp ifm. rutefunksjonalitet
*
* @param stoppNr - Stoppens unike nummer
* @param antMin - Minutter fra stoppet rett før på ruten
*/
Stopp::Stopp(const int stoppNr, const int antMin) {
// Kopierer medsendte verdier til å være egne data:
nr = stoppNr; minutter = antMin;
}
/**
* Henter antall minutter fra en stopp til forrige stopp på ruten
*
* @return Antall minutter fra en stopp til forrige stopp
*/
int Stopp::hentMin() {
return minutter;
}
/**
* Henter en stopps unike nr
*
* @return Et stoppesteds unike nr
*/
int Stopp::hentNr() {
return nr;
}
/**
* Skriver ut data om en Stopp til fil
*
* @param ut - Filen det skrives til
*/
void Stopp::skrivTilFil(ofstream & ut) {
ut << nr << ' ' << minutter << '\n';
}
//********RUTE FUNKSJONER*******************
/**
* Default constructor for en Rute, faktiske data leses inn i lesData
*/
Rute::Rute() {
// Gjør ingenting, men må være her så man kan opprette buss/bane
}
/**
* Opretter en ny rute fra fil
*
* @param inn - filen det leses fra
*/
Rute::Rute(ifstream & inn) {
int antStopp,
stoppNr,
antMin;
inn >> antStopp; inn.ignore(); // Leser antall stopp på ruten
for (int i = 0; i < antStopp; i++) { // For hvert stopp:
inn >> stoppNr >> antMin; inn.ignore();
// Oppretter ny stopp på ruten:
stoppene.push_back(new Stopp(stoppNr, antMin));
}
}
/**
* Sjekker om en rute har mer enn en stopp (= gyldig rute)
*
* @return true Hvis ruten er gyldig (>1 stopp)
* @return false Hvis ruten ikke er gyldig (<1 stopp)
*/
bool Rute::erListeGyldig() {
if (stoppene.size() > 1) {
return true;
}
return false;
}
/**
* Går gjennom et medsendt navn fra bruker, sjekker
* alle tegn i strengen er tall eller ei
*
* @param nvn - Mulig stoppestedsnavn eller stoppestedsnr
* @return true Hvis alle tegnene i strengen er tall
* @return false Hvis strengen inneholder tegn som ikke er tall
*/
bool Rute::erTall(std::string nvn) {
return all_of(nvn.begin(), nvn.end(), ::isdigit);
}
/**
* Går gjennom om alle Stopp på en rute for å sjekke om deres
* unike nr matcher en nr som bruker mener finnes på ruten
*
* @param nr - Et stopps nummer som skal forsøkes finnes på ruten
* @return true - Hvis stoppnummeret finnes på ruten
* @return false - Hvis stoppnummeret ikke finnes på ruten
* @see Stopp::hentNr()
*/
bool Rute::finnesStopp(const int nr) {
// For alle stopp på ruten:
for (auto it = stoppene.begin(); it != stoppene.end(); it++) {
if ((*it)->hentNr() == nr) // Ser om eget nr matcher medsendt nr
return true; // Match, returnerer at stoppet finnes på ruten
}
return false; // Ingen match
}
/**
* Funksjon for å sjekke om et klokkeslett er gyldig (00:00-23:59)
*
* @param time - Time i et klokkeslett som skal sjekkes for gyldighet
* @param minutt - Minutter i et klokkeslett som skal sjekkes for gyldighet
* @return true - Hvis klokkeslettet er gyldig
* @return false - Hvis klokkeslettet er ugyldig (utenfor intervall)
*/
bool Rute::gyldigTid(const int time, const int minutt) {
if ((time >= 0 && time <= 23) && (minutt >= 0 && minutt <= 59)) {
return true; // Klokkeslett mellom 00:00 og 23:59
} else
return false; // Klokkeslett utenfor lovlig intervall
}
/**
* Finner antall minutter mellom et faktisk stopp på ruten
* og startstoppestedet på ruten
*
* @param nr - Et stoppesteds unike nummer
* @param retning - Fram eller Tilbake (ulikt startsted) avhengig
* av hvilken vei ruten går
* @return Antall minutter mellom et startsted på ruten og et gitt
* stoppested på ruten
* @see Stopp::hentMin()
* @see Stopp:hentNr()
*/
int Rute::finnDifferanse(const int nr, const Retning retning) {
int totMin = 0;
if (retning == Fram) {
// For hvert stopp på ruten:
for (auto it = stoppene.begin(); it != stoppene.end(); it++) {
totMin += (*it)->hentMin(); // Teller opp antall minutter
if ((*it)->hentNr() == nr) // Hvis egen stopp
return totMin; // Returnerer antall minutter fra start
// til eget stopp
}
} else if (retning == Tilbake) {
// For hvert stopp på ruten, traverserer ruten "baklengs":
for (auto it = stoppene.rbegin(); it != stoppene.rend(); it++) {
if ((*it)->hentNr() == nr) // Hvis egen stopp
return totMin; // Returnerer antall minutter mellom
totMin += (*it)->hentMin(); // Hvis ikke funn, teller opp
// antall minutter
}
}
return -1; // Skal ikke skje
}
/**
* Henter navn på startstasjonen på en rute
*
* @param retning Om ruten er Fram (original) eller Tilbake ("baklengs")
* @return Navnet på startstopp på rute avhengig av retning
* @see Stoppesteder::hentNavnVhaIndeks(...)
* @see Stopp::hentNr()
*/
string Rute::hentNavn(const Retning retning) {
string startSted;
if (retning == Fram) { // Henter navn på første stopp i listen:
startSted = gStoppestederBase.hentNavnVhaIndeks(stoppene.front()->hentNr());
} else if (retning == Tilbake) // Henter navn på bakerste stopp i listen:
startSted = gStoppestederBase.hentNavnVhaIndeks(stoppene.back()->hentNr());
return startSted; // Returnerer navnet på startstopp på ruten
}
/**
* Leser inn og oppretter en rutetabell for et gitt stoppested på en rute
* med utgangspunkt i omregning fra et startsted på ruten
*
* @param diff - differanse mellom startsted og aktuelt stoppested i minutter
* @param start - faktisk startstedsnavn på ruten
* @param stSted - faktisk navn på aktuellt stoppested
* @see Rute::gyldigTid(...)
*/
void Rute::ruteTabell(const int diff, const string start, const string stSted) {
int startT, // starttime
startTotal, // regner ut total starttid i minutter
sluttT, // slutt-time
sluttTotal, // regner ut total slutttid i minutter
startM, // startminutter
sluttM, // slutt-minutter
tidMellom, // Tid mellom hver avgang i minutter
tPrint, // hjelpevariabel for å sørge for korrekt utskrift av time
antGanger, // omregning for å legge inn riktig antall avgangstider
startTid, // omregning for å legge inn starttid
n = -1, // hjelpevariabel for linjeskift ved ny time
timer, // hjelpevariabel for å skrive ut time
minutter, // hjelpevariabel for å skrive ut minutter
avgangsTid, // omregning for å legge inn riktig avgangstid
mPrint; // hjelpevariabel for å sørge for korrekt utskrift av minutter
vector <int> avgangstider; // Hjelpevektor for å ta vare på avgangstider
cout << "\nRuteavganger fra startstedet (" << start << ") - "
<< "avslutt med 0 0):\n\n";
// 23:53 her da det må være minimum 6 min mellom avganger:
cout << "Fra kl. (00:01 - 23:53): ";
cin >> startT >> startM; cin.ignore(); // Leser starttid
startTid = (startT*60)+startM; // Regner ut første avgangstid
// Sørger for at starttid er gyldig, samt ikke senere enn 23:53 (1433)
while (!gyldigTid(startT, startM) || startTid > 1433) {
cout << "\nUlovlig klokkeslett. Prøv igjen (tt mm): ";
cin >> startT >> startM; cin.ignore();
startTid = (startT*60)+startM;
}
while (startT != 0 || startM != 0) { // Så lenge bruker ikke taster 0 0
avgangsTid = startTid+diff;
// Må ha en sjekk her for lang tid mellom stoppesteder, som
// kan føre til at antall minutter blir mer enn 1440 (24:00)
// så man ikke får output med et klokkeslett 25:xx f.eks.
if (avgangsTid < 1440) { // < 24:00
avgangstider.push_back(avgangsTid); // Legger første avgang
// i vector
} else { // Omregning av hva som skal i vector, for spesielle
// tilfeller, unngå 25:xx f.eks.:
avgangstider.push_back(avgangsTid%1440);
}
// Leser tid mellom avganger:
// Ny sjekk her for å sørge for riktig output til bruker
// basert på valgt "fra"-tid. Godtar ikke 6-120 min for
// avganger senere enn 21:59, da vi kun skal lese inn
// for en dag
if (avgangsTid < 1319) { // < 21:59
tidMellom = lesInt("Tid mellom avganger", MINTID, MAXTID);
} else { // Senere klokkeslett enn 21:59, gjør om output til bruker:
tidMellom = lesInt("Tid mellom avganger", MINTID, 1439%startTid);
}
startTotal = (startT*60)+startM+tidMellom; // Omregner for sjekk
tPrint = startTotal/60; // Regner ut gyldig utskrift av t og min:
mPrint = startTotal%60;
cout << "Til kl. (" << ((tPrint < 10) ? "0" : "") << tPrint
<< ':' << ((mPrint < 10) ? "0" : "") << mPrint
<< " - 23:59): ";
// Leser slutt tid
cin >> sluttT >> sluttM; cin.ignore();
sluttTotal = (sluttT*60)+sluttM; // Omregner for sjekk
// Sørger for lovlig slutt-tid
while (!gyldigTid(sluttT, sluttM) || sluttTotal < startTotal) {
cout << "\nUlovlig klokkeslett. Prøv igjen (tt mm): ";
cin >> sluttT >> sluttM; cin.ignore();
sluttTotal = (sluttT*60)+sluttM; // Omregner for sjekk
}
// Omregning for for-loop, antall avganger som skal legges i vector:
antGanger = (((sluttT-startT)*60)+sluttM-startM)/tidMellom;
avgangsTid = startTid+diff; // Setter på differanse en gang
for (int i = 0; i < antGanger; i++) { // For antall avgangstider:
avgangsTid = avgangsTid + tidMellom; // Omregning
if (avgangsTid < 1440) { // < 24:00
avgangstider.push_back(avgangsTid);
} else { // Omregning ved for å unngå 25:xx osv.:
avgangstider.push_back(avgangsTid%1440); // Legges i vektor
}
}
tPrint = (sluttTotal+1)/60; // Regner ut gyldig utskrift av t og min:
mPrint = (sluttTotal+1)%60;
// Hvis slutttid er før 23:53 (siste lovlige avgang mtp. 6 min):
if (sluttTotal < 1433) {
cout << "\n\nFra kl. (" << ((tPrint < 10) ? "0" : "") << tPrint
<< ':' << ((mPrint < 10) ? "0" : "") << mPrint
<< " - 23:53): ";
cin >> startT >> startM; cin.ignore(); // Leser ny starttid
startTotal = (startT*60)+startM; // Omregning
// Sørger for ny lovlig starttid:
while ((!gyldigTid(startT, startM) || startTotal <= sluttTotal)
&& (startT != 0 || startM != 0)) {
cout << "\nUlovlig klokkeslett. Prøv igjen (tt mm): ";
cin >> startT >> startM; cin.ignore();
startTotal = (startT*60)+startM; // Omregning
}
startTid = (startT*60)+startM; // Omregning
} else { // Avslutter innlesning fra bruker hvis slutttid er 23:53
// eller senere (da det må være +1 min minimum til neste
// avgang).
startT = 0; startM = 0; // Sørger for stopp av innlesning
}
}
cout << "\n\nRutetabell for stoppested: " << stSted << "\n\n";
// Sorterer vektoren, slik at man ikke får duplikat utskrift av
// evt. veldig tidlige avganger og sene avganger:
sort(avgangstider.begin(), avgangstider.end());
for (int i = 0; i < avgangstider.size(); i++) { // For hver avgangstid:
timer = avgangstider[i]/60; // Regner ut time
minutter = avgangstider[i]%60; // Regner ut minutter
if (timer == n) { // Skriver ut minutter hvis time er lik indikator
cout << ' ' << ((minutter < 10) ? "0" : "") << minutter;
} else { // Skriver ut time hvis time er mer enn indikator
if (timer < 24) { // Hvis time er mindre enn 24:
cout << '\n' << ((timer < 10) ? "0" : "")
<< timer << ':' << ' ' << ((minutter < 10) ? "0" : "")
<< minutter;
} else { // Hvis time er mer enn 24 (skjer ved stor avstand)
// mellom stoppesteder på en rute, gjør modulo
// slik at det ikke skrives ut 25:xx f.eks.:
cout << '\n' << ((timer%24 < 10) ? "0" : "") << timer%24
<< ": " << ((minutter < 10) ? "0" : "")
<< minutter;
}
n = timer; // Oppdaterer indikator
}
}
}
/**
* Skriver ut til bruker endestasjonene på en rute i begge retninger
*
* @see Stopp::hentNr()
* @see Stoppesteder::hentNavnVhaIndeks(...)
*/
void Rute::skrivRetninger() const {
// Hjelpevariabler for å hente endestasjonsnavnene på ruten:
int startIndeks = stoppene.front()->hentNr(),
stoppIndeks = stoppene.back()->hentNr();
string startStasjon = gStoppestederBase.hentNavnVhaIndeks(startIndeks),
endeStasjon = gStoppestederBase.hentNavnVhaIndeks(stoppIndeks);
// Skriver ut start- og endestasjon for ruten i begge retninger:
cout << "\nFram: Retningen: " << startStasjon << " - "
<< endeStasjon << "\nTilbake: Retningen: "
<< endeStasjon << " - " << startStasjon << '\n';
}
/**
* Skriver ut hele ruten forlengs eller baklengs, med tid mellom
* stopper samt totaltid på ruten
*
* @param retning Fram (forlengs) eller Tilbake (baklengs)
* @see Stoppesteder::hentNavnVhaIndeks(...)
*/
void Rute::skrivRute(const Retning retning) {
int minF = 0,
indeks = 0,
totMin = 0;
string navn;
if (retning == Fram) {
// For hvert stopp på ruten
for (auto it = stoppene.begin(); it != stoppene.end(); it++) {
indeks = (*it)->nr; // Henter eget nr
minF = (*it)->minutter; // Henter antall min til forrige stopp
// Henter eget navn:
navn = gStoppestederBase.hentNavnVhaIndeks(indeks);
totMin += minF; // Oppdaterer totalt antall min på ruten
cout << setw(25) << navn << " - " << setw(2) << minF
<< " min fra forrige (" << setw(3) << totMin
<< " min fra rutestart)\n";
}
}
if (retning == Tilbake) {
// For hvert stopp på ruten, traverserer listen "baklengs":
for (auto it = stoppene.rbegin(); it != stoppene.rend(); it++) {
indeks = (*it)->nr; // Henter eget nr
// Henter eget navn
navn = gStoppestederBase.hentNavnVhaIndeks(indeks);
cout << setw(25) << navn << " - " << setw(2) << minF
<< " min fra forrige (" << setw(3) << totMin
<< " min fra rutestart)\n";
minF = (*it)->minutter; // Henter antall minutter fra forrige stopp
totMin += minF; // Oppdaterer totalt antall minutter på ruten
}
}
}
/**
* Sletter en ugyldig rute (mindre enn et stopp, tømmer listen)
*/
void Rute::slettData(){
stoppene.clear(); // Tømmer listen for stopp
}
/**
* Leser og oppretter stopp for en ny rute, så lenge bruker ønsker
* eller det finnes stopp som ikke allerede eksisterer
* på ruten
*
* @see Stoppesteder::byttBokstaver(...)
* @see Rute::erTall(...)
* @see Stoppesteder::finnesIndeks(...)
* @see Stoppesteder::hentNavnVhaIndeks(...)
* @see Stoppesteder::finnEntydig(...)
* @see Stoppesteder::hentIndeksVhaNavn(...)
* @see Stoppesteder::finnDuplikat(...)
* @see Rute::finnesStopp(...)
* @see Stoppested::finnesNabo(...)
* @see Stoppested::hentNaboIndeks(...)
* @see Stoppested::hentNaboTid(...)
* @see Stoppested::settNaboIndeks(...)
* @see Stoppested::settNaboTid(...)
*/
void Rute::lesData() {
string navn,
fNavn;
int stoppNr = 0,
indeks = 0,
naboIndeks = 0,
tidTilF = 0; // Tid til forrige nabo
Stopp* nyStopp = nullptr; // Peker til nytt stopp på ruten
Stoppested* fStopp = nullptr; // Peker til forrige faktiske stoppested
Stoppested* nStopp = nullptr; // Peker til nåværende faktiske stoppested
cout << "\nStoppested (entydig navn / tall / ENTER for å avslutte): ";
getline(cin, navn);
while (navn.size() > 0) { //Kjør så lenge ikke blank/enter er trykket.
navn = gStoppestederBase.byttBokstaver(navn); // Fjerner æøåÆØÅ
if (erTall(navn)) { // Sjekker om navn kun består av tall
stoppNr = stoi(navn); //Hvis kun tall, gjør om til int
// Hvis tallet som er oppgitt er et faktisk stoppstedsnr:
if (gStoppestederBase.finnesIndeks(stoppNr-1)) {
navn = gStoppestederBase.hentNavnVhaIndeks(stoppNr); // Hent navn
}
}
fNavn = gStoppestederBase.finnEntydig(navn); // Sjekker for entydighet
if (fNavn.size() > 0) { // Hvis entydig navn:
cout << '\n' << fNavn << '\n';
// Henter et stoppesteds faktiske indeks i vector:
indeks = gStoppestederBase.hentIndeksVhaNavn(fNavn);
// Hvis stopp ikke finnes fra før på ruten:
if (!finnesStopp(indeks+1)) {
if (stoppene.size() > 0) { // Hvis ikke første stopp på ruten
// Henter peker til eget stoppested:
nStopp = gStoppestederBase.finnDuplikat(fNavn);
// Hvis nabo finnes fra før:
if (nStopp->finnesNabo(naboIndeks+1)) {
// Henter naboens indeks
naboIndeks = nStopp->hentNaboIndeks(naboIndeks+1);
// Henter tid til naboen:
tidTilF = nStopp->hentNaboTid(naboIndeks);
// Oppretter en ny stopp på ruten:
nyStopp = new Stopp(indeks+1, tidTilF);
stoppene.push_back(nyStopp); // Legges i lista
// Oppdaterer naboindeks for videre bruk:
naboIndeks = indeks;
cout << "\nTiden mellom stoppestedene er allerede"
<< " registrert som "
<< tidTilF << " minutter.\n";
} else { // Hvis nabo ikke finnes fra før:
// Leser tid til forrige nabo:
tidTilF = lesInt("Tid fra forrige stopp", 1, 10);
// Finner egen peker:
nStopp = gStoppestederBase.finnDuplikat(fNavn);
// Oppdaterer forrige stopps nabovektor
fStopp->settNaboIndeks(indeks);
// Oppdaterer forrige stopps tid til nabo
fStopp->settNaboTid(tidTilF);
// Oppdaterer nåværende stopps nabovektor
nStopp->settNaboIndeks(naboIndeks);
// Oppdaterer naværende stopps tid til nabo
nStopp->settNaboTid(tidTilF);
// Oppretter ny stopp på ruten:
nyStopp = new Stopp(indeks+1, tidTilF);
// Stoppen legges til ruten:
stoppene.push_back(nyStopp);
// Oppdaterer naboindeks for videre bruk:
naboIndeks = indeks;
}
} else { // Hvis første stopp på ruten:
// Henter peker til eget stoppested:
nStopp = gStoppestederBase.finnDuplikat(fNavn);
nyStopp = new Stopp(indeks+1, 0); // Setter stopp sitt nr
// til å korrespondere med indeks i vector, og tid til
// forrige nabo å være 0, da første stopp på ruten
stoppene.push_back(nyStopp); // Legges til ruten
// Oppdaterer naboindeks for videre bruk
naboIndeks = indeks;
}
// Setter peker til forrige stopp til å peke på riktig
// stoppested for videre bruk:
fStopp = nStopp;
} else // Stoppet finnes allerede på ruten:
cout << "\nStoppet er allerede registrert på ruten!\n";
} else { // Hvis ikke entydig:
cout << "\nIkke funnet (den entydige) stoppestedet!\n";
}
// Forsøker å lese evt. ny eller korrekt stopp:
cout << "\nStoppested (entydig navn / tall / ENTER for å avslutte): ";
getline(cin, navn);
} // Ved enter på første navn/tall for early "uthopp":
cout << "\nOk, du angrer og ønsker ikke å legge til ny rute.\n";
}
/**
* Skriver hele ruten begge veier (forlengs) og (baklengs)
* ifm. menyvalg R B
*
* @see Rute::skrivRute(...)
*/
void Rute::skrivBeskrivelse() {
cout << "Ruten:\n";
skrivRute(Fram);
cout << "\n\n";
skrivRute(Tilbake);
}
/**
* Skriver ut en rutes startstoppested og sluttstoppested
*
* @see Stopp::hentNr()
* @see Stoppesteder::hentNavnVhaIndeks(...)
*/
void Rute::skrivData() const {
int startIndeks,
stoppIndeks;
string startNavn,
stoppNavn;
startIndeks = stoppene.front()->hentNr(); // Henter startsteds unike nr
stoppIndeks = stoppene.back()->hentNr(); // Henter stopsteds unike nr
startNavn = gStoppestederBase.hentNavnVhaIndeks(startIndeks);
stoppNavn = gStoppestederBase.hentNavnVhaIndeks(stoppIndeks);
cout << startNavn << " - " << stoppNavn;
}
/**
* Skriver ut kort informasjon om en rute (virtuell)
*/
void Rute::skrivKort() const {
// Gjør ingenting, må være her så Buss og Bane kan bruke
// sin skrivKort funksjon
}
/**
* Skriver ut en rute til fil
*
* @param ut fila det skrives til
* @see Stopp::skrivTilFil(...)
*/
void Rute::skrivTilFil(ofstream & ut) {
ut << stoppene.size() << '\n'; // Skriver ut antall stopp på ruta
// For hver stopp:
for (auto it = stoppene.begin(); it != stoppene.end(); it++)
(*it)->skrivTilFil(ut); // Stopp skriver seg selv til fil
}