@infinity100: Możesz wykonać to na podstawie drzewa. To moja propozycja do rozwiązania. Zadanie można wykonać na wiele sposobów.
To co napisałem jest na szybko i niechlujnie więc możliwe są błędy, jednak po skompilowaniu i sprawdzeniu działa i robi co trzeba.
Najpierw trzeba utworzyć jakąś strukturę na przykład taką:
struct conversion{
double value;
std::string conv;
};
Następnie na podstawie tej struktury oraz mapy tworzysz drzewo zależności jednostek:
static const std::map<std::string,conversion> Conversions{
{"cm", {1.0, ""}},
{"cal", {2.54, "cm"}},
{"m", {100.0, "cm"}},
{"st", {12.0, "cal"}},
{"km", {1000.0,"m"}}
};
Potem jakieś algorytmy do tworzenia trasy poprzez to drzewo. Starasz się znaleźć trasę przez drzewo aby uzyskać odpowiednią translację.
*Jeśli wyobrazisz sobie strukturę drzewa to konwersja jednostek większych na mniejsze nie powinna mieć rozgałęzień dla tego podanego algorytmu.
Za pomocą tej funkcji poruszasz się po drzewie w przód(st->cal->cm) - ścieżki bez rozgałęzień. Po każdym ruchu w przód następuje sprawdzenie ścieżki "w tył".
bool findTrace(std::vector<std::pair<bool,conversion>> &trace,std::string source,std::string destination){
std::string src = source;
while(src != destination){
if(Conversions.find(src) == Conversions.end())
return false;
if(findTraceBack(trace,src,destination))
break;
trace.push_back(std::pair<bool,conversion>(false,Conversions.at(src)));
src = Conversions.at(src).conv;
}
return true;
}
Poszukiwanie do tyłu (cm->m lub cm->cal->st) - tutaj jest sprawdzenie wszystkich "gałęzi" drzewa i zwrócenie pierwszej poprawnej jeśli istnieje:
bool findTraceBack(std::vector<std::pair<bool,conversion>> &trace,std::string source,std::string destination){
if(source == destination)
return true;
for(const std::pair<std::string,conversion> &conv : Conversions)
if(source == conv.second.conv)
if(findTraceBack(trace,conv.first,destination)){
trace.push_back(std::pair<bool,conversion>(true,conv.second));
return true;
}
return false;
}
Potem gdy wyznaczysz trasę możesz już obliczyć wartość, ogólnie funkcja mnoży lub dzieli w zależności czy "przechodziła do przodu czy do tyłu".
double calc(double value,std::vector<std::pair<bool,conversion>> &trace){
for(std::pair<bool,conversion> &conv : trace){
if(!conv.first){value *= conv.second.value;}
else{value /= conv.second.value;}
}
return value;
}
Sama funkcja pojedynczej konwersji może wyglądać tak:
//Wywołanie: przykład convert(3.0,"cm","st");
conversion convert(double value,std::string source,std::string destination){
std::vector<std::pair<bool,conversion>> trace;
if(findTrace(trace,source,destination)){
return conversion{calc(value,trace),destination};
}
return conversion{0,""};
}
Nie wiem na ile to co napisałem jest zrozumiałe.
Algorytm można wymienić, możliwe jest też jego skompresowanie, ale nie będę się z tym bawił.
Funkcję calc można podmienić, do struktury można dodać pole functional z obliczaniem (konwersji np dla temperatury), więc jest troszkę elastycznie.