|
|
|
@ -1,14 +1,17 @@ |
|
|
|
|
#pragma region Hidden Setup Stuff |
|
|
|
|
#pragma region Includes |
|
|
|
|
#define OLC_PGE_APPLICATION |
|
|
|
|
#include "olcPixelGameEngine.h" |
|
|
|
|
#include <set> |
|
|
|
|
|
|
|
|
|
using namespace olc; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum Run{ |
|
|
|
|
FILE1, |
|
|
|
|
FILE2 |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#pragma endregion |
|
|
|
|
#pragma region Hidden Setup Stuff |
|
|
|
|
// Override base class with your custom functionality
|
|
|
|
|
class AoC2023 : public olc::PixelGameEngine |
|
|
|
|
{ |
|
|
|
@ -23,6 +26,7 @@ void wait(int pauseMs=0){ |
|
|
|
|
|
|
|
|
|
#pragma endregion |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const int DAY = 7; |
|
|
|
|
Run runInput=FILE2; |
|
|
|
|
|
|
|
|
@ -38,7 +42,7 @@ friend std::ostream&operator<<(std::ostream&rhs,const Hand&hand){ |
|
|
|
|
} |
|
|
|
|
rhs<<",,"<<hand.bid; |
|
|
|
|
return rhs; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
enum{ |
|
|
|
|
FIVE_OF_A_KIND, |
|
|
|
@ -50,6 +54,307 @@ enum{ |
|
|
|
|
HIGH_CARD |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
int CalculateHandRank(Hand&hand){ |
|
|
|
|
int maxSame=0; |
|
|
|
|
int twoOfAKindCount=0; |
|
|
|
|
for(auto&[key,value]:hand.cardCounts){ |
|
|
|
|
if(value>maxSame)maxSame=value; |
|
|
|
|
if(value==2)twoOfAKindCount++; |
|
|
|
|
} |
|
|
|
|
if(maxSame==5)return FIVE_OF_A_KIND; |
|
|
|
|
else if(maxSame==4)return FOUR_OF_A_KIND; |
|
|
|
|
else if(maxSame==3){ |
|
|
|
|
if(twoOfAKindCount>0){ |
|
|
|
|
return FULL_HOUSE; |
|
|
|
|
}else{ |
|
|
|
|
return THREE_OF_A_KIND; |
|
|
|
|
} |
|
|
|
|
}else if(maxSame==2){ |
|
|
|
|
if(twoOfAKindCount==2){ |
|
|
|
|
return TWO_PAIR; |
|
|
|
|
}else{ |
|
|
|
|
return ONE_PAIR; |
|
|
|
|
} |
|
|
|
|
}else return HIGH_CARD; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
void doStuff2(){ |
|
|
|
|
while(true){ //lines is accessible as a global.
|
|
|
|
|
std::vector<Hand>hands; |
|
|
|
|
for(std::string&line:lines){ |
|
|
|
|
Hand hand; |
|
|
|
|
for(int i=0;i<5;i++){ |
|
|
|
|
int cardRank=0; |
|
|
|
|
switch(line[i]){ |
|
|
|
|
case 'J':cardRank=0;break; |
|
|
|
|
case '2':cardRank=1;break; |
|
|
|
|
case '3':cardRank=2;break; |
|
|
|
|
case '4':cardRank=3;break; |
|
|
|
|
case '5':cardRank=4;break; |
|
|
|
|
case '6':cardRank=5;break; |
|
|
|
|
case '7':cardRank=6;break; |
|
|
|
|
case '8':cardRank=7;break; |
|
|
|
|
case '9':cardRank=8;break; |
|
|
|
|
case 'T':cardRank=9;break; |
|
|
|
|
case 'Q':cardRank=10;break; |
|
|
|
|
case 'K':cardRank=11;break; |
|
|
|
|
case 'A':cardRank=12;break; |
|
|
|
|
} |
|
|
|
|
hand.cards.push_back(cardRank); |
|
|
|
|
hand.cardCounts[cardRank]++; |
|
|
|
|
} |
|
|
|
|
hand.bid=std::stoi(line.substr(5)); |
|
|
|
|
hands.push_back(hand); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto findHighestCardNonJoker=[](Hand&hand){ |
|
|
|
|
int highest=-1; |
|
|
|
|
for(int i=0;i<hand.cards.size();i++){ |
|
|
|
|
if(hand.cards[i]!=0&&hand.cards[i]>highest)highest=hand.cards[i]; |
|
|
|
|
} |
|
|
|
|
return highest; |
|
|
|
|
}; |
|
|
|
|
auto findMostFrequentCardNonJoker=[](Hand&hand){ |
|
|
|
|
int highest=-1; |
|
|
|
|
int count=-1; |
|
|
|
|
for(auto&[key,value]:hand.cardCounts){ |
|
|
|
|
if(key!=0){ |
|
|
|
|
if(value>count){ |
|
|
|
|
highest=key; |
|
|
|
|
count=value; |
|
|
|
|
}else |
|
|
|
|
if(value==count&&key>highest){ |
|
|
|
|
highest=key; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return highest; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
auto CreateHand = [](std::vector<int>&newHand)->Hand{ |
|
|
|
|
Hand h; |
|
|
|
|
for(int i:newHand){ |
|
|
|
|
h.cards.push_back(i); |
|
|
|
|
h.cardCounts[i]++; |
|
|
|
|
} |
|
|
|
|
return h; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
for(int counter=0;Hand&hand:hands){ |
|
|
|
|
if(hand.cardCounts[0]>0){ |
|
|
|
|
int bestRank=HIGH_CARD; |
|
|
|
|
std::map<int,int>bestCardCount; |
|
|
|
|
std::set<int>jokerToCardNumbers; |
|
|
|
|
for(auto&[key,value]:hand.cardCounts){ |
|
|
|
|
if(key!=0)jokerToCardNumbers.insert(key); |
|
|
|
|
} |
|
|
|
|
std::vector<int>jokerPositions; |
|
|
|
|
for(int counter=0;int i:hand.cards){ |
|
|
|
|
if(i==0)jokerPositions.push_back(counter); |
|
|
|
|
counter++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(jokerPositions.size()==5){ |
|
|
|
|
bestRank=FIVE_OF_A_KIND; |
|
|
|
|
bestCardCount=hand.cardCounts; |
|
|
|
|
goto done; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(jokerPositions.size()==4){ |
|
|
|
|
for(auto&key:jokerToCardNumbers){ |
|
|
|
|
std::vector<int>newHand=hand.cards; |
|
|
|
|
newHand[jokerPositions[0]]=key; |
|
|
|
|
for(auto&key:jokerToCardNumbers){ |
|
|
|
|
std::vector<int>newHand2=newHand; |
|
|
|
|
newHand2[jokerPositions[1]]=key; |
|
|
|
|
for(auto&key:jokerToCardNumbers){ |
|
|
|
|
std::vector<int>newHand3=newHand2; |
|
|
|
|
newHand3[jokerPositions[2]]=key; |
|
|
|
|
for(auto&key:jokerToCardNumbers){ |
|
|
|
|
std::vector<int>newHand4=newHand3; |
|
|
|
|
newHand4[jokerPositions[3]]=key; |
|
|
|
|
Hand newHand=CreateHand(newHand4); |
|
|
|
|
int rank=CalculateHandRank(newHand); |
|
|
|
|
if(rank<bestRank){ |
|
|
|
|
bestRank=rank; |
|
|
|
|
bestCardCount=newHand.cardCounts; |
|
|
|
|
if(bestRank==FIVE_OF_A_KIND)goto done; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}else |
|
|
|
|
if(jokerPositions.size()==3){ |
|
|
|
|
for(auto&key:jokerToCardNumbers){ |
|
|
|
|
std::vector<int>newHand=hand.cards; |
|
|
|
|
newHand[jokerPositions[0]]=key; |
|
|
|
|
for(auto&key:jokerToCardNumbers){ |
|
|
|
|
std::vector<int>newHand2=newHand; |
|
|
|
|
newHand2[jokerPositions[1]]=key; |
|
|
|
|
for(auto&key:jokerToCardNumbers){ |
|
|
|
|
std::vector<int>newHand3=newHand2; |
|
|
|
|
newHand3[jokerPositions[2]]=key; |
|
|
|
|
Hand newHand=CreateHand(newHand3); |
|
|
|
|
int rank=CalculateHandRank(newHand); |
|
|
|
|
if(rank<bestRank){ |
|
|
|
|
bestRank=rank; |
|
|
|
|
bestCardCount=newHand.cardCounts; |
|
|
|
|
if(bestRank==FIVE_OF_A_KIND)goto done; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}else |
|
|
|
|
if(jokerPositions.size()==2){ |
|
|
|
|
for(auto&key:jokerToCardNumbers){ |
|
|
|
|
std::vector<int>newHand=hand.cards; |
|
|
|
|
newHand[jokerPositions[0]]=key; |
|
|
|
|
for(auto&key:jokerToCardNumbers){ |
|
|
|
|
std::vector<int>newHand2=newHand; |
|
|
|
|
newHand2[jokerPositions[1]]=key; |
|
|
|
|
Hand newHand=CreateHand(newHand2); |
|
|
|
|
int rank=CalculateHandRank(newHand); |
|
|
|
|
if(rank<bestRank){ |
|
|
|
|
bestRank=rank; |
|
|
|
|
bestCardCount=newHand.cardCounts; |
|
|
|
|
if(bestRank==FIVE_OF_A_KIND)goto done; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}else{ |
|
|
|
|
for(auto&key:jokerToCardNumbers){ |
|
|
|
|
std::vector<int>newHand0=hand.cards; |
|
|
|
|
newHand0[jokerPositions[0]]=key; |
|
|
|
|
Hand newHand=CreateHand(newHand0); |
|
|
|
|
int rank=CalculateHandRank(newHand); |
|
|
|
|
if(rank<bestRank){ |
|
|
|
|
bestRank=rank; |
|
|
|
|
bestCardCount=newHand.cardCounts; |
|
|
|
|
if(bestRank==FIVE_OF_A_KIND)goto done; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
done: |
|
|
|
|
hand.cardCounts=bestCardCount; |
|
|
|
|
} |
|
|
|
|
counter++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::array<std::vector<int>,7>handScores{}; //Contains indices in hands vector of the different score pools.
|
|
|
|
|
for(int counter=0;Hand&hand:hands){ |
|
|
|
|
handScores[CalculateHandRank(hand)].push_back(counter); |
|
|
|
|
counter++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for(int i:handScores[FIVE_OF_A_KIND]){ |
|
|
|
|
Hand&h=hands[i]; |
|
|
|
|
std::map<int,int>cards; |
|
|
|
|
for(int card:h.cards){ |
|
|
|
|
cards[card]++; |
|
|
|
|
} |
|
|
|
|
if(cards.size()!=1){ |
|
|
|
|
if(cards[0]==0){ |
|
|
|
|
throw; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for(int i:handScores[FOUR_OF_A_KIND]){ |
|
|
|
|
Hand&h=hands[i]; |
|
|
|
|
std::map<int,int>cards; |
|
|
|
|
for(int card:h.cards){ |
|
|
|
|
cards[card]++; |
|
|
|
|
} |
|
|
|
|
if(cards.size()!=2){ |
|
|
|
|
if(cards[0]==0)throw; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for(int i:handScores[FULL_HOUSE]){ |
|
|
|
|
Hand&h=hands[i]; |
|
|
|
|
std::map<int,int>cards; |
|
|
|
|
int card1=-1; |
|
|
|
|
int card2=-1; |
|
|
|
|
for(int card:h.cards){ |
|
|
|
|
if(card1==card||card2==card)continue; |
|
|
|
|
if(card==0)continue; |
|
|
|
|
if(card1==-1)card1=card; |
|
|
|
|
else if(card2==-1)card2=card; |
|
|
|
|
else if(card!=0)throw; |
|
|
|
|
} |
|
|
|
|
if(card1==-1||card2==-1)throw; |
|
|
|
|
} |
|
|
|
|
for(int i:handScores[THREE_OF_A_KIND]){ |
|
|
|
|
Hand&h=hands[i]; |
|
|
|
|
bool threeFound=false; |
|
|
|
|
bool twoFound=false; |
|
|
|
|
for(auto&[key,value]:h.cardCounts){ |
|
|
|
|
if(value==3)threeFound=true; |
|
|
|
|
if(value==2)throw; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for(int i:handScores[TWO_PAIR]){ |
|
|
|
|
Hand&h=hands[i]; |
|
|
|
|
int pairCounts=0; |
|
|
|
|
for(auto&[key,value]:h.cardCounts){ |
|
|
|
|
if(value==2)pairCounts++; |
|
|
|
|
} |
|
|
|
|
if(pairCounts!=2)throw; |
|
|
|
|
} |
|
|
|
|
for(int i:handScores[ONE_PAIR]){ |
|
|
|
|
Hand&h=hands[i]; |
|
|
|
|
int pairCounts=0; |
|
|
|
|
for(auto&[key,value]:h.cardCounts){ |
|
|
|
|
if(value==2)pairCounts++; |
|
|
|
|
} |
|
|
|
|
if(pairCounts!=1)throw; |
|
|
|
|
} |
|
|
|
|
for(int i:handScores[HIGH_CARD]){ |
|
|
|
|
Hand&h=hands[i]; |
|
|
|
|
for(auto&[key,value]:h.cardCounts){ |
|
|
|
|
if(key==0&&value>0)throw; |
|
|
|
|
} |
|
|
|
|
if(h.cardCounts.size()<5)throw; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
auto handSort=[&](int h1,int h2){ |
|
|
|
|
std::vector<int>&cards1=hands[h1].cards; |
|
|
|
|
std::vector<int>&cards2=hands[h2].cards; |
|
|
|
|
for(int i=0;i<5;i++){ |
|
|
|
|
if(cards1[i]>cards2[i])return true; |
|
|
|
|
else if(cards2[i]>cards1[i])return false; |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
for(int i=0;i<=HIGH_CARD;i++){ |
|
|
|
|
if(handScores[i].size()>1){ |
|
|
|
|
std::sort(handScores[i].begin(),handScores[i].end(),handSort); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
long long score=0; |
|
|
|
|
|
|
|
|
|
int rank=hands.size(); |
|
|
|
|
for(int i=0;i<=HIGH_CARD;i++){ |
|
|
|
|
std::cout<<"----------------"<<std::endl; |
|
|
|
|
for(int hand:handScores[i]){ |
|
|
|
|
Hand&h=hands[hand]; |
|
|
|
|
std::cout<<h<<std::endl; |
|
|
|
|
score+=h.bid*rank; |
|
|
|
|
rank--; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::cout<<score<<std::endl; |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
//wait(0); //Wait for 0ms and render the screen (calls draw())
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void doStuff(){ |
|
|
|
|
while(true){ //lines is accessible as a global.
|
|
|
|
|
std::vector<Hand>hands; |
|
|
|
@ -173,7 +478,7 @@ public: |
|
|
|
|
|
|
|
|
|
bool OnUserUpdate(float fElapsedTime) override |
|
|
|
|
{ |
|
|
|
|
static std::thread aocSolver(&AoC2023::doStuff,this); |
|
|
|
|
static std::thread aocSolver(&AoC2023::doStuff2,this); |
|
|
|
|
|
|
|
|
|
if(waitForRender){ |
|
|
|
|
draw(); |
|
|
|
|