8

ピースの基本クラスがあります

 class piece;

および派生オブジェクトを含む配列

piece* board[8][8];

仮想機能による利点、クリーンなデザイン。欠点は、ボード内のピースを見つけたり、ピースを比較したりする必要がある場合、動的キャスト (または typeid) に戻さなければならないことです。これは醜く、何百万ものリクエストを行うとパフォーマンスが低下する可能性があります。

一方、ピースを識別するためのタイプフィールドを持つ単一ピースクラスの配列を作成すると、この問題は発生しません (そして、より高速になるはずです) が、非常に醜い switch ステートメントを作成する必要があります。ピースの数は有限であり、私自身がそれほど多くの切り替えを行っているとは思わないので、最終的にはこれがより良い選択になる可能性があると思いますが、どう思いますか?

これは楽しみのためです(ビットボードはありません)。

==いくつかの回答を読んで、演算子のオーバーロード ( 、!=、 ...) にのみ型フィールドを使用すると、両方の単語を最大限に活用できると思います。

boost::variant見た目もとても面白いです。

4

6 に答える 6

5

または、クラスのセットが限られている場合、つまり数がわかっている場合は、バリアントとビジターを使用します。たとえばboost::variant<king, queen, bishop, knight ...>、ボードはこのタイプの 2D 配列で構成されています。質問するには、訪問者を使用できます...

于 2010-12-31T13:51:42.377 に答える
4

クラス階層を使用します。

作品を見つけるために、作品の種類ごとに区切られたリストを保持できます。これで、各ピースのタイプを探す場所がわかります。

比較のために、仮想メソッドにも依存できます。

別のアプローチは、コンポーネント アーキテクチャを使用することです (ここで説明されているように: http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/ ) が、明確に知っているチェス ゲームには多すぎると思います。タイプとそれらのタイプがすぐに変更されないことを知っています:)。

于 2010-12-31T13:40:49.240 に答える
1

私はチェスプログラムを書いたことがありませんが、最も一般的な操作は次のようなものだと思います。

  • ボードを表示/印刷する
  • 各ピースの可能な動きのセットを取得します
  • ボードのすべてのピースの値を合計します。おそらく、ピースに依存するある種の「位置の値」を合計します(白線でルークするなど)

さらに、一部の駒には、1種類の駒にのみ適用される「状態」があります(王は、前に移動したことがない場合にのみ城を城に入れることができ、他のポーンが2マス移動した場合に、ポーンは通過することができます)。

それはすべて私にクラス階層を叫びます。(ビットボードのパフォーマンスは必要ないと仮定します)

一方、新しいピースタイプを追加する必要があることや、ピースタイプの1つを分離して再利用できることはほとんどありません。つまり、拡張性とモジュール性は実際には問題ではありません。したがって、実際には1つの場所にあるはずのアルゴリズムの重要な部分が複数のピースクラスに散在していることがわかった場合は、switchステートメントを使用してください。Piece列挙型を返すクラスに抽象メソッドtpを追加し、PieceTypeそれをオンにするだけです。

于 2010-12-31T14:09:45.143 に答える
1

私は階層を使用し、型を知りたい場合 (なぜですか?) 型を識別する仮想メソッドを用意します。

于 2010-12-31T13:37:57.177 に答える
1

楽しみのためにパフォーマンスとコードを同時に心配することはできません:)

各ニブルが 1 つのピース タイプを表す、ビットボードの代わりに「ニブルボード」(または少なくともバイトボード) を使用することを検討してください。各ニブルは、そのピース タイプで動作するシングルトン オブジェクトのテーブルのインデックスでもあります。

class Empty : public Piece {};
class Rook : public Piece {};
...

const int wrook = 1;
...
const int bpawn = 12;

Piece* Operator[13] = {new Empty(), new Rook(), ..., new Pawn()};

byte table[64] = {
    wrook, wbishop, wknight, wking, wqueen, wknight, wbishop, wrook,
    wpawn, wpawn, wpawn, wpawn, wpawn, wpawn, wpawn, wpawn, 
    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, 
    bpawn, bpawn, bpawn, bpawn, bpawn, bpawn, bpawn, bpawn, 
    brook, bbishop, bknight, bking, bqueen, bknight, bbishop, brook};

// Given some position and some operation DoSomething we would have this:
Operator[table[position]]->DoSomething(table, position, <other parameters>);

// Possible return value of DoSomething might be new table
于 2010-12-31T14:42:15.297 に答える
0

「非常に醜い switch ステートメント」が正しいテクニックです。それは醜いではありません。それは関数型プログラミングと呼ばれます。

継承は完全に間違った手法です。各ピースは異なる方法で動き、異なるグラフィックやその他のプロパティを持っています。一般的なものは何もありません。チェスの駒は抽象的ではありません。それらは個別のオブジェクトの具体的なコレクションです。

統一によって何か共通のものを作る必要があります: 和型と呼ばれるものを作成します。Ocaml では:

type shape = Pawn | Rook | Knight | Bishop | Queen | King
type color = Black | White
type piece = shape * color
type pos = { row:int;  col:int }

let check_white_move piece board from to = match piece with
| Pawn -> on_board to && (from.row = 2 && to.row = 4 or to.row = from.row + 1)
| ....

C++ には適切な合計型がありません。代わりに使用できます。

enum shape { pawn, rook, knight, bishop, queen, king};
..
bool check_white_move (..) { switch piece {
 case pawn: ...

もっと不器用です。C および C++ 委員会に苦情を申し立てます。ただし、正しい概念を使用してください。合計型 (判別共用体、バリアント) は具体的な型の個別のセットを統合する方法です。クラスと継承は、抽象化を表し、その実装を提供するために使用されます。

チェスについて抽象的なことは何もありません。それはすべての組み合わせについてです。これは、さまざまな手法の長所と短所の問題ではなく、正しい手法を使用することです。

[ところで、ええ、ブーストバリアントを試すことができますが、このアプリケーションには推奨できません。ピースには関連するデータがないため、列挙型は完璧です]

于 2010-12-31T14:38:22.847 に答える