I suppose it's fitting that the team that really introduced me to the world of statistics within FRC would lead me to spend several hours on figuring out this problem. Two years ago, we were playing the Waterloo 2014 webcast in our lab, and it was the first regional I really remember watching. It was an event that not not just totally amazed me and got me really obsessed with watching other teams, but also introduced me to OPR, BBQ, and OP's streak. Thank you 2056 (among many other teams) for changing the way I saw FRC.
Quote:
Originally Posted by Patriot
These shirts will be available in limited quantities, please see us in the stands at champs for details. Please NOT our PIT.
|
I'm definitely going to try and get one of these.
Quote:
Originally Posted by Richard Wallace
This shirt is a great idea, and a fitting tribute to the thirty partners and three final opponents who were part of OP's historic win streak.
In the spirit of the Erdős number that mathmeticians track, I propose that teams be assigned "OP Numbers", defined as follows:
- Team 2056 has OP Number = 0. They are unique.
- A team that has been on the winning alliance n times with 2056 at an official FRC event has OP Number = 1/n.
- A team that has been on the winning alliance with any team whose OP Number is greater than zero and less than or equal to one has OP Number = 2.
- A team that has been on the winning alliance with any team whose OP Number is 2 has OP Number = 3.
- And so on.
To start,
1114 has OP Number = 1/16
1547 has OP Number = 1/2
The following teams have OP Number = 1
Can anyone provide a script to calculate OP numbers for all currently active FRC teams?*
-------------
*Ether, you are ineligible. However, following your lead I will give rep points to the first CD student who shows a correct result, with sufficient detail to let others check the method used.
|
I used a rather convoluted combination of the TBA API, notepad/excel formatting and extracting, and c++ to figure this out. It's definitely not a particularly elegant solution, but I'm also still confused about how the API works (my dad helped me with the get requests but he just sent the entire string to a text file (it was literally 25 years worth of award data in a single line)) so I figured I'd just stick to what I know.
I checked a couple of random teams, but I couldn't find an easy way to verify everything so I'm not sure if they're all correct.
General steps:
1. Get event lists per year from 1992 to 2016
2. Use excel to extract the list of event codes, and keep the list of all of all the official events
3. Use the event code list to get awards list for each of those events (FIRST/TBA is missing quite a lot of award data, so any alliances at those events were not counted)
4. Use excel to extract the winning teams from those events and create a table of alliances, save as a text file
5. Copy a list of all teams from TBA, save as a text file
6. Use these two lists and the program at the bottom to compute OP numbers (below)
OP numbers:
Code:
OP num # of teams
0 1
1 74
2 302
3 485
4 238
5 41
6 3
My code:
(I didn't clean it up because I figured I should be getting back to homework, so it's definitely messy; sorry about that)
Code:
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
class Team {
public:
Team(int x) {teamNum = x; matches = 0; opNum = -1;};
void setOpNum(double x) {opNum = x;};
void incMatches() {matches++;};
int getNum() {return teamNum;};
int getMatches() {return matches;};
double getOpNum() {return opNum;};
private:
int teamNum;
int matches; // num of matches played with OP
double opNum; // OP number
};
struct ALLIANCE {
vector<int> team1;
vector<int> team2;
vector<int> team3;
vector<int> team4;
};
void createTeamVector(vector<Team> & v) {
int x;
ifstream file("teamlist.txt");
while(file >> x) {
v.push_back(x);
}
file.close();
}
void createAllianceVector(ALLIANCE & a) {
int x1, x2, x3, x4;
ifstream file("winningalliances.txt");
while(file >> x1 >> x2 >> x3 >> x4) {
a.team1.push_back(x1);
a.team2.push_back(x2);
a.team3.push_back(x3);
a.team4.push_back(x4);
}
file.close();
}
int index(int teamNum, vector<Team> &v) {
for(size_t i = 0; i < v.size(); i++) {
if(teamNum == v[i].getNum())
return i;
}
return 0; // index of team "0"
}
int main() {
vector<Team> teams; // list of all teams + placeholder team "0"
ALLIANCE alliances; // winning alliances for all events
vector< vector<int> > teamsSorted; // vector of vectors of teams sorted by op number
createTeamVector(teams);
createAllianceVector(alliances);
/// set 2056 to op number = 0
vector<int> newColumn;
teamsSorted.push_back(newColumn);
teamsSorted.at(0).push_back(2056);
/// find all teams that 2056 has played with and find the number of times they won together
for(size_t i = 0; i < teams.size(); i++) {
if(alliances.team1[i] == 2056) {
teams[index(alliances.team2[i], teams)].incMatches();
teams[index(alliances.team3[i], teams)].incMatches();
teams[index(alliances.team4[i], teams)].incMatches();
}
else if(alliances.team2[i] == 2056) {
teams[index(alliances.team1[i], teams)].incMatches();
teams[index(alliances.team3[i], teams)].incMatches();
teams[index(alliances.team4[i], teams)].incMatches();
}
else if(alliances.team3[i] == 2056) {
teams[index(alliances.team1[i], teams)].incMatches();
teams[index(alliances.team2[i], teams)].incMatches();
teams[index(alliances.team4[i], teams)].incMatches();
}
else if(alliances.team4[i] == 2056) {
teams[index(alliances.team1[i], teams)].incMatches();
teams[index(alliances.team2[i], teams)].incMatches();
teams[index(alliances.team3[i], teams)].incMatches();
}
}
/// add those teams to the sorted vector and set their op number
teamsSorted.push_back(newColumn);
for(size_t i = 1; i < teams.size(); i++) { // skip team "0"
if(teams[i].getMatches() > 0) {
teamsSorted.at(1).push_back(teams[i].getNum());
teams[i].setOpNum(1.0/(teams[i].getMatches()));
cout << teams[i].getNum() << " " << teams[i].getMatches() << endl;
}
}
/// find teams with op numbers > 1
int j = 2, temp = 1;
while(temp > 0) { // loop while there are teams with the previous op number
temp = 0;
for(size_t i = 0; i < teamsSorted.at(j-1).size(); i++) { // inc through teams in last op number
for(size_t k = 1; k < alliances.team1.size(); k++) { // skip team "0", inc through all teams
if(alliances.team1[k] == teamsSorted[j-1][i]) {
temp++;
if(teams[index(alliances.team2[k], teams)].getOpNum() == -1) {teams[index(alliances.team2[k], teams)].setOpNum(j);}
if(teams[index(alliances.team3[k], teams)].getOpNum() == -1) {teams[index(alliances.team3[k], teams)].setOpNum(j);}
if(teams[index(alliances.team4[k], teams)].getOpNum() == -1) {teams[index(alliances.team4[k], teams)].setOpNum(j);}
}
else if(alliances.team2[k] == teamsSorted[j-1][i]) {
temp++;
if(teams[index(alliances.team1[k], teams)].getOpNum() == -1) {teams[index(alliances.team1[k], teams)].setOpNum(j);}
if(teams[index(alliances.team3[k], teams)].getOpNum() == -1) {teams[index(alliances.team3[k], teams)].setOpNum(j);}
if(teams[index(alliances.team4[k], teams)].getOpNum() == -1) {teams[index(alliances.team4[k], teams)].setOpNum(j);}
}
else if(alliances.team3[k] == teamsSorted[j-1][i]) {
temp++;
if(teams[index(alliances.team1[k], teams)].getOpNum() == -1) {teams[index(alliances.team1[k], teams)].setOpNum(j);}
if(teams[index(alliances.team2[k], teams)].getOpNum() == -1) {teams[index(alliances.team2[k], teams)].setOpNum(j);}
if(teams[index(alliances.team4[k], teams)].getOpNum() == -1) {teams[index(alliances.team4[k], teams)].setOpNum(j);}
}
else if(alliances.team4[k] == teamsSorted[j-1][i]) {
temp++;
if(teams[index(alliances.team1[k], teams)].getOpNum() == -1) {teams[index(alliances.team1[k], teams)].setOpNum(j);}
if(teams[index(alliances.team2[k], teams)].getOpNum() == -1) {teams[index(alliances.team2[k], teams)].setOpNum(j);}
if(teams[index(alliances.team2[k], teams)].getOpNum() == -1) {teams[index(alliances.team3[k], teams)].setOpNum(j);}
}
}
} // end for loop
teamsSorted.push_back(newColumn);
if(temp > 0) {
for(size_t i = 1; i < teams.size(); i++) { // skip team "0"
if(teams[i].getOpNum() == j) {
teamsSorted.at(j).push_back(teams[i].getNum());
}
}
}
j++;
} // end while loop
teams[index(2056, teams)].setOpNum(0); // reset 2056's op number to 0
/// print number of teams per op number
for(size_t i = 0; i < teamsSorted.size(); i++)
cout << i << " " << teamsSorted.at(i).size() << endl;
/// write data to file, sorted by team number
ofstream file;
file.open("op_numbers.txt");
for(size_t i = 1; i < teams.size(); i++) { // skip team "0"
file << teams[i].getNum() << "\t\t" << teams[i].getOpNum() << "\n";
}
file.close();
/// write data to file, sorted by op number
file.open("op_numbers_2.txt");
// teams with op number < 1 (searched through op_numbers.txt...not a true sort...)
file << 2056 << "\t\t" << 0 << "\n";
file << 1114 << "\t\t" << teams[index(1114, teams)].getOpNum() << "\n";
file << 217 << "\t\t" << teams[index(217, teams)].getOpNum() << "\n";
file << 1547 << "\t\t" << teams[index(1547, teams)].getOpNum() << "\n";
file << 2185 << "\t\t" << teams[index(2185, teams)].getOpNum() << "\n";
file << 2200 << "\t\t" << teams[index(2200, teams)].getOpNum() << "\n";
// teams with op number between 1 and 6
for(int i = 1; i <= 6; i++) {
for(size_t k = 1; k < teams.size(); k++) {
if(teams[k].getOpNum() == i)
file << teams[k].getNum() << "\t\t" << i << "\n";
}
}
// teams with op number = -1 (no connection to 2056)
for(size_t k = 1; k < teams.size(); k++) {
if(teams[k].getOpNum() == -1)
file << teams[k].getNum() << "\t\t" << -1 << "\n";
}
file.close();
return 0;
}