詰め探索を利用

久しぶりに詰め将棋コードをさわりました。
挙動が変な証明数探索はやめて、
王手の手数、受けの手数を探索深さ引き算する探索深さ制御の反復進化でコードを作ってみました。
無駄合いの処理はいれてませんが、7手探索は0.05秒ぐらいで探索できるのでわりと速いです。
これを使って、初回時に、頓死する手を見つけたらハッシュに登録して、指さないようにしてみました。
いまいち信用できませんが……
あと、詰めろをやろうと思って、
打ってみて、相手がパスしたら、次に詰めがある手を、「詰めろ」とみなすというのもやってみましたが、
パスせずに受けると、ただ損するような手を「詰めろ」とみなしてしまうので、使えない方法でした(^^;
さすがに探索中に詰めルーチンを呼ぶのは、全幅探索ではもったいないかと思います。


以下のような探索深さではなくて、受け手数を、パラメーター(cn)から引いて探索すると、
王手の受けの手数が多いものは、あまり有望じゃない変化なので、その手数を引く(探索削減)
さっき書いてたコードは、思いっきり間違ってたので修正(^^; 書かないと気づかなかった。恐ろしい。
と思って修正したコードがさらに間違ってた(汗
再度修正。


結局、王手の応手の数を引くだけじゃなくて、王手の数も引かないとだめらしい。
王手がたくさんできるのは、良いことと思うけど、証明しないといけない展開図が増える方向は探索削減しないと
収束しないからかなあ。
もうちょっとコードをリファイン。

char mateITDeep( uchar SorE )
{
	for(int cn=20;cn<=50;cn+=10) {
		ret=attack( cn,SorE,0 );
		if(ret==1) break;
	}
	return ret;
}

char attack(int cn,uchar SorE,int depth )
{
//hash確認
	HashEntry e = HashTbl[hashVal & HASHMASK];
	if ( e.hashVal==hashVal && e.SorE==SorE && e.ret!=0 ) return e.ret;

	char ret=-1;

	Te t[600];
	int tp=makeMoves(SorE,t);
	if(tp==0) goto AddHash; //手が無いなら不詰み

//王手の手数を数える
	int c=0;
	for(int i=0;i< tp ;i++) {
		moveMateFast( t[i],SorE );
		if( !isMate(enemy(SorE)) ) {
			undoMateFast( t[i],SorE );
			t[i].to=0;
		}
		else {
			undoMateFast( t[i],SorE );
			c++;
		}
	}
	if(cn-c<0) return 0;//不明

	for(int i=0;i< tp ;i++) {
		if(t[i].to==0) continue;
		push();moveFast( t[i],SorE );
		int v=defense(cn-c,enemy(SorE),depth+1 );
		undoFast( t[i],SorE );pop();

		if(v>ret) ret=v;
		if(ret==1) break;
	}

AddHash:
//ハッシュ登録
	if(ret==0) return 0;

	e.hashVal = hashVal;
	e.ret=ret;
	e.SorE=SorE;
	HashTbl[hashVal & HASHMASK]=e;
	return ret;
}

char defense(int cn,uchar SorE,int depth )
{
//hash確認
	HashEntry e = HashTbl[hashVal & HASHMASK];
	if ( e.hashVal==hashVal && e.SorE==SorE && e.ret!=0 ) return e.ret;

	char ret=1;

	Te t[100];
	int tp=makeMoves(SorE,t);
	if(tp==0) goto AddHash;//手が無いなら詰み


//受けの手数を数える
	int c=0;
	for(int i=0;i< tp ;i++) {
		moveMateFast( t[i],SorE );
		if( isMate(enemy(SorE)) ) {
			undoMateFast( t[i],SorE );
			ret=0;goto AddHash;//相手を王手できる応手があれば不明
		}
		else c++;
		undoMateFast( t[i],SorE );
	}
	if(cn-c<0) return 0;//不明

	for(int i=0;i< tp ;i++) {
		push();moveFast( t[i],SorE );
		int v=attack(cn-c,enemy(SorE),depth+1 );
		undoFast( t[i],SorE );pop();

		if(v<ret) ret=v;
		if(ret==-1) break;//詰まなかった
		if(ret==0) break;//詰まなかった
	}

AddHash:
//ハッシュ登録
	if(ret==0) return 0;

	e.hashVal = hashVal;
	e.ret=ret;
	e.SorE=SorE;
	HashTbl[hashVal & HASHMASK]=e;
	return ret;
}


以下、7手詰めを解いた場合

▼持駒v歩十四v香三v桂三v銀二v金三v角二v飛二
 9 8 7 6 5 4 3 2 1   987654321
---------------------------+  ------------------+
 ・ ・ ・ ・ ・ ・ ・ ・ ・|一  0 0 0 0 0 0 0 0 0|一
 ・ ・ ・ ・ ・ ・ ・ ・ ・|二  0 0 0 0 0 0 0 0 0|二
 ・ ・ ・ ・ ・ ・ ・ ・ ・|三  0 0 0 0 0 0 0 0 0|三
 ・ ・ ・ ・ ・ ・ ・ ・ ・|四  0 0 0 0 0 0 0 0 0|四
 ・ ・ ・ ・ ・ ・ ・ ・ ・|五  0 1 1 1 1 1 1 0 0|五
 ・ ・ と ・ ・ 杏 ・ ・ ・|六  0 1 0 1 1 0 0 0 0|六
 ・ ・ ・ ・ ・ ・v圭 ・ ・|七  0 0 1 0 0 0 0-1 0|七
 ・ ・v歩 ・ ・ ・ ・ ・ ・|八  0 1-1-1 0-1-1-1 0|八
 ・ 歩 ・v玉 歩 ・ ・ ・ ・|九  0 0-2 0-1 0 0 0 0|九
---------------------------+  ------------------+
△持駒 銀二 金

#020   0.00s +0 (135)
#030   0.02s +1 (268)
詰み(268):△58銀打▼59王△49金打▼68王△77銀打▼79王△88銀