-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplayerHours.cpp
More file actions
212 lines (152 loc) · 7.55 KB
/
Copy pathplayerHours.cpp
File metadata and controls
212 lines (152 loc) · 7.55 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
// playerHours.cpp
// by 9yz
// orig. 5/13/21 - updated 7/9/21 to use args
// Takes a .csv from the datatracker program and outputs the number of times each map was recorded * the number of players online, per map. Will ignore the first line.
// ./playerhours <csv path> -wdc [number]
// -w: proccesses the last week of data (the last 2,016 entries)
// -d: proccesses the last day of data (288 entries)
// -c <number>: procces all data starting at line <number>. 0 for the beginning of the file.
// ex. ./playerhours results.csv -c 10562
// Each line in the csv should be in this format: timestamp (ignored),T players,CT players,mapname,T steamids (ignored),CT steamids (ignored).
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdlib>
using namespace std;
//delimitors for columns and lines. you can probbably leave these at default unless you're using a weird csv format.
const char columnDelimitor = ',';
const char lineDelimitor = '\n';
void seekToNextColumn(ifstream &);
void seekToNextLine(ifstream &);
bool loadCSV(string, vector <int> &, vector <string> &);
void analyze(vector <int> &, vector <string> &, vector <int> &, vector <string> &, int);
void sort(vector <int> &, vector <string> &);
int main(int argc, char** argv){
//input validation, gotta put this first or the variables fuck it up
if(argc > 4 && argc < 3){ //make sure we have the correct number of args
cout << "Incorrect number of parameters entered.\n";
return 1;
}
vector <int> playerCount{}; //input playercount
vector <string> mapNames{}; //input mapnames
vector <int> playerCountOut{}; //output playercount
vector <string> mapNamesOut{}; //output mapnames
string filePath(argv[1]); //getting the first param and casting it to string
string startLocationParam(argv[2]); //getting what param (-wdc) to start with
int startLocation; //if positive, start at that location, if -2, start at a week ago, if -1, start at a day ago
char* end; //what the fuck does this do
//more input validation
if(startLocationParam == "-d"){
startLocation = -1;
}
else if(startLocationParam == "-w"){
startLocation = -2;
}
else if(startLocationParam == "-c"){
if(argc == 4){ //anti-segfault: make sure there's actually a 3rd param
if( strtol(argv[3], &end, 10) < 0){
cout << "Invalid start position entered. Must be positive.\n";
return 1;
}
startLocation = strtol(argv[3], &end, 10); //cast the final param from c-style string to int
}
else{
cout << "-c requires a line number to start at.\n";
return 1;
}
}
else{
cout << "Invalid parameter " << startLocationParam << " entered. Acceptable values are -w, -d, -c <number>.\n";
return 1;
}
//actually running the program
if( loadCSV(filePath, playerCount, mapNames) ){ //prompt for csv, load it into vectors. if it returns true, there was an error and we should exit the program.
return 1;
}
analyze(playerCount, mapNames, playerCountOut, mapNamesOut, startLocation);
sort(playerCountOut, mapNamesOut);
for (int i = 0; i < playerCountOut.size(); i++) //run through all the recorded maps
{
cout << mapNamesOut[i] << ": " << playerCountOut[i] << endl; //and print them all out
}
return 0;
}
void seekToNextLine(ifstream &fileIn){
string junk;
getline(fileIn, junk, lineDelimitor); //reads from filein until we hit lineDelimitor. puts everything it reads into junk
return;
}
void seekToNextColumn(ifstream &fileIn){
string junk;
getline(fileIn, junk, columnDelimitor); //reads from filein until we hit columnDelimitor. puts everything it reads into junk
return;
}
bool loadCSV(string filePath, vector <int> &playerCount, vector <string> &mapNames){ //Prompts and loads the input CSV file. returns true if there's an error
string num1, num2; // for storing the numbers before we add to vector
string name1; //for storing the mapname before adding to vector
string junk;
ifstream fileIn(filePath);
cout << "loading file...\n";
if( fileIn.fail() ){ //make sure the file opened properly
cerr << "could not open file. \n";
return true;
}
seekToNextLine(fileIn); //first line is just header info, we don't need to copy it.
while( !fileIn.eof() ){ //checks for eof
seekToNextColumn(fileIn); //we skip the first column (timestamp)
getline(fileIn, num1, columnDelimitor); //get the first number (t players). get tata from, put data in, stop at this character
getline(fileIn, num2, columnDelimitor); //get 2nd number (ct players)
playerCount.push_back( stoi(num1) + stoi(num2) ); //add numbers together and put into vector
getline(fileIn, name1, columnDelimitor); //get mapname
mapNames.push_back(name1); //add to vector
seekToNextLine(fileIn); //we're done getting data from this line, move to the next
}
fileIn.close();
cout << "done loading!\n";
cout << playerCount.size() << " entries loaded.\n";
return false;
}
void analyze(vector <int> &playerCount, vector <string> &mapNames, vector <int> &playerCountOut, vector <string> &mapNamesOut, int startPosition){ //runs through all of the entries in the vector and counts up the total players for each map
bool success = false;
if(startPosition == -1){
startPosition = playerCount.size() - 288; //start at 288 entries ago (1 day)
}
else if(startPosition == -2){
startPosition = playerCount.size() - 2016; //start at 2016 entries ago (1 week)
} //if it's any other number we can just start there.
cout << "Starting at line " << startPosition << endl;
cout << "Analylizing...\n";
for (int i = startPosition; i < playerCount.size(); i++) //go through all of the entries
{
for (int j = 0; j < mapNamesOut.size(); j++) //and go through all of the unique maps we've recorded so far
{
if( mapNames[i] == mapNamesOut[j] ){ //and if the entry has a map we've seen before
playerCountOut[j] += playerCount[i]; //then add the players from the entry to the recorded map
success = true;
}
}
if(success == false){ //if we went through all the recorded maps and we haven't recorded this map yet...
playerCountOut.push_back(playerCount[i]); //record the new map
mapNamesOut.push_back(mapNames[i]); //and record its players
}
success = false;
}
cout << "done analyzing!\n";
return;
}
void sort(vector <int> &playerCountOut, vector <string> &mapNamesOut){ //sorts the entries from most players to least players
bool success = true;
while(success) //keep looping until it's sorted
{
success = false;
for (int i = 0; i < playerCountOut.size() - 1; i++) //run through all of the entries
{
if( playerCountOut[i] > playerCountOut[i+1] ){ //if the lower number is bigger than the upper one,
swap( playerCountOut[i],playerCountOut[i+1] ); //swap them
swap( mapNamesOut[i], mapNamesOut[i+1] ); //and swap the names
success = true; //if we manage to get through the whole list without making it true, it's sorted.
}
}
}
return;
}