// ------- BBallCpW.Cpp Baseball probability program in C++ /* =========================================================== *\ ** BBallCpW.cpp ** ** =========================================================== ** ** ** ** =========================================================== ** ** Copyright (c) 1994 by Harry J. Smith. All rights reserved. ** \* =========================================================== */ char name[] = "BBallCpW - Baseball probability."; char version[] = "C++ Windows Version 2.04, last revised: 1994-07-08, 0600 hour"; char author[] = "Copyright \xA9 1981-1994 by author: Harry J. Smith,"; char address[] = "19628 Via Monte Dr., Saratoga CA 95070. All rights reserved."; char hint1[] = "Uses a bivariate binomial distribution as a model,"; char hint2[] = "and assumes each game is a 50-50 chance."; // Computes the probability that the 1st place team will beat the 2nd place // team for the division title, assuming each has a 50-50 chance of winning // any given future game. Uses a bivariate binomial distribution as a model. // Developed in Turbo Pascal 5.0, converted to // Converted to Borland C++ 4.0 and OWL 2.0 #include <owl\applicat.h> #include <owl\framewin.h> #include <owl\menu.h> #include <owl\dialog.h> #include <owl\edit.h> #include <owl\validate.h> #include <owl\printer.h> #include <classlib\date.h> #include <mem.h> #include <cstring.h> #pragma hdrstop #include "BBallCpW.rh" #include <stdio.h> // Definitions for stream input/output #include <math.h> // Definitions for the math floating point package #include <conio.h> // Direct MS-DOS console input/output, getch() #include <stdlib.h> // Definition of exit() etc. #include <string.h> // Definition of srtcpy() etc. // Detect Windows NT or Win32s for 32-bit mode #ifdef __WIN32__ char WinMode[] = ", (32-bit mode)"; #else char WinMode[] = ", (16-bit mode)"; #endif #define GL1_SIZE 4 #define GL2_SIZE 4 #define GE_SIZE 3 #define GA_SIZE 6 #define TN1_SIZE 13 #define TN2_SIZE 13 #define DATE_SIZE 13 #define P_SIZE 16 #define Q_SIZE 16 #define OOQ_SIZE 16 #define POQ_SIZE 16 #define MNT1_SIZE 16 #define MNW1_SIZE 16 #define MNT2_SIZE 16 #define MNW2_SIZE 16 #define ER_GA_SIZE 16 #define ER_GE_SIZE 16 struct TBBBuffer { char GL1[GL1_SIZE]; char GL2[GL2_SIZE]; char GE[GE_SIZE]; char GA[GA_SIZE]; char TN1[TN1_SIZE]; char TN2[TN2_SIZE]; char Date[DATE_SIZE]; }; // Global constants and variables const char ESC = 27; char TN1[11]; // Team's name, 1st place team char TN2[11]; // Team's name, 2nd place team int GL1; // Games Left to play, 1st place team int GL2; // Games Left to play, 2nd place team int GE; // Games to play each other double GA; // Games 1st place team is ahead. 0, 0.5, ... long GA2; // Twice games ahead = 2 * GA, 0, 1, ... long MNT1; // Magic Number to tie for 1st place team long MNW1; // Magic Number to win for 1st place team long MNT2; // Magic Number to tie for 2nd place team long MNW2; // Magic Number to win for 2nd place team double P; // Probability that 1st place team beats 2nd place team double Q; // Probability that 2nd place team beats 1st place team BOOL GAEr; // True if GA value not possible BOOL GEEr; // True if GE value not possible BOOL PEr; // True if Overflow while computing P string msg; // Message for printer // Procedure prototypes void ExpandCase( void); // Compute related data void ComputeProb( void); // Compute probability using a bivariate binomial // distribution as a model // ------- Compute related data void ExpandCase( void) { long I; GA2 = 2 * GA + 0.5; // Round I = GL1 + GL2 - GA2; MNT1 = I / 2; MNW1 = MNT1 + 1; MNT2 = GL1 + GL2 - MNT1; MNW2 = MNT2 + 1; I = GL1 + GL2 + GA2; GAEr = (I % 2 == 1); // True if I is odd } // --end-- ExpandCase // ------- Compute probability using a bivariate binomial dist. as a model void ComputeProb( void) { int I, J; double A, B; double* E; // 25 Binomial coefficients, games to play each other double* S; // 25 Running sum of 2 * E[I] double* F; // 163 B. C., games not played with each other double* G; // 163 Sum of 2 * E[I] for 2nd place team win, E[I] for tie E =(double*) calloc( GE+1, sizeof(double)); S =(double*) calloc( GE+1, sizeof(double)); F =(double*) calloc( (size_t)max(1L, MNT1+1), sizeof(double)); G =(double*) calloc( (size_t)max(1L, MNT1+1), sizeof(double)); PEr = FALSE; A = GL1 + GL2 - GE - GE; // A = not played with each other games B = 1.0; F[0] = 1.0; for (I = 1; I <= MNT1; I++) { // Compute binomial coefficients F[I] = F[I - 1] * A / B; A = A - 1.0; B = B + 1.0; } A = GE; B = 1.0; E[0] = 1.0; S[0] = 2.0; for (I = 1; I <= GE; I++) { // Compute binomial coefficients E[I] = E[I - 1] * A / B; A = A - 1.0; B = B + 1.0; S[I] = S[I - 1] + 2 * E[I]; } for (I = 0; I <= MNT1; I++) { // Compute G[I] J = (int)((MNT1 - I) / 2); if (J <= GE) { G[I] = S[J]; if ((J + J) == (MNT1 - I)) G[I] = G[I] - E[J]; // Adjust for tie } else G[I] = S[GE]; } Q = 0.0; // Compute probability that 2nd place team beats 1st place team for (I = 0; I <= MNT1; I++) { Q = Q + F[I] * G[I]; } A = GL1 + GL2 - GE + 1; B = pow( 2.0, A); // 2 ** Flips Q = Q / B; P = 1.0 - Q; //catch (...) { // string msg; // string NL('\n'), DL("\n\n"); // msg += """"; // msg += "Overflow" + DL; // msg += "Input numbers are too large!"; // MessageBox( // Display message // NULL, // msg.c_str(), // "Overflow", // MB_OK); // P = Q = 0; PEr = TRUE; //} } // --end-- ComputeProb // =========================================================== // The Printout class // =========================================================== class TBBPrintout: public TPrintout { public: TBBPrintout(TWindow* window, const char* title); protected: void PrintPage(int page, TRect& rect, unsigned flags); private: TWindow* parentWindow; }; // Constructor TBBPrintout::TBBPrintout( TWindow* window, const char* title) : TPrintout(title) { parentWindow = window; } // Print pages of document (only 1 page) void TBBPrintout::PrintPage( int /*page*/, TRect& rect, unsigned /*flags*/) { TPrintDC& dc = *DC; TSize pageSize = PageSize; TEXTMETRIC tm; int h; // // Size the fonts to whatever DC we print to // h = -MulDiv(dc.GetDeviceCaps(LOGPIXELSY), abs(-12), 72); // 12-point font TFont fontNormal(h, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DRAFT_QUALITY, VARIABLE_PITCH | FF_SWISS, NULL); TSize extent; dc.SetBkMode(TRANSPARENT); dc.SelectObject(fontNormal); dc.GetTextMetrics(tm); dc.DrawText(msg.c_str(), -1, rect, DT_LEFT); parentWindow->Paint(*DC, FALSE, rect); } // =========================================================== // The application's main dialog // =========================================================== class TBBDialog: public TDialog { public: TBBDialog(TWindow* parent, TBBBuffer* BBBuffer); ~TBBDialog(); TEdit* EditDate; protected: void CmCheckInput(); // Respond to Check Input button void CmUpdateOutput(); // Respond to Update Output button void CmReset(); // Respond to Reset button void CmFilePrintSetup(); // Respond to File|Print Setup menu command void CmFilePrint(); // Respond to File|Print menu command void CmFileExit(); // Respond to File|Exit menu command void CmHelpTest(); // Respond to Help|Test menu command void CmHelpAbout(); // Respond to Help|About menu command void UpdateInput(); // Common code void UpdateOutput(); // Common code private: TPrinter* printer; TEdit* EditGL1; TEdit* EditGL2; TEdit* EditGE; TEdit* EditGA; TEdit* EditTN1; TEdit* EditTN2; //TEdit* EditDate; TStatic* StaticP; TStatic* StaticQ; TStatic* Static1oQ; TStatic* StaticPoQ; TStatic* StaticMNT1; TStatic* StaticMNW1; TStatic* StaticMNT2; TStatic* StaticMNW2; TStatic* ErrorGE; TStatic* ErrorGA; DECLARE_RESPONSE_TABLE(TBBDialog); }; DEFINE_RESPONSE_TABLE1(TBBDialog, TDialog) EV_COMMAND(CM_CHECK_INPUT, CmCheckInput), EV_COMMAND(CM_UPDATE_OUTPUT, CmUpdateOutput), EV_COMMAND(CM_RESET, CmReset), EV_COMMAND(CM_FILE_PRINTSETUP, CmFilePrintSetup), EV_COMMAND(CM_FILE_PRINT, CmFilePrint), EV_COMMAND(CM_FILE_EXIT, CmFileExit), EV_COMMAND(CM_HELP_TEST, CmHelpTest), EV_COMMAND(CM_HELP_ABOUT, CmHelpAbout), END_RESPONSE_TABLE; // Constructor TBBDialog::TBBDialog( TWindow* parent, TBBBuffer* BBBuffer) : TDialog(parent, DIALOG_1) { EditGL1 = new TEdit(this, ED_GL1, GL1_SIZE); EditGL1->SetValidator(new TRangeValidator(0, 162)); EditGL2 = new TEdit(this, ED_GL2, GL2_SIZE); EditGL2->SetValidator(new TRangeValidator(0, 162)); EditGE = new TEdit(this, ED_GE, GE_SIZE); EditGE->SetValidator(new TRangeValidator(0, 24)); EditGA = new TEdit(this, ED_GA, GA_SIZE); EditGA->SetValidator(new TFilterValidator("0-9.")); EditTN1 = new TEdit(this, ED_TN1, TN1_SIZE); EditTN2 = new TEdit(this, ED_TN2, TN2_SIZE); EditDate = new TEdit(this, ED_DATE, DATE_SIZE); SetTransferBuffer(BBBuffer); StaticP = new TStatic(this, O_P, P_SIZE); StaticQ = new TStatic(this, O_Q, Q_SIZE); Static1oQ = new TStatic(this, O_1OQ, OOQ_SIZE); StaticPoQ = new TStatic(this, O_POQ, POQ_SIZE); StaticMNT1 = new TStatic(this, O_MNT1, MNT1_SIZE); StaticMNW1 = new TStatic(this, O_MNW1, MNW1_SIZE); StaticMNT2 = new TStatic(this, O_MNT2, MNT2_SIZE); StaticMNW2 = new TStatic(this, O_MNW2, MNW2_SIZE); ErrorGE = new TStatic(this, ER_GE, ER_GE_SIZE); ErrorGA = new TStatic(this, ER_GA, ER_GA_SIZE); printer = new TPrinter; } // Destructor TBBDialog::~TBBDialog() { delete printer; } // Respond to Check Input button void TBBDialog::CmCheckInput() { UpdateInput(); } // Respond to Update Output button void TBBDialog::CmUpdateOutput() { UpdateOutput(); } // Respond to Reset button void TBBDialog::CmReset() { EditGL1->SetText(""); EditGL2->SetText(""); EditGE->SetText(""); EditGA->SetText(""); EditTN1->SetText(""); EditTN2->SetText(""); TDate Date; string msg = Date.AsString(); EditDate->SetText(msg.c_str()); StaticP->SetText(""); StaticQ->SetText(""); Static1oQ->SetText(""); StaticPoQ->SetText(""); StaticMNT1->SetText(""); StaticMNW1->SetText(""); StaticMNT2->SetText(""); StaticMNW2->SetText(""); ErrorGE->SetText(""); ErrorGA->SetText(""); } // Respond to File|Print Setup menu command void TBBDialog::CmFilePrintSetup() { printer->Setup(this); } // Respond to File|Print menu command void TBBDialog::CmFilePrint() { string NL("\n "), DL = ("\n") + NL; msg = "\n\n" + DL; msg += name + NL; msg += version; msg += WinMode + NL; msg += author + NL; msg += address + DL; msg += hint1 + NL; msg += hint2 + DL; char st[16]; EditDate->GetText(st, DATE_SIZE); msg += st; msg += " = Date of morning after last game" + NL; EditGL1->GetText(st, GL1_SIZE); msg += st; msg += " = Games Left to play, 1st place team ("; msg += TN1; msg += ")" + NL; EditGL2->GetText(st, GL2_SIZE); msg += st; msg += " = Games Left to play, 2nd place team ("; msg += TN2; msg += ")" + NL; EditGE->GetText(st, GE_SIZE); msg += st; msg += " = Games to play each other" + NL; EditGA->GetText(st, GA_SIZE); msg += st; msg += " = Games 1st place team is ahead. 0, 0.5, ..." + DL; StaticMNT1->GetText(st, MNT1_SIZE); msg += st; msg += " = Magic Number to tie for 1st place team" + NL; StaticMNW1->GetText(st, MNW1_SIZE); msg += st; msg += " = Magic Number to win for 1st place team" + NL; StaticMNT2->GetText(st, MNT2_SIZE); msg += st; msg += " = Magic Number to tie for 2nd place team" + NL; StaticMNW2->GetText(st, MNW2_SIZE); msg += st; msg += " = Magic Number to win for 2nd place team" + DL; StaticP->GetText(st, P_SIZE); msg += st; msg += " = Probability that 1st place team beats 2nd place team" + NL; StaticQ->GetText(st, Q_SIZE); msg += st; msg += " = Probability that 2nd place team beats 2nd place team" + NL; StaticQ->GetText(st, Q_SIZE); msg += st; msg += " = Probability that 2nd place team beats 2nd place team" + NL; Static1oQ->GetText(st, OOQ_SIZE); msg += st; msg += " = 1 / Q, (Odds = "; StaticPoQ->GetText(st, POQ_SIZE); msg += st; msg += " : 1)"; if (printer) { TBBPrintout printout(this, "BB Printout"); printer->Print(this, printout, TRUE); } } // Respond to File|Exit menu command void TBBDialog::CmFileExit() { // MainWindow->CmFileExit(); CmExit(); CloseWindow(); } // Respond to Help|Test menu command void TBBDialog::CmHelpTest() { EditGL1->SetText("6"); EditGL2->SetText("7"); EditGE->SetText("0"); EditGA->SetText("1.5"); EditTN1->SetText("Braves"); EditTN2->SetText("Giants"); EditDate->SetText("1993-09-27"); UpdateOutput(); } // Respond to Help|About menu command void TBBDialog::CmHelpAbout() { string msg; string NL('\n'), DL("\n\n"); msg += name + DL; msg += version; msg += WinMode + DL; msg += author + DL; msg += address + DL + DL; msg += hint1 + NL; msg += hint2; MessageBox( msg.c_str(), "About BBallCpW", MB_OK); } // Respond to Update Input common code void TBBDialog::UpdateInput() { char st[16]; EditGL1->GetText(st, GL1_SIZE); GL1 = atoi(st); EditGL2->GetText(st, GL2_SIZE); GL2 = atoi(st); EditGE->GetText(st, GE_SIZE); GE = atoi(st); EditGA->GetText(st, GA_SIZE); GA = atof(st); sprintf( st, "%1d", GL1); EditGL1->SetText(st); sprintf( st, "%1d", GL2); EditGL2->SetText(st); sprintf( st, "%1d", GE); EditGE->SetText(st); GA2 = floor(2 * GA + 0.5); // Round GA = GA2 / 2.0; if (GA2 % 2 == 1) sprintf( st, "%.1f", GA); else sprintf( st, "%.0f", GA); EditGA->SetText(st); EditTN1->GetText(TN1, TN1_SIZE); EditTN2->GetText(TN2, TN2_SIZE); if (GE > GL1 || GE > GL2) { GEEr = TRUE; ErrorGE->SetText("ERROR -->"); //ErrorGE->SetTextColor(4); // Red //EditGE->SetTextColor(4); } else { GEEr = FALSE; ErrorGE->SetText(""); //ErrorGE->SetTextColor(0); // Black //EditGE->SetTextColor(0); } ExpandCase(); if (GAEr) { ErrorGA->SetText("ERROR -->"); //ErrorGA->SetTextColor(4); // Red //EditGA->SetTextColor(4); } else { ErrorGA->SetText(""); //ErrorGA->SetTextColor(0); // Black //EditGA->SetTextColor(0); } } // Respond to Update Output common code void TBBDialog::UpdateOutput() { UpdateInput(); char st[16]; if (GEEr) { PEr = TRUE; Q = 0; } else { ComputeProb(); } if (PEr) { StaticP->SetText(""); StaticQ->SetText(""); Q = 0; } else { sprintf( st, "%#6.4f", P); StaticP->SetText(st); sprintf( st, "%#6.4f", Q); StaticQ->SetText(st); if (!Q) { // If Q is zero StaticP->SetText("One"); StaticQ->SetText("Zero"); } else { if (!strcmp(st, "0.0000")) { // If Q looks like zero StaticQ->SetText("Very Small"); StaticP->SetText("Almost 1.0000"); } } } if (Q) { if (1/Q < 9999999999.9999) { sprintf( st, "%#6.4f", 1/Q); Static1oQ->SetText(st); sprintf( st, "%#6.4f", P/Q); StaticPoQ->SetText(st); } else { Static1oQ->SetText("> 10^10"); StaticPoQ->SetText("> 10^10"); } sprintf( st, "%13ld", MNT1); StaticMNT1->SetText(st); sprintf( st, "%13ld", MNW1); StaticMNW1->SetText(st); sprintf( st, "%13ld", MNT2); StaticMNT2->SetText(st); sprintf( st, "%13ld", MNW2); StaticMNW2->SetText(st); } else { Static1oQ->SetText(""); StaticPoQ->SetText(""); StaticMNT1->SetText(""); StaticMNW1->SetText(""); StaticMNT2->SetText(""); StaticMNW2->SetText(""); } } // =========================================================== // The application's main window // =========================================================== class TBBallCpWWin: public TFrameWindow { public: TBBallCpWWin(TWindow* parent, const char far* title); ~TBBallCpWWin(); protected: void SetupWindow(); void CmFilePrintSetup(); void CmFileExit(); void CmRunGo(); void CmHelpAbout(); private: TMenu* windowMenu; // Pointer to window's menu TBBBuffer BBBuffer; // Dialog transfer buffers TPrinter* printer; DECLARE_RESPONSE_TABLE(TBBallCpWWin); }; DEFINE_RESPONSE_TABLE1(TBBallCpWWin, TFrameWindow) EV_COMMAND(CM_FILE_PRINTSETUP, CmFilePrintSetup), EV_COMMAND(CM_FILE_EXIT, CmFileExit), EV_COMMAND(CM_RUN_GO, CmRunGo), EV_COMMAND(CM_HELP_ABOUT, CmHelpAbout), END_RESPONSE_TABLE; // Constructor TBBallCpWWin::TBBallCpWWin(TWindow* parent, const char far* title) : TFrameWindow(parent, title), TWindow(parent, title) { AssignMenu(ID_MENU); printer = new TPrinter; memset(&BBBuffer, 0, sizeof(BBBuffer)); strcpy(BBBuffer.GL1, ""); strcpy(BBBuffer.GL2, ""); strcpy(BBBuffer.GE, ""); strcpy(BBBuffer.GA, ""); strcpy(BBBuffer.TN1, ""); strcpy(BBBuffer.TN2, ""); TDate Date; string msg = Date.AsString(); strcpy(BBBuffer.Date, msg.c_str()); } // Destructor TBBallCpWWin::~TBBallCpWWin() { delete windowMenu; delete printer; } // Initialize window object void TBBallCpWWin::SetupWindow() { TFrameWindow::SetupWindow(); // Create menu object interface for this window's menu windowMenu = new TMenu(HWindow); } // Respond to File|Print Setup menu command void TBBallCpWWin::CmFilePrintSetup() { printer->Setup(this); } // Respond to File|Exit menu command void TBBallCpWWin::CmFileExit() { CmExit(); } // Respond to Run|Go menu command void TBBallCpWWin::CmRunGo() { // Input GL1 from the operator TBBDialog* BBDialog = new TBBDialog(this, &BBBuffer); // BBDialog->SetIcon(this, ID_ICON); if (BBDialog->Execute() == IDOK) {} } // Respond to Help|About information menu command void TBBallCpWWin::CmHelpAbout() { string msg; string NL('\n'), DL("\n\n"); msg += name + DL; msg += version; msg += WinMode + DL; msg += author + DL; msg += address + DL + DL; msg += hint1 + NL; msg += hint2; MessageBox( msg.c_str(), "About BBallCpW", MB_OK); } // =========================================================== // The application class // =========================================================== class TBBallCpWApp: public TApplication { public: TBBallCpWApp(const char far* name) : TApplication(name) {}; void InitMainWindow(); }; // Initialize the program's main window void TBBallCpWApp::InitMainWindow() { //EnableCtl3d(); // Did not work in Windows NT EnableBWCC(); MainWindow = new TBBallCpWWin(0, "Baseball Probability"); MainWindow->SetIcon(this, ID_ICON); } #pragma argsused // Main program int OwlMain(int argc, char* argv[]) { TBBallCpWApp app("BBallCpW"); return app.Run(); } // --end-- file BBallCpW.Cpp