/*
    Program :   Code Breaker Game   ( cbreak.* )
    Purpose :   Fun and pleasure, as well as a learning
                experiment in Windows programming.
                
    Author :    Ken Fogel
                Omnibus Systems
                8108 Norfolk Road
                Cote St-Luc, Qubec
                Canada  H4X 1A3
                (514) 487-1565
                CIS: 74646,2157
                
    Co-Author : Charles W. Haden
                Shoebox Software
                699 Lantana Street, Apt. #54
                Camarillo, CA   93010
                USA
                CIS: 71760,3557
    
    Revision :  April 15, 1991  - Version 1         (KF)
                April 22, 1991  - Version 1.01      (KF)
                May    9, 1991  - Version 1.01.a    (CWH)
                
    Notes :
    
*/
/* -------------------------------------------------------- */

#include <windows.h>
#include <stdlib.h>
#include <time.h>
#include "cbreak.h"

/* -------------------------------------------------------- */

/* Function declarations */
long FAR PASCAL WndProc( HWND hWnd, WORD message, WORD wParam, LONG lParam );
BOOL FAR PASCAL AboutProc( HWND hDlg, WORD message, WORD wParam, LONG lParam );
BOOL FAR PASCAL HelpProc( HWND hDlg, WORD message, WORD wParam, LONG lParam );
void vInitialize();
void vMakeGoal();
BOOL bCheckFill();
BOOL bCheckGuess();
BOOL bMakeGameButtons( HWND hWnd );

/* -------------------------------------------------------- */

HANDLE  hInst;
HWND    hGameGrid[ROWMAX][COLMAX];
int     guess[ROWMAX][COLMAX], guess_allowed;
int     goal[COLMAX];
char    clues[ROWMAX][COLMAX];
int     current_row;
HPEN    hSolidPen;
char    str[80];

/* -------------------------------------------------------- */

int PASCAL
WinMain( HANDLE hInstance, HANDLE hPrevInstance,
         LPSTR lpCmdLine, int nCmdShow ){

    MSG         msg;
    WNDCLASS    wc;
    HWND        hWnd;
    
    if( !hPrevInstance ){
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = WndProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = hInstance;
        wc.hIcon = LoadIcon( hInstance, "CBrkIcon" );
        wc.hCursor = LoadCursor( NULL, IDC_ARROW );
        wc.hbrBackground = GetStockObject( WHITE_BRUSH );
        wc.lpszMenuName = "CBrkMenu";
        wc.lpszClassName = "CBrkClass";

        RegisterClass( &wc );
    }

    guess_allowed = TRUE;
    hInst = hInstance;
    hWnd = CreateWindow( "CBrkClass", "Code Breaker 1.01.a",
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, NULL, NULL, hInstance, NULL );

    if( !hWnd )
        return FALSE;
            
    ShowWindow( hWnd, nCmdShow );
    UpdateWindow( hWnd );

    while( GetMessage( &msg, NULL, 0, 0 )){
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
    return msg.wParam;
}

/* -------------------------------------------------------- */
long FAR PASCAL
WndProc( HWND hWnd, WORD message, WORD wParam, LONG lParam ){
    FARPROC     lpProcAbout, lpProcHelp;
    HDC         hDC;
    PAINTSTRUCT ps;
    int         col, a, b;

    switch( message ){
     case WM_CREATE:
        if( hSolidPen == NULL )
            hSolidPen = CreatePen( PS_SOLID, 2, RGB( 0, 0, 0 ));

        if( !bMakeGameButtons( hWnd ))
            MessageBox( hWnd, "Unable to create buttons.", NULL,
                MB_OK | MB_ICONHAND );

        vInitialize();
        for( col = 0; col < COLMAX; col++ )
            EnableWindow( hGameGrid[current_row][col], TRUE );
        vMakeGoal();
        break;

     case WM_COMMAND:
        if(( wParam >= 0 ) && ( wParam < ( ROWMAX * COLMAX ))){
            if( HIWORD( lParam ) == BN_CLICKED ){
                col = wParam % COLMAX;
                guess[current_row][col]++;
                if( guess[current_row][col] > 8 )
                    guess[current_row][col] = 1;
                sprintf( str, "%d", guess[current_row][col] );
                SetWindowText( hGameGrid[current_row][col], str );
            }
        } else {
            switch( wParam ){
             case IDM_GUESS:
                if(( guess_allowed ) && ( bCheckFill() )){
                    if( bCheckGuess() ){
                    /* Player has won the game. */
                        guess_allowed = FALSE;
                        sprintf( str, "You guessed the correct answer of %d %d %d %d %d",
                            goal[0], goal[1], goal[2], goal[3], goal[4] );
                        MessageBox( hWnd, str, "Congratulations !!!",
                            MB_OK | MB_ICONINFORMATION );
                        for( col = 0; col < COLMAX; col++ ){
                            EnableWindow( hGameGrid[current_row][col], FALSE );
                        }
                    } else {
                    /* guess was incorrect, dispay clue. */
                        hDC = GetDC( hWnd );
                        sprintf( str, "%c %c %c %c %c", clues[current_row][0],
                            clues[current_row][1], clues[current_row][2],
                            clues[current_row][3], clues[current_row][4] );
                        TextOut( hDC, 300, 300 - ( current_row * 28 ), str,
                            strlen( str ));
                        ReleaseDC( hWnd, hDC );
                        current_row++;
                        if( current_row >= 10 ){
                        /* Player lost. */
                            guess_allowed = FALSE;
                            sprintf( str, "The code was %d %d %d %d %d.",
                                goal[0], goal[1], goal[2], goal[3], goal[4] );
                            MessageBox( hWnd, str, "Sorry. Better luck next time.",
                                MB_OK | MB_ICONINFORMATION );
                        } else {
                            for( col = 0; col < COLMAX; col++ ){
                                EnableWindow( hGameGrid[current_row-1][col], FALSE );
                                EnableWindow( hGameGrid[current_row][col], TRUE );
                            }
                        }
                    }
                }
                break;
             case IDM_NEW:
                guess_allowed = TRUE;
                InvalidateRect( hWnd, NULL, TRUE );
                SendMessage( hWnd, WM_CREATE, NULL, NULL );
                break;
             case IDM_EXIT:
                SendMessage( hWnd, WM_CLOSE, 0, 0L );
                break;
             case IDM_HELP:
                lpProcHelp = MakeProcInstance( HelpProc, hInst );

                DialogBox( hInst, "HelpBox", hWnd, lpProcHelp );

                FreeProcInstance( lpProcHelp );
                break;
             case IDM_ABOUT:
                lpProcAbout = MakeProcInstance( AboutProc, hInst );

                DialogBox( hInst, "AboutBox", hWnd, lpProcAbout );

                FreeProcInstance( lpProcAbout );
                break;
             default:
                return( DefWindowProc( hWnd, message, wParam, lParam ));
            }
        }
        break;
     case WM_PAINT:
        hDC = BeginPaint( hWnd, &ps );
        for( a = 0; a < ROWMAX; a++ ){
            sprintf( str, "%c %c %c %c %c", clues[a][0], clues[a][1],
                clues[a][2], clues[a][3], clues[a][4] );
            TextOut( hDC, 300, 300 - ( a * 28 ), str, strlen( str ));
        }
        EndPaint( hWnd, &ps );
        break;
     case WM_DESTROY:
        DeleteObject( hSolidPen );
        PostQuitMessage( 0 );
        break;
     default:
        return( DefWindowProc( hWnd, message, wParam, lParam ));
    }
    return 0;
}

/* -------------------------------------------------------- */
BOOL FAR PASCAL
AboutProc( HWND hDlg, WORD message, WORD wParam, LONG lParam ){
    switch( message ){
     case WM_INITDIALOG:
        return TRUE;
     case WM_COMMAND:
        if(( wParam == IDOK ) || ( wParam == IDCANCEL )){
            EndDialog( hDlg, TRUE );
            return TRUE;
        }
        break;
    }
    return FALSE;
}

/* -------------------------------------------------------- */
BOOL FAR PASCAL
HelpProc( HWND hDlg, WORD message, WORD wParam, LONG lParam ){
    switch( message ){
     case WM_INITDIALOG:
        return TRUE;
     case WM_COMMAND:
        if(( wParam == IDOK ) || ( wParam == IDCANCEL )){
            EndDialog( hDlg, TRUE );
            return TRUE;
        }
        break;
    }
    return FALSE;
}

/* -------------------------------------------------------- */
void
vInitialize(){
    int x, y;

    for( x = 0; x < ROWMAX; x++ ){
        for( y = 0; y < COLMAX; y++ ){
            guess[x][y] = 0;
            clues[x][y] = ' ';
        }
    }
    current_row = 0;
}

/* -------------------------------------------------------- */
void
vMakeGoal(){
    int     x;
    time_t  t;

    srand( (unsigned)time( &t ));
    for( x = 0; x < COLMAX; x++ ){
        goal[x] = ( rand() % 8 ) + 1;
    }
}

/* -------------------------------------------------------- */
BOOL
bCheckFill(){
    int x;

    for( x = 0; x < COLMAX; x++ ){
        if( guess[current_row][x] == 0 )
            return FALSE;
    }
    return TRUE;
}

/* -------------------------------------------------------- */
BOOL
bCheckGuess(){
    int x, y = 0, z = 0;
    int tgoal[COLMAX], tguess[COLMAX];

    for( x = 0; x < COLMAX; x++ ){
        if( guess[current_row][x] == goal[x] ){
            clues[current_row][z] = '1';
            tguess[x] = 0;
            tgoal[x] = -1;
            z++;
        } else {
            tguess[x] = guess[current_row][x];
            tgoal[x] = goal[x];
        }
    }

    if( z >= COLMAX )
        return TRUE;    /* Player guessed the right number. */

    for( x = 0; x < COLMAX; x++ ){
        for( y = 0; y < COLMAX; y++ ){
            if( tguess[x] == tgoal[y] ){
                clues[current_row][z] = '0';
                tguess[x] = 0;
                tgoal[y] = -1;
                z++;
                break;
            }
        }
    }
    return FALSE;
}

/* -------------------------------------------------------- */
BOOL
bMakeGameButtons( HWND hWnd ){
    int     x, y, Bnum = 0;
    HWND    hGuessButton;

    if( current_row >= ROWMAX )
        current_row--;

    for( x = 0; x < ROWMAX; x++ ){
        for( y = 0; y < COLMAX; y++ ){
            if( hGameGrid[x][y] != NULL ){
                if( x == current_row )
                    EnableWindow( hGameGrid[current_row][y], FALSE );
                SetWindowText( hGameGrid[x][y], "?" );
                Bnum++;
            } else
                hGameGrid[x][y] = CreateWindow( "button", "?",
                    BS_PUSHBUTTON | WS_CHILD | WS_DISABLED,
                    50 + ( y * 40 ), 300 - ( x * 28 ), 40, 25,
                    hWnd, Bnum++, hInst, NULL );
            if( !hGameGrid[x][y] )
                return FALSE;
            ShowWindow( hGameGrid[x][y], SW_SHOW );
            UpdateWindow( hGameGrid[x][y] );
        }
    }

    if( hGuessButton != NULL )
        DestroyWindow( hGuessButton );
    hGuessButton = CreateWindow( "button", "Did I get it right?",
        BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, 65, 330, 170, 30,
        hWnd, IDM_GUESS, hInst, NULL );
    if( !hGuessButton )
        return FALSE;
    ShowWindow( hGuessButton, SW_SHOW );
    UpdateWindow( hGuessButton );

    return TRUE;
}

/* -------------------------------------------------------- */

