aboutsummaryrefslogtreecommitdiff
path: root/src/utils.cc
blob: 75f13a3dd909784e8b352c1ccda7faf264f28202 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "utils.h"
#include <nlohmann/json.hpp>
#include "settings.h"
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <filesystem>
#include <stdexcept>
#include <map>
#include <algorithm>

namespace fs = std::filesystem;

nlohmann::json utils::loadJson(const fs::path& path) {
    std::ifstream f(path);
    nlohmann::json j;
    f >> j;
    return j;
}

nlohmann::json utils::loadJson(const std::string& type, const std::string& name) {
    for(auto data : utils::loadAllJson(settings::getString(type))) {
        if(data["name"] == name) {
            return data;
        }
    }
    throw std::invalid_argument("Unknown name: `" + name + "' for type `" + type + "'.");
}

nlohmann::json utils::findByName(const std::string& name) {
    for(auto type : settings::objectTypes) {
        try {
            return utils::loadJson(type, name);
        } catch(std::exception& e) {} // eat.
    }
    throw std::invalid_argument("Could not find data matching: " + name);
}

int utils::parseInt(const std::string& s) {
    try {
        return std::stoi(s);
    } catch(std::exception& e) {
        throw std::runtime_error("An integer was expected but " + s + " was given");
    }
}

void utils::saveJson(const nlohmann::json& data, const fs::path& path) {
    std::ofstream f(path);
    f << std::setw(4) << data << std::endl;
}

static std::map<std::string, std::vector<nlohmann::json>> cache;

std::vector<nlohmann::json> utils::loadAllJson(const std::string& directory) {
    if(cache.contains(directory)) {
        return cache[directory];
    }
    std::vector<nlohmann::json> ret;
    for(auto path : fs::recursive_directory_iterator(directory)) {
        if(path.path().extension() == ".json") {
            ret.push_back(utils::loadJson(path.path()));
        }
    }
    cache[directory] = ret;
    return ret;
}

// Accepts coins formatted "X Yp" where X is an integer and Y is any of c, s, e, g, p.
int utils::coins2copper(const std::string& coins) {
    int num = std::stoi(coins.substr(0, coins.find(" ")));
    std::string denomination(coins.substr(coins.find(" ") + 1));
    if(! cpValue.contains(denomination)) {
        throw std::invalid_argument("Unknown coin type: " + denomination);
    }
    return num * cpValue.at(denomination);
}

// Greedily selects highest coin values to minimize total number of coins
// Returns a vector of pairs mapping coin type to coint
std::vector<std::pair<std::string, int>> utils::copper2coins(int coppers) {
    std::vector<std::pair<std::string, int>> ret;
    while(coppers > 0) {
        // Find the largest denomination in cpValue under coppers
        std::pair<std::string, int> largest("", 0);
        for(auto pair : cpValue) {
            if(pair.second <= coppers && pair.second > largest.second) {
                largest = pair;
            }
        }
        std::pair<std::string, int> amnt(largest.first, coppers / largest.second);
        coppers -= amnt.second * largest.second;
        ret.push_back(amnt);
    }
    if(ret.empty()) {
        ret.push_back({"cp", 0});
    }
    return ret;
}

std::string utils::getCostString(int coppers) {
    std::vector<std::string> parts;
    for(auto pair : utils::copper2coins(coppers)) {
        parts.push_back(std::to_string(pair.second) + " " + pair.first);
    }
    return utils::join(parts, ", ");
}

std::string utils::toOrdinal(std::size_t number) {
    std::string suffix = "th";
    if (number % 100 < 11 || number % 100 > 13) {
        switch (number % 10) {
            case 1:
                suffix = "st";
                break;
            case 2:
                suffix = "nd";
                break;
            case 3:
                suffix = "rd";
                break;
        }
    }
    return std::to_string(number) + suffix;
}

std::string utils::lower(std::string& in) {
    std::transform(in.begin(), in.end(), in.begin(), ::tolower);
    return in;
}