home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_122 / 10.ddi / TTT.ZIP / TTT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  11.0 KB  |  376 lines

  1. // ObjectWindows - (C) Copyright 1992 by Borland International
  2.  
  3. // -------------------------------------------------------------------------
  4. //
  5. //    TTT - TicTacToe Demo Program
  6. //
  7. //    Plays a game of TicTacToe with the user.
  8. //
  9. //    TTTTGameApp - Main TicTacToe application, derived from TApplication
  10. //    TGameWindow - Main window for the app, derived from TWindow
  11. //    Square - Game squares (windows), derived from TWindow
  12. //    TGameAboutBox - A TDialog box for info about TicTacToe
  13. //    TGameOptionsBox - A TDialog box for setting TicTacToe options
  14. //    YouMeRadioButton - A radio button which controls game settings
  15. //    XORadioButton - A radio button which controls game settings
  16. //
  17. // -------------------------------------------------------------------------
  18.  
  19. #include <owl.h>
  20. #include <bbutton.h>
  21. #include <bwcc.h>
  22. #include <bstatic.h>
  23. #include <bradio.h>
  24. #include <bgrpbox.h>
  25. #include <string.h>
  26.  
  27. #include "ttt.h"
  28.  
  29. const unsigned int TGW_WIDTH = 280, TGW_HEIGHT = 300;
  30. const unsigned int TGAB_WIDTH = 250, TGAB_HEIGHT = 300;
  31. const unsigned int TGAB_INITIAL_X = 5, TGAB_INITIAL_Y = 10;
  32.  
  33. const unsigned int SW_SIZE = 40;
  34. const unsigned int BOARDXOFFSET = 30+SW_SIZE+3;
  35. const unsigned int BOARDYOFFSET = 10+SW_SIZE+2;
  36.  
  37. enum SQUARESTATUS { SQS_UNOCCUPIED, SQS_X, SQS_O };
  38.  
  39. SQUARESTATUS UserSide;
  40. BOOL Playing;
  41.  
  42. class Square : public TWindow
  43. {
  44. public:
  45.    Square(PTWindowsObject, int, int);
  46.    void makeAnX(void)
  47.    {
  48.        SquareStatus = SQS_X;
  49.        InvalidateRect(HWindow, NULL, TRUE);
  50.    }
  51.    void makeAnO(void)
  52.    {
  53.        SquareStatus = SQS_O;
  54.        InvalidateRect(HWindow, NULL, TRUE);
  55.    }
  56.    void reset(void)
  57.    {
  58.        SquareStatus = SQS_UNOCCUPIED;
  59.        InvalidateRect(HWindow, NULL, TRUE);
  60.    }
  61.    virtual void WMLButtonDown(RTMessage Msg) = [WM_FIRST + WM_LBUTTONDOWN];
  62.    virtual void Paint(HDC PaintDC, PAINTSTRUCT _FAR &PaintInfo);
  63.    SQUARESTATUS SquareStatus;
  64. private:
  65.    int Row, Col;
  66. };
  67.  
  68. class TTTTGameApp : public TApplication
  69. {
  70. public:
  71.    TTTTGameApp(LPSTR AName, HINSTANCE hInstance, HINSTANCE hPrevInstance,
  72.                LPSTR lpCmdLine, int nCmdShow)
  73.     : TApplication(AName, hInstance, hPrevInstance, lpCmdLine, nCmdShow)
  74.    {
  75.       UserSide = SQS_X;
  76.       ComputerGoesFirst = FALSE;
  77.       Playing = TRUE;
  78.       UserBoardMap = ComputerBoardMap = 0;
  79.    }
  80.    virtual void InitMainWindow();
  81.    BOOL isWon(void);
  82.    int UserBoardMap, ComputerBoardMap;
  83.    BOOL ComputerGoesFirst;
  84.    void computerTurn(void);
  85.    BOOL gameOver(void)
  86.        { return ( (UserBoardMap|ComputerBoardMap) == 0x1FF ); }
  87.    Square *theBoard[3][3];
  88. };
  89.  
  90. class TGameWindow : public TWindow
  91. {
  92. public:
  93.    TGameWindow(PTWindowsObject AParent, LPSTR ATitle);
  94.    virtual void CMGameNew(RTMessage Msg) = [CM_FIRST + CM_GAMENEW];
  95.    virtual void CMGameOptions(RTMessage Msg) = [CM_FIRST + CM_GAMEOPTIONS];
  96.    virtual void CMAbout(RTMessage Msg) = [CM_FIRST + CM_ABOUT];
  97.    virtual void Paint(HDC PaintDC, PAINTSTRUCT _FAR &PaintInfo);
  98. };
  99.  
  100. class TGameAboutBox : public TDialog
  101. {
  102. public:
  103.    TGameAboutBox::TGameAboutBox(PTWindowsObject AParent);
  104. };
  105.  
  106. class TGameOptionsBox : public TDialog
  107. {
  108. public:
  109.    TGameOptionsBox::TGameOptionsBox(PTWindowsObject AParent);
  110.    virtual void SetupWindow(void);
  111.    TBGroupBox     *YouMeGroup, *XOGroup;
  112.    TBRadioButton  *You, *Me, *X, *O;
  113.    virtual void HandleYouMeGroupMsg(RTMessage Msg) =
  114.        [ID_FIRST + IDYOUMEGROUP];
  115.    virtual void HandleXOGroupMsg(RTMessage Msg) = [ID_FIRST + IDXOGROUP];
  116. };
  117.  
  118. TTTTGameApp *GameApp;
  119.  
  120. static const int freeMasks[] =
  121.     { 0x006, 0x005, 0x003, 0x030, 0x028, 0x018, 0x180, 0x140, 0x0C0,
  122.       0x048, 0x041, 0x009, 0x090, 0x082, 0x012, 0x120, 0x104, 0x024,
  123.       0x110, 0x101, 0x011, 0x050, 0x044, 0x014 };
  124.  
  125. static const int winningMasks[] =
  126.     { 0x1C0, 0x038, 0x007, 0x124, 0x092, 0x049, 0x111, 0x054 };
  127.  
  128. static void freeSquare( int mask, int i, int *row, int *col )
  129. {
  130.    int j, test, mode = i/9; // row, col, or diag
  131.    if (mode==0)
  132.       mask ^= 0x007 << (i/3)*3;
  133.    else if (mode==1)
  134.       mask ^= 0x049 << ((i%9)/3);
  135.    else if (((i%9)/3)==0)
  136.       mask ^= 0x111;
  137.    else
  138.       mask ^= 0x054;
  139.    for( j = 0, test = 1; test; test <<= 1, j++ )
  140.       if ( test & mask )
  141.          break;
  142.    *row = j/3; *col = j%3;
  143. }
  144.  
  145. // The following routine can be improved upon.  Write your own
  146. // version of this routine so that the machine always wins or draws the game.
  147. void TTTTGameApp::computerTurn(void)
  148. {
  149.    BOOL madeMove = FALSE;
  150.    for( int i = 0; i < 24; i++ )
  151.       if ( ( UserBoardMap & freeMasks[i] ) == freeMasks[i] )
  152.       {
  153.          int targetRow, targetCol, targetMask;
  154.          freeSquare( freeMasks[i], i, &targetRow, &targetCol );
  155.          if ( ComputerBoardMap &
  156.              ( targetMask = 1 << ((targetRow*3)+targetCol) ) )
  157.             continue;
  158.          if ( UserSide == SQS_X )
  159.             (theBoard[targetRow][targetCol])->makeAnO();
  160.          else
  161.         (theBoard[targetRow][targetCol])->makeAnX();
  162.          ComputerBoardMap |= targetMask;
  163.          madeMove = TRUE;
  164.          break;
  165.       }
  166.    if ( !madeMove )
  167.    {
  168.       if ( !( (ComputerBoardMap|UserBoardMap) & 0x010 ) )
  169.       {
  170.          if ( UserSide == SQS_X )
  171.             (theBoard[1][1])->makeAnO();
  172.          else
  173.             (theBoard[1][1])->makeAnX();
  174.          ComputerBoardMap |= 0x010;
  175.       }
  176.       else
  177.       {
  178.          int i, mask = UserBoardMap|ComputerBoardMap;
  179.          for( i = 0; mask & 1; mask >>= 1 )
  180.             i++;
  181.          if ( UserSide == SQS_X )
  182.             (theBoard[i/3][i%3])->makeAnO();
  183.          else
  184.             (theBoard[i/3][i%3])->makeAnX();
  185.          ComputerBoardMap |= 1 << i;
  186.       }
  187.    }
  188.    if ( isWon() )
  189.    {
  190.       Playing = FALSE;
  191.       MessageBox(MainWindow->HWindow, "I won!", "", MB_OK );
  192.    }
  193.    else if ( gameOver() )
  194.    {
  195.       Playing = FALSE;
  196.       MessageBox(MainWindow->HWindow, "Scratch", "", MB_OK );
  197.    }
  198. }
  199.  
  200. BOOL TTTTGameApp::isWon(void)
  201. {
  202.    for( int i = 0; i < 8; i++ )
  203.       if ( ((UserBoardMap & winningMasks[i]) == winningMasks[i]) ||
  204.               ((ComputerBoardMap & winningMasks[i]) == winningMasks[i] ) )
  205.          return TRUE;
  206.    return FALSE;
  207. }
  208.  
  209. Square::Square(PTWindowsObject AParent, int x, int y) :
  210.     TWindow(AParent, ""), SquareStatus(SQS_UNOCCUPIED), Row(x), Col(y)
  211. {
  212.    Attr.W = Attr.H = SW_SIZE;
  213.    Attr.X = BOARDXOFFSET + y*(SW_SIZE+3); // x and y are reversed because
  214.    Attr.Y = BOARDYOFFSET + x*(SW_SIZE+3); // of screen coordinates
  215.    Attr.Style = WS_VISIBLE|WS_CHILD;
  216. }
  217.  
  218. void Square::WMLButtonDown(RTMessage)
  219. {
  220.    if ( Playing && ( SquareStatus == SQS_UNOCCUPIED ) )
  221.    {
  222.       if ( UserSide == SQS_X )
  223.       {
  224.          makeAnX();
  225.          GameApp->UserBoardMap |= 1 << ((Row*3)+Col);
  226.       }
  227.       else
  228.       {
  229.          makeAnO();
  230.          GameApp->UserBoardMap |= 1 << ((Row*3)+Col);
  231.       }
  232.       if ( GameApp->isWon() )
  233.       {
  234.          Playing = FALSE;
  235.          MessageBox(HWindow, "You won!", "", MB_OK );
  236.       }
  237.       else if ( GameApp->gameOver() )
  238.       {
  239.          Playing = FALSE;
  240.          MessageBox(HWindow, "Scratch", "", MB_OK );
  241.       }
  242.       else
  243.          GameApp->computerTurn();
  244.    }
  245.    else
  246.       MessageBeep(0);
  247. }
  248.  
  249. void Square::Paint(HDC PaintDC, PAINTSTRUCT&)
  250. {
  251.    if ( SquareStatus == SQS_O )
  252.       Ellipse(PaintDC,0,0,SW_SIZE,SW_SIZE);
  253.    else if ( SquareStatus == SQS_X )
  254.    {
  255.       MoveTo(PaintDC,0,0);
  256.       LineTo(PaintDC,SW_SIZE,SW_SIZE);
  257.       MoveTo(PaintDC,SW_SIZE,0);
  258.       LineTo(PaintDC,0,SW_SIZE);
  259.    }
  260. }
  261.  
  262. TGameWindow::TGameWindow(PTWindowsObject AParent, LPSTR ATitle) :
  263.     TWindow(AParent, ATitle)
  264. {
  265.    AssignMenu("COMMANDS");
  266.    Attr.X = TGAB_INITIAL_X;
  267.    Attr.Y = TGAB_INITIAL_Y;
  268.    Attr.W = TGW_WIDTH;
  269.    Attr.H = TGW_HEIGHT;
  270. }
  271.  
  272. void TGameWindow::Paint(HDC PaintDC, PAINTSTRUCT&)
  273. {
  274.    MoveTo(PaintDC, BOARDXOFFSET+SW_SIZE+2, BOARDYOFFSET);
  275.    LineTo(PaintDC, BOARDXOFFSET+SW_SIZE+2, BOARDYOFFSET+(SW_SIZE*3)+6);
  276.    MoveTo(PaintDC, BOARDXOFFSET+(SW_SIZE*2)+5, BOARDYOFFSET);
  277.    LineTo(PaintDC, BOARDXOFFSET+(SW_SIZE*2)+5, BOARDYOFFSET+(SW_SIZE*3)+6);
  278.    MoveTo(PaintDC, BOARDXOFFSET, BOARDYOFFSET+SW_SIZE+2);
  279.    LineTo(PaintDC, BOARDXOFFSET+(SW_SIZE*3)+6, BOARDYOFFSET+SW_SIZE+2);
  280.    MoveTo(PaintDC, BOARDXOFFSET, BOARDYOFFSET+(SW_SIZE*2)+5);
  281.    LineTo(PaintDC, BOARDXOFFSET+(SW_SIZE*3)+6, BOARDYOFFSET+(SW_SIZE*2)+5);
  282. }
  283.  
  284. void TGameWindow::CMGameNew(RTMessage)
  285. {
  286.    Playing = TRUE;
  287.    GameApp->UserBoardMap = 0;
  288.    GameApp->ComputerBoardMap = 0;
  289.    for(int i = 0; i < 3; i++ )
  290.       for(int j = 0; j < 3; j++ )
  291.          GameApp->theBoard[i][j]->reset();
  292.    if ( GameApp->ComputerGoesFirst )
  293.       GameApp->computerTurn();
  294. }
  295.  
  296. void TGameWindow::CMGameOptions(RTMessage)
  297. {
  298.    TGameOptionsBox *OptionsDialog = new TGameOptionsBox(this);
  299.    GetApplication()->ExecDialog(OptionsDialog);
  300. }
  301.  
  302. void TGameWindow::CMAbout(RTMessage)
  303. {
  304.    TGameAboutBox *HelpDialog = new TGameAboutBox(this);
  305.    GetApplication()->ExecDialog(HelpDialog);
  306. }
  307.  
  308. TGameAboutBox::TGameAboutBox(PTWindowsObject AParent) :
  309.     TDialog(AParent, "ABOUT")
  310. {
  311. #  define ABOUTSTR "Tic Tac Toe\n(C) Borland International\n 1992"
  312.    PTStatic textPtr = new TBStatic(this, IDSTATIC, ABOUTSTR, 23, 20, 190,
  313.            45, strlen(ABOUTSTR) );
  314.    textPtr->Attr.Style |= SS_CENTER;
  315.    new TBButton(this, IDOK, "Ok", 80, 90, 40, 40, TRUE);
  316. }
  317.  
  318. TGameOptionsBox::TGameOptionsBox(PTWindowsObject AParent) :
  319.     TDialog(AParent, "OPTIONS")
  320. {
  321.    new TBButton(this, IDOK, "Ok", 30, 240, 40, 40, TRUE);
  322.    new TBButton(this, IDCANCEL, "Cancel", 150, 240, 40, 40, TRUE);
  323.    YouMeGroup = new TBGroupBox(this, IDYOUMEGROUP, "Who goes first?", 15,
  324.        30, 200, 20);
  325.    You = new TBRadioButton(this, IDYOU, "You", 15, 55, 50, 20, YouMeGroup);
  326.    Me = new TBRadioButton(this, IDME, "Me", 15, 80, 50, 20, YouMeGroup);
  327.    XOGroup = new TBGroupBox(this, IDXOGROUP, "I am playing", 15, 120,
  328.        200, 20);
  329.    X = new TBRadioButton(this, IDX, "X's", 15, 145, 50, 20, XOGroup);
  330.    O = new TBRadioButton(this, IDO, "O's", 15, 170, 50, 20, XOGroup);
  331. }
  332.  
  333. void TGameOptionsBox::SetupWindow(void)
  334. {
  335.    TDialog::SetupWindow();
  336.    if ( GameApp->ComputerGoesFirst )
  337.       Me->Check();
  338.    else
  339.       You->Check();
  340.  
  341.    if ( UserSide == SQS_X )
  342.       O->Check();
  343.    else
  344.       X->Check();
  345. }
  346.  
  347. void TGameOptionsBox::HandleYouMeGroupMsg(RTMessage)
  348. {
  349.    GameApp->ComputerGoesFirst =
  350.        (You->GetCheck() == BF_CHECKED) ? FALSE : TRUE;
  351. }
  352.  
  353. void TGameOptionsBox::HandleXOGroupMsg(RTMessage)
  354. {
  355.    UserSide = (X->GetCheck() == BF_CHECKED) ? SQS_O : SQS_X;
  356.    Playing = FALSE;
  357. }
  358.  
  359. void TTTTGameApp::InitMainWindow()
  360. {
  361.    (void)BWCCGetVersion();    // Make sure BWCC gets initialized.
  362.    MainWindow = new TGameWindow(NULL, Name);
  363.    for(int i = 0; i < 3; i++ )
  364.       for(int j = 0; j < 3; j++ )
  365.      theBoard[i][j] = new Square(MainWindow, i, j);
  366. }
  367.  
  368. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  369.     LPSTR lpCmdLine, int nCmdShow)
  370. {
  371.    GameApp = new TTTTGameApp("TicTacToe", hInstance, hPrevInstance,
  372.        lpCmdLine, nCmdShow);
  373.    GameApp->Run();
  374.    return GameApp->Status;
  375. }
  376.