#include <windows.h>
#include <time.h>
#define Size 75

time_t t; // from time.h
int Buttons[16], temp;
int x, y, z, i, j, prevj, cxScreen, cyScreen, Frame, Title, Width, Height, x0 = 0, y0 = 0;
int Scramble[] = {VK_DOWN, VK_UP, VK_RIGHT, VK_LEFT};
char szAppName[] = "Puzzle";
BOOL first = TRUE;
HWND hwnd, Hwnd, Hwnds[16];
HWND hwndButton1, hwndButton2, hwndButton3, hwndButton4, hwndButton5, hwndButton6, hwndButton7, hwndButton8, hwndButton9, hwndButtonA, hwndButtonB, hwndButtonC, hwndButtonD, hwndButtonE, hwndButtonF;
HINSTANCE hInstance;
RECT rect;
HFONT hFont;
LOGFONT lf;
char Arial[] = "Arial";
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	MSG          msg;
	WNDCLASS     wndclass;

	wndclass.style         = CS_HREDRAW|CS_VREDRAW;
	wndclass.lpfnWndProc   = WndProc;
	wndclass.cbClsExtra    = 0;
	wndclass.cbWndExtra    = 0;
	wndclass.hInstance     = hInstance;
	wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName  = NULL;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass(&wndclass))
		return 0;

	hwnd = CreateWindow(szAppName, szAppName,
		WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX,
		0,0,0,0,
		NULL, NULL, hInstance, NULL);

	ShowWindow(hwnd, SW_SHOWNORMAL);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (msg.message == WM_LBUTTONDOWN) {
			for (x = 1; x <= 16; x++) {
				if (IsDialogMessage(Hwnds[x], &msg)) {
					PostMessage(hwnd, WM_USER, (WPARAM)x, 0);
					break;
				}
			}
		}
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch(message)
	{
	case WM_CREATE:
		t = time(NULL);
		for (x = 0; x < 16; x++)
			Buttons[x] = x;
		lf.lfHeight = -37;
		lf.lfWeight = 700;
		lf.lfItalic = 0;
		lf.lfUnderline = 0;
		lf.lfStrikeOut = 0;
		lf.lfCharSet = 0;
		lf.lfOutPrecision = 1;
		lf.lfClipPrecision = 2;
		lf.lfQuality = 1;
		lf.lfPitchAndFamily = 0x31;
		for (x = 0; Arial[x] != 0; x++)
			lf.lfFaceName[x] = Arial[x];
		lf.lfFaceName[x] = 0;
		hFont = CreateFontIndirect (&lf);

		cxScreen = GetSystemMetrics(SM_CXFULLSCREEN);
		cyScreen = GetSystemMetrics(SM_CYFULLSCREEN);
		Frame = GetSystemMetrics(SM_CXSIZEFRAME);
		Title = GetSystemMetrics(SM_CYCAPTION);

		Width = (Size*4)+Frame;
		Height = (Size*4)+Title+Frame;
		GetClientRect(hwnd, &rect);
		MoveWindow(hwnd, (cxScreen/2)-(Width/2), (cyScreen/2)-(Height/2), Width, Height, TRUE);

		Hwnds[0] = 0;
		hwndButton1 = CreateWindow("BUTTON", "1", WS_CHILD | WS_VISIBLE, Size,   0,      Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[1] = hwndButton1;
		hwndButton2 = CreateWindow("BUTTON", "2", WS_CHILD | WS_VISIBLE, 2*Size, 0,      Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[2] = hwndButton2;
		hwndButton3 = CreateWindow("BUTTON", "3", WS_CHILD | WS_VISIBLE, 3*Size, 0,      Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[3] = hwndButton3;
		hwndButton4 = CreateWindow("BUTTON", "4", WS_CHILD | WS_VISIBLE, 0,      Size,   Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[4] = hwndButton4;
		hwndButton5 = CreateWindow("BUTTON", "5", WS_CHILD | WS_VISIBLE, Size,   Size,   Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[5] = hwndButton5;
		hwndButton6 = CreateWindow("BUTTON", "6", WS_CHILD | WS_VISIBLE, 2*Size, Size,   Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[6] = hwndButton6;
		hwndButton7 = CreateWindow("BUTTON", "7", WS_CHILD | WS_VISIBLE, 3*Size, Size,   Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[7] = hwndButton7;
		hwndButton8 = CreateWindow("BUTTON", "8", WS_CHILD | WS_VISIBLE, 0,      2*Size, Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[8] = hwndButton8;
		hwndButton9 = CreateWindow("BUTTON", "9", WS_CHILD | WS_VISIBLE, Size,   2*Size, Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[9] = hwndButton9;
		hwndButtonA = CreateWindow("BUTTON", "A", WS_CHILD | WS_VISIBLE, 2*Size, 2*Size, Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[0xA] = hwndButtonA;
		hwndButtonB = CreateWindow("BUTTON", "B", WS_CHILD | WS_VISIBLE, 3*Size, 2*Size, Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[0xB] = hwndButtonB;
		hwndButtonC = CreateWindow("BUTTON", "C", WS_CHILD | WS_VISIBLE, 0,      3*Size, Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[0xC] = hwndButtonC;
		hwndButtonD = CreateWindow("BUTTON", "D", WS_CHILD | WS_VISIBLE, Size,   3*Size, Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[0xD] = hwndButtonD;
		hwndButtonE = CreateWindow("BUTTON", "E", WS_CHILD | WS_VISIBLE, 2*Size, 3*Size, Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[0xE] = hwndButtonE;
		hwndButtonF = CreateWindow("BUTTON", "F", WS_CHILD | WS_VISIBLE, 3*Size, 3*Size, Size, Size, hwnd, NULL, hInstance, NULL);
		Hwnds[0xF] = hwndButtonF;
		for (x = 1; x <= 16; x++)
			SendMessage(Hwnds[x], WM_SETFONT, (UINT)hFont, TRUE);
		break;

	case WM_USER:
		for (z = 0; (z < 16) && (Buttons[z] != wParam); z++)
			;
		x = z % 4;
		y = z / 4;
		if ((x == (x0-1)) && (y == y0))
			SendMessage(hwnd, WM_KEYDOWN, VK_RIGHT, 0);
		else if ((x == (x0+1)) && (y == y0))
			SendMessage(hwnd, WM_KEYDOWN, VK_LEFT, 0);
		else if ((x == x0) && (y == (y0+1)))
			SendMessage(hwnd, WM_KEYDOWN, VK_UP, 0);
		else if ((x == x0) && (y == (y0-1)))
			SendMessage(hwnd, WM_KEYDOWN, VK_DOWN, 0);
		SetFocus(hwnd);
		break;

	case WM_KEYDOWN:
		if (first)
		{
			first = FALSE;
			srand((unsigned)t);
			for (i = 0; i < 256; ) // i is incremented in Scramble[j] routines
			{
				j = rand() % 4;
				if (((j == 0) && (prevj != 1)) || ((j == 2) && (prevj != 3)) || ((j == 1) && (prevj != 0)) || ((j == 3) && (prevj != 2))) //don't just move it back
					SendMessage(hwnd, WM_KEYDOWN, Scramble[j], 0);
				prevj = j;
			}
		}
		switch (wParam)
		{
		case VK_DOWN:
			if (y0) {
				x = x0;
				y = y0 - 1;
				Hwnd = Hwnds[Buttons[x+(y*4)]];
				temp = Buttons[x+(y*4)];
				Buttons[x+(y*4)] = Buttons[x0+(y0*4)];
				Buttons[x0+(y0*4)] = temp;
				MoveWindow(Hwnd, x0*Size, y0*Size, Size, Size, TRUE); // from x,y to x0,y0
				y0 -= 1;
				i++;
			}
			break;

		case VK_UP:
			if (y0 < 3) {
				x = x0;
				y = y0 + 1;
				Hwnd = Hwnds[Buttons[x+(y*4)]];
				temp = Buttons[x+(y*4)];
				Buttons[x+(y*4)] = Buttons[x0+(y0*4)];
				Buttons[x0+(y0*4)] = temp;
				MoveWindow(Hwnd, x0*Size, y0*Size, Size, Size, TRUE); // from x,y to x0,y0
				y0 += 1;
				i++;
			}
			break;

		case VK_LEFT:
			if (x0 < 3) {
				x = x0 + 1;
				y = y0;
				Hwnd = Hwnds[Buttons[x+(y*4)]];
				temp = Buttons[x+(y*4)];
				Buttons[x+(y*4)] = Buttons[x0+(y0*4)];
				Buttons[x0+(y0*4)] = temp;
				MoveWindow(Hwnd, x0*Size, y0*Size, Size, Size, TRUE); // from x,y to x0,y0
				x0 += 1;
				i++;
			}
			break;

		case VK_RIGHT:
 			if (x0) {
				x = x0 - 1;
				y = y0;
				Hwnd = Hwnds[Buttons[x+(y*4)]];
				temp = Buttons[x+(y*4)];
				Buttons[x+(y*4)] = Buttons[x0+(y0*4)];
				Buttons[x0+(y0*4)] = temp;
				MoveWindow(Hwnd, x0*Size, y0*Size, Size, Size, TRUE); // from x,y to x0,y0
				x0 -= 1;
				i++;
			}
			break;

		case VK_ESCAPE:
			DestroyWindow(hwnd);
			break;
		} // end of switch (wParam)
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	} // end of switch(message)
	return DefWindowProc(hwnd, message, wParam, lParam);
}
