You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
460 lines
22 KiB
460 lines
22 KiB
#include "pixelGameEngine.h"
|
|
#include "olcPGEX_QuickGUI.h"
|
|
#include <set>
|
|
|
|
using namespace olc;
|
|
|
|
QuickGUI::TextBox*prevTextBox=nullptr;
|
|
|
|
QuickGUI::TextBox*activeBox=nullptr;
|
|
|
|
// Override base class with your custom functionality
|
|
class ChampionsLeaguePointSolver : public olc::PixelGameEngine
|
|
{
|
|
std::string slurp(std::ifstream& in) {
|
|
std::ostringstream sstr;
|
|
sstr << in.rdbuf();
|
|
return sstr.str();
|
|
}
|
|
|
|
struct ScoreData{
|
|
int difficulty=0;
|
|
std::string song;
|
|
int totalEX=0;
|
|
int ex1=0,ex2=0,ex3=0;
|
|
std::string str()const{
|
|
return "["+std::to_string(difficulty)+"] "+song+": "+std::to_string(totalEX)+" total, "+" EX1: "+std::to_string(ex1)+" EX2: "+std::to_string(ex2)+" EX3: "+std::to_string(ex3);
|
|
}
|
|
friend std::ostream&operator<<(std::ostream&os,const ScoreData&data){
|
|
os<<data.str();
|
|
return os;
|
|
}
|
|
};
|
|
|
|
std::string GetNext(int&marker,std::string str){
|
|
int originalMarker=marker;
|
|
marker=str.find_first_of(',',originalMarker)+1;
|
|
return str.substr(originalMarker,marker-1);
|
|
};
|
|
|
|
struct TestCase{
|
|
int p1Amt,p2Amt,p3Amt;
|
|
};
|
|
|
|
struct SongCombinations{
|
|
std::vector<std::pair<int,int>>p1; //Index to song followed by EX of song.
|
|
std::vector<std::pair<int,int>>p2;
|
|
std::vector<std::pair<int,int>>p3;
|
|
std::set<int>p1Picked;
|
|
std::set<int>p2Picked;
|
|
std::set<int>p3Picked;
|
|
int totalEX=0;
|
|
int remainingA,remainingB,remainingC;
|
|
};
|
|
std::vector<ScoreData>dataA,dataB;
|
|
std::vector<std::pair<int,int>>player1Score,player2Score,player3Score;
|
|
std::vector<TestCase>cases;
|
|
std::vector<SongCombinations> bestComboA,bestComboB;
|
|
int calculationStep=0;
|
|
void Evaluate(int caseInd,bool ASet){
|
|
auto ChooseSong = [&](SongCombinations&combinations,std::vector<ScoreData>&dat,int index){
|
|
if(combinations.remainingA>0&&combinations.p1Picked.count(index)==0&&combinations.p2Picked.count(index)==0&&combinations.p3Picked.count(index)==0){
|
|
combinations.remainingA--;
|
|
if(ASet){
|
|
combinations.totalEX+=player1Score[index].first;
|
|
combinations.p1.push_back(std::pair<int,int>{index,player1Score[index].first});
|
|
}else{
|
|
combinations.totalEX+=player1Score[index].second;
|
|
combinations.p1.push_back(std::pair<int,int>{index,player1Score[index].second});
|
|
}
|
|
combinations.p1Picked.insert(index);
|
|
}else
|
|
if(combinations.remainingB>0&&combinations.p1Picked.count(index)==0&&combinations.p2Picked.count(index)==0&&combinations.p3Picked.count(index)==0){
|
|
combinations.remainingB--;
|
|
if(ASet){
|
|
combinations.totalEX+=player2Score[index].first;
|
|
combinations.p1.push_back(std::pair<int,int>{index,player2Score[index].first});
|
|
}else{
|
|
combinations.totalEX+=player2Score[index].second;
|
|
combinations.p1.push_back(std::pair<int,int>{index,player2Score[index].second});
|
|
}
|
|
combinations.p2Picked.insert(index);
|
|
}else
|
|
if(combinations.remainingC>0&&combinations.p1Picked.count(index)==0&&combinations.p2Picked.count(index)==0&&combinations.p3Picked.count(index)==0){
|
|
combinations.remainingC--;
|
|
if(ASet){
|
|
combinations.totalEX+=player3Score[index].first;
|
|
combinations.p1.push_back(std::pair<int,int>{index,player3Score[index].first});
|
|
}else{
|
|
combinations.totalEX+=player3Score[index].second;
|
|
combinations.p1.push_back(std::pair<int,int>{index,player3Score[index].second});
|
|
}
|
|
combinations.p3Picked.insert(index);
|
|
}
|
|
};
|
|
|
|
if(ASet){
|
|
bestComboA.push_back({});
|
|
bestComboA[caseInd].remainingA=cases[caseInd].p1Amt;
|
|
bestComboA[caseInd].remainingB=cases[caseInd].p2Amt;
|
|
bestComboA[caseInd].remainingC=cases[caseInd].p3Amt;
|
|
SongCombinations testCombo=bestComboA[caseInd];
|
|
for(int i=0;i<12;i++){
|
|
SongCombinations c1=testCombo;
|
|
ChooseSong(c1,dataA,i);
|
|
for(int j=0;j<12;j++){
|
|
SongCombinations c2=c1;
|
|
ChooseSong(c2,dataA,j);
|
|
for(int k=0;k<12;k++){
|
|
SongCombinations c3=c2;
|
|
ChooseSong(c3,dataA,k);
|
|
for(int l=0;l<12;l++){
|
|
SongCombinations c4=c3;
|
|
ChooseSong(c4,dataA,l);
|
|
for(int m=0;m<12;m++){
|
|
SongCombinations c5=c4;
|
|
ChooseSong(c5,dataA,m);
|
|
for(int n=0;n<12;n++){
|
|
SongCombinations c6=c5;
|
|
ChooseSong(c6,dataA,n);
|
|
if(bestComboA[caseInd].totalEX<c6.totalEX){
|
|
bestComboA[caseInd]=c6;
|
|
bestComboA[caseInd].totalEX=c6.totalEX;
|
|
std::cout<<"New Best Song Combinations found for Case ("<<cases[caseInd].p1Amt<<","<<cases[caseInd].p2Amt<<","<<cases[caseInd].p3Amt<<") - Total EX: "<<bestComboA[caseInd].totalEX<<":"<<std::endl;
|
|
std::cout<<"\t";
|
|
for(std::pair<int,int>&p1:bestComboA[caseInd].p1){
|
|
std::cout<<"P1["<<p1.first<<"]:"<<p1.second<<" ";
|
|
}
|
|
for(std::pair<int,int>&p2:bestComboA[caseInd].p2){
|
|
std::cout<<"P2["<<p2.first<<"]:"<<p2.second<<" ";
|
|
}
|
|
for(std::pair<int,int>&p3:bestComboA[caseInd].p3){
|
|
std::cout<<"P3["<<p3.first<<"]:"<<p3.second<<" ";
|
|
}
|
|
std::cout<<std::endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}else{
|
|
bestComboB.push_back({});
|
|
bestComboB[caseInd].remainingA=cases[caseInd].p1Amt;
|
|
bestComboB[caseInd].remainingB=cases[caseInd].p2Amt;
|
|
bestComboB[caseInd].remainingC=cases[caseInd].p3Amt;
|
|
SongCombinations testCombo=bestComboB[caseInd];
|
|
for(int i=0;i<12;i++){
|
|
SongCombinations c1=testCombo;
|
|
ChooseSong(c1,dataB,i);
|
|
for(int j=0;j<12;j++){
|
|
SongCombinations c2=c1;
|
|
ChooseSong(c2,dataB,j);
|
|
for(int k=0;k<12;k++){
|
|
SongCombinations c3=c2;
|
|
ChooseSong(c3,dataB,k);
|
|
for(int l=0;l<12;l++){
|
|
SongCombinations c4=c3;
|
|
ChooseSong(c4,dataB,l);
|
|
for(int m=0;m<12;m++){
|
|
SongCombinations c5=c4;
|
|
ChooseSong(c5,dataB,m);
|
|
for(int n=0;n<12;n++){
|
|
SongCombinations c6=c5;
|
|
ChooseSong(c6,dataB,n);
|
|
if(bestComboB[caseInd].totalEX<c6.totalEX){
|
|
bestComboB[caseInd]=c6;
|
|
bestComboB[caseInd].totalEX=c6.totalEX;
|
|
std::cout<<"New Best Song Combinations found for Case ("<<cases[caseInd].p1Amt<<","<<cases[caseInd].p2Amt<<","<<cases[caseInd].p3Amt<<") - Total EX: "<<bestComboB[caseInd].totalEX<<":"<<std::endl;
|
|
std::cout<<"\t";
|
|
for(std::pair<int,int>&p1:bestComboB[caseInd].p1){
|
|
std::cout<<"P1["<<p1.first<<"]:"<<p1.second<<" ";
|
|
}
|
|
for(std::pair<int,int>&p2:bestComboB[caseInd].p2){
|
|
std::cout<<"P2["<<p2.first<<"]:"<<p2.second<<" ";
|
|
}
|
|
for(std::pair<int,int>&p3:bestComboB[caseInd].p3){
|
|
std::cout<<"P3["<<p3.first<<"]:"<<p3.second<<" ";
|
|
}
|
|
std::cout<<std::endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
calculationStep++;
|
|
}
|
|
public:
|
|
int highestEX=0;
|
|
struct SongElement{
|
|
SongElement(QuickGUI::Manager&manager,std::string songName,vf2d pos){
|
|
label=new QuickGUI::Label(manager,songName,pos,{164,12});
|
|
p1Score=new QuickGUI::TextBox(manager,"",pos+vf2d{192,0},{36,12});
|
|
p2Score=new QuickGUI::TextBox(manager,"",pos+vf2d{192+42*1,0},{36,12});
|
|
p3Score=new QuickGUI::TextBox(manager,"",pos+vf2d{192+42*2,0},{36,12});
|
|
|
|
//NOTE for future Sig: The Text Entry mode has the enter key functionality DISABLED as we use it for tab/enter key navigation. If you need it for some reason you need to go re-enable it.
|
|
if(prevTextBox!=nullptr){
|
|
prevTextBox->tabNext=p1Score;
|
|
}
|
|
p1Score->tabNext=p2Score;
|
|
p1Score->tabPrev=prevTextBox;
|
|
p2Score->tabNext=p3Score;
|
|
p2Score->tabPrev=p1Score;
|
|
prevTextBox=p3Score;
|
|
p3Score->tabPrev=p2Score;
|
|
}
|
|
QuickGUI::Label*label;
|
|
QuickGUI::TextBox*p1Score;
|
|
QuickGUI::TextBox*p2Score;
|
|
QuickGUI::TextBox*p3Score;
|
|
};
|
|
QuickGUI::Manager gui;
|
|
std::vector<SongElement>songs;
|
|
QuickGUI::Label*p1Label;
|
|
QuickGUI::Label*p2Label;
|
|
QuickGUI::Label*p3Label;
|
|
QuickGUI::Button*calculateButton;
|
|
std::array<QuickGUI::Button*,11>inputButtons;
|
|
int totalCalculationSteps=0;
|
|
bool calculating=false;
|
|
|
|
ChampionsLeaguePointSolver()
|
|
{
|
|
// Name your application
|
|
sAppName = "Champions League Point Solver";
|
|
}
|
|
|
|
public:
|
|
bool OnUserCreate() override
|
|
{
|
|
std::ifstream file("assets/team2");
|
|
std::string line;
|
|
//First two lines are garbage data.
|
|
std::getline(file,line);
|
|
std::getline(file,line);
|
|
for(int i=0;i<12;i++){
|
|
std::getline(file,line);
|
|
int marker=0;
|
|
ScoreData dat{
|
|
stoi(GetNext(marker,line)),
|
|
GetNext(marker,line),
|
|
stoi(GetNext(marker,line)),
|
|
stoi(GetNext(marker,line)),
|
|
stoi(GetNext(marker,line)),
|
|
stoi(GetNext(marker,line))};
|
|
player1Score.push_back(std::pair<int,int>{0,0});
|
|
player2Score.push_back(std::pair<int,int>{0,0});
|
|
player3Score.push_back(std::pair<int,int>{0,0});
|
|
dataA.push_back(dat);
|
|
songs.push_back(SongElement{gui,dat.song.substr(0,dat.song.find(',')),{4.f,2.f+12*i+16}});
|
|
}
|
|
//Two more lines of garbage data.
|
|
std::getline(file,line);
|
|
std::getline(file,line);
|
|
for(int i=0;i<12;i++){
|
|
std::getline(file,line);
|
|
int marker=0;
|
|
ScoreData dat{
|
|
stoi(GetNext(marker,line)),
|
|
GetNext(marker,line),
|
|
stoi(GetNext(marker,line)),
|
|
stoi(GetNext(marker,line)),
|
|
stoi(GetNext(marker,line)),
|
|
stoi(GetNext(marker,line))};
|
|
player1Score[i].second=0;
|
|
player2Score[i].second=0;
|
|
player3Score[i].second=0;
|
|
dataB.push_back(dat);
|
|
songs.push_back(SongElement{gui,dat.song.substr(0,dat.song.find(',')),{4.f,2.f+12*(i+13)+16}});
|
|
}
|
|
std::cout<<"File Contents:"<<std::endl<<std::endl;
|
|
for(auto&list:{dataA,dataB}){
|
|
for(auto&dat:list){
|
|
std::cout<<dat<<std::endl;
|
|
}
|
|
}
|
|
std::cout<<"==================="<<std::endl;
|
|
|
|
|
|
p1Label=new QuickGUI::Label(gui,"P1",vf2d{4.f,2.f}+vf2d{192,0},{36,12});
|
|
p2Label=new QuickGUI::Label(gui,"P2",vf2d{4.f,2.f}+vf2d{192+42*1,0},{36,12});
|
|
p3Label=new QuickGUI::Label(gui,"P3",vf2d{4.f,2.f}+vf2d{192+42*2,0},{36,12});
|
|
calculateButton=new QuickGUI::Button(gui,"Calculate",{4,2},{100,16});
|
|
|
|
for(int i=0;i<inputButtons.size();i++){
|
|
if(i==0){
|
|
inputButtons[i]=new QuickGUI::Button(gui,std::to_string(i),{2.f+(1%3)*50,ScreenHeight()-(4-9/3)*26.f},{49,25});
|
|
}else
|
|
if(i==10){
|
|
inputButtons[i]=new QuickGUI::Button(gui,"<--",{2.f+(2%3)*50,ScreenHeight()-(4-9/3)*26.f},{49,25});
|
|
}else{
|
|
inputButtons[i]=new QuickGUI::Button(gui,std::to_string(i),{2.f+((i-1)%3)*50,ScreenHeight()-(4-(i-1)/3)*26.f},{49,25});
|
|
}
|
|
inputButtons[i]->bVisible=false;
|
|
inputButtons[i]->Enable(false);
|
|
}
|
|
|
|
for(int i=0;i<5;i++){
|
|
for(int j=0;j<5;j++){
|
|
for(int k=0;k<5;k++){
|
|
if(i+j+k==6){
|
|
cases.push_back(TestCase{i,j,k});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OnUserUpdate(float fElapsedTime) override
|
|
{
|
|
Clear(VERY_DARK_CYAN);
|
|
|
|
if(calculateButton->bPressed&&!calculating){
|
|
calculateButton->Enable(false);
|
|
int index=0;
|
|
for(SongElement&element:songs){
|
|
element.p1Score->Enable(false);
|
|
element.p2Score->Enable(false);
|
|
element.p3Score->Enable(false);
|
|
element.p1Score->bHasBackground=element.label->bHasBackground=false;
|
|
if(index<12){
|
|
player1Score[index].first=element.p1Score->sText.length()>0?stoi(element.p1Score->sText):0;
|
|
player2Score[index].first=element.p2Score->sText.length()>0?stoi(element.p2Score->sText):0;
|
|
player3Score[index].first=element.p3Score->sText.length()>0?stoi(element.p3Score->sText):0;
|
|
}else{
|
|
player1Score[index-12].second=element.p1Score->sText.length()>0?stoi(element.p1Score->sText):0;
|
|
player2Score[index-12].second=element.p2Score->sText.length()>0?stoi(element.p2Score->sText):0;
|
|
player3Score[index-12].second=element.p3Score->sText.length()>0?stoi(element.p3Score->sText):0;
|
|
}
|
|
element.p2Score->bHasBackground=element.label->bHasBackground=false;
|
|
element.p3Score->bHasBackground=element.label->bHasBackground=false;
|
|
index++;
|
|
}
|
|
calculating=true;
|
|
calculationStep=0;
|
|
totalCalculationSteps=cases.size()*2;
|
|
bestComboA={};
|
|
bestComboB={};
|
|
}
|
|
QuickGUI::TextBox*prevActiveBox=activeBox;
|
|
if(GetMouse(0).bPressed&&(GetMouseY()<ScreenHeight()-(4-(0-1)/3)*26+2||GetMouseX()>2+((10-1)/3)*50+2)){
|
|
prevActiveBox=nullptr;
|
|
activeBox=nullptr;
|
|
}
|
|
gui.Update(this);
|
|
gui.Draw(this);
|
|
|
|
if(highestEX!=0){
|
|
DrawString({112,4},std::to_string(highestEX)+" EX",YELLOW);
|
|
}
|
|
if(!calculating){
|
|
if(prevActiveBox!=nullptr){
|
|
for(int i=0;i<inputButtons.size();i++){
|
|
inputButtons[i]->bVisible=true;
|
|
inputButtons[i]->Enable(true);
|
|
if(inputButtons[i]->bPressed){
|
|
if(i==10){
|
|
prevActiveBox->sText=prevActiveBox->sText.substr(0,std::max(0,int(prevActiveBox->sText.length())-1));
|
|
}else{
|
|
if(prevActiveBox->sText.length()<4){
|
|
prevActiveBox->sText+=inputButtons[i]->sText;
|
|
}
|
|
}
|
|
activeBox=prevActiveBox;
|
|
prevActiveBox->m_bTextEdit=true;
|
|
TextEntryEnable(true,prevActiveBox->sText);
|
|
}
|
|
}
|
|
}else{
|
|
for(int i=0;i<inputButtons.size();i++){
|
|
inputButtons[i]->bVisible=false;
|
|
inputButtons[i]->Enable(false);
|
|
}
|
|
}
|
|
}
|
|
if(calculating){
|
|
activeBox=nullptr;
|
|
if(calculationStep<cases.size()){
|
|
Evaluate(calculationStep,true);
|
|
}else{
|
|
Evaluate(calculationStep%cases.size(),false);
|
|
}
|
|
|
|
FillRect({0,ScreenHeight()-12},{ScreenWidth(),12},DARK_GREY);
|
|
FillRect({0,ScreenHeight()-12},{int(calculationStep/float(totalCalculationSteps)*ScreenWidth()),12},WHITE);
|
|
DrawRect({0,ScreenHeight()-12},{ScreenWidth(),12},BLACK);
|
|
|
|
if(calculationStep==totalCalculationSteps){
|
|
highestEX=0;
|
|
SongCombinations picked1,picked2;
|
|
for(SongCombinations&A:bestComboA){
|
|
for(SongCombinations&B:bestComboB){
|
|
if(A.totalEX+B.totalEX>highestEX&&A.p1Picked.size()+B.p1Picked.size()<=4&&A.p2Picked.size()+B.p2Picked.size()<=4&&A.p3Picked.size()+B.p3Picked.size()<=4){
|
|
highestEX=A.totalEX+B.totalEX;
|
|
picked1=A;
|
|
picked2=B;
|
|
std::cout<<"New Best Song Combinations found for Final Picks - Total EX: "<<highestEX<<":"<<std::endl;
|
|
std::cout<<"\t Set A: ";
|
|
for(std::pair<int,int>&p1:picked1.p1){
|
|
std::cout<<"P1["<<p1.first<<"]:"<<p1.second<<" ";
|
|
}
|
|
for(std::pair<int,int>&p2:picked1.p2){
|
|
std::cout<<"P2["<<p2.first<<"]:"<<p2.second<<" ";
|
|
}
|
|
for(std::pair<int,int>&p3:picked1.p3){
|
|
std::cout<<"P3["<<p3.first<<"]:"<<p3.second<<" ";
|
|
}
|
|
std::cout<<std::endl;
|
|
std::cout<<"\t Set B: ";
|
|
for(std::pair<int,int>&p1:picked2.p1){
|
|
std::cout<<"P1["<<p1.first<<"]:"<<p1.second<<" ";
|
|
}
|
|
for(std::pair<int,int>&p2:picked2.p2){
|
|
std::cout<<"P2["<<p2.first<<"]:"<<p2.second<<" ";
|
|
}
|
|
for(std::pair<int,int>&p3:picked2.p3){
|
|
std::cout<<"P3["<<p3.first<<"]:"<<p3.second<<" ";
|
|
}
|
|
std::cout<<std::endl;
|
|
}
|
|
}
|
|
}
|
|
calculating=false;
|
|
calculateButton->bPressed=false;
|
|
calculateButton->Enable(true);
|
|
int index=0;
|
|
for(SongElement&element:songs){
|
|
element.p1Score->Enable(true);
|
|
element.p2Score->Enable(true);
|
|
element.p3Score->Enable(true);
|
|
if(index<12){
|
|
if(picked1.p1Picked.count(index)){element.p1Score->bHasBackground=element.label->bHasBackground=true;}
|
|
if(picked1.p2Picked.count(index)){element.p2Score->bHasBackground=element.label->bHasBackground=true;}
|
|
if(picked1.p3Picked.count(index)){element.p3Score->bHasBackground=element.label->bHasBackground=true;}
|
|
}else{
|
|
if(picked2.p1Picked.count(index-12)){element.p1Score->bHasBackground=element.label->bHasBackground=true;}
|
|
if(picked2.p2Picked.count(index-12)){element.p2Score->bHasBackground=element.label->bHasBackground=true;}
|
|
if(picked2.p3Picked.count(index-12)){element.p3Score->bHasBackground=element.label->bHasBackground=true;}
|
|
}
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
int main()
|
|
{
|
|
ChampionsLeaguePointSolver solver;
|
|
if (solver.Construct(320, 320, 4, 4))
|
|
solver.Start();
|
|
return 0;
|
|
} |