-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcsv.cpp
More file actions
232 lines (180 loc) · 6.97 KB
/
csv.cpp
File metadata and controls
232 lines (180 loc) · 6.97 KB
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#include "csv.h"
Table readCsv(std::string &file) {
Table contents;
std::ifstream csv(file);
if (!csv.is_open()) {
throw TurnipException(FILE_NOT_FOUND);
}
std::string line;
// read header col
if (csv.good()) {
std::string col;
// first line in csv
std::getline(csv, line);
std::istringstream ss(line);
while (std::getline(ss, col, ',')) {
contents.push_back({col, std::vector < int > {}});
}
}
int idx = 0;
// get prev pattern type, first buy, daisy mae price & turnip sell prices
while (std::getline(csv, line)) {
std::istringstream ss(line);
std::string price;
while (std::getline(ss, price, ',')) {
if (price == "\r") { // cursed carriage return on csv
ss.ignore();
contents[idx++].second.push_back(
INT_MIN); // edge case where 2 or more rows of data but first row's last one is unfilled
} else if (price.empty()) {
// no price entered on csv, use holder INT_MIN
contents[idx++].second.push_back(INT_MIN);
} else {
try {
contents[idx++].second.push_back(std::stoi(price));
}
catch (...) {
throw TurnipException(NUM_VAL_REQUIRED);
}
}
}
if (idx == SELL_PRICE_LAST_COL_IDX) { // edge case for when csv has only one row but last cell is unfilled
contents[idx].second.push_back(INT_MIN);
}
idx = 0;
}
csv.close();
return contents;
}
bool validateTurnips(Table & t) {
if (t.empty()) {
throw TurnipException(EMPTY_CSV);
}
if (t.size() != TurnipPattern::HALF_DAYS + 3) {
// 12 cols for mon-sat am & pm, 1 for daisy mae's price col, 1 for first time buy col, 1 for prev pattern col
throw TurnipException(CSV_COL_NUM_INVALID);
}
// validate previous week pattern type
for (int prevPat: t[PREVIOUS_WEEK_PATTERN_COL_IDX].second) {
if (!Turnip::validatePrevPatType(prevPat)) {
throw TurnipException(INVALID_PREV_PATTERN);
}
}
// validate daisy mae's sunday price
for (int daisymae : t[DAISY_MAE_BASE_PRICE_COL_IDX].second) {
if (!Turnip::validateBasePrice(daisymae)) {
throw TurnipException(BASE_PRICE_OUT_OF_RANGE + std::to_string(daisymae));
}
}
// validate selling price at nooklings
for (int day = SELL_PRICE_START_COL_IDX; day < t.size(); ++day) {
for (int sell : t[day].second) {
if (!SellPrice::validateSellPrice(sell)) {
throw TurnipException(NOOKLING_PRICE_OUT_OF_RANGE + std::to_string(sell));
}
}
}
return true;
}
std::vector<Turnip *> tableToTurnip(Table & t) {
std::vector < Turnip * > islandTurnips;
for (int island = 0; island < t[0].second.size(); ++island) { // iterate over rows
int unfilledDays = 0;
std::vector<int> islandPrice;
for (int day = SELL_PRICE_START_COL_IDX; day < t.size(); day += 2) { // get that row's vals (an island's prices)
int amPrice = t[day].second[island];
int pmPrice = t[day + 1].second[island];
if (isUnfilledField(amPrice)) {
++unfilledDays;
}
if (isUnfilledField(pmPrice)) {
++unfilledDays;
}
islandPrice.emplace_back(amPrice);
islandPrice.emplace_back(pmPrice);
} // done one island's prices
if (unfilledDays == TurnipPattern::HALF_DAYS) {
// no data filled in for any day, not even one, how do we predict?
throw TurnipException(NOT_ENOUGH_SELL_DATA);
}
unfilledDays = 0;
// create turnip obj
int prevPattern = t[PREVIOUS_WEEK_PATTERN_COL_IDX].second[island];
bool firstTimeBuyer = t[FIRST_TIME_BUY_COL_IDX].second[island];
int basePrice = t[DAISY_MAE_BASE_PRICE_COL_IDX].second[island];
islandTurnips.emplace_back(new Turnip(prevPattern, basePrice, firstTimeBuyer, islandPrice));
}
return islandTurnips;
}
bool isUnfilledField(int n) {
return n == INT_MIN;
}
bool onlyOnePatternTypeInMatch(MatchMap &m) {
int random = m[0].empty();
int large = m[1].empty();
int dec = m[2].empty();
int small = m[3].empty();
return random + large + dec + small == 3; // 3 are empty
}
std::string percentStr(int n) {
return std::to_string(n) + "%";
}
std::string minMaxStr(int min, int max) {
return std::to_string(min) + " - " + std::to_string(max);
}
OutputTable matchMapToTable(MatchMap &m, int prevPat, bool firstBuy) {
OutputTable t;
// header cols
t.push_back({"Pattern Type", {}});
t.push_back({"Pattern Chance", {}});
for (auto &col: graphLabels) {
t.push_back({col, {}});
}
const int PRICE_COL_START = 2;
// add pattern type & chance, sequence prices (as max-min) in each row
for (auto &pat: m) {
int pt = pat.first; // pattern type
int chance = prevPat == INT_MIN ? INT_MIN : PATTERN_RATES[prevPat][pt]; // probability pt occurs
if (firstBuy || onlyOnePatternTypeInMatch(m)) {
chance = 100;
}
for (int curSeq = 0; curSeq < pat.second.size(); ++curSeq) { // matched seqs under pattern type
t[0].second.push_back(PATTERN_NAMES[pt]); // pattern type col
t[1].second.push_back(chance != INT_MIN ? percentStr(chance) : ""); // pattern chance col
for (int half = 0; half < pat.second[curSeq].size(); ++half) { // iterate over seq vals
std::pair<int, int> &minMaxPricePair = pat.second[curSeq][half];
t[half + PRICE_COL_START].second.push_back(minMaxStr(minMaxPricePair.first, minMaxPricePair.second));
}
}
}
return t;
}
void writeCsv(int islandNum, MatchMap &matches, int prevPat, bool firstBuy) {
std::cout << "Generating csv with all matched price sequences..." << std::endl;
const std::string csvName = "Island " + std::to_string(islandNum) + ".csv";
OutputTable save = matchMapToTable(matches, prevPat, firstBuy);
const int MAX_COL_IDX = save.size() - 1;
const int DATA_SIZE = save[0].second.size();
std::ofstream outCsv(csvName);
// add header cols to output csv
for (int colIdx = 0; colIdx < save.size(); ++colIdx) {
outCsv << save[colIdx].first;
if (colIdx != MAX_COL_IDX) {
outCsv << ",";
}
}
outCsv << "\n";
// populate each row after header cols
for (int data = 0; data < DATA_SIZE; ++data) {
for (int colIdx = 0; colIdx < save.size(); ++colIdx) {
outCsv << save[colIdx].second[data];
if (colIdx != MAX_COL_IDX) {
outCsv << ",";
}
}
outCsv << "\n";
}
// close csv
outCsv.close();
std::cout << "Saved all matched price sequences as: " << csvName << std::endl;
}