First, one of the smallest Windows programs possible...my version of the excellent code breaking game, Mastermind. The code is best compiled with the QuickC Compiler, version 2.5. Good luck finding it! The executable is < 9KB!
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "master.h"
HANDLE hInst;
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
if (!hPrevInstance)
if (!InitApplication(hInstance)) return FALSE;
if (!InitInstance(hInstance, nCmdShow)) return FALSE;
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
BOOL InitApplication(HANDLE hInstance)
{
WNDCLASS wc;
wc.style = NULL;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(GRAY_BRUSH);
wc.lpszMenuName = "masterMenu";
wc.lpszClassName = "masterWClass";
return RegisterClass(&wc);
}
BOOL InitInstance(HANDLE hInstance, int nCmdShow)
{
HWND hWnd;
int i, j;
COLORREF colorref;
hInst = hInstance;
hWnd = CreateWindow("masterWClass", "Mastermind",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
350, 400, NULL, NULL, hInstance, NULL);
if (!hWnd) return FALSE;
// Create the windows for drawing the board.
for (i = 0; i < 10; i++)
{
for (j = 0; j < 4; j++)
{
guess[i][j].color = NOCOLOR;
guess[i][j].rect.top = 90 + (j * 28);
guess[i][j].rect.bottom = guess[i][j].rect.top + 16;
guess[i][j].rect.left = 40 + (i * 28);
guess[i][j].rect.right = guess[i][j].rect.left + 16;
guess[i][j].hwnd = CreateWindow("Button", "",
BS_OWNERDRAW | WS_CHILD | WS_VISIBLE,
guess[i][j].rect.top,
guess[i][j].rect.left,
guess[i][j].rect.right -
guess[i][j].rect.left,
guess[i][j].rect.bottom -
guess[i][j].rect.top, hWnd,
IDC_GUESSES + (i * 4) + j,
hInstance, NULL);
result[i][j].color = NOCOLOR;
result[i][j].rect.top = 216 + (j * 24);
result[i][j].rect.bottom = result[i][j].rect.top + 16;
result[i][j].rect.left = 40 + (i * 28);
result[i][j].rect.right = result[i][j].rect.left + 16;
result[i][j].hwnd = CreateWindow("Button", "",
BS_OWNERDRAW | WS_CHILD | WS_VISIBLE,
result[i][j].rect.top,
result[i][j].rect.left,
result[i][j].rect.right -
result[i][j].rect.left,
result[i][j].rect.bottom -
result[i][j].rect.top, hWnd,
IDC_RESULTS + (i * 4) + j,
hInstance, NULL);
}
}
for (i = 0; i < MAXCOLORS; i++)
{
usercolors[i].hwnd = CreateWindow("Button", "",
BS_OWNERDRAW | WS_CHILD | WS_VISIBLE,
70 + (25 * i), 325, 16,
16, hWnd, IDC_COLOR1 + i, hInstance, NULL);
usercolors[i].color = WHITE + i;
GetWindowRect(usercolors[i].hwnd, &usercolors[i].rect);
switch ((MMCOLOR)i)
{
case WHITE:
colorref = RGB(255, 255, 255);
break;
case RED:
colorref = RGB(255, 0, 0);
break;
case GREEN:
colorref = RGB(0, 128, 0);
break;
case BLUE:
colorref = RGB(0, 0, 255);
break;
case YELLOW:
colorref = RGB(255, 255, 0);
break;
case BLACK:
default:
colorref = RGB(0, 0, 0);
break;
}
hbrush[i] = CreateSolidBrush(colorref);
}
hTestButton = CreateWindow("Button", "Test", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,
224, 325, 64, 20, hWnd, IDC_TEST, hInstance, NULL);
srand((short)GetTickCount());
ShowWindow(hWnd, nCmdShow);
StartGame(hWnd);
UpdateWindow(hWnd);
return TRUE;
}
LONG FAR PASCAL MainWndProc(HWND hWnd, unsigned message, WORD wParam, LONG lParam)
{
HDC hDC;
HBRUSH hOldBrush;
int i, j, bulls, cows;
FARPROC lpProcAbout;
DRAWITEMSTRUCT *lpDIS;
switch (message)
{
case WM_DRAWITEM:
lpDIS = (DRAWITEMSTRUCT *)lParam;
if (lpDIS->CtlID < NO_MORE_COLORS) // Color select tool
{
hOldBrush = SelectObject(lpDIS->hDC,
hbrush[lpDIS->CtlID - IDC_COLOR1]);
Ellipse(lpDIS->hDC, lpDIS->rcItem.top, lpDIS->rcItem.left,
lpDIS->rcItem.right, lpDIS->rcItem.bottom);
SelectObject(lpDIS->hDC, hOldBrush);
}
else if (lpDIS->CtlID < IDC_GUESSES + 40) // User guess window
{
i = lpDIS->CtlID - IDC_GUESSES;
j = i;
if (i >= 4) i /= 4;
j -= (i * 4);
hOldBrush = SelectObject(lpDIS->hDC, hbrush[guess[i][j].color]);
Ellipse(lpDIS->hDC, lpDIS->rcItem.top, lpDIS->rcItem.left,
lpDIS->rcItem.right, lpDIS->rcItem.bottom);
SelectObject(lpDIS->hDC, hOldBrush);
}
else if (lpDIS->CtlID < IDC_RESULTS + 40) // Result window
{
i = lpDIS->CtlID - IDC_RESULTS;
j = i;
if (i >= 4) i /= 4;
j -= (i * 4);
if (result[i][j].color == NOCOLOR)
hOldBrush = SelectObject(lpDIS->hDC,
GetStockObject(GRAY_BRUSH));
else
hOldBrush =
SelectObject(lpDIS->hDC, hbrush[result[i][j].color]);
Ellipse(lpDIS->hDC, lpDIS->rcItem.top, lpDIS->rcItem.left,
lpDIS->rcItem.right, lpDIS->rcItem.bottom);
SelectObject(lpDIS->hDC, hOldBrush);
}
switch (lpDIS->itemAction)
{
case ODA_DRAWENTIRE: // No further action required.
//
break;
case ODA_SELECT:
// The control ID of the DRAWITEMSTRUCT can be used to determine what action
// to take. The user color select tools are the first resources in the list.
// Use that knowledge to change the current color based on the ID.
if (lpDIS->CtlID < NO_MORE_COLORS)
current_color = lpDIS->CtlID - IDC_COLOR1;
// This bit of code unwinds which element of the user guesses array is being
// selected, and sets the color of the element to the current color.
else if (lpDIS->CtlID < IDC_GUESSES + 40)
{
i = lpDIS->CtlID - IDC_GUESSES;
j = i;
if (i >= 3) i /= 4;
else i = 0;
if (j >= 4) j -= (i * 4);
guess[try_num][j].color = current_color;
}
break;
default:
break;
}
//
break;
case WM_COMMAND:
switch (wParam)
{
case IDM_ABOUT:
lpProcAbout = MakeProcInstance(About, hInst);
DialogBox(hInst, "AboutBox", hWnd, lpProcAbout);
FreeProcInstance(lpProcAbout);
break;
case IDM_PLAY:
StartGame(hWnd);
break;
case IDC_TEST:
for (i = 0; i < 4; i++)
{
if (guess[try_num][i].color == code[i])
result[try_num][i].color = BLACK;
else
for (j = 0; j < 4; j++)
if (guess[try_num][j].color == code[i])
result[try_num][i].color = WHITE;
}
if (result[try_num][0].color == BLACK &&
result[try_num][1].color == BLACK &&
result[try_num][2].color == BLACK &&
result[try_num][3].color == BLACK)
{
MessageBox(hWnd, "CODE BROKEN", "Mastermind", MB_OK);
StartGame(hWnd);
}
else if (++try_num == 10)
{
MessageBox(hWnd, "Tries exceeded.", "Mastermind", MB_OK);
StartGame(hWnd);
}
InvalidateRect(hWnd, NULL, TRUE);
break;
default: return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
for (i = 0; i < MAXCOLORS; i++)
{
if (usercolors[i].hwnd != NULL) DestroyWindow(usercolors[i].hwnd);
if (hbrush[i] != NULL) DeleteObject(hbrush[i]);
}
for (i = 0; i < 10; i++)
for (j = 0; j < 4; j++)
{
DestroyWindow(result[i][j].hwnd);
DestroyWindow(guess[i][j].hwnd);
}
DestroyWindow(hTestButton);
break;
default: return DefWindowProc(hWnd, message, wParam, lParam);
}
return NULL;
}
BOOL FAR PASCAL About(HWND hDlg, unsigned 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;
default:
break;
}
return FALSE;
}
void GenerateCode(void)
{
int i, iRand;
for (i = 0; i < 4; i++)
{
iRand = rand();
if (iRand < 5461) code[i] = WHITE;
else if (iRand < 10922) code[i] = BLACK;
else if (iRand < 16383) code[i] = RED;
else if (iRand < 21844) code[i] = GREEN;
else if (iRand < 27305) code[i] = BLUE;
else code[i] = YELLOW;
}
}
void StartGame(HWND hWnd)
{
int i, j;
current_color = WHITE;
GenerateCode();
for (i = 0; i < 10; i++)
for (j = 0; j < 4; j++)
{
guess[i][j].color = WHITE;
result[i][j].color = NOCOLOR;
}
try_num = 0;
InvalidateRect(hWnd, NULL, TRUE);
//
}
// Games like Mastermind are excellent projects when you are in the phase of
// learning the environment you are programming. The game is simple, the rules
// are rigid, and there are no pesky real time animations with which to contend.
// My implementation is a demonstration of how owner drawn controls can be
// used by an application with my smart data concept to define a specific set
// of behaviors. Notice that this obviates the need for a WM_PAINT message
// handler. This version is also very easy to port to other platforms. If you
// want to learn many languages, this program can help you to benchmark your
// progress in a particular language.