領域判別と面積計算

連結領域の判別や面積の計算をどのように処理しているかについて解説。
マップ上の任意の位置を起点に、連結している同色パネルに同一グループ番号を割り当ててパネル数も調べます。
具体的なコードは以下の通り。

sffq=eep	; キュー先頭に開始位置の値を登録
repeat
	if( cnt>eeq ){ break }	; キューの末尾まで到達済みなら調査終了
	c0=sffq(cnt)
	if((mapf(c0)!=emapf)|mapg(c0)|mapd(c0)<grpchklim){}else{
		mapg(c0)=sffq; 該当セルのmapgにグループ番号(開始位置)をマークして調査済にする
		mapc(sffq)+	;	グループのパネル数をカウントアップ
		repeat 4	;上下左右のセルに範囲拡張する。※Size優先で無条件に拡張
			eeq+:sffq(eeq)=c0+du(cnt)	; 対象とする位置を計算して登録
		loop 
	}
loop

マップ配列は例によって一次元で持っています。
それぞれの役割は、
・mapf →壁、パネル各色の区別を保持
・mapg →連結領域のグループ番号を格納。同じ番号なら連結された同一グループの一員。
・mapd →個々のパネルの状態 -32〜-1:消失中、0:床色登録タイミング、1〜31:生成中、32:生成済
・mapc →グループのパネル数(面積)。要素番号がグループ番号である配列要素だけ値を保持。
この処理に入る前に、mapgとmapcはオール0クリアしています。
調査対象の位置情報は、配列sffqでキューとして管理しています。
キューのポインタeeqは、eep.1相当としてDUPされており、この処理に入る前にeep=開始位置,0 で開始位置指定と同時にクリアしています。
ちなみに、面積検査のときは左上から右下の各パネル番号を順次開始位置として処理し、張替え範囲探索の場合はクリックしたパネルを開始位置として処理します。
では各コードの詳細について。

sffq=eep	; キュー先頭に開始位置の値を登録

ループ内では、sffqから調査対象を取り出して処理していますので、調査開始位置をキューの先頭に入れておきます。

if( cnt>eeq ){ break }	; キューの末尾まで到達済みなら調査終了

無限ループの体裁になっているので、調査対象の残りが無くなったことをもってBreakします。

c0=sffq(cnt)

キューから調査対処の位置情報を取り出します。

if((mapf(c0)!=emapf)|mapg(c0)|mapd(c0)<grpchklim){}else{<処理>}

調査対処の各種マップ値を判定し、
 調査開始位置の色(emapfに代入済)と異なる色、グループ値が0以外、パネル状態が閾値grpchklim未満、
のどれにも当てはまらない場合に<処理>を実行します。
素直に書くなら

		if((mapf(c0)==emapf)&(mapg(c0)==0)&(mapd(c0)>=grpchklim)){<処理>}

ですが、先のようにすると2バイト削減になります。(今回は圧縮はほどほどでよいのですが、習性には抗えず…)
grpchklimは、パネル生成やり直しや狭小領域の判定では-100を使い、mapdのとりうる値によらず連結対象としますが、クリックした張り替え範囲を判別する際は、32を使って生成済のパネルのみを連結対象としています。
(クリック時に生成済以外のパネルを含めると、生成中のパネルを跨ぐような張り替えが起きて違和感があるので)

mapg(c0)=sffq; 該当セルのmapgにグループ番号(開始位置)をマークして調査済にする

グループ番号には、調査開始位置の値を使います。
それを該当パネルのグループマップに設定することで、所属グループ確定&調査済にしています。
(これにより、マップクリアするまでは、グループ番号が確定済のパネルを開始位置とした判別処理は、素通りになります。)

mapc(sffq)+	;	グループのパネル数をカウントアップ

パネル数は、調査開始位置(グループ番号が示す)の要素にのみ格納しています。

repeat 4	;上下左右のセルに範囲拡張する。※Size優先で無条件に拡張
	eeq+:sffq(eeq)=c0+du(cnt)	; 対象とする位置を計算して登録
loop 

調査対象のパネルの周囲(上下左右)4カ所について、調査対象とするようにキューに追加登録します。
調査済のところも含まれることがありますが、上のifで除外されるので構わず登録。


壁以外のすべてのパネルを起点としてこの判別処理を繰り返していくと、パネルの領域判別と面積計算が出来上がります。