Skip to main content
combined strings
Source Link
Edward
  • 67.2k
  • 4
  • 120
  • 284
#include "Universe.hpp"

int main()
{
    Universe Uno("Uno");
    Uno.readCSV("Galaxy.txt");

    bool exit = false;
    while (!exit)
    {
        std::cout << "Welcome to the Galaxy Management Unit (GMU)." << '\n'
            <<\n\n" '\n'
            << "0. Print." << '\n'
            << '\n'\n\n"
            << "1. Sort X." << '\n'\n"
            << "2. Sort Y." << '\n'\n"
            << "3. Sort Z." << '\n'
            << '\n'\n\n"
            << "4. Sort Mlvl." << '\n'\n"
            << "5. Sort Clvl." << '\n'\n"
            << "6. Sort Dlvl." << '\n'\n"
            << "7. Sort Plvl." << '\n'
            << '\n'\n\n"
            << "999. Exit." << '\n'
            << '\n'\n\n"
            << "Choice: "
            ;
        int choice;
        std::cin >> choice;
        switch (choice)
        {
        case 0:
            std::cout << Uno << std::endl;
            std::cin.sync();
            std::cin.clear();
            std::cin.get();
            break;
        case 1:
            Uno.sort(Planet::X);
            break;
        case 2:
            Uno.sort(Planet::Y);
            break;
        case 3:
            Uno.sort(Planet::Z);
            break;
        case 4:
            Uno.sort(Planet::MLVL);
            break;
        case 5:
            Uno.sort(Planet::CLVL);
            break;
        case 6:
            Uno.sort(Planet::DLVL);
            break;
        case 7:
            Uno.sort(Planet::PLVL);
            break;
        case 999:
            exit = true;
            break;
        default:
            break;
        }
    }
}
  1. Don't hardcode the file name
  2. Delegate I/O to the object being read
  3. Use C++11 range-for to simplify printing a collection
  4. Use const where practical
  5. Combine strings into a single one where practical
#include "Universe.hpp"

int main()
{
    Universe Uno("Uno");
    Uno.readCSV("Galaxy.txt");

    bool exit = false;
    while (!exit)
    {
        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:
            std::cout << Uno << std::endl;
            std::cin.sync();
            std::cin.clear();
            std::cin.get();
            break;
        case 1:
            Uno.sort(Planet::X);
            break;
        case 2:
            Uno.sort(Planet::Y);
            break;
        case 3:
            Uno.sort(Planet::Z);
            break;
        case 4:
            Uno.sort(Planet::MLVL);
            break;
        case 5:
            Uno.sort(Planet::CLVL);
            break;
        case 6:
            Uno.sort(Planet::DLVL);
            break;
        case 7:
            Uno.sort(Planet::PLVL);
            break;
        case 999:
            exit = true;
            break;
        default:
            break;
        }
    }
}
  1. Don't hardcode the file name
  2. Delegate I/O to the object being read
  3. Use C++11 range-for to simplify printing a collection
  4. Use const where practical
#include "Universe.hpp"

int main()
{
    Universe Uno("Uno");
    Uno.readCSV("Galaxy.txt");

    bool exit = false;
    while (!exit)
    {
        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:
            std::cout << Uno << std::endl;
            std::cin.sync();
            std::cin.clear();
            std::cin.get();
            break;
        case 1:
            Uno.sort(Planet::X);
            break;
        case 2:
            Uno.sort(Planet::Y);
            break;
        case 3:
            Uno.sort(Planet::Z);
            break;
        case 4:
            Uno.sort(Planet::MLVL);
            break;
        case 5:
            Uno.sort(Planet::CLVL);
            break;
        case 6:
            Uno.sort(Planet::DLVL);
            break;
        case 7:
            Uno.sort(Planet::PLVL);
            break;
        case 999:
            exit = true;
            break;
        default:
            break;
        }
    }
}
  1. Don't hardcode the file name
  2. Delegate I/O to the object being read
  3. Use C++11 range-for to simplify printing a collection
  4. Use const where practical
  5. Combine strings into a single one where practical
added more thorough review
Source Link
Edward
  • 67.2k
  • 4
  • 120
  • 284

A few more thoughts

Rather than doing all of that complicated I/O I'd suggest using the standard stream extractors and inserters. When you do so, the code shrinks considerably:

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>

class Planet
{
public:
    Planet() : x(0), y(0), z(0), Mlvl(0), Clvl(0), Dlvl(0), Plvl(0), Mstor(0), Cstor(0), Dstor(0) {}
    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) {}

    int getMlvl() const { return Mlvl; }
    int getClvl() const { return Clvl; }
    int getDlvl() const { return Dlvl; }
    enum sortby { X, Y, Z, MLVL, CLVL, DLVL, PLVL };
    static bool (*sorter(sortby field))(const Planet &a, const Planet &b) {
        switch (field) {
            case Y:
                return byY;
                break;
            case Z:
                return byZ;
                break;
            case MLVL:
                return byMLVL;
                break;
            case CLVL:
                return byCLVL;
                break;
            case DLVL:
                return byDLVL;
                break;
            case PLVL:
                return byPLVL;
                break;
            default:
                return byX;
        } 
    }
    friend std::istream &operator>>(std::istream &in, Planet &planet) {
        Planet p;
        char ch[9];
        int i=0;
        in  >> p.x >> ch[i++];
        in  >> p.y >> ch[i++];
        in  >> p.z >> ch[i++];
        in  >> p.Mlvl >> ch[i++];
        in  >> p.Clvl >> ch[i++];
        in  >> p.Dlvl >> ch[i++];
        in  >> p.Plvl >> ch[i++];
        in  >> p.Mstor >> ch[i++];
        in  >> p.Cstor >> ch[i++];
        in  >> p.Dstor >> ch[i++];
        if (!in) 
            return in;
        for (i=0; i < 2; ++i)
            if (ch[i] != ':') 
                in.setstate(std::ios_base::failbit);
        for (  ; i < 9; ++i)
            if (ch[i] != ';')
                in.setstate(std::ios_base::failbit);
        if (in) 
            std::swap(p, planet);
        return in;
    }
    friend std::ostream &operator<<(std::ostream &out, const Planet &p)
    {
        return out 
            << p.x << ':'
            << p.y << ':'
            << p.z << ' '
            << p.Mlvl << ' '
            << p.Clvl << ' '
            << p.Dlvl << ' '
            << p.Plvl << ' '
            << p.Mstor << ' '
            << p.Cstor << ' '
            << p.Dstor
            << '\n';
    }
    static bool byX(const Planet &a, const Planet &b) { return a.x < b.x; };
    static bool byY(const Planet &a, const Planet &b) { return a.y < b.y; };
    static bool byZ(const Planet &a, const Planet &b) { return a.z < b.z; };
    static bool byMLVL(const Planet &a, const Planet &b) { return a.Mlvl < b.Mlvl; };
    static bool byCLVL(const Planet &a, const Planet &b) { return a.Clvl < b.Clvl; };
    static bool byDLVL(const Planet &a, const Planet &b) { return a.Dlvl < b.Dlvl; };
    static bool byPLVL(const Planet &a, const Planet &b) { return a.Plvl < b.Plvl; };
private:
    int x;
    int y;
    int z;
    int Mlvl;
    int Clvl;
    int Dlvl;
    int Plvl;
    int Mstor;
    int Cstor;
    int Dstor;
};

class Universe
{
public:
    Universe(std::string sName) : sName(sName) {}
    void readCSV(const std::string &filename)
    {
        std::ifstream input(filename, std::ios::in);
        Planet p;
        while (input >> p) {
            vPlanet.push_back(p);
        }
    }

    friend std::ostream &operator<<(std::ostream &out, const Universe &u)
    {
        out << '\n';
        for (const auto &p : u.vPlanet)
            out << p;
        return out;
    }
    void sort(Planet::sortby field) {
        std::sort(vPlanet.begin(), vPlanet.end(), Planet::sorter(field));
    }
private:
    std::string sName;
    std::vector<Planet> vPlanet;
};
#endif

Here is the revised Main to go with it:

Main.cpp

#include "Universe.hpp"

int main()
{
    Universe Uno("Uno");
    Uno.readCSV("Galaxy.txt");

    bool exit = false;
    while (!exit)
    {
        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:
            std::cout << Uno << std::endl;
            std::cin.sync();
            std::cin.clear();
            std::cin.get();
            break;
        case 1:
            Uno.sort(Planet::X);
            break;
        case 2:
            Uno.sort(Planet::Y);
            break;
        case 3:
            Uno.sort(Planet::Z);
            break;
        case 4:
            Uno.sort(Planet::MLVL);
            break;
        case 5:
            Uno.sort(Planet::CLVL);
            break;
        case 6:
            Uno.sort(Planet::DLVL);
            break;
        case 7:
            Uno.sort(Planet::PLVL);
            break;
        case 999:
            exit = true;
            break;
        default:
            break;
        }
    }
}

Among the many changes made to the code:

  1. Don't hardcode the file name
  2. Delegate I/O to the object being read
  3. Use C++11 range-for to simplify printing a collection
  4. Use const where practical

A few more thoughts

Rather than doing all of that complicated I/O I'd suggest using the standard stream extractors and inserters. When you do so, the code shrinks considerably:

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>

class Planet
{
public:
    Planet() : x(0), y(0), z(0), Mlvl(0), Clvl(0), Dlvl(0), Plvl(0), Mstor(0), Cstor(0), Dstor(0) {}
    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) {}

    int getMlvl() const { return Mlvl; }
    int getClvl() const { return Clvl; }
    int getDlvl() const { return Dlvl; }
    enum sortby { X, Y, Z, MLVL, CLVL, DLVL, PLVL };
    static bool (*sorter(sortby field))(const Planet &a, const Planet &b) {
        switch (field) {
            case Y:
                return byY;
                break;
            case Z:
                return byZ;
                break;
            case MLVL:
                return byMLVL;
                break;
            case CLVL:
                return byCLVL;
                break;
            case DLVL:
                return byDLVL;
                break;
            case PLVL:
                return byPLVL;
                break;
            default:
                return byX;
        } 
    }
    friend std::istream &operator>>(std::istream &in, Planet &planet) {
        Planet p;
        char ch[9];
        int i=0;
        in  >> p.x >> ch[i++];
        in  >> p.y >> ch[i++];
        in  >> p.z >> ch[i++];
        in  >> p.Mlvl >> ch[i++];
        in  >> p.Clvl >> ch[i++];
        in  >> p.Dlvl >> ch[i++];
        in  >> p.Plvl >> ch[i++];
        in  >> p.Mstor >> ch[i++];
        in  >> p.Cstor >> ch[i++];
        in  >> p.Dstor >> ch[i++];
        if (!in) 
            return in;
        for (i=0; i < 2; ++i)
            if (ch[i] != ':') 
                in.setstate(std::ios_base::failbit);
        for (  ; i < 9; ++i)
            if (ch[i] != ';')
                in.setstate(std::ios_base::failbit);
        if (in) 
            std::swap(p, planet);
        return in;
    }
    friend std::ostream &operator<<(std::ostream &out, const Planet &p)
    {
        return out 
            << p.x << ':'
            << p.y << ':'
            << p.z << ' '
            << p.Mlvl << ' '
            << p.Clvl << ' '
            << p.Dlvl << ' '
            << p.Plvl << ' '
            << p.Mstor << ' '
            << p.Cstor << ' '
            << p.Dstor
            << '\n';
    }
    static bool byX(const Planet &a, const Planet &b) { return a.x < b.x; };
    static bool byY(const Planet &a, const Planet &b) { return a.y < b.y; };
    static bool byZ(const Planet &a, const Planet &b) { return a.z < b.z; };
    static bool byMLVL(const Planet &a, const Planet &b) { return a.Mlvl < b.Mlvl; };
    static bool byCLVL(const Planet &a, const Planet &b) { return a.Clvl < b.Clvl; };
    static bool byDLVL(const Planet &a, const Planet &b) { return a.Dlvl < b.Dlvl; };
    static bool byPLVL(const Planet &a, const Planet &b) { return a.Plvl < b.Plvl; };
private:
    int x;
    int y;
    int z;
    int Mlvl;
    int Clvl;
    int Dlvl;
    int Plvl;
    int Mstor;
    int Cstor;
    int Dstor;
};

class Universe
{
public:
    Universe(std::string sName) : sName(sName) {}
    void readCSV(const std::string &filename)
    {
        std::ifstream input(filename, std::ios::in);
        Planet p;
        while (input >> p) {
            vPlanet.push_back(p);
        }
    }

    friend std::ostream &operator<<(std::ostream &out, const Universe &u)
    {
        out << '\n';
        for (const auto &p : u.vPlanet)
            out << p;
        return out;
    }
    void sort(Planet::sortby field) {
        std::sort(vPlanet.begin(), vPlanet.end(), Planet::sorter(field));
    }
private:
    std::string sName;
    std::vector<Planet> vPlanet;
};
#endif

Here is the revised Main to go with it:

Main.cpp

#include "Universe.hpp"

int main()
{
    Universe Uno("Uno");
    Uno.readCSV("Galaxy.txt");

    bool exit = false;
    while (!exit)
    {
        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:
            std::cout << Uno << std::endl;
            std::cin.sync();
            std::cin.clear();
            std::cin.get();
            break;
        case 1:
            Uno.sort(Planet::X);
            break;
        case 2:
            Uno.sort(Planet::Y);
            break;
        case 3:
            Uno.sort(Planet::Z);
            break;
        case 4:
            Uno.sort(Planet::MLVL);
            break;
        case 5:
            Uno.sort(Planet::CLVL);
            break;
        case 6:
            Uno.sort(Planet::DLVL);
            break;
        case 7:
            Uno.sort(Planet::PLVL);
            break;
        case 999:
            exit = true;
            break;
        default:
            break;
        }
    }
}

Among the many changes made to the code:

  1. Don't hardcode the file name
  2. Delegate I/O to the object being read
  3. Use C++11 range-for to simplify printing a collection
  4. Use const where practical
Source Link
Edward
  • 67.2k
  • 4
  • 120
  • 284

This is not a complete review, but rather an elaboration on a single point already made. Having multiple ways of sorting things is not a bad idea, but there are better ways of doing it. Here are three different ways to do that which, I think, are successively better.

Use a lambda

As @glampert already said, your sort routines would be better expressed as a lambda:

void Universe::sort_x() { 
    std::sort(vPlanet.begin(), vPlanet.end(), 
        [](const Planet &a, const Planet &b){ 
            return a.x < b.x; 
        }); 
}

However, it's a bit messy to have to write that out for each member variable of Planet, so that leads to the next way to do it:

Use a macro

#define sort_on(x) sort_##x() { std::sort(vPlanet.begin(), vPlanet.end(), [](const Planet &a, const Planet &b){ return a.x < b.x; }); }

void Universe::sort_on(x)
void Universe::sort_on(y)
void Universe::sort_on(z)
void Universe::sort_on(Mlvl)
void Universe::sort_on(Dlvl)
void Universe::sort_on(Plvl)
void Universe::sort_on(Clvl)

Now all of the member functions are defined but it's still somewhat readable. It's still a bit unfortunate, though because it means Universe has to have intimate knowledge of and access to internal members of Planet. This is generally a red flag telling you that there may be something wrong with the class design.

Implement comparisons in the Planet class

You could have the comparison implementations as static members of the Planet class.

static bool byX(const Planet &a, const Planet &b) { return a.x < b.x; };
// etc.

Then you could have an enum within Planet:

enum sortby { X, Y, Z, MLVL, CLVL, DLVL, PLVL };

Then have a function which takes this enum as an argument and returns the appropriate function pointer.

static bool (*sorter(sortby field))(const Planet &a, const Planet &b) {
    switch (field) {
        case Y:
            return byY;
            break;
        case Z:
            return byZ;
            break;
        // all of the other cases
        default:
            return byX;
    } 
}

Then instead of having multiple sort functions in Universe, you would just have one:

void Universe::sort(Planet::sortby field) {
    std::sort(vPlanet.begin(), vPlanet.end(), 
            Planet::sorter(field));
}