-1

essentially i have a function that writes a score to a text file, however i'm not sure how to write to a respective line in the text file based on the score so it writes to the bottom of the file on the next available line, and i also want a function to print the top 10 scores, however since that file is not sorted by score ( if there's an easy way to do that instead an answer for that is welcome ) my idea was to read all the lines in the file and put them into an array of strings, and then sort the array based on the numbers inside the array.

for example, the text file has the format of SCORE then NAME, here is an example of the file

1548 Bob Jones
604 James Jones
5516 Example Name
24 Bad Score ikr

to print this to the file i get input for the name from user, then i output to file with

HighScore << totalScore << "  " << Name << std::endl;

i would like to be able to print the top 10 scores and the respective names of the player to the console, so the output would look something like this in the console

1) 5516 Example Name
2) 1548 Bob Jones
3) 604 James Jones
4) 24 Bad Score ikr

since my idea was to use arrays of strings, i still dont know how to sort it by the initial score numbers in the string, if there is a better solution to printing out the top 10 scores from a file then please let me know! thankyou

m e m e
  • 105
  • 2
  • 11
  • 1
    Your approach seems legit, just do it. When you have an actual problem (not just the description of your homework), you can ask here. Make sure you take smaller steps though, solve different things separately. – Ulrich Eckhardt Jan 03 '20 at 22:57
  • my point was that i dont know how to order an array based on the numbers at the beginning of the strings, thats what i was asking xD – m e m e Jan 04 '20 at 00:49
  • @meme Don't treat the whole line as a string. Use an integer for the score as both answers suggests. – Ted Lyngmo Jan 04 '20 at 01:02

2 Answers2

3

I suggest creating a class for keeping the score and name. You can then add operators for streaming objects of that class and a comparison operator. operator< is required by many standard functions and containers, so we'll add that. You can keep the scores you read in any container. I've used a std::set here which will keep the contents ordered at all times.

#include <algorithm> // std::copy, std::min
#include <iostream>  // std::cin, std::cout
#include <iterator>  // std::istream_iterator, std::ostream_iterator
#include <set>       // std::set
#include <sstream>   // std::istringstream
#include <string>    // std::string
#include <tuple>     // std::tie

class score_t {
public:
    bool operator<(const score_t& s) const {
        // sort on score in decending order
        // if scores are equal, sort on name, ascending order
        return std::tie(s.score, name) < std::tie(score, s.name);
    }

    friend std::istream& operator>>(std::istream& is, score_t& s) {
        if(is >> s.score) {
            is.ignore(1);             // ignore space between score and name
            std::getline(is, s.name); // read rest of line
        }
        return is;
    }

    friend std::ostream& operator<<(std::ostream& os, const score_t& s) {
        return os << s.score << ' ' << s.name;
    }

private:
    int score{};
    std::string name{};
};

int main() {
    // test data
    std::istringstream cin{
        "1548 Bob Jones\n"
        "604 James Jones\n"
        "5516 Example Name\n"
        "100 BBB\n"
        "100 AAA\n"
        "24 Bad Score ikr\n"};

    // Use the new operator>> to read score_t's from a stream and put them in a
    // set. std::set has a constructor taking iterators that can be used to populate the
    // set directly. Since cin is a stream and not an iterator, we can use
    // std::istream_iterator<score_t>(cin) to create an iterator to use as beginning.
    // std::istream_iterator<score_t>{} creates an end iterator. Read to the end of file.
    std::set<score_t> scores(std::istream_iterator<score_t>(cin),
                             std::istream_iterator<score_t>{});

    // print the top 5 of the collected score_t's
    // std::copy can copy a range of values given by iterators and insert them
    // where a third iterator points.
    // We copy from the beginning and then max 5 score_t's by creating the end
    // iterator using std::next. The result is copied to an ostream_iterator
    std::copy(scores.cbegin(),
              std::next(scores.cbegin(), std::min(scores.size(), 5ul)),
              std::ostream_iterator<score_t>(std::cout, "\n"));
}

Output:

5516 Example Name
1548 Bob Jones
604 James Jones
100 AAA
100 BBB
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • 2
    Also interesting: [`typedef std::istream_iterator isscoreit; typedef std::ostream_iterator osscoreit; std::set scores(isscoreit(cin), isscoreit{}); std::copy(scores.cbegin(), scores.cend(), osscoreit(std::cout, "\n"));`](http://coliru.stacked-crooked.com/a/f33c8515d93a4c89) – Mooing Duck Jan 04 '20 at 00:49
  • @MooingDuck Yes, that's even nicer. Changed the code. – Ted Lyngmo Jan 04 '20 at 00:58
  • Well, it's shorter, but it's also harder to understand at a glance. I consider it a cute trick for professionals, but it's probably too confusing to use in real code or with students. – Mooing Duck Jan 04 '20 at 01:03
  • yeah may i have a bit more explanation, im new to coding let alone c++, since im a student and all – m e m e Jan 04 '20 at 01:11
  • 1
    @meme Added some explanation. Keep asking if it's unclear and I'll try to improve the answer. – Ted Lyngmo Jan 04 '20 at 01:28
  • i think i will use the other guys method as that seems alot simpler and my head seems to easily see how to implement that, however i dont think im quite as advanced as to understand your method but i heavily appreciate the time you put into helping me! – m e m e Jan 04 '20 at 01:58
  • @meme Is it the parts populating the set and using `std::copy` to print that's making it hard to understand? I can put my original code back if that helps. – Ted Lyngmo Jan 04 '20 at 02:01
  • nah its more the use of many different libraries and iterators and sets that im extremely unfamiliar with, dont get me wrong, your solution is very very good, im just very new with coding, aka being fast tracked c++ and its only like my 2nd month – m e m e Jan 04 '20 at 02:17
1

You can't use just one big string because 604 James Jones is lexicographically larger than 5516 Example Name. The first character of 604, 6, is greater than the 5 of 5516 in spite of 5516 being a larger number than 604.

Rather than an array of strings, I'd use a container, probably a std::vector, of a score structure. score would contain the score (possibly an int), the name (a string), and an operator< that could be used to arrange scores by their scores. Something like

struct score
{
    int mScore;
    std::string mName;
    bool operator<(const score & other)
    {
        return mScore < other.mScore;
    }
};

When parsing the file into the structure, use option 2 of this answer as inspiration.

You can then use std::sort from the algorithm library to sort the container.

user4581301
  • 33,082
  • 7
  • 33
  • 54
  • if i were to use your method using the file parsing suggestion aswell, i understand using iss >> a >> b, however if i were using iss >> score >> name would whitespace be taken into account with the name string, or if the line was 240 John Deere, would it return score = 240, name = john, and then nothing else? how would i include the rest of the name inc the whitespace so it would output score = 240, name = John Deere? – m e m e Jan 04 '20 at 01:46
  • @meme I neglected that. Good eye. Use `iss >> score && iss.ignore() && std::getline(iss, name)`. `ignore` will remove the space after the number and `getline` will suck up the rest of `iss` since it's looking for the end of the line and will find the end of `iss` first. – user4581301 Jan 04 '20 at 01:52
  • i will try that and report back with results – m e m e Jan 04 '20 at 02:01
  • seems perfect, thankyou, i will use 2 arrays, one for scores, one for names, and sort them, and whatever sorting i do to the scores array il do to the names array, and it should work perfectly if i just make a for loop that prints score[i] name[i] for top 10 – m e m e Jan 04 '20 at 02:03
  • @meme Why keep two separate arrays. The answer you accepted suggests using a struct which can then keep the two field together. Having two separate arrays complicates things and will be error prone. – Ted Lyngmo Jan 04 '20 at 02:18
  • im getting segmentation faults and all i have done is use that method and added scores to int array and names to name array – m e m e Jan 04 '20 at 02:21
  • its the only way i understand lol – m e m e Jan 04 '20 at 02:21
  • When you create a struct or class, you create a new type, just like `std::string`. You can create an array of your structs just as you can put strings in arrays. – Ted Lyngmo Jan 04 '20 at 02:24
  • would i have to create a new object of the struct for every score+name stored in the text file? – m e m e Jan 04 '20 at 02:24
  • ohhhh i see an array of structs, how would i get my program to create an object of the struct for every line in my highscores text file – m e m e Jan 04 '20 at 02:25
  • 1
    For that, you would need a variable length array (VLA) (or a very large fixed size array) since you don't know how many `score` entries there are in the file. VLA:s are not supported by standard C++ so you should use a `std::vector` or `std::set` or some other standard container to put new `score`'s in. – Ted Lyngmo Jan 04 '20 at 02:29
  • im okay with keeping the array size to something like [100], and not using a VLA, as im yet to learn about vectors and sets, so an array shall do for now – m e m e Jan 04 '20 at 02:33
  • @meme Ok, it's your choice but using a `std::vector` instead of an array is really easy and doing it in this application would be a perfect opportunity to learn how to use it. – Ted Lyngmo Jan 04 '20 at 06:02
  • as im short on time i ended up doing an array of structs and sorting it with std::sort as other answer suggested and it works perfectly, im on a time constraint as i also have 6 days to implement graphics and doing the highscores thing with a text file isnt on the spec for my assignment, i just went overboard for fun haha – m e m e Jan 04 '20 at 16:34