// ■迷路作成
//   乱数で方向を選びながらブロックを置いていきます。
//   ブロックが置かれた位置が壁になります。
//   処理を進める過程で、ブロックを置ける可能性がある座標を
//   X[],Y[]に登録しておきます。
//   ブロックを置けなくなったら、X[],Y[]から1箇所を選んで、
//   再度、プロックを置いていきます。
//   X[],Y[]が空になったら迷路完成です。
// 【実行】
//   実行後、迷路が表示されます。
//   左ボタンをクリックすると、新たな迷路が表示されます。
#include "myWin.h"
#include "time.h"
#include "stdlib.h"
#define frand() ((double) rand()/(RAND_MAX+1))
#define XMAX 40		// X方向の数(偶数とする)
#define YMAX 20		// Y方向の数(偶数とする)
#define XDIV XMAX / 2 - 2
#define YDIV YMAX / 2 - 2
#define MAXBLK 200	// ブロック配列大きさ(XMAX*YMAX/4以下とする)
int map[XMAX+1][YMAX+1];
int X[MAXBLK+1], Y[MAXBLK+1];
int dir[][2]={{ 2, 0}, { 0, 2},{ -2, 0},{ 0, -2}};
int nBlk, nDir;
void insBlk(int i, int j){
	nBlk++; X[nBlk]=i; Y[nBlk]=j; 
}
void init(){//初期設定
	int i,j; 
	for(i=0; i<=XMAX;i++) for(j=0; j<=YMAX;j++) {map[i][j] = true;}
	for(i=3; i<=(XMAX-3);i++) for(j=3; j<=(YMAX-3);j++) {map[i][j] = false;}
	map[2][3] = false; map[XMAX-2][YMAX-3] = false; nBlk=0;
	for(i=2;i<=XDIV;i++){ insBlk(i*2,2); insBlk(i*2,YMAX-2);}
	for(j=2;i<=YDIV;i++){ insBlk(2,j*2); insBlk(XMAX-2,j*2);}
}
void selBlk(int *i, int *j){//ブロック位置の選択
	int R=(int)(frand()*nBlk)+1; *i = X[R]; *j = Y[R];
	X[R] = X[nBlk]; Y[R] = Y[nBlk]; nBlk--;
}
void selDir(int *i, int *j){//方向の選択
	int R=(int)(frand()*nDir);	*i = dir[R][0]; *j=dir[R][1];
	dir[R][0]=dir[nDir-1][0];dir[R][1]=dir[nDir-1][1];
	dir[nDir-1][0]=*i;dir[nDir-1][1]=*j;
	nDir--;
}
void genMap(){//迷路作成
	int i,j,dI,dJ,OK;
	while(nBlk>0){
		selBlk(&i, &j);
		do{
			nDir=4;
			do{	selDir(&dI, &dJ); OK= !map[i+dI][j+dJ];
			}while((!OK) &&( nDir!=0));
			if(OK){
				map[i+dI/2][j+dJ/2]=true;i+=dI; j+=dJ;map[i][j]=true;
				insBlk(i,j);
			}
		}while(OK);
	}
}

void procPaint(HWND hw, WPARAM wp,LPARAM lp){
	PAINTSTRUCT ps;	HDC hdc=BeginPaint(hw, &ps);
	HBRUSH hb=CreateSolidBrush(0x77FF);	SelectObject(hdc,hb);
	for(int j=2,Y=10; j<=(YMAX-2);j++, Y+=10){
		for(int i=2, X=10; i<=(XMAX-2);i++,X+=10)
			if(map[i][j]) Rectangle(hdc,X,Y,X+11,Y+11) ;
	}
	DeleteObject(hb);
	EndPaint(hw,&ps);
}
void procLButtonDown(HWND hw, WPARAM wp,LPARAM lp){
	init(); genMap();
	InvalidateRect(hw,NULL,TRUE);
}
void procCreate(HWND hw, WPARAM wp,LPARAM lp){
	SetWindowText(hw,TEXT("迷路(左クリックで再生成)"));
	MoveWindow(hw,0,0,500,300,TRUE);
	srand((unsigned int)time(NULL));
	procLButtonDown(hw,wp,lp);
}
LRESULT CALLBACK WndProc(HWND hw, UINT msg, WPARAM wp,LPARAM lp){
	switch(msg){
	case WM_DESTROY     : PostQuitMessage(0)       ; return 0;
	case WM_CREATE      : procCreate(hw,wp,lp)     ; return 0;
	case WM_PAINT       : procPaint(hw,wp,lp)      ; return 0;
	case WM_LBUTTONDOWN : procLButtonDown(hw,wp,lp); return 0;
	}
	return DefWindowProc(hw,msg,wp,lp);
}