Open Side Menu Go to the Top
Register
SnG Luck Analyzer (Beta) SnG Luck Analyzer (Beta)

01-27-2008 , 07:13 PM
Any chance we can get this to work with tourney manager please.... I dont use poker tracker and from the looks of things it doesn't work properly with pokerstars anyway. I had a quick look at importing my hand historys to poker tracker but I don't have the summarys so I can't fix the buyin problem.
SnG Luck Analyzer (Beta) Quote
01-27-2008 , 08:55 PM
In Poker Tracker under File | T results you can auto-request tourney summaries.
SnG Luck Analyzer (Beta) Quote
01-28-2008 , 08:45 AM
Thanks Juk, looks nice. I exported these from pokertracker, no errors except 92 tourneys that I had only imported the summary for, those tourneys didn't work at all. 11s and 22s are March-July 07, 33s and 55s July-December 07. Seems kinda strange to have that big of a difference or maybe it's something different with the way the games play? FWIW, I actually ran hot in the 33s. Google docs didn't wanna import the file with all tourneys together and oo freezes when I try to resize the graph. Total for the 3,768 tourneys (11,578 data points) is +579.063% and -t21,841 (the csv file says it's -2.18414e+006 ?).

450 11s


1357 33s


1040 33s


921 55s
SnG Luck Analyzer (Beta) Quote
01-28-2008 , 11:29 AM
I am too lazy to read the whole thread, but I get this error: "invalid Pokertracker database". I get that by all the databases I try to select.
SnG Luck Analyzer (Beta) Quote
01-28-2008 , 02:07 PM
Quote:
Originally Posted by Finnisher
Thanks Juk, looks nice. I exported these from pokertracker, no errors except 92 tourneys that I had only imported the summary for, those tourneys didn't work at all.
Yep, there isn't much you can do from just the summary as there's no data-points to compare.

Quote:
11s and 22s are March-July 07, 33s and 55s July-December 07. Seems kinda strange to have that big of a difference or maybe it's something different with the way the games play?
I still can't be 100% sure that there isn't a nasty bug lurking in there, but I've tried pretty hard to verify that there isn't. I re-tested the 2-way and 3-way outcome/pot-shareout code vs Monte Carlo and got the same results, so I can be pretty sure that that bit is working 100%. I also ran a very long backtest on datamined hands and the cumulative $EV graph didn't show signs of divergence and (P(lose|actual)-P(lose|expected))/N ended up at ~-0.0001, so that looks OK too.

It's surprising though how much variance you can get from even a fairly large sub-sample: 50% of 1.3M data-points came out at anything from +10000% to -10000% after a few different runs.

Perhaps one other idea would be to plot the $EV luck graph with a scaled version of your actual winnings. When I compared my PT graph with the $EV luck graph for last year, then the places where I had very big downswings and long break-even stretches matched up quite well with the $EV luck graph (another reason to believe that it is working correctly).

Quote:
FWIW, I actually ran hot in the 33s.
It could just be that you ran hot in a "different way", but didn't run so well for "all-in luck". -200% isn't really that much and I'm down about -1000% just this year so far (and was up as high as +4000% for parts of last year). It could just be that you "ran hot" at the 33s when it came to your own cards and/or the cards you were pushing into, but didn't run so well when it came to the all-ins. I don't really know how you can qualify "dealt hands luck", other than for running into hands like AA and KK which you know an opponent will never fold.

Quote:
Google docs didn't wanna import the file with all tourneys together and oo freezes when I try to resize the graph.
Yep, I managed to crash my whole PC trying to import a huge csv file into Statistica the other day. I'll fix that (at the same time as I fix the hand # ordering problem) by sampling to take <10,000 points at the end.

Quote:
Total for the 3,768 tourneys (11,578 data points) is +579.063% and -t21,841 (the csv file says it's -2.18414e+006 ?).
I think +600% seems well within reason (I've not really been plotting cEV and the crazy csv cEV output is prolly just a bug... I'll look into fixing it).

Juk

PS: ImageShack is being a real pain again and your 11s graph is not showing up for me for some reason?
SnG Luck Analyzer (Beta) Quote
01-28-2008 , 04:13 PM
Quote:
Originally Posted by jukofyork
Yep, there isn't much you can do from just the summary as there's no data-points to compare.
No they were the summaries party e-mails, with all the hands. But they're different format than the files the client saves

Quote:
Perhaps one other idea would be to plot the $EV luck graph with a scaled version of your actual winnings. When I compared my PT graph with the $EV luck graph for last year, then the places where I had very big downswings and long break-even stretches matched up quite well with the $EV luck graph (another reason to believe that it is working correctly).
Ya my graphs for 11s, 22s and 55s match up with the EV graphs. 33s are weird, I actually won during the drop at the end while at 55s I had a 30+ bi drop So ya showdown luck isn't everything

Quote:
PS: ImageShack is being a real pain again and your 11s graph is not showing up for me for some reason?
Ya it seems to be dead so here it is, with sngla graph.



And sngla graph for 55s

SnG Luck Analyzer (Beta) Quote
01-28-2008 , 04:41 PM
Quote:
Originally Posted by Finnisher
No they were the summaries party e-mails, with all the hands. But they're different format than the files the client saves
Ah, I see - I'll have a look and see how easy it would be to get them working too.

Quote:
Ya my graphs for 11s, 22s and 55s match up with the EV graphs. 33s are weird, I actually won during the drop at the end while at 55s I had a 30+ bi drop So ya showdown luck isn't everything
I think this is useful to have for comparison, so I'll try and add a scaled version of the winnings to the csv file.

Will post the updated version sometime later today.

Juk
SnG Luck Analyzer (Beta) Quote
01-28-2008 , 10:12 PM
New version: http://www.jukofyork.com/Juks_BackTestAllInLuck.rar

Instructions
1) Download it and unrar it to a folder somewhere.
2) Copy some of your 10-man Party HH files into the same folder.
3) Run the batch file called "RunMe.bat" and leave it to do it's work
4) After it's finished it will tell you your total $EV (and cEV) luck differences along with actual/adjusted winnings and ROI.
5) It will also create a file called "luck_results.csv" which you can load into Excel to plot your cumulative winnings and luck.

NOTE: It doesn't work with anything other than Party 10-man SNGs.

Code:
// ***************************************************************************
// *                                  INCLUDES                               *
// ***************************************************************************

#include <vector>
#include <map>
#include <string>
#include <algorithm>

#include "../core/misc.h"
#include "../core/random_number_generator.h"

#include "../holdem_game_state.h"
#include "../holdem_game_state_with_history.h"
#include "../holdem_hole_card_ranking.h"
#include "../sng_icm_calculator.h"
#include "../holdem_parser.h"

#include "../party_nl_holdem_sng_parser.h"

// ***************************************************************************
// *                                  CONSTANTS                              *
// ***************************************************************************

// This the the fee we pay to enter in terms of prize pool.
#define ENTRY_FEE_PERCENTAGE 11.0						// 11% for Party 10-man.

// ***************************************************************************
// *                                 STRUCTURES                              *
// ***************************************************************************

// Used to hold a single data-point (for sort based on hand # at end).
typedef struct DataPoint {
	char   TournamentNumber[MAX_HAND_NUMBER_CHARS+1];	// Used to index into our own prize.
	char   HandNumber[MAX_HAND_NUMBER_CHARS+1];			// Used as sort key.
	double PrizeEquityDifference;						// $EV_actual-$EV_expected (in %)
	double ChipEquityDifference;						// cEV_actual-cEV_expected (in t)
} DataPoint;

// Order based using Tournament number as primary key and Hand number as secondary.
// NOTE: This won't be quite right if we multi-table, but can't just use hand #...
bool operator<(const DataPoint& D1,const DataPoint& D2) {
	if (strcmp(D1.TournamentNumber,D2.TournamentNumber)==0)
		return (strcmp(D1.HandNumber,D2.HandNumber)<0?true:false);
	else
		return (strcmp(D1.TournamentNumber,D2.TournamentNumber)<0?true:false);
}

// ===========================================================================

void BackTestAllInLuck(const char** Folders,const int NumFolders)
{	

	// The parser we are going to use.
	PartyNLHoldemSNGParser Parser;

	// The vector of hands we get from the parser.
	vector<HoldemGameStateWithHistory> Hands;

	// The vector of data-points (so we can sort at the end).
	vector<DataPoint> DataPoints;

	// This holds the result of each tournament.
	typedef pair<string,double>	TournamentResultPair;
	map<string,double>			TournamentResultMap;

	// This is what we use to get the EV at the end of the hand.
	SNG_ICM_Calculator ICM;

	// The number of 2-way, 3-way and multi-way data-points seperately.
	int Num2WayAllIns=0;
	int Num3WayAllIns=0;
	int NumMultiWayAllIns=0;										// We don't deal with these atm.

	// These are the possible finish rankings for each outcome.
	const int TwoWayFinishRanking[3][2]    = {{1,1},  {1,2},  {2,1}};
	const int ThreeWayFinishRanking[13][3] = {{1,1,1},{1,1,2},{1,2,1},
											  {1,2,2},{1,2,3},{1,3,2},
											  {2,1,2},{2,2,1},{2,1,3},
											  {2,3,1},{2,1,1},{3,1,2},
	                                          {3,2,1}};

	// These hold the outcomes for each 2-way and 3-way hand matchup.
	// NOTE: Use floats to reduce memory consumption.
	static float TwoWayOutcomeChances[3][169][169];
	static float ThreeWayOutcomeChances[13][169][169][169];

	// *************************************************************************
	// ************** LOAD THE LOOKUP AND/OR CREATE BINARY VERSIONS ************
	// *************************************************************************

	// Have to use two different once because C++ messes up on 2nd use...
	ifstream InFile1,InFile2;

	// This flag gets unset if we failed to loaded either of the (fast) binary versions ok.
	bool LoadedBinary=true;

	// Lets first try and open the binary versions.
	InFile1.open("2WAY_HandEval_binary.dat",ios::binary);
	InFile2.open("3WAY_HandEval_binary.dat",ios::binary);

	// If all ok, then read these instead.
	if (!InFile1.fail() && !InFile2.fail()) {
		InFile1.read((char*)&TwoWayOutcomeChances,sizeof(TwoWayOutcomeChances));
		InFile2.read((char*)&ThreeWayOutcomeChances,sizeof(ThreeWayOutcomeChances));
	}		
	else {
		LoadedBinary=false;
	}

	// Close the input files.
	InFile1.close();
	InFile2.close();

	// if we couldn't open the binary versions, lets load from the test and then save the binary again.
	if (LoadedBinary==false) {

		// Have to use two different once because C++ messes up on 2nd use...
		ifstream InFileT1,InFileT2;

		// Have to use two different once because C++ messes up on 2nd use...
		ofstream OutFile1,OutFile2;

		// Use for reading in the outcome look files.
		int H1,H2,H3;
		double Outcome;

		// Tell the user what's going on.
		cout << "Failed to load binary equity lookup tables. Re-creating them now... "; cout.flush();

		// Open and read each line of the test data files.
		// NOTE: Inversed as HoldemHoleCardRanking::GetIndex() uses AA in top left, A2s top right, etc.
		InFileT1.open("2WAY_HandEval.dat");
		InFileT2.open("3WAY_HandEval.dat");

		// If all ok, then read these in.
		if (InFileT1.fail() || InFileT2.fail())
			Error(FATAL,"Could not load the (text) equity lookups.");
		while (InFileT1 >> H1 >> H2) {
			for (int I=0;I<3;I++)
				InFileT1 >> TwoWayOutcomeChances[I][168-H1][168-H2];
		}
		while (InFileT2 >> H1 >> H2 >> H3) {
			for (int I=0;I<13;I++)
				InFileT2 >> ThreeWayOutcomeChances[I][168-H1][168-H2][168-H3];
		}

		// Close the input files.
		InFileT1.close();
		InFileT2.close();

		// Lets save the binary versions for use next time.
		OutFile1.open("2WAY_HandEval_binary.dat",ios::binary);
		OutFile2.open("3WAY_HandEval_binary.dat",ios::binary);

		// If all OK, save them out.
		if (OutFile1.fail() || OutFile2.fail())
			Error(FATAL,"Could not save the (binary) equity lookups.");
		OutFile1.write((char*)&TwoWayOutcomeChances,sizeof(TwoWayOutcomeChances));
		OutFile2.write((char*)&ThreeWayOutcomeChances,sizeof(ThreeWayOutcomeChances));

		// Close the output files.
		OutFile1.close();
		OutFile2.close();

		// All done creating them now.
		cout << "Done." << endl;

	}

	// *************************************************************************
	// *************************************************************************

	// Lets do it on each folder.
	for (int Folder=0;Folder<NumFolders;Folder++) {

		// Lets try and get the first vector of hands.
		Parser.InitHandHistorySearcher(Folders[Folder]);
		while (Parser.SearchForAndParseNextHandHistoryFile(Hands,true)==true) {

			// Lets keep going until we get no more.
			for (int I=0;I<Hands.size();I++) {

				// The stacks for each player at the start and end of hand.
				int StackAtStartOfHand[10];
				int StackAtEndOfHand[10];

				// The number of players left at the end of the hand (used to test for game over).
				int NumPlayersLeftAtEndOfHand;

				// If we're not here or not all-in, then skip it (data-mined or after we busted).
				if (Hands[I].GetOurSeatIndex()==NO_SEAT
					|| Hands[I].IsInHandCurrently(Hands[I].GetOurSeatIndex())==false) {
					continue;
				}

				// Lets work out the stacks at the start/end of the hand.
				NumPlayersLeftAtEndOfHand=0;
				for (int K=0;K<10;K++) {
					StackAtStartOfHand[K]=0;
					StackAtEndOfHand[K]=0;
				}
				for (int K=0;K<10;K++) {
					if (Hands[I].WasInHandAtStartOfHand(K)==true) {
						StackAtStartOfHand[K]=Hands[I].GetStackAtStartOFHand(K);
						StackAtEndOfHand[K]=Hands[I].GetCurrentStack(K)+Hands[I].GetUnCalledBets(K)+Hands[I].GetAmountWon(K);
						if (StackAtEndOfHand[K]>0)
							NumPlayersLeftAtEndOfHand++;
					}
				}

				// Check we have not lost any chips.
				// #### NOTE: This happens for truncated HH files where their is no "wins" line...
				int TotalChipsStart=0;
				int TotalChipsEnd=0;
				for (int K=0;K<10;K++) {
					TotalChipsStart+=StackAtStartOfHand[K];
					TotalChipsEnd+=StackAtEndOfHand[K];
				}
				if (TotalChipsStart!=TotalChipsEnd) {
					Error(WARNING,Hands[I].GetHandNumber(),"Chips at end of hand != start of hand. Ignoreing hand...");
					continue;
				}

				// If we just busted out or the game is over, we need to calculate and store the tournament result for us.
				// @@@ We re-caluclate this below, but prolly won't slow down too much...
				if (ICM.TestBustout(StackAtStartOfHand,StackAtEndOfHand,Hands[I].GetOurSeatIndex())==true) {
					TournamentResultMap.insert(TournamentResultPair(Hands[I].GetTournamentNumber(),
											   ICM.CalculateBustoutPrizeEV(StackAtStartOfHand,StackAtEndOfHand,Hands[I].GetOurSeatIndex())
											   *100.0));
				}
				else if (NumPlayersLeftAtEndOfHand==1) {
					TournamentResultMap.insert(TournamentResultPair(Hands[I].GetTournamentNumber(),
											   ICM.CalculatePrizeEV(StackAtEndOfHand,Hands[I].GetOurSeatIndex())*100.0));
				}

				// If we have gone from pre-flop to river, then this is an all-in hand.
				if (Hands[I].GetNumStates()>=2
					&& Hands[I].GetCurrentGameStage()==RIVER
					&& Hands[I][Hands[I].GetNumStates()-2].GetCurrentGameStage()==PRE_FLOP
					&& Hands[I].GetTotalInHandCurrently()>=2) {

					// This is the number of all-in players we are dealing with here.
					int NumAllInPlayers=Hands[I].GetTotalInHandCurrently();

					// This is the index of each of the players who are left.
					int PlayerIndex[10];	// ### Only use the first 3, but need 10 incase we start to sim for 4+ players...
					int NumValidShowdownHands=0;

					// The (temp) "finishing rank" assigned depending on outcome.
					int PlayersFinishingRank[10];

					// The chance of each outcome (retrived from the lookup table).
					double ChanceOfOutcome;

					// This holds the rank indexes (0..168) for the player's hand.
					int PlayerHandType[10];

					// These are used to temporailty sim the outcomes.
					int CurrentStacks[10];
					int CurrentStakes[10];
					bool InHandCurrently[10];

					// The actaul EV from the start to end of hand.
					double ActualPrizeEquity,ActualChipEquity;

					// Expected average EV based on the hand matchup.
					double ExpectedPrizeEquity;
					double ExpectedChipEquity;

					// @@@@@@@@@@@@@@ Don't really need this @@@@@@@@@@@@@@@@@@@@@
					// Lets make sure that 1 or both players are all-in.
					int NumNonAllInPlayers=0;
					for (int J=0;J<10;J++) {
						if (Hands[I].IsInHandCurrently(J)==true && Hands[I].GetCurrentStack(J)!=0)
							NumNonAllInPlayers++;
					}
					if (NumNonAllInPlayers>1) {
						Error(WARNING,"Non all-in hand (should not get here...).");
						continue;
					}
					// @@@@@@@@@@@@@@ Don't really need this @@@@@@@@@@@@@@@@@@@@@

					// If the player is in the hand currently and his cards are known, then lets count him and get his seat index.
					for (int J=0;J<10;J++) {
						if (Hands[I].IsInHandCurrently(J)==true && Hands[I].GetShowdownHoleCard(J,0).Rank!=RANK_NONE) {
							PlayerIndex[NumValidShowdownHands]=J;
							PlayerHandType[J]=HoldemHoleCardRanking::GetIndex((Hands[I].GetShowdownHoleCard(J,0).Suit*13)+Hands[I].GetShowdownHoleCard(J,0).Rank,
																			  (Hands[I].GetShowdownHoleCard(J,1).Suit*13)+Hands[I].GetShowdownHoleCard(J,1).Rank);
							NumValidShowdownHands++;	// One more.
						}
					}

					// If we don't have cards for all the players at the end then skip this hand.
					if (NumValidShowdownHands!=NumAllInPlayers)
						continue;

					// At the moment we can only deal with 2-way and 3-way all-in, but we will count the rest.
					if (NumAllInPlayers>3) {
						NumMultiWayAllIns++;
						continue;
					}
					else if (NumAllInPlayers==3) {
						Num3WayAllIns++;
					}
					else {
						Num2WayAllIns++;
					}

					// We must make sure that player's indexes are ordered based on their cards (for lookup into the outcome tables).
					// NOTE: Bubble-sort is fine for this...
					for (int J=0;J<(NumAllInPlayers-1);J++) {
						for (int K=J+1;K<NumAllInPlayers;K++) {
							if (PlayerHandType[PlayerIndex[J]]>PlayerHandType[PlayerIndex[K]]) {
								int Temp=PlayerIndex[J];
								PlayerIndex[J]=PlayerIndex[K];
								PlayerIndex[K]=Temp;
							}
						}
					}

					// Now lets do the calculation for each of the players.
					for (int Player=0;Player<NumAllInPlayers;Player++) {

						// Looks at the hands from our perspective only.
						if (Hands[I].GetOurSeatIndex()!=PlayerIndex[Player])
							continue;

						// Lets print the hand number first. @@@ DEBUG ONLY @@@
						//cerr << Hands[I].GetHandNumber() << ", ";

						// If we didn't just bust out we need to calculate the real EV using ICM.
						// NOTE: Also store here the reult of the SNG (if we busted or won).
						if (ICM.TestBustout(StackAtStartOfHand,StackAtEndOfHand,PlayerIndex[Player])==true)
							ActualPrizeEquity=ICM.CalculateBustoutPrizeEV(StackAtStartOfHand,StackAtEndOfHand,PlayerIndex[Player]);
						else
							ActualPrizeEquity=ICM.CalculatePrizeEV(StackAtEndOfHand,PlayerIndex[Player]);

						// Get the cEV too.
						ActualChipEquity=StackAtEndOfHand[PlayerIndex[Player]];

						// Init ready to sum for each outcome.
						ExpectedPrizeEquity=0.0;
						ExpectedChipEquity=0.0;

						// Lets go through the three possible outcomes.
						for (int OutCome=0;OutCome<(NumAllInPlayers==2?3:13);OutCome++) {

							// We can share the pot much faster if only 2 players.
							if (NumAllInPlayers==2) {

								// Lets assign a finishing rank to each player based on the current outcome index.
								for (int J=0;J<2;J++)
									PlayersFinishingRank[PlayerIndex[J]]=TwoWayFinishRanking[OutCome][J];

								// Get the chance of outcome from the lookup table.
								ChanceOfOutcome=TwoWayOutcomeChances[OutCome][PlayerHandType[PlayerIndex[0]]][PlayerHandType[PlayerIndex[1]]];

								// Lets make a copy of the current stacks and amounts staked.
								// NOTE: For the 2-way code we need to take off the amount staked AFTER we have equalized the stakes below.
								for (int J=0;J<10;J++) {
									CurrentStacks[J]=Hands[I].GetStackAtStartOFHand(J);
									CurrentStakes[J]=Hands[I].GetStackAtStartOFHand(J)-Hands[I].GetCurrentStack(J);
								}

								// Get the chance of outcome from the lookup table.
								ChanceOfOutcome=TwoWayOutcomeChances[OutCome][PlayerHandType[PlayerIndex[0]]][PlayerHandType[PlayerIndex[1]]];

								// Lets return any uncalled bets so they have both staked the same.
								CurrentStakes[PlayerIndex[0]]=Min(CurrentStakes[PlayerIndex[0]],CurrentStakes[PlayerIndex[1]]);
								CurrentStakes[PlayerIndex[1]]=CurrentStakes[PlayerIndex[0]];

								// Now work out the size of the pot available to each left in the hand.
								int CurrentPot=0;
								for (int J=0;J<10;J++) {
									CurrentPot+=CurrentStakes[J];
									CurrentStacks[J]-=CurrentStakes[J]; // Take off now.
								}

								// Lets work out the chance dependig on the outcome type.
								// NOTE: We assign any odd chips to an aribtary player.
								if (PlayersFinishingRank[PlayerIndex[0]]<PlayersFinishingRank[PlayerIndex[1]]) {
									CurrentStacks[PlayerIndex[0]]+=CurrentPot;
								}
								else if (PlayersFinishingRank[PlayerIndex[1]]<PlayersFinishingRank[PlayerIndex[0]]) {
									CurrentStacks[PlayerIndex[1]]+=CurrentPot;
								}
								else {
									CurrentStacks[PlayerIndex[0]]+=(CurrentPot/2)+(CurrentPot%2);
									CurrentStacks[PlayerIndex[1]]+=(CurrentPot/2);
								}

							} // End 2-way pot shareout.

							// Will have to do the slower way for 3 players them.
							else {

								// Lets assign a finishing rank to each player based on the current outcome index.
								for (int J=0;J<3;J++)
									PlayersFinishingRank[PlayerIndex[J]]=ThreeWayFinishRanking[OutCome][J];

								// Get the chance of outcome from the lookup table.
								ChanceOfOutcome=ThreeWayOutcomeChances[OutCome][PlayerHandType[PlayerIndex[0]]][PlayerHandType[PlayerIndex[1]]][PlayerHandType[PlayerIndex[2]]];

								// Lets make a copy of the current stacks, amounts staked and Inhand flags.
								// NOTE: For the 3-way code we need to take off the amount staked BEFORE.
								for (int J=0;J<10;J++) {
									CurrentStacks[J]=Hands[I].GetCurrentStack(J);
									CurrentStakes[J]=Hands[I].GetStackAtStartOFHand(J)-Hands[I].GetCurrentStack(J);
									InHandCurrently[J]=Hands[I].IsInHandCurrently(J);
								}

								// Lets share out all the side-pots.
								for (;;) {

									// Lets set any player who has nothing staked anymore to not be in the hand.
									for (int J=0;J<10;J++)
										if (CurrentStakes[J]==0)
											InHandCurrently[J]=false;					// Not in hand now.

									// Find he smallest amount staked.
									int MinAmountStaked=0x7fffffff;
									for (int J=0;J<10;J++)
										if (InHandCurrently[J]==true)
											MinAmountStaked=Min(MinAmountStaked,CurrentStakes[J]);

									// Create the side-pot and subtract from the staked amounts.
									int CurrentPot=0;
									for (int J=0;J<10;J++) {
										CurrentPot+=Min(CurrentStakes[J],MinAmountStaked);
										CurrentStakes[J]-=Min(CurrentStakes[J],MinAmountStaked);
									}

									// Test if we are done.
									// NOTE: The last side-pot will just be the biggest stack geting his excess chips returned.
									if (CurrentPot==0)
										break;

									// Share out the pot based on the hand rank of each player.
									int NumHandWinners=0;
									int BestHand=0x7fffffff;
									for (int J=0;J<10;J++) {
										if (InHandCurrently[J]==true) {
											if (PlayersFinishingRank[J]<BestHand) {
												NumHandWinners=1;
												BestHand=PlayersFinishingRank[J];
											}
											else if (PlayersFinishingRank[J]==BestHand) {
												NumHandWinners++;
											}
										}
									}

									// Now lets take off the smount they put into the vurrent pot and give them any pot they might need.
									// NOTE: We assign any odd chips to an aribtary player.
									int OddChips=(CurrentPot%NumHandWinners);
									for (int J=0;J<10;J++) {
										if (InHandCurrently[J]==true && PlayersFinishingRank[J]==BestHand) {
											CurrentStacks[J]+=(CurrentPot/NumHandWinners)+OddChips;
											OddChips=0;			// If there were any, they have been assigned now.
										}
									}

								}

							} // End 3-way pot shareout.

							double TempExpectedPrizeEquity,TempExpectedChipEquity,TempPLoseDiff;

							// Work out our $EV for this outcome.
							if (ICM.TestBustout(StackAtStartOfHand,CurrentStacks,PlayerIndex[Player])==true)
								TempExpectedPrizeEquity=ICM.CalculateBustoutPrizeEV(StackAtStartOfHand,CurrentStacks,PlayerIndex[Player]);
							else
								TempExpectedPrizeEquity=ICM.CalculatePrizeEV(CurrentStacks,PlayerIndex[Player]);

							// Work out the cEV for this outcome.
							TempExpectedChipEquity=CurrentStacks[PlayerIndex[Player]];

							// Lets add to the sums.
							ExpectedPrizeEquity+=TempExpectedPrizeEquity*ChanceOfOutcome;
							ExpectedChipEquity+=TempExpectedChipEquity*ChanceOfOutcome;

							// Lets print the EVs and the outcomes. @@@ DEBUG ONLY @@@
							// @@@ This file is gonna be a nightmare to read, as it will have different numbers of feilds for 2-way and 3-way lines...
							//cerr << ChanceOfOutcome << ',' << TempExpectedPrizeEquity << ',' << TempExpectedChipEquity << ", ";

						} // End for each outcome.

						// Lets create and save the reultant data-point.
						DataPoint TempDataPoint;
						strcpy(TempDataPoint.TournamentNumber,Hands[I].GetTournamentNumber());
						strcpy(TempDataPoint.HandNumber,Hands[I].GetHandNumber());
						TempDataPoint.PrizeEquityDifference=(ActualPrizeEquity-ExpectedPrizeEquity)*100.0;	// As %.
						TempDataPoint.ChipEquityDifference=ActualChipEquity-ExpectedChipEquity;				// As t.
						DataPoints.push_back(TempDataPoint);

						// Lets print the EV for this hand. @@@ DEBUG ONLY @@@
						//cerr << ExpectedPrizeEquity << ',' << ActualPrizeEquity << ',' << ActualPrizeEquity-ExpectedPrizeEquity << ", "
						//		<< ExpectedChipEquity << ',' << ActualChipEquity << ',' << ActualChipEquity-ExpectedChipEquity << ", ";

					} // End for each player.

				} // End if valid all-in hand.

			} // End for each hand in hand history.

		} // End for each hand history in folder.

	} // For each folder.

	// *************************************************************************
	// *************************************************************************

	// The number of SNGs we have played.
	int NumValidSNGs=0;
	int NumSNGsSkipped=0;			// Invalid.

	// The number of all-in we have been involved in.
	int NumValidDataPoints=0;
	int NumDataPointsSkipped=0;		// Invalid.

	// The sum of prizes we have won (as %).
	double SumPrizes=0.0;

	// The sum of differences from our predicted EV.
	double SumPrizeEquityDifferences=0.0;
	double SumChipEquityDifferences=0.0;

	// The last tourney number.
	char LastTournamentNumber[MAX_HAND_NUMBER_CHARS+1]={'\0'};

	// The ".csv" file for results to plot.
	ofstream Outfile;

	// Lets sort the DataPoints vector based on tournament (and hand) number.
	sort(DataPoints.begin(),DataPoints.end());

	// Open the output file.
	Outfile.open("luck_results.csv");
	if (Outfile.fail())
		Error(FATAL,"Could not open 'luck_results.csv'");

	// Print the csv headers.
	Outfile << "HandNumber,ActualWinnings,AjustedWinnings,$EV_Luck,cEV_Luck" << endl;

	// Save out each data-point we have.
	int I=0;
	for (map<string,double>::iterator T=TournamentResultMap.begin();T!=TournamentResultMap.end();T++) {

		// One more (valid) SNG.
		NumValidSNGs++;

		// Add to the sum of prizes (seems more sensible to do before each SNG for graphing purposes...).
		SumPrizes+=T->second;

		// If the data-point doesn't have a valid corresponding result, we must skip it.
		if (TournamentResultMap.find(DataPoints[I].TournamentNumber)==TournamentResultMap.end()) {
			Error(WARNING,DataPoints[I].TournamentNumber,"Hero's final hand missing... Ignoreing SNG.");
			NumSNGsSkipped++;
		}
		for (;I<DataPoints.size() && TournamentResultMap.find(DataPoints[I].TournamentNumber)==TournamentResultMap.end();I++)
			NumDataPointsSkipped++;

		// Output all the data-points that correspond to this tournament number.
		for (;I<DataPoints.size() && strcmp((T->first).c_str(),DataPoints[I].TournamentNumber)==0;I++) {

			// One more (valid) data-point.
			NumValidDataPoints++;

			// Add to the cumulative sum of differenes.
			SumPrizeEquityDifferences+=DataPoints[I].PrizeEquityDifference;
			SumChipEquityDifferences+=DataPoints[I].ChipEquityDifference;

			// Lets print each data-point.
			// NOTE: Remeber to take off the 11% fee.
			Outfile << DataPoints[I].HandNumber << ','
					<< SumPrizes-((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE) << ',' 
					<< (SumPrizes-SumPrizeEquityDifferences)-((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE) << ','
					<< SumPrizeEquityDifferences << ',' << SumChipEquityDifferences << endl;

		}

	}

	// Close the output file.
	Outfile.close();

	// Print the difference between expected and real.
	cout << endl << "NumSNGs      : " << NumValidSNGs
		 << " (NumAllIns[2,3,4+]=" << Num2WayAllIns << ',' << Num3WayAllIns << ',' << NumMultiWayAllIns
		 << " / NumDataPoints=" << NumValidDataPoints
		 << ")" << endl
		 << "Actual Won   : " << (int)(SumPrizes-((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE))
		 << "% (Actual ROI=" << ((SumPrizes-((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE))/((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE))*100.0
		 << "%)" << endl 
		 << "Adjusted Won : " << (int)((SumPrizes-SumPrizeEquityDifferences)-((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE))
		 << "% (Adjusted ROI=" << (((SumPrizes-SumPrizeEquityDifferences)-((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE))
								   /((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE))*100.0
		 << "%)" << endl
		 << "$EV Luck     : " << (int)SumPrizeEquityDifferences
		 << "% (" << SumPrizeEquityDifferences/(double)(NumValidDataPoints>0?NumValidDataPoints:1)
		 << "% per all-in)" << endl
		 << "cEV Luck     : " << (int)SumChipEquityDifferences
		 << "t (" << SumChipEquityDifferences/(double)(NumValidDataPoints>0?NumValidDataPoints:1)
		 << "t per all-in)" << endl << endl;

	// Report how many we skipped.
	cout << "NOTE: " << NumSNGsSkipped << " SNGs (" << NumDataPointsSkipped << " data-points) with missing final hands were ignored." << endl;

} // End BackTestAllInLuck.
New for this version
a) We now work out and print at the end both actual and adjusted winnings (+ actual and adjusted ROI).
b) Any SNGs where we didn't see the hero bust or the SNG end are ignored (for ROI and adjusted calculations).
c) We now save cumulative: real winnings, adjusted winnings, $EV luck and cEV luck to the ".csv" file.
d) Fixed a bug where cEV was being scaled by 100 in the ".csv" file.
e) All hands are now sorted based on tournament number (hand number is used as secondary key) for the ".csv" output file.

NOTE: Your ROI might not quite be the same as PT if you have had any crashes where the end of the final hand(s) gets cut off, etc.

NOTE: Your graph might not look the same as the previous version, as I don't think ordering based on filename was working as expected... Your final $EV luck value should be almost the same (depending on how many SNGs get skipped dues to missing Hero's final hand), as it's not dependant on ordering.

Here is an example of plotting real winnings, adjusted winnings and $EV luck:



It looks like $EV luck is definitely capturing some of the variance as the adjusted line is much smoother. It's even smoothed out those 3 big humps at the start of my graph. These correspond to last last Feb/March where I had 3 big downswings/break-even patches... Man I wish I had this back then!

NOTE: If you are new to SNGs and have improved your game over time (I played alot at Pacific before Party) or have systematically moved up levels (I've had about the same ROI for 11s, 22s and 33s and move up/down quite alot depending on the time of day and/or if I have a new Party/Empire nick to exploit), then don't expect your adjusted line to look like mine! It should still look "smoother" though...

Juk
SnG Luck Analyzer (Beta) Quote
01-29-2008 , 05:04 AM
It would be sooooooooo good if I could use the analyser with PostRegDb or (stars) raw HH.

RLY.
SnG Luck Analyzer (Beta) Quote
01-29-2008 , 09:11 AM
That graph is awesome, I can't believe how much variance it has cut out. Please make it work with stars hhs Juk.
SnG Luck Analyzer (Beta) Quote
01-29-2008 , 10:23 AM
Nice graph! It would be awesome if it could be made to work with stars.

I tried using this for 3 party $11s, and in the ActualWin column it gives -11 for a loss, 8 for a 3rd and 17 for a 2nd. Is this normal? I thought it should be 100*.2-11=9 for 3rd and 100*.3-11=19 for 2nd?
SnG Luck Analyzer (Beta) Quote
01-29-2008 , 12:36 PM
Thanks Juk, now it's even better

For some reason it only took a second for Oo to resize this graph with 3 lines. It's about 3750 tourneys total.
SnG Luck Analyzer (Beta) Quote
01-29-2008 , 01:40 PM
Quote:
Originally Posted by dave_w11
Nice graph! It would be awesome if it could be made to work with stars.

I tried using this for 3 party $11s, and in the ActualWin column it gives -11 for a loss, 8 for a 3rd and 17 for a 2nd. Is this normal? I thought it should be 100*.2-11=9 for 3rd and 100*.3-11=19 for 2nd?
Can you double check this and post the cvs file. I just double checked and still got +9 for a 3rd, +19 for a win and +39 for a 3rd, as expected (plus my ROI is spot on when compared to PT).

Juk
SnG Luck Analyzer (Beta) Quote
01-29-2008 , 02:40 PM
The hand history I used may have been from FreePHG rather than being written by partypoker software. Could this be the problem?

One file contains 3 hand histories and I wondered if this was the problem so split it up into seperate files. Now if only 1 of the 3 files are in the folder it gives the expected results for each individual tournament seperately, but if I put all 3 files in the folder the same error occurs.

Code:
HandNumber,ActualWinnings,AjustedWinnings,$EV_Luck,cEV_Luck
6040550851,-11,-8.80256,-2.19744,-446.138
6040557901,-11,-5.25522,-5.74478,-1199.63
6040558744,-11,-13.3458,2.34577,200.854
6040574231,-11,-12.7628,1.76284,71.1461
6040575328,-11,-7.36836,-3.63164,-876.318
6040882819,8,13.8302,-5.83023,-1335.55
6040909054,8,5.13661,2.86339,298.475
6040924365,8,11.9489,-3.94891,-1270.5
6040930531,8,14.0074,-6.00743,-3329.02
6041004085,17,23.6648,-6.66475,-3573.56
6041010825,17,14.8753,2.12468,-1909.59
6041022064,17,17.6244,-0.624366,-2619.19
6041036672,17,10.4297,6.57035,456.627
6041037816,17,19.0518,-2.05181,-3445.7
Here is 1 hand, let me know if you want more.
Code:
#Game No : 6041037816 
***** Hand History for Game 6041037816 *****
NL Texas Hold'em $11 USD Buy-in Trny:33838244 Level:7   Blinds-Antes(400/800 -25) - Thursday, June 07, 11:12:27 ET 2007
Table Speed #1330206 (Real Money)
Seat 10 is the button
Total number of players : 3 
Seat 7: TargetChamp ( 4,585 )
Seat 6: davew422 ( 3,805 )
Seat 10: twentyfive80 ( 11,610 )
Trny:33838244 Level:7 
 Blinds-Antes(400/800 -25)
davew422 posts ante [25]
TargetChamp posts ante [25]
twentyfive80 posts ante [25]
** Dealing down cards **
Dealt to davew422 [  5c 5h ]
twentyfive80 folds
davew422 is all-In  [3,380]
>You have options at Speed #1330013 Table!.
TargetChamp calls [2,980]
** Dealing Flop ** [ 3c, Kd, 3s ]
** Dealing Turn ** [ Qh ]
** Dealing River ** [ 8s ]
davew422 shows [ 5c, 5h ]two pairs, Fives and Threes.
TargetChamp shows [ Td, Qs ]two pairs, Queens and Threes.
TargetChamp wins 7,635 chips from  the main pot  with two pairs, Queens and Threes.
davew422 finished in 3 place and won $20 USD.
I were trying this with some party hand histories I had because I am considering attempting to make stars->party hand history converter with AHK. As far as I can tell the only difficulty is in making the "finished in 3 place and won $20 USD." line as the rest is all in the stars HH.

Does your program read the blinds and antes from the hand history directly, or by just reading the level and looking it up? If so the different levels on stars will be a problem.

Also... would it be possible for you to compile a version that takes "ENTRY_FEE_PERCENTAGE" as an input, so that it can be adjusted for the different rake 9 mans on stars?

Thanks!
SnG Luck Analyzer (Beta) Quote
01-29-2008 , 03:16 PM
Quote:
Originally Posted by dave_w11
The hand history I used may have been from FreePHG rather than being written by partypoker software. Could this be the problem?

One file contains 3 hand histories and I wondered if this was the problem so split it up into seperate files. Now if only 1 of the 3 files are in the folder it gives the expected results for each individual tournament seperately, but if I put all 3 files in the folder the same error occurs.

Code:
HandNumber,ActualWinnings,AjustedWinnings,$EV_Luck,cEV_Luck
6040550851,-11,-8.80256,-2.19744,-446.138
6040557901,-11,-5.25522,-5.74478,-1199.63
6040558744,-11,-13.3458,2.34577,200.854
6040574231,-11,-12.7628,1.76284,71.1461
6040575328,-11,-7.36836,-3.63164,-876.318
6040882819,8,13.8302,-5.83023,-1335.55
6040909054,8,5.13661,2.86339,298.475
6040924365,8,11.9489,-3.94891,-1270.5
6040930531,8,14.0074,-6.00743,-3329.02
6041004085,17,23.6648,-6.66475,-3573.56
6041010825,17,14.8753,2.12468,-1909.59
6041022064,17,17.6244,-0.624366,-2619.19
6041036672,17,10.4297,6.57035,456.627
6041037816,17,19.0518,-2.05181,-3445.7
I can see why you thought there was a problem here, but it is working as it should: the value stored is the "cumulative sum of profit so far" and if you came 2nd in the 2nd SNG -11+19=8, and if you came 3rd in the 3rd SNG 8+9=17. It's just bad luck that you picked those 3 exact HHs which didn't make the cumulative nature of the column apparent...

Quote:
I were trying this with some party hand histories I had because I am considering attempting to make stars->party hand history converter with AHK. As far as I can tell the only difficulty is in making the "finished in 3 place and won $20 USD." line as the rest is all in the stars HH.
My app doesn't actually use that line at all. I detect when a player busts (or when the SNG is over) simply by looking at their stack at the start of the hand and the end of the hand, so there is no need to add that line to the converted HH files.

Quote:
Does your program read the blinds and antes from the hand history directly, or by just reading the level and looking it up? If so the different levels on stars will be a problem.
I read the SB, BB and ante directly, so there shouldn't be any problems if you just make "fake" levels for the converted hand (I don't read the level at all). I don't know how Stars treats a "dead SB", but for Party I detect it by looking for the line which looks like this:

Code:
#Game No : 5735787875 
***** Hand History for Game 5735787875 *****
NL Texas Hold'em $33 Buy-in Trny: 32104297 Level: 4   Blinds(100/200) - Monday, March 05, 03:25:07 ET 2007
Table Speed #1329890 (Real Money)
Seat 10 is the button
Total number of players : 7 
Seat 2: Babay101 ( $4560 )
Seat 4: zoissi ( $1440 )
Seat 5: nilez77 ( $1680 )
Seat 6: DrawingDeadAgain ( $3730 )
Seat 7: flopdrop29 ( $3960 )
Seat 8: BOSSMAN_80 ( $2910 )
Seat 10: BiggieHB ( $1720 )
Trny: 32104297 Level: 4 
 Blinds(100/200)
There is no Small Blind in this hand as the Big Blind of the previous hand left the table.
** Dealing down cards **
zoissi folds
nilez77 calls [200]
DrawingDeadAgain folds
flopdrop29 folds
BOSSMAN_80 folds
BiggieHB folds
Babay101 checks
** Dealing Flop ** [ 4c, Th, 8c ]
Babay101 checks
nilez77 bets [400]
Babay101 folds
nilez77 does not show cards.
nilez77 wins 800 chips
Game #5735788356 starts.
Quote:
Also... would it be possible for you to compile a version that takes "ENTRY_FEE_PERCENTAGE" as an input, so that it can be adjusted for the different rake 9 mans on stars?
Yep, I can re-compile so that it's taken on the command line and I can also re-compile so that the prize structure is taken on the command line too (atm it's just fixed to 50/30/20). My ICM class can't handle more than 3 prizes though (ie: for MTTs) as the prizes awarded for busting out get generated using a function that only works with <=3 players.

Thanks for this and if you get a working converter then post it here and I'll make another batch file that first converts the hands, then show examples of using a different "ENTRY_FEE_PERCENTAGE" (high limit Party SNGs need this to be variable too) and/or prize structure in the batch file. I can't really do any testing though as I have no Stars hands to work with.

Juk
SnG Luck Analyzer (Beta) Quote
01-29-2008 , 04:15 PM
Quote:
Originally Posted by jukofyork
I can see why you thought there was a problem here, but it is working as it should: the value stored is the "cumulative sum of profit so far" and if you came 2nd in the 2nd SNG -11+19=8, and if you came 3rd in the 3rd SNG 8+9=17. It's just bad luck that you picked those 3 exact HHs which didn't make the cumulative nature of the column apparent...
Aaaah whoops sorry my bad!


Quote:
My app doesn't actually use that line at all. I detect when a player busts (or when the SNG is over) simply by looking at their stack at the start of the hand and the end of the hand, so there is no need to add that line to the converted HH files.
That should save a lot of work! I tried deleting that line from the last hand history and it gave an error but it seems that's because I deleted the last line of the file and didn't add a new line doh.

Quote:
I read the SB, BB and ante directly, so there shouldn't be any problems if you just make "fake" levels for the converted hand (I don't read the level at all). I don't know how Stars treats a "dead SB", but for Party I detect it by looking for the line which looks like this:


Yep, I can re-compile so that it's taken on the command line and I can also re-compile so that the prize structure is taken on the command line too (atm it's just fixed to 50/30/20). My ICM class can't handle more than 3 prizes though (ie: for MTTs) as the prizes awarded for busting out get generated using a function that only works with <=3 players.

Thanks for this and if you get a working converter then post it here and I'll make another batch file that first converts the hands, then show examples of using a different "ENTRY_FEE_PERCENTAGE" (high limit Party SNGs need this to be variable too) and/or prize structure in the batch file. I can't really do any testing though as I have no Stars hands to work with.

Juk

Thanks! It won't be for a couple of days as I have exams but I've made other AHK scripts that go through stars hand histories bit by bit for other reasons that I should be able to edit so it hopefully won't take long. I'm not sure how fast it will be but I don't suppose it matters massively for a 1 time thing like this.
SnG Luck Analyzer (Beta) Quote
01-29-2008 , 06:18 PM
Quote:
Originally Posted by dave_w11
Thanks! It won't be for a couple of days as I have exams but I've made other AHK scripts that go through stars hand histories bit by bit for other reasons that I should be able to edit so it hopefully won't take long. I'm not sure how fast it will be but I don't suppose it matters massively for a 1 time thing like this.
Cool, keep us posted and good luck with the exams!

Juk

PS: If anybody had problems running the old version of my app, then it turns out it had some SSE2 instruction-set stuff still turned on. I updated the RAR file with the fixed version now.
SnG Luck Analyzer (Beta) Quote
01-29-2008 , 08:48 PM
Juk, sure I'm doing something dumb here. I keep getting this error message.

SnG Luck Analyzer (Beta) Quote
01-29-2008 , 09:04 PM
Quote:
Originally Posted by JoeSchmo
Juk, sure I'm doing something dumb here. I keep getting this error message.

I thought for a second you were getting the same error as Bodypull, but his said "The system cannot execute the specified program" and I think it was due to me having some SSE2 instructions compiled in still (that should be fixed in the new version I uploaded this afternoon).

Make sure that you have all the files are extracted from the RAR first (ie: don't try and run it from within the RAR).

I think this error is something to do with Windows 2000 not having the right stuff installed to run stuff from the command prompt (google for that error comes up with alot of stuff). If that is the case then you need to make a shortcut and add a single dot to the end of the shortcut's command line, eg: "C:\temp\BackTestAllInLuck.exe" "." (assuming all the files have been unrared into "C:\temp"). This will let your create the csv file, but the results at the end will flash up too quick too see, so it's prolly worth reading up about that error and finding the fix.

Juk
SnG Luck Analyzer (Beta) Quote
01-29-2008 , 09:16 PM
I must say this really does make you feel ALOT better when you're running like total ****... These last two days I've been dishing out my hard earned cash to every donk going, but in actual fact I've earned a ton of Sklansky bucks:

NumSNGs : 333 (NumAllIns[2,3,4+]=963,55,6 / NumDataPoints=1018)
Actual Won : -153% (Actual ROI=-4.1769%)
Adjusted Won : 253% (Adjusted ROI=6.92258%)
$EV Luck : -406% (-0.399385% per all-in)
cEV Luck : -192278t (-188.878t per all-in)


Just need to work out how to cash them in now...

Juk
SnG Luck Analyzer (Beta) Quote
01-30-2008 , 12:39 AM
I have been following this thread since its inception but i am confused as to which version to install...

I run pokerstars and have PT
SnG Luck Analyzer (Beta) Quote
01-30-2008 , 05:15 AM
So I'm supposed to be getting a file called BackTestAllinLuck.exe?

After I extract from the RAR, I have the following files only:

2WAY_HandEval_binary.dat
3WAY_HandEval_binary.dat
README.DOC
RunMe.bat
SNG_helper.exe
SnG Luck Analyzer (Beta) Quote
01-30-2008 , 08:25 AM
Quote:
Originally Posted by RexWoo
It would be sooooooooo good if I could use the analyser with PostRegDb or (stars) raw HH.

RLY.
I'm also interested.
Can you do something ?
TY
SnG Luck Analyzer (Beta) Quote
01-30-2008 , 02:02 PM
Quote:
Originally Posted by JoeSchmo
So I'm supposed to be getting a file called BackTestAllinLuck.exe?

After I extract from the RAR, I have the following files only:

2WAY_HandEval_binary.dat
3WAY_HandEval_binary.dat
README.DOC
RunMe.bat
SNG_helper.exe
Oh sorry, I see what I did now: I forgot to rename SNG_helper.exe to BackTestAllinLuck.exe last time. Just rename it and the batch file should work OK.

Juk
SnG Luck Analyzer (Beta) Quote
01-30-2008 , 03:04 PM
OK, I changed SNG_Helper.exe to BackTestAllinLuck.exe and tried to run RunMe.bat. Now I get this one:



I'm running this on one of my old Party HH's (a Speed SNG from 06) which was exported from PT.
SnG Luck Analyzer (Beta) Quote

      
m