Score.cc (2971B)
1 #include "Score.hpp" 2 3 Score::Score(const char *scorefile, const char *name) 4 { 5 fpath = std::string(scorefile); 6 7 sf.exceptions(std::fstream::badbit); 8 sf.open(fpath, std::fstream::in | std::fstream::binary); 9 if (!sf.is_open()) 10 throw std::runtime_error(fpath + ": cannot open file"); 11 for (int i = 0; i < hiscores.size(); i++) { 12 sf.read((char *)&hiscores[i].name, sizeof(hiscores[i].name)); 13 sf.read((char *)&hiscores[i].score, sizeof(hiscores[i].score)); 14 } 15 sf.close(); 16 17 /* Initialize the current name and score. */ 18 (void)strncpy(curname, name, sizeof(curname)); 19 curscore = 0; 20 } 21 22 /* 23 * I'm not sure if this stupid or not... 24 */ 25 Score::~Score() 26 { 27 add_new_hiscore(); 28 29 sf.open(fpath, std::fstream::out | std::fstream::binary); 30 if (sf.is_open()) { 31 for (int i = 0; i < hiscores.size(); i++) { 32 sf.write((char *)&hiscores[i].name, 33 sizeof(hiscores[i].name)); 34 sf.write((char *)&hiscores[i].score, 35 sizeof(hiscores[i].score)); 36 } 37 sf.close(); 38 } 39 } 40 41 /* 42 * The following 2 overloads return a reference to `this`, so that 43 * we can chain arguments together. 44 * 45 * Take the following chain as an example: 46 * `*score << "string" << 100` 47 * 48 * First, `*score << "string"` will call the overload which 49 * takes a `const char *` , and will return a reference to `this`. 50 * 51 * After the first overload has returned, `*score << "string"` will 52 * be replaced with just `*score` and the initial overload will 53 * look like this: 54 * `*score << 100` 55 * 56 * Now, the overload getting a `const int` argument will get called. 57 * 58 * Technically, this chain can work no matter the order or number 59 * of the arguments. 60 */ 61 Score& 62 Score::operator<< (const char *name) 63 { 64 (void)strncpy(curname, name, sizeof(curname)); 65 return *this; 66 } 67 68 Score& 69 Score::operator<< (const int score) 70 { 71 curscore = score; 72 return *this; 73 } 74 75 /* 76 * Convert the hiscores array to something the `popup` method in 77 * `Engine` can print. 78 */ 79 std::vector<std::string> 80 Score::scores_strfmt() const 81 { 82 std::vector<std::string> v; 83 84 for (int i = 0; i < hiscores.size(); i++) 85 v.push_back(std::string(hiscores[i].name) + ": " + 86 std::to_string(hiscores[i].score)); 87 v.push_back("Press any key to continue"); 88 89 return v; 90 } 91 92 const char * 93 Score::get_curname() const 94 { 95 return curname; 96 } 97 98 int 99 Score::get_curscore() const 100 { 101 return curscore; 102 } 103 104 void 105 Score::add_new_hiscore() 106 { 107 auto cmp = [](const HighScore& a, const HighScore& b) -> bool { 108 return a.score > b.score; 109 }; 110 111 /* 112 * Add our new score in the array in case it's higher 113 * than any of the existing entries. The array is sorted 114 * in descending order, so we'll search it backwards -- 115 * this will have the effect of replacing the lower scores 116 * first. 117 */ 118 for (int i = hiscores.size() - 1; i >= 0; i--) { 119 if (curscore > hiscores[i].score) { 120 hiscores[i].score = curscore; 121 (void)strncpy(hiscores[i].name, curname, 122 sizeof(hiscores[i].name)); 123 break; 124 } 125 } 126 std::sort(hiscores.begin(), hiscores.end(), cmp); 127 }