# 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 ;
}