/*****************************************************************
// 爆弾捜しゲーム / bomb sweeper
//	アイディアは違うけど、プログラムは
//	Copyright (C) 1993,2012 by AIG-SOFT
//		うわぁ、約20年ぶりに移植したのか！
/*****************************************************************
// for X-BASIC' v3.20
// なんか、まれに全部開いても終わらない(爆弾の数を数え間違っている？)バグがいるようです m(_ _)m
// 全機種対応

enum
	WX =64
	MX =(WX/2)-2	:/* マップ最大横幅(-2は枠用) / map max x width (-2 for frame)
	MY =19			:/* マップ最大縦幅 / map max y heigh
	MXX=5			:/* マップ最小横幅 / map min x width
	MYY=4			:/* マップ最小縦幅 / map min y height
//
	BOMB='*'				:/* 爆弾コード / bomb code：'*'=&h2a =< &h3f
	ERR=9					:/* 判定間違い / Judgment mistake
	BMBIT=&h80://bit(7)		:/* 爆弾在るはずビット / bit for should bomb
	CHBIT=&h40://bit(6)		:/* わかんないビット / unknown bit
	OPBIT=(BMBIT or CHBIT)	:/* オープン状態を示すビット / bits for open status
	NOPBIT=(not OPBIT)		:/* キャラクターのみを取り出すビット / bits for get character only

/* 画面表示ホーム座標 / screen home position
	SX=2	:/* sx>=2 & sx+(MX+1)*2<画面ｘ幅 screen x width
	SY=4	:/* sy>=4 & sy+MY+1    <画面ｙ幅 screen y height
// Key code
	ESC=&h1B
	CR =&h0d
endenum

font("IPAGothic")
int fzenhan
int WY=width(WX,,fzenhan)
int xw=1:/* 全角１文字の桁数
if fzenhan then xw=2

/*****************************************************************
/* グローバル変数 / global variable

dim char map( MX,MY)	:/* 現在マップ / current map
dim char map0(MX,MY)	:/* 表示用仮想画面 / virtual screen

dim int	touchNo(10)	:// タッチエリア番号
int touchCnt	:// タッチエリア数

int wx,wy		:/* マップ幅 / map width
int seed,bomb	:/* 全爆弾数,爆弾ありそう数 / the number of bomb and should bomb
int all			:/* 開けるべき全ますの数 / the number of point on all should open
int ts,dt		:/* 開始時間、経過時間 / start time, elapsed time

/*****************************************************************

int ret
int minbomb,maxbomb
/* フィールド幅、爆弾個数設定 / set field width and the number of bombs
str widthStr,heightStr,bombStr,defaultStr,messageStr
if isLocalizeJapan() then {
	widthStr ="横幅"
	heightStr="縦幅"
	bombStr="爆弾数"
	defaultStr="標準"
	messageStr="選択してください"
} else {
	widthStr ="width "
	heightStr="height"
	bombStr="bombs"
	defaultStr="default"
	messageStr="Please select"
}
	print widthStr ;"(";MXX;"～";MX;")";
	dim str menues(5)
	menues={"10","20","30"}:// 0,1,2
	menues(3)=defaultStr
	wx=selectMenu(widthStr,menues):// selectMenu()の最終項目は特別
	if wx=3 then wx=2:// 標準を選択した時
	wx=(wx+1)*10
	print wx
	print heightStr;"(";MYY;"～";MY;")";
	menues={"5","10","15","19"}
	repeat
		wy=selectMenu2(heightStr,menues)
	until wy<>-1
	wy=val(menues(wy))
	print wy

	minbomb=wx*wy/8		://MXX*MYY/8:/* 最小1/8 / min=1/8
	maxbomb=wx*wy*3/4	:///2	 :/* 最大1/2 / max=1/2
	print bombStr;"(";minbomb;"～";maxbomb")";

	int step=(maxbomb-minbomb)/4:// 5段階で表示するため
	int i
	for i=0 to 4
		menues(i)=str$(minbomb+step*i)
	next
	seed=selectMenuWithMessage(bombStr,messageStr,menues)
	seed=val(menues(seed))
	print seed
	if seed<minbomb then seed=minbomb
	if seed>maxbomb then seed=maxbomb

int sno=a_setPlayData("bomb11.aiff")

/* メインルーチン / main routine
repeat
	/* 乱数初期化 / initialize random number
	srand2()
	
	/* 爆弾配置 / place bombs
	all=BombSeed(seed)
	bomb=0
	BombCount()
	dt=0:/* 経過時間 / elapsed time
	
	/* 初期画面表示 / display initial screen
	InitScreen()

	/* キー操作 / key operation
	ret=CursorMove()
	
	/* 終わり判定 / end check
	if ret=-2 then break:/* 強制終了 / force end
	switch ret
		case -1:/* やり直し / try again
			MapPrintAll(YES):/* 全表示 / display all
			break
		case 0: /* Game clear
			GameClear()
			break
		case 1: /* Game over
			MapPrintAll(YES):/* 全表示 / display all
			GameOver()
			break
	endswitch
	WaitPCM(sno)

	/* 再開処理 / Try again
	locate(20,2)
	kbhit()
	if isLocalizeJapan() then {
		print "《もう一度しますか？》";
		setFunctionKey(0,"はい"  ,CR)
		setFunctionKey(1,"いいえ",ESC)
	} else {
		print "<< Try Again ? >>";
		setFunctionKey(0,"YES",CR)
		setFunctionKey(1,"NO" ,ESC)
	}
	displayFunctionKey(YES,0,1)
	repeat
		ret=inkey()
	until ret<>0
	displayFunctionKey(NO,0,1)
	// タッチエリアの解除 // remove touch area
	// 一旦解除してから再設定しないと重なり続ける / Once release and re-set up. Otherwise, it will continue to overlap area.
	resetTouchArea()
until (ret=ESC)
a_end(sno):// 音声バッファー解放 / release sound buffer
if isLocalizeJapan() then {
	print "終了"
} else {
	print "end"
}
end

/*****************************************************************
/* 関数群 / Functions
/*****************************************************************

func int CursorMove()
/* カーソル移動＆操作 / cursor move and operation
int x,y,c
int t
	/* 初期座標 / initial position
	/* 爆弾が無い座標に置く / move cursor to no bomb place
	for x=0 to wx-1
		for y=0 to wy-1
			if ((map(x,y) and NOPBIT)<>BOMB) then goto "CM1"
		next
	next
label "CM1"
	ts=time():/* 開始時間 / start time
	//locate(0,0):print "x=";x,"y=";y"
	while YES
		/* カーソル位置を反転表示 / reverse display at cursor point
		c=map(x,y)
		tatrb(ATRB_REVERSE)
		locate2(x,y)
		print printChr$(c);
		tatrb(ATRB_NORMAL)
		
		// キー入力待ちしながら時計を回す / timer count until key input
//		int cnt=0
		while (not keysns())
			/* キー入力の無い間
			t=time()
			if t-ts>dt then { :/* 秒が変った / change second
				dt=dt+1
				PrintTime(dt)
//				beep2(0)
//				print "cnt=";cnt
			}
//			inc(cnt)
		endwhile
		
		/* カーソル位置を普通表示 / normal display at cursor point
		locate2(x,y)
		print printChr$(c);
		//
		// キー操作判定 / key operation
		c=inkey()
		beep2(0)	:// click sound
		switch c
			case &h1b: /* やり直し / retry
				return(-1)
			
			/* カーソルは画面端でロールする / cursor roll at screen edge
			case '2': /* ↓
				if y<wy-1 then y=y+1 else y=0
				break
			case '4': /* ←
				if x>0 then x=x-1 else x=wx-1
				break
			case '6': /* →
				if x<wx-1 then x=x+1 else x=0
				break
			case '8': /* ↑
				if y>0 then y=y-1 else y=wy-1
				break
			
			case '5': /* Check
				CheckMapPoint(x,y)
				MapPrint()
				/* チェックでは全開きにはならない / The check should not be open to all
				break
			
			case ' ': /* Open
				if OpenMapPoint(x,y) then return(YES):/* game over
				/* 表示 / display
				if MapPrint() then return(NO)
				break
		endswitch
	endwhile
	return (YES)
endfunc

/*****************************************************************

func int MapPrint()
/* マップを表示する＆仮想画面変更 / diaplay map and update virtual screen
/* リターン値：0=まだ全ては開いていない , 1=全部開いた
/* return：0=It is not already open all , 1=open all
int x,y,c
int all0=0
	for y=0 to wy-1
		for x=0 to wx-1
			c=map(x,y)
			if map0(x,y)<>c then {
				/* 画面に変更がある / update screen
				locate2(x,y)
				print printChr$(c)
				map0(x,y)=c:/* 仮想画面も変更 / update virtual screen
			}
			/* 開いているポイントを数える / count open point
			if ((c and OPBIT)=OPBIT) then all0=all0+1
		next
	next
	return(all0=all)
endfunc

/*****************************************************************

func MapPrintAll(mode;int)
/* マップ全表示 / display map all
/* mode : 0=そのままで , 1=すべて開いて（間違い判定付き）
/* mode : 0=is still , 1=all open (With a judgment mistake)
int x,y,c
str ls
	for y=0 to wy-1
		ls=""
		for x=0 to wx-1
			c=map(x,y)
			if mode then {
				if (c and OPBIT)=BMBIT then {
					/* 爆弾ありとしているが・・ / checked with 'bomb is here'
					/* そこに爆弾がなければ間違い / if there is no bomb then it is doubt
					if (c and NOPBIT)<>BOMB then c=ERR
				}
				c=(c or OPBIT):/* 開く / open
			}
			ls=ls+printChr$(c)
		next
		locate2(0,y)
		print ls
	next
	// color(7)
endfunc

/*****************************************************************

func str printChr$(c;int)
/* キャラクター表示 / display character
/* c : bit6,7 = 開き済み(11)/チェックマーク(10)/爆弾マーク(01)/閉じている(00)
/*     bit0-5 = マップ状態 &h00～&h3f
/* c : bit6,7 = opened(11)/check mark(10)/bomb mark(01)/close(00)
/*     bit0-5 = map status &h00 - &h3f
str cs
	int cc=(c and OPBIT)
	switch cc
		case 0
			/* 閉じている / close
			return ("□")

		case CHBIT
			/* CHBIT チェックマーキング中 / check marking
			return ("？")

		case BMBIT
			/* 爆弾ありマーキング中 / bomb is here marking
			return ("☆")

		case OPBIT
			/* 開いている / opend
			// color(6) /* 開いた部分 / opend point
			switch (c and NOPBIT)
				case  0:cs= "・":break
				case  1:cs= "１":break
				case  2:cs= "２":break
				case  3:cs= "３":break
				case  4:cs= "４":break
				case  5:cs= "５":break
				case  6:cs= "６":break
				case  7:cs= "７":break
				case  8:cs= "８":break
				case  ERR:/* 間違い / mistake
					// color(2,7)
					cs= "×"
					break
				case BOMB:/* 爆弾 / bomb
					// color(2)
					cs= "★"
					break
			endswitch
			break
	endswitch
	// color(7,0)
	return (cs)
endfunc

/*****************************************************************

func locate2(x;int,y;int)
	locate(SX+(x)*xw,SY+y)	:/* *xw for 全角文字 / double-width character
endfunc

/*****************************************************************

func WakuPrint(yoko;str,tate;str,kado;str,fall;int)
/* マップ枠表示 / display map frame
int i
	// color(1,7)
	/* 横線 / horizontal line
	str yokos=""
	for i=0 to wx-1:yokos=yokos+yoko:next
	locate2(0,-1):print yokos
	locate2(0,wy):print yokos

	/* 縦線 / vertical line
	if fall then {
		// 内側も消す＝速い
		str tates=tate+space$(wx*xw)+tate
		for i=0 to wy-1
			locate2(-1,i):print tates;
		next
	} else {
		// 枠だけ＝遅い
		for i=0 to wy-1
			locate2(-1,i):print tate;
			locate2(wx,i):print tate;
		next
	}
	
	/* 角 / corner
	locate2(-1,-1):print kado;
	locate2(-1,wy):print kado;
	locate2(wx,-1):print kado;
	locate2(wx,wy):print kado;
	// color(7,0)
endfunc

/*****************************************************************

func InitScreen()
/* 初期画面表示 / display initial screen
	cls()
	WakuPrint("－","｜","＋",YES)
	MapPrintAll(NO)
	locate(5,0)
	if isLocalizeJapan() then {
		print using "マップ幅：##×##  爆弾数：###／###  時間：#####";wx,wy,bomb,seed,dt
			/*		 0         1           2         3   	   4	
			/*		+0123456789012345678901234567890123456789012	
			/*		+locate
	} else {
		print using "map size：##×##  bombs ：###／###  time：#####";wx,wy,bomb,seed,dt
	}
	str open$,exit$
	if isLocalizeJapan() then {
		open$="開く"
		exit$="中断"
	} else {
		open$="open"
		exit$="exit"
	}
	int x=WX/2-18
	int y=SY+wy+2
					//	 012345678901234567890123456789
	locate(x,y+0):print "      ┏━┓"
	locate(x,y+1):print "      ┃↑┃"
	locate(x,y+2):print "      ┗━┛"
	locate(x,y+3):print "┏━┓┏━┓┏━┓    ┏━━┓"
	locate(x,y+4):print "┃←┃┃？┃┃→┃    ┃";open$;"┃"
	locate(x,y+5):print "┗━┛┗━┛┗━┛    ┗━━┛"
	locate(x,y+6):print "      ┏━┓"
	locate(x,y+7):print "      ┃↓┃"
	locate(x,y+8):print "      ┗━┛"
	
	int i=0
	touchNo(inc(i))=setTouchAreaWithText(x+ 6,y  ,xw*3,3,'8',YES,125,0,5,100)
	touchNo(inc(i))=setTouchAreaWithText(x+ 6,y+6,xw*3,3,'2',YES,125,0,5,100)
	touchNo(inc(i))=setTouchAreaWithText(x   ,y+3,xw*3,3,'4',YES,125,0,5,100)
	touchNo(inc(i))=setTouchAreaWithText(x+12,y+3,xw*3,3,'6',YES,125,0,5,100)
	//
	touchNo(inc(i))=setTouchAreaWithText(x+ 6,y+3,xw*3,3,'5',YES,150,50, 5,120):/* check
	touchNo(inc(i))=setTouchAreaWithText(x+22,y+3,xw*4,3,' ',YES,150, 5 ,5,120):/* open
	touchCnt=i
	//
	setFunctionKey(0,exit$,ESC)
	displayFunctionKey(YES,0,0)
endfunc

func resetTouchArea()
// タッチエリアの解除
int i
	for i=0 to touchCnt
		removeTouchArea(touchNo(i))
	next
	touchCnt=0
endfunc

/*****************************************************************

func PrintBombCount()
/* 残り爆弾数表示 / display left bombs
	locate(5+26,0)
	print using "###";bomb
endfunc

/*****************************************************************

func PrintTime(dt;int)
/* 経過時間表示 / display time
	locate(5+42,0)
	print using "#####";dt
endfunc

/*****************************************************************

func GameClear()
/* ゲームクリア時画面表示 / display game clear screen
	/* 枠の模様を代える / change frame design
	beep()
	WakuPrint("◇","◇","◇",NO)
	beep()
	locate(6,1)
	if isLocalizeJapan() then {
		print "§§ おめでとう！ あなたは総ての爆弾を捜し当てました §§";
	} else {
		print "<< Congratulations! You've turned up all bomb >>";
	}
endfunc

/*****************************************************************

func GameOver()
/* ゲームオーバー時画面表示 / display game over screen
	/* 枠の模様を代える / change frame design
	a_play(sno)
	WakuPrint("☆","☆","☆",NO)
	a_play(sno)
	locate(10,1)
	if isLocalizeJapan() then {
		print "＠＠ あなたは爆弾にぶち当たってしまいました ＠＠";
	} else {
		print "@@ You've hit a bomb @@";
	}
endfunc

/*****************************************************************

func CheckMapPoint(x;int,y;int)
/* マップ上のポイントをチェックする / check point on the map
int c
	c=map(x,y)
	c=(c and OPBIT)
	switch c
		case OPBIT
			/* すでに開いている / already open
			/* 開いている所を調べることは不用 / Reopen the place is open waste
			beep()
			break

		case 0
			/* 閉じている -> 爆弾ありそう / closed -> probable bomb
			map(x,y)=(BMBIT or map(x,y))
			bomb=bomb+1
			PrintBombCount()
			break

		case BMBIT
			/* 爆弾ありそう -> チェックしてね / probable bomb -> check please
			map(x,y)=(c and NOPBIT)or CHBIT
			break

		case CHBIT
			/* チェックしてね -> 閉じる / please check -> close
			map(x,y)=(NOPBIT and map(x,y))
			bomb=bomb-1
			PrintBombCount()
	endswitch
endfunc

/*****************************************************************

func int OpenMapPoint(x;int,y;int)
/* マップ上のポイントを開く / open point on the map
int c
	c=map(x,y)
	if ((c and OPBIT)=OPBIT) then {
		/* すでに開いている / already open
		/* 開いているところを再度開くことは不用 / Reopen the place is open waste
		beep()
		return(NO):/* 警告以外は何もしない / nothing to do without warning
	}
	if ((c and NOPBIT)=BOMB) then {
		/* 爆弾を開けてしまった / open bomb
		a_play(sno)
		return(YES):/* game over
	}
	/* そこはまだ開いていない所なので開ける / There is open so it is not already open
	if (c=0) then {
		/* 周りに爆弾がない所ならペイント型で開く / If there is no bomb around open in the paint type
		PaintMap(x,y)
	} else {
		/* 周りに１つでも爆弾がある時は１ポイントだけ開ける
		/* When there is at least one bomb around, the only one open point
		map(x,y)=(OPBIT or map(x,y)):/* 開けた印 / opened symbol
	}
	return(NO)
endfunc

/*****************************************************************

func PaintMap(x;int,y;int)
/* マップの(x,y)から０の点を開く / open 0 point from map (x,y)
/* 基本的にはペイントと同じルーチンになるが、境界まで開くのが違う
/* Basically it is same as the paint routine, but it is different to open border
int c,xs,xe
	if map(x,y)<>0 then {
		/* 最初の点が０でなければ終わり / if the first point is not zero then end
		return()
	}
	/* 0 <- x : 左サーチ / left search
	xe=x+1 :/* 右へ捜し始めるポイント / point that is search start right
	while x>=0
		c=map(x,y)
		if ((c and OPBIT)=0) then {
			map(x,y)=(OPBIT or map(x,y))
		}
		if (c<>0) then break:/* 境界 / border
		/* 境界も開かれる / open border too
		//	境界は爆弾ではない。/ border is not bomb
		//	なぜなら爆弾の周りには１～８が必ずあるから。
		// Bacause there are from 1 to 8 around the bomb always.
		x=x-1:/* 左へ / to left
	endwhile
	if x<0 then xs=0 else xs=x
	/* xs=線分左端（境界も含む）
	/* xs=Leftmost segment(include with border)

	/* x -> wx-1 : 右サーチ / right search
	while xe<=wx-1
		c=map(xe,y)
		if (c and OPBIT)=0 then map(xe,y)=(OPBIT or map(xe,y))
		if c<>0 then break:/* 境界 / order
		xe=xe+1 :/* 右へ / to right
	endwhile
	if xe=wx then xe=xe-1
	/* xe=線分右端（境界を含む）
	/* xe=rightmost segment(include with border)
	if y>0    then PaintMapSub(xs,xe,y-1):/* 上チェック / upper check
	if y<wy-1 then PaintMapSub(xs,xe,y+1):/* 下チェック / lower check
endfunc

/*****************************************************************

func PaintMapSub(xs;int,xe;int,yy;int)
/* PaintMap()サブルーチン：上下チェック用
/* PaintMap() subroutine : for upper/lower check
int x,c
	for x=xs to xe
		c=map(x,yy)
		if c=0 then {
			PaintMap(x,yy)
		} else {
			if (c and OPBIT)=0 then map(x,yy)=(OPBIT or map(x,yy)):/* 境界も開く / open with border
		}
	next
endfunc

/*****************************************************************

func int BombSeed(seeds;int)
/* マップ内に爆弾をまく / bomb placement in the map
/* seeds : 爆弾個数 < wx*wyにすること / seeds : the number of bomb < wx*wy
/* 乱数の初期化は外部で行なうこと /  random initialize outside
int x,y
int all
	/* マップクリア / map clear
	for y=0 to wy-1
		for x=0 to wx-1
			map(x,y)=0
		next
	next
	
	/* 要開き数：爆弾以外すべて / Number must be open to all non-bomb
	all=wx*wy-seeds
	
	/* 爆弾配置 / bomb placement
	while seeds>0
		x=rand2(wx)
		y=rand2(wy)
		if map(x,y)=0 then {
			//print "bomp mapped"
			/* 爆弾を置く
			 map(x,y)=BOMB:/* マップ / map
			map0(x,y)=BOMB:/* 仮想画面 / virtual screen
			seeds=seeds-1 :/* 残りを１つ減らす / decrement left bomb
		}:/* そこにすでに爆弾がある時は別の場所を探す
		  /* When there is a bomb there already will look for another location
	endwhile
	
	return(all)
endfunc

/*****************************************************************

func BombCount()
/* マップ内の爆弾状況を書き込む / write bomb status in the map
/* 各ポイント毎の周りの爆弾の数をあらかじめ書き込む
/* Writing in advance the number of bomb around each point
int x,y,xx,yy,xs,ys,xe,ye,c
	for y=0 to wy-1
		ys=y-1:if ys<0    then ys=0
		ye=y+1:if ye>wy-1 then ye=wy-1
		for x=0 to wx-1
			if map(x,y)=BOMB then continue:/* 爆弾の所はスキップ / skip bomb
			xs=x-1:if xs<0    then xs=0
			xe=x+1:if xe>wx-1 then xe=wx-1
			/* 周りをカウント / count around
			c=0
			for yy=ys to ye
				for xx=xs to xe
					if map(xx,yy)=BOMB then c=c+1
				next
			next
			/* c=0～8
			 map(x,y)=c:/* マップ / map
			map0(x,y)=c:/* 仮想画面 / virtual screen
		next
	next
endfunc

/*****************************************************************
