I recently started re-factoring a project I hadn't touched in many months.
The original purpose was to be an inventory management system for a game I played, Ogame. In this game you play inside a universe filled with galaxies, which are filled with systems, which are filled with planets. Those planets have a coordinate consisting of three parts (galaxy, system, location in system). The usual sizes are 9 galaxies, 499 systems and 15 planets per system, which allows for 67365 planets.
I wrote a pseudo-CSV reader (the first two seperators are :
instead of ;
because that's what's used in-game as well) which can sort planets based on coordinates or properties. The properties of relevance are 3 mining facilities and the Solar (Power) plant.
Note negative values shouldn't exist. Although I feel it's the user's responsibility not to input those, I'm not checking for it either. This is by design, but may be a bad practice.
The brief UI is also by design. I think it's intuitive enough (especially since I'm currently the only user), but if it's possible to achieve the same result with more elegance I'm all for it.
CSV (Galaxy.txt):
1:2:12;20;18;15;0;7;6;4;
1:5:12;20;18;11;0;6;5;3;
1:9:4;10;7;6;0;1;0;0;
1:9:8;17;14;8;0;3;2;1;
1:9:9;18;16;7;0;4;3;2;
1:10:5;9;6;2;0;2;1;0;
1:10:12;2;2;2;0;1;0;0;
1:11:11;19;16;10;0;5;3;1;
1:11:12;23;20;16;0;7;6;5;
1:12:4;2;2;2;0;0;1;0;
1:14:5;4;2;1;0;1;0;0;
1:15:5;20;18;10;0;5;3;1;
1:16:5;18;16;9;0;5;4;4;
1:20:7;24;21;6;0;8;7;2;
1:20:8;22;20;14;0;9;7;5;
1:20:9;23;22;13;0;8;7;4;
1:21:6;11;12;11;0;6;4;3;
1:21:7;23;20;13;0;7;6;3;
1:22:7;14;13;9;0;3;2;2;
1:25:6;19;18;12;0;7;6;3;
1:25:11;16;15;4;0;6;5;3;
1:27:12;12;11;8;0;6;4;2;
1:32:6;19;17;13;0;6;5;3;
1:38:7;22;21;12;0;8;7;6;
1:38:10;18;14;13;0;7;5;4;
1:39:5;18;15;10;0;6;5;4;
1:39:12;20;18;12;0;7;6;4;
1:40:6;9;8;7;0;3;2;2;
1:42:7;19;18;15;6;6;5;4;
1:43:11;19;19;14;5;7;7;7;
1:43:12;19;19;14;5;7;7;7;
1:45:4;20;18;16;0;8;7;7;
1:45:5;20;17;16;0;7;6;5;
1:45:9;15;15;12;0;5;5;4;
1:45:13;15;15;15;0;5;5;4;
1:46:12;11;11;3;0;2;2;1;
1:56:8;22;18;12;0;7;6;5;
1:59:6;23;21;21;0;8;7;6;
1:61:7;17;16;17;5;2;1;2;
1:62:4;14;13;13;0;4;4;2;
1:62:10;3;2;0;0;0;0;0;
1:63:5;10;8;4;0;4;3;2;
1:64:3;5;2;1;0;2;2;0;
1:64:4;21;15;12;0;8;6;3;
1:64:8;9;9;6;0;3;2;2;
1:65:5;14;9;4;0;5;3;1;
1:65:8;23;20;17;7;8;7;7;
1:65:9;23;21;16;7;8;7;7;
1:65:10;13;16;14;0;5;5;6;
1:65:11;24;22;16;7;9;7;7;
1:67:4;17;16;10;0;5;5;3;
1:67:5;17;16;9;0;5;5;2;
1:152:7;16;14;12;0;5;5;4;
1:153:6;23;22;17;0;8;7;9;
1:154:8;23;20;18;0;6;6;3;
1:292:8;24;19;11;0;7;6;3;
2:157:6;24;20;20;6;9;6;6;
2:157:7;23;20;20;6;8;6;6;
2:157:12;10;7;2;0;1;1;0;
I think I got the Single Responsibility Principle right on most things, although there are still a couple of large functions.
The naming isn't too bad, but could probably be better.
There is much repetition in the sorting functions, which is bad.
The maintainability-factor of this code is quite bad.
I tried to keep an overview at the start of
Main.cpp
with available classes and functions. It feels obsolete since the maintainability versus profit doesn't seem worth it.I'm probably copying too much data. There are probably optimizations to be gained in how I pass variables around. I suspect I'm not using enough pointers.
Main.cpp
#ifndef MAIN_CPP
#define MAIN_CPP
/*
Project : Universe
By : Mast
Date : August '14
structUniverse
--------
sName : std::string
vPlanet : std::vector<Planet> vPlanet;
vsSanitizeData(std::vector<std::string>) : std::vector<std::string>
sort_x(); : void
sort_y(); : void
sort_z(); : void
sort_Mlvl(); : void
sort_Clvl(); : void
sort_Dlvl(); : void
sort_Plvl(); : void
readCSV(); : void
addPlanet(Planet); : void
splitString(std::string); : int
getUniverse(); : void
printUniverse(); : void
structPlanet
--------
x : int
y : int
z : int
Mlvl : int
Clvl; : int
Dlvl; : int
Plvl; : int
Mstor; : int
Cstor; : int
Dstor; : int
getPlanet(); : int
printPlanet(); : void
getMlvl(); : int
getClvl(); : int
getDlvl(); : int
*/
#include "Universe.hpp"
struct Planet;
struct Universe;
int main()
{
Universe Uno("Uno");
Uno.readCSV();
bool exit = false;
while (!exit)
{
system("cls");
std::cout << "Welcome to the Galaxy Management Unit (GMU)." << '\n'
<< '\n'
<< "0. Print." << '\n'
<< '\n'
<< "1. Sort X." << '\n'
<< "2. Sort Y." << '\n'
<< "3. Sort Z." << '\n'
<< '\n'
<< "4. Sort Mlvl." << '\n'
<< "5. Sort Clvl." << '\n'
<< "6. Sort Dlvl." << '\n'
<< "7. Sort Plvl." << '\n'
<< '\n'
<< "999. Exit." << '\n'
<< '\n'
<< "Choice: "
;
int choice;
std::cin >> choice;
switch (choice)
{
case 0:
Uno.printUniverse();
std::cin.sync();
std::cin.clear();
std::cin.get();
break;
case 1:
Uno.sort_x();
break;
case 2:
Uno.sort_y();
break;
case 3:
Uno.sort_z();
break;
case 4:
Uno.sort_Mlvl();
break;
case 5:
Uno.sort_Clvl();
break;
case 6:
Uno.sort_Dlvl();
break;
case 7:
Uno.sort_Plvl();
break;
case 999:
exit = true;
break;
default:
break;
}
}
}
#endif
Universe.hpp
#ifndef UNIVERSE_HPP
#define UNIVERSE_HPP
/*
Project : Universe
By : Mast
Date : August '14
*/
#include <algorithm>
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
struct Planet
{
int x;
int y;
int z;
int Mlvl;
int Clvl;
int Dlvl;
int Plvl;
int Mstor;
int Cstor;
int Dstor;
Planet(int x, int y, int z, int Mlvl, int Clvl, int Dlvl, int Plvl, int Mstor, int Cstor, int Dstor) : x(x), y(y), z(z), Mlvl(Mlvl), Clvl(Clvl), Dlvl(Dlvl), Plvl(Plvl), Mstor(Mstor), Cstor(Cstor), Dstor(Dstor) {}
~Planet(){};
int getPlanet();
void printPlanet();
int getMlvl();
int getClvl();
int getDlvl();
};
int Planet::getPlanet()
{
return x, y, z, Mlvl, Clvl, Dlvl, Plvl, Mstor, Cstor, Dstor;
}
void Planet::printPlanet()
{
std::cout << x << ':'
<< y << ':'
<< z << ' '
<< Mlvl << ' '
<< Clvl << ' '
<< Dlvl << ' '
<< Plvl << ' '
<< Mstor << ' '
<< Cstor << ' '
<< Dstor
<< '\n';
}
int Planet::getMlvl()
{
return Mlvl;
}
int Planet::getClvl()
{
return Clvl;
}
int Planet::getDlvl()
{
return Dlvl;
}
struct Universe
{
std::string sName;
std::vector<Planet> vPlanet;
Universe(std::string sName) : sName(sName) {}
~Universe(){};
std::vector<std::string> vsSanitizeData(std::vector<std::string>);
void sort_x();
void sort_y();
void sort_z();
void sort_Mlvl();
void sort_Clvl();
void sort_Dlvl();
void sort_Plvl();
void readCSV();
void addPlanet(Planet);
int splitString(std::string);
void getUniverse();
void printUniverse();
};
struct compare_x
{
inline bool operator() (const Planet& left, const Planet& right)
{
return (left.x < right.x);
}
};
struct compare_y
{
inline bool operator() (const Planet& left, const Planet& right)
{
return (left.y < right.y);
}
};
struct compare_z
{
inline bool operator() (const Planet& left, const Planet& right)
{
return (left.z < right.z);
}
};
struct compare_Mlvl
{
inline bool operator() (const Planet& left, const Planet& right)
{
return (left.Mlvl < right.Mlvl);
}
};
struct compare_Clvl
{
inline bool operator() (const Planet& left, const Planet& right)
{
return (left.Clvl < right.Clvl);
}
};
struct compare_Dlvl
{
inline bool operator() (const Planet& left, const Planet& right)
{
return (left.Dlvl < right.Dlvl);
}
};
struct compare_Plvl
{
inline bool operator() (const Planet& left, const Planet& right)
{
return (left.Plvl < right.Plvl);
}
};
void Universe::sort_x()
{
std::sort(vPlanet.begin(), vPlanet.end(), compare_x());
}
void Universe::sort_y()
{
std::sort(vPlanet.begin(), vPlanet.end(), compare_y());
}
void Universe::sort_z()
{
std::sort(vPlanet.begin(), vPlanet.end(), compare_z());
}
void Universe::sort_Mlvl()
{
std::sort(vPlanet.begin(), vPlanet.end(), compare_Mlvl());
}
void Universe::sort_Clvl()
{
std::sort(vPlanet.begin(), vPlanet.end(), compare_Clvl());
}
void Universe::sort_Dlvl()
{
std::sort(vPlanet.begin(), vPlanet.end(), compare_Dlvl());
}
void Universe::sort_Plvl()
{
std::sort(vPlanet.begin(), vPlanet.end(), compare_Plvl());
}
std::vector<std::string> Universe::vsSanitizeData(std::vector<std::string> Vec)
{
std::vector<std::string>::iterator vI = Vec.begin();
while (vI != Vec.end())
{
if (*vI == "")
{
vI = Vec.erase(vI);
}
else
{
vI++;
}
}
return Vec;
};
void Universe::readCSV()
{
std::ifstream input("Galaxy.txt", std::ios::in);
std::string sRead;
std::vector<std::string> sData;
std::vector<std::string>::iterator itData;
while (input.good())
{
getline(input, sRead);
sData.push_back(sRead);
}
sData = vsSanitizeData(sData);
for (itData = sData.begin(); itData != sData.end(); itData++)
{
splitString(*itData);
std::cout << '\n';
}
}
void Universe::addPlanet(Planet p)
{
vPlanet.push_back(p);
}
void Universe::getUniverse()
{
for (unsigned i = 0; i < vPlanet.size(); i++)
{
vPlanet[i].getPlanet();
}
}
void Universe::printUniverse()
{
std::cout << '\n';
for (unsigned i = 0; i < vPlanet.size(); i++)
{
vPlanet[i].printPlanet();
}
}
int Universe::splitString(std::string sSplitInp)
{
char primaryLimiter = ';';
char secondLimiter = ':';
std::string sTemp;
std::vector<int> vTemp;
for (size_t p = 0, q = 0; p != sSplitInp.npos; p = q)
{
sTemp = sSplitInp.substr(p + (p != 0), (q = sSplitInp.find(primaryLimiter, p + 1)) - p - (p != 0));
std::cout << sTemp << ' ';
if (p == 0)
{
std::string sNew;
size_t j = 0, k = 0;
for (unsigned i = 0; i <= 2; i++)
{
sNew = sTemp.substr(j + (j != 0), (k = sTemp.find(secondLimiter, j + 1)) - j - (j != 0));
vTemp.push_back(atoi(sNew.c_str()));
j = k;
}
}
else
{
vTemp.push_back(atoi(sTemp.c_str()));
}
}
addPlanet(Planet(vTemp[0], vTemp[1], vTemp[2], vTemp[3], vTemp[4], vTemp[5], vTemp[6], vTemp[7], vTemp[8], vTemp[9])); // ugly
return 0;
}
#endif