では、今度はデバックの方法を考えてみます。
スタックという方法を取られたので、それを元にもうちょっと改良をご提案します。
まず、メモリの観点から省メモリというのは望ましい方向ですが、それにより分かりづらくなるのはデバックの観点からみるとイマイチなので、スタックを構造体にしてみます。
コード:
struct {
int pos; // 位置
int value; // その場所での評価値
int dep; // 評価値を得た深さ
int max_min; // その時点での最大値あるいは最低値
} debug_stack[30000]; /* デバッグ用スタック */
コメントに書いた通り評価値の他に、評価値が得られた場所、その時の深さ、その時点での評価の最大値(あるいは最小値)を記録します。
一つの面での候補手が最大でも30として、それを深さ3まで探査するとしたら30×30×30=27,000なので一応容量としては30,000としておきます(メモリを全く使わない方法もありますが、見にくくなるので今はこの方法で)。
コード:
// for(i=0;i<50000;i++) {
// debug_stack[i]=0;
// }
スタックの初期化は不要です。
ファイル書き込み部分は、
コード:
fprintf_s( fp, "[turn:%d]\n",debug_turn);
for(i=0;i<debug_st;i++) {
for(int k=0;k<debug_stack[i].dep;k++) {
fprintf_s( fp, " ");
}
fprintf_s( fp, "深さ:%d 位置:%d 評価値:%d ",debug_stack[i].dep,debug_stack[i].pos,debug_stack[i].value);
if(debug_stack[i].dep%2==0) fprintf_s( fp, "Min:%d\n",debug_stack[i].max_min);
else fprintf_s( fp, "Max:%d\n",debug_stack[i].max_min);
}
の様に、構造体の情報をわかりやすく書き込みます。深さが偶数の時は必ずMin局面なのでdebug_stack
.max_minの値はMinとして表示、それ以外はMax局面です。 (ファイルに関する関数はVC++2010対応でfprintf_s等_sの付いた関数を使ってます。)
今度はtansaku()の中で、まず最深部で評価関数を呼ぶ部分は、小細工は不要なのでそのまま返すようにします。
また、この面でのスタック場所を記憶するための変数stackを宣言しておきます。
コード:
int stack;
if (n == 0) { /* 残りの探索の深さが0だったらその盤面の評価値を返す */
int temp=hyouka(rev_turn)-hyouka(now_turn);
// temp+=100; /* 評価値がマイナスにならないようにする */
// debug_stack[debug_st++]=1000*(first_n-n+1)+temp;
return temp;
}
得られた候補手をそれぞれ探査する部分ですが、//でコメントした部分が変更部分です。
ちょっと分かりづらいかも知れませんが、stackという変数にその局面で記憶すべき場所を深く探査する前に記憶しておきます。
で、再帰から戻って来た時にその場所に評価値などを記録する方法です。
コード:
for(i=0;i<k;i++) { /* 全ての手に対して */
flip(&com_ban[0],now_turn,putable[i],TRUE); /* 石を置いてみる(com_banが更新される) */
stack=debug_st; // この面での書き込む位置を記憶しておく
++debug_st; // 次のスタック値へ
value = tansaku(n-1,first_n,rev_turn); /* 置いた盤面で、この関数を呼ぶ(再帰)first_nはそのまま渡す */
if(n==first_n){ /* 石を置いてみた後の手が相手(=Not COM)の場合で、この関数が始めに呼ばれた場合 */
hyoukati[putable[i]]=max; /* 評価値配列に書き込み */
printf("hyoukati[%d]=%d(max)\n", putable[i] ,(max-100) );
}
if(!iscomturn) {
if(value>max) {
max=value;
}
if(n==first_n){
hyoukati[putable[i]]=max;
printf("hyoukati[%d]=%d(max)\n", putable[i] ,max );
}
debug_stack[stack].max_min=max; // 現時点でのMax値をスタックに記録
} else {
if (value<min) {
min=value;
}
debug_stack[stack].max_min=min; // 現時点でのMin値をスタックに記録
}
debug_stack[stack].dep=first_n-n+1; // 深さを記録
debug_stack[stack].pos=putable[i]; // 位置を記録
debug_stack[stack].value=value; // 評価値を記録
++stack;
undo(); /* 次の手を調べるために、置いてみた手をもとに戻す */
}
/* 今の手が相手(=Not COM)の場合はmaxを返す */
// debug_stack[debug_st++]=1000*(first_n-n+1)+max;
return !iscomturn ? max : min;
// return max;
最後のスタックに関する部分も削除して、returnもmaxあるいはminを返します。
これでYssTreeで見てください。分かり易くなり、デバックもしやすくなるかと思われます。
長文失礼しました。