web-dev-qa-db-ja.com

チェスプログラムを開発するときに、与えられた値で以下の方向配列を初期化することの重要性は何ですか?

私は競技プログラミングに不慣れであり、多くの優れたコーダーのコードに次の4行が含まれていることに頻繁に気づきました(特に配列を含むもの)。

int di[] = { 1, -1, 0, 0, 1, -1, 1, -1 };
int dj[] = { 0, 0, 1, -1, 1, -1, -1, 1 };
int diK[] = { -2, -2, -1, 1, 2, 2, 1, -1 };
int djK[] = { -1, 1, 2, 2, 1, -1, -2, -2 };

これは本当に何を意味し、テクニックは何に使用されますか?

106
ejjyrex

これは、すべての方向を配列としてエンコードする手法です。di[i],dj[i]のすべてのペアは異なる方向です。

ある場所x、yにピースがあり、そのxとyの値を加算して近くの場所に移動したい場合、1,0は東、-1,0は西、0,1です。は南、0、-1は北などです。

(ここでは、左上が0,0、右下が4,4であり、配列の各インデックスが中心点Xから2,2でどのように移動するかを示しています。)

.....
.536.
.1X0.
.724.
.....

設定方法では、インデックスで^1^はビット単位のXOR)を実行すると、反対の方向になります。0と1は反対、2と3は反対などです。 (設定するもう1つの方法は、北から時計回りに移動することです。その後、^4で反対方向に移動します。)

これで、di配列とdj配列をループすることで、特定のポイントからすべての方向をテストできます。各方向を独自の行に書き出す必要はありません(合計8つです!)(ちょうど境界チェックを行うことを忘れないでください:))

diKdjKは、隣接するすべての方向ではなく、すべて 騎士の方向 を形成します。ここで、^1は1つの軸に沿って反転し、^4は反対の騎士を飛躍させます。

.7.6.
0...5
..K..
1...4
.2.3.
84
Patashu

パタシュの説明がわかりにくいと感じた方のために、明確にしようと思います。

チェス盤の特定のポイントからのすべての可能な動きを検討しようとしていると想像してください。

Di値とdj配列をループし、di値をxオフセットとして解釈し、dj値をyオフセットとして解釈すると、可能な8つの方向のそれぞれをカバーします。

正のxが東で、正のyが南であると仮定すると(Patashuの回答のように)、次のようになります。

 | di/x | dj/y |方向
-+ ------ + ------ + ----------- 
 0 | 1 | 0 |東
 1 | -1 | 0 |西
 2 | 0 | 1 |南
 3 | 0 | -1 |北
 4 | 1 | 1 |南東
 5 | -1 | -1 |北西
 6 | 1 | -1 |北東
 7 | -1 | 1 |南西

DiK配列とdjK配列は同じように解釈して、ナイトピースの可能な動きを確立できます。チェスに慣れていない場合、ナイトはLパターンで移動します。1つの方向に2つの正方形、次にそれに直角に1つの正方形(またはその逆)です。

 | diK/x | djK/y |方向
-+ ------- + ------- + ---------------- 
 0 | -2 | -1 |西2、北1 
 1 | -2 | 1 |西に2つ、南に1つ
 2 | -1 | 2 |西に1つ、南に2つ
 3 | 1 | 2 |東に1つ、南に2つ
 4 | 2 | 1 |東2、南1 
 5 | 2 | -1 |東2、北1 
 6 | 1 | -2 | 1東、2北
 7 | -1 | -2 |西に1つ、北に2つ
64

定義された配列を使用して、すべての方向で可能な移動の量をチェックするための小さなコードスニペット。

int di[] = { 1, -1, 0, 0, 1, -1, 1, -1 };
int dj[] = { 0, 0, 1, -1, 1, -1, -1, 1 };
int movesPossible[8];
int move = 0;
int posx, posy; // position of the figure we are checking

for (int d=0; d<8; d++) {
  for (move = 1; board.getElt(posx+di[d]*move, posy+dj[d]*move)==EMPTY; move++) ;
  movesPossible[d] = move-1;
}
1
Dariusz