/*
陣取りゲームのようなもの
再帰呼び出しのサンプルとして作成
このプログラムの要（かなめ）となる「まだ誰のものでもない通路を自分の色で踏み進む」処理は
gomap() 関数の再帰呼び出しで実現されており、ここがきわめてシンプルにできている点に注目。
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <eggx.h>

#define MM 30              // 最大サイズ
#define LL 3               // 最小サイズ
int map[MM][MM];  // 迷路パターン
int ww, hh;                // 幅、高さの最大サイズを保持する
int rate;                    // 通路になる率（100 分率中の数値）
int win; // eggx window
int offset=20; // eggx drawing offset
int size=10; // map block size
int rmargin=100; // 右側の余地サイズ

#define PMAX 10 // 最大試行回数(pcount)

void usage(char * msg)
{
	fprintf(stderr, "#error# %s\n", msg);
	fprintf(stderr, "usage : jintori r w h\n");
	fprintf(stderr, "      r : rate of the path / wall. (from 0 to 100)\n");
	fprintf(stderr, "      w : width of the map.\n");
	fprintf(stderr, "      h : height of the map.\n");
	fprintf(stderr, "  ex. jintori 40 30 20\n");
}


/* map[][] は壁なら -2, 通路なら -1 */
int initmap()
{
	int w, h;
	
	for(w=0;w<ww;w++){
		for(h=0;h<hh;h++){
			if((w==0)||(w==(ww-1))||(h==0)||(h==(hh-1))) {
				map[w][h]= -2; // 最外周は全部カベとしておく
			} else {
				if((rand()%100) < rate) { 
					map[w][h]= -1; // 通路
				} else {
					map[w][h]= -2; // カベ
				}
			}
		}
	}
	
	return 0;
}

/*現状の絵を描く */
int drawmap(int pcount)
{
	int w, h, n, k;
	
	gclr(win);
	
	for(w=0;w<ww;w++){
		for(h=0;h<hh;h++){
			switch(map[w][h]) {
			  case -1:
				newpen(win, 1); // 通路
				break;
			  case -2:
				newpen(win, 2); // カベ
				break;
			  default:
				newpen(win, 3+map[w][h]); // 踏み跡の色を適当に決める
			}
			fillrect(win, offset+w*size, offset+h*size, size, size);
		}
	}
	// ラベルを描く
	newpen(win, 2);
	fillrect(win, offset+ww/2*size, offset/4, offset/2, offset/2);
	newpen(win, 1);
	fillrect(win, offset+ww/2*size+50, offset/4, offset/2, offset/2);
	drawstr(win, offset+ww/2*size+offset/4, offset/4, 12.0, 0.0, "  wall");
	drawstr(win, offset+ww/2*size+offset/4+50, offset/4, 12.0, 0.0, "  road");
	
	// exit ボタン
	newpen(win, 1);
	drawrect(win, offset+ww*size+offset/4, offset, 40, 15);
	drawstr(win, offset+ww*size+offset/4, offset+5, 12.0, 0.0, " exit");
	
	
	// 試行回数ごとの踏み跡を数える
	for(n=1;n<=PMAX;n++){
		if(n>pcount) {
			newpen(win, 1);
			drawrect(win, offset+ww*size+offset/4, hh*size-n*offset/1.5, offset/2, offset/2);
		} else {
			k=0;
			for(w=0;w<ww;w++){
				for(h=0;h<hh;h++){
					if(map[w][h]==n) k++; 
				}
			}
			newpen(win, 3+n); // 踏み跡の色を適当に決める
			fillrect(win, offset+ww*size+offset/4, hh*size-n*offset/1.5, offset/2, offset/2);
			newpen(win, 1);
			drawstr(win, offset+ww*size+offset/4, hh*size-n*offset/1.5, 12.0, 0.0, "  %3d", k);
		}
	}
	
	copylayer(win, 1, 0); 
	
	return 0;
}		

/* 指定された座標位置から指定された値で踏んでいく */
int gomap(int p, int w, int h)
{
	if(map[w][h] != -1 ) return 0; // そこは通路じゃないので行けません
	
	map[w][h]=p; // 踏めたので自分の色で染めておく
	drawmap(p); msleep(100); // アニメーション的に再描画
	
	gomap(p, w-1, h);  // 左
	gomap(p, w+1, h);  // 右
	gomap(p, w, h-1);  // 上
	gomap(p, w, h+1);  // 下　へ踏んでみる
	
	return 0;	
}

/* たどりたいところをクリックする */
int play()
{
	int pcount=0; // 試行回数をゼロに初期化	
	int w, h, code;
	float x, y;
	
	drawmap(pcount); // 初期状態で描画
	
	while(1) {
		if(ggetxpress( win, &code, &x, &y)==ButtonPress) {
			if((x>(offset+ww*size+offset/4))&&(x<(offset+ww*size+offset/4+40))
					&&(y>offset)&&(y<(offset+15))) break; // exit
			if(pcount==PMAX) continue; // 回数上限に達したらexit以外無視
			if((x<offset)||(x>(offset+ww*size))||(y<offset)||(y>(offset+hh*size))) continue; // マップ外をクリックしたので無視
			w=(x-offset)/size;
			h=(y-offset)/size;
			if(map[w][h] != -1) continue; // 通路じゃないところをクリックしたので無視　
			pcount++;
			// printf("%d : w=%d h=%d - (%f, %f)\n", pcount, w, h, x, y);
			gomap(pcount, w, h);
			drawmap(pcount);
		};
	}
	
	return 0;
}

// ----------------------------
int main(int argc, char *argv[])
{
	if(argc!=4) {
		usage("3 parameters are required.");
		exit(1);
	}
	rate=atoi(argv[1]);
	ww=atoi(argv[2]);
	hh=atoi(argv[3]);
	if((ww<LL)||(hh<LL)) {
		char msg[100];
		sprintf(msg, "width and height should be from %d to %d", LL, MM);
		usage(msg);
		exit(1);
	}
	
	srand((unsigned int)time(NULL));
	
	win=gopen(ww*size+offset*2+rmargin,hh*size+offset*2);   
	winname(win, "JINTORI");
	layer(win, 0, 1); /* 表示は 0 番、描画は 1 番レイヤーで */
	
	initmap(); // 迷路を作成
	
	play(); // ゲーム開始
	
	// 終了後には exit ボタン反転
	newpen(win, 1);
	fillrect(win, offset+ww*size+offset/4, offset, 40, 15);
	newpen(win, 0);
	drawstr(win, offset+ww*size+offset/4, offset+5, 12.0, 0.0, " exit");
	copylayer(win, 1, 0); 
	msleep(500);
	
	gclose(win);
	
	return 0;
	
}

