100

厳密には質問ではなく、もっとパズルです...

何年にもわたって、私は新入社員のいくつかの技術面接に携わってきました。標準的な「Xテクノロジーを知っていますか」という質問をする以外に、私はそれらがどのように問題に取り組むかについても感じ取ろうとしました。通常、面接の前日にメールで質問を送信し、翌日までに解決策を考え出すことを期待しています。

多くの場合、結果は非常に興味深いものになります-間違っていますが、興味深いものです-そして、彼らが特定のアプローチをとった理由を説明できれば、その人はまだ私の推薦を得るでしょう。

だから私は、StackOverflowの聴衆に私の質問の1つを投げかけると思いました。

質問:チェスゲーム(またはそのサブセット)の状態をエンコードするために考えることができる最もスペース効率の良い方法は何ですか?つまり、駒が合法的に配置されたチェス盤が与えられた場合、この初期状態と、ゲーム内のプレーヤーが行ったその後のすべての合法的な動きの両方をエンコードします。

答えにコードは必要ありません。使用するアルゴリズムの説明だけです。

編集:ポスターの1つが指摘しているように、私は移動間の時間間隔を考慮していませんでした。オプションの追加としてそれも自由に説明してください:)

EDIT2:さらに明確にするために...エンコーダー/デコーダーはルールを認識していることを忘れないでください。実際に保存する必要があるのは、プレーヤーの選択だけです。それ以外のものは、エンコーダー/デコーダーによって認識されていると見なすことができます。

EDIT3:ここで勝者を選ぶのは難しいでしょう:)たくさんの素晴らしい答え!

4

31 に答える 31

134

更新:私はこのトピックがとても好きで、プログラミングパズル、チェスの位置、ハフマンコーディングを書きました。これを読んだ場合、完全なゲーム状態を保存する唯一の方法は、動きの完全なリストを保存することであると判断しました。理由を読んでください。そのため、ピースのレイアウトには、問題の少し簡略化されたバージョンを使用します。

問題

この画像は、チェスの開始位置を示しています。チェスは8x8のボードで発生し、各プレーヤーは、次の図に示すように、8つのポーン、2つのルーク、2つのナイト、2つのビショップ、1つのクイーン、1つのキングで構成される16個の同一のセットから始まります。

チェスの開始位置

位置は通常、列の文字とそれに続く行の番号として記録されるため、ホワイトのクイーンはd1にあります。移動は、ほとんどの場合、代数表記で保存されます。これは明確であり、通常、必要な最小限の情報のみを指定します。この開口部を検討してください:

  1. e4 e5
  2. Nf3 Nc6
  3. …</li>

これは次のように解釈されます。

  1. 白は王のポーンをe2からe4に移動します(e4、つまり「e4」に到達できる唯一の駒です)。
  2. 黒は王のポーンをe7からe5に移動します。
  3. 白は騎士(N)をf3に移動します。
  4. 黒は騎士をc6に移動させます。
  5. …</li>

ボードは次のようになります。

早期開店

プログラマーにとって重要な能力は、問題を正確かつ明確に特定できることです。

では、何が欠けているか、あいまいですか?結局のところ、たくさんあります。

ボード状態とゲーム状態

最初に決定する必要があるのは、ゲームの状態を保存するのか、ボード上のピースの位置を保存するのかです。ピースの位置を単純にエンコードすることは1つのことですが、問題は「その後のすべての法的措置」を意味します。この問題は、この時点までの動きを知ることについても何も述べていません。これから説明するように、これは実際には問題です。

キャスリング

ゲームは次のように進行しました。

  1. e4 e5
  2. Nf3 Nc6
  3. Bb5 a6
  4. Ba4 Bc5

ボードは次のようになります。

後で開く

白にはキャスリングのオプションがあります。このための要件の一部は、キングと関連するルークが移動することはできないということです。そのため、キングまたは各サイドのルークのいずれかが移動したかどうかを保存する必要があります。明らかに、開始位置にない場合は移動しています。そうでない場合は、指定する必要があります。

この問題に対処するために使用できるいくつかの戦略があります。

まず、追加の6ビットの情報(ルークとキングごとに1つ)を保存して、そのピースが移動したかどうかを示すことができます。適切なピースが入っている場合は、これらの6つの正方形の1つにビットを格納するだけで、これを合理化できます。または、動かない各ピースを別のピースタイプとして扱うこともできます。そのため、各サイドに6つのピースタイプ(ポーン、ルーク、ナイト、ビショップ、クイーン、キング)の代わりに、8つ(動かないルークと動かないキングを追加)があります。

アンパッサン

チェスのもう1つの独特で、しばしば無視されるルールは、アンパッサンです。

アンパッサン

ゲームが進行しました。

  1. e4 e5
  2. Nf3 Nc6
  3. Bb5 a6
  4. Ba4 Bc5
  5. OO b5
  6. Bb3 b4
  7. c4

b4の黒のポーンには、b4のポーンをc3に移動して、c4の白のポーンを取得するオプションがあります。これは最初の機会にのみ発生します。つまり、ブラックがオプションを渡した場合、次の動きをとることができなくなります。したがって、これを保存する必要があります。

前の動きを知っていれば、アンパッサンが可能であれば間違いなく答えることができます。または、4番目のランクの各ポーンが2回前進して、そこに移動したかどうかを保存することもできます。または、ボード上の可能な各アンパッサンの位置を見て、それが可能かどうかを示すフラグを立てることもできます。

昇進

ポーンプロモーション

ホワイトの動きです。ホワイトがh7からh8にポーンを移動すると、他のピースに昇格できます(ただしキングは昇格できません)。99%の確率で女王に昇格しますが、昇格しない場合もあります。通常、そうでない場合は勝つと膠着状態になる可能性があるためです。これは次のように書かれています:

  1. h8 = Q

これは私たちの問題において重要です。なぜなら、それは、両側に固定された数のピースがあることを期待できないことを意味するからです。8つのポーンすべてが昇格した場合、片側が9つのクイーン、10のルーク、10のビショップ、または10のナイトになる可能性は完全にあります(ただし、信じられないほどありそうにありません)。

膠着状態

あなたが最善の戦術を勝ち取ることができない立場にあるときは、膠着状態を試みることです。最も可能性の高い変種は、合法的な移動を行うことができない場合です(通常、キングをチェックしたときに移動が発生するため)。この場合、引き分けを請求できます。これは簡単に対応できます。

2番目の変形は、 3回の繰り返しによるものです。同じボードポジションがゲームで3回発生した場合(または次の手で3回発生する場合)、ドローを要求できます。位置は特定の順序で発生する必要はありません(つまり、同じ一連の移動を3回繰り返す必要はありません)。これは、以前のすべてのボード位置を覚えておく必要があるため、問題を非常に複雑にします。これが問題の要件である場合、問題に対する唯一の可能な解決策は、以前のすべての動きを保存することです。

最後に、50手ルールがあります。ポーンが移動しておらず、前の50回の連続した移動で駒が取られていない場合、プレーヤーは引き分けを要求できます。そのため、ポーンが移動された、または駒が取られてからの移動数を保存する必要があります(2つのうち最新のもの。これには必要です。 6ビット(0-63)。

誰の番ですか?

もちろん、それが誰の番かを知る必要もあります。これはほんの少しの情報です。

2つの問題

膠着状態の場合のため、ゲームの状態を保存するための唯一の実行可能または賢明な方法は、この位置につながったすべての動きを保存することです。その1つの問題に取り組みます。ボードの状態の問題はこれに単純化されます。キャスリング、アンパッサン、膠着状態を無視してボード上のすべてのピースの現在の位置を保存し、その順番はです

ピースのレイアウトは、各正方形の内容を保存するか、各ピースの位置を保存するかの2つの方法のいずれかで広く処理できます。

シンプルな内容

6つのピースタイプ(ポーン、ルーク、ナイト、ビショップ、クイーン、キング)があります。各ピースは白または黒にすることができるので、正方形には12個の可能なピースの1つを含めることができます。または、空にすることで13個の可能性があります。13は4ビット(0〜15)で格納できるため、最も簡単な解決策は、各正方形に4ビットを掛けて64平方または256ビットの情報を格納することです。

この方法の利点は、操作が非常に簡単で高速であることです。これは、ストレージ要件を増やすことなく、さらに3つの可能性を追加することで拡張することもできます。最後のターンで2スペース移動したポーン、移動していないキング、移動していないルークです。前述の問題の。

しかし、私たちはもっとうまくやることができます。

ベース13エンコーディング

ボードの位置を非常に大きな数と考えると役立つことがよくあります。これは、コンピュータサイエンスでよく行われます。たとえば、停止問題はコンピュータプログラムを(正しく)多数として扱います。

最初のソリューションでは、位置を64桁の16進数として扱いますが、示されているように、この情報には冗長性があり(「桁」あたり3つの未使用の可能性があるため)、数値スペースを64進数の13桁に減らすことができます。もちろん、これはベース16ほど効率的に行うことはできませんが、ストレージ要件を節約できます(そして、ストレージスペースを最小限に抑えることが私たちの目標です)。

基数10では、数値234は2 x 10 2 + 3 x 10 1 + 4 x100に相当します

基数16では、数値0xA50は10 x 16 2 + 5 x 16 1 + 0 x 16 0 = 2640(10進数)に相当します。

したがって、位置をp 0 x 13 63 + p 1 x 13 62 + ... + p 63 x 13 0としてエンコードできます。ここで、 piは正方形iの内容を表します

2256は約1.16e77に相当します。13 64は約1.96e71に相当し、237ビットのストレージスペースが必要です。わずか7.5%の節約には、操作コストが大幅に増加します。

可変ベースエンコーディング

法務委員会では、特定の部分が特定の正方形に表示されない場合があります。たとえば、ポーンは1番目または8番目のランクでは発生しないため、これらの正方形の可能性は11に減少します。これにより、可能なボードは11 16 x 13 48 = 1.35e70(約)に減少し、233ビットのストレージスペースが必要になります。

実際には、このような値を10進数(または2進数)との間でエンコードおよびデコードするのは少し複雑ですが、確実に実行でき、読者の練習問題として残されています。

可変幅アルファベット

前の2つの方法は、どちらも固定幅のアルファベットエンコーディングとして説明できます。アルファベットの11、13、または16の各メンバーは、別の値に置き換えられます。各「文字」は同じ幅ですが、各文字の可能性が同じではないことを考慮すると、効率を向上させることができます。

モールス信号

モールス信号(上の写真)を考えてみましょう。メッセージ内の文字は、ダッシュとドットのシーケンスとしてエンコードされます。それらのダッシュとドットは、それらを区切るためにそれらの間に一時停止を入れて(通常)無線で転送されます。

文字E(英語で最も一般的な文字)が単一のドットであり、可能な限り短いシーケンスであるのに対し、Z(最も頻度が低い)は2つのダッシュと2つのビープ音であることに注意してください。

このようなスキームは、予想されるメッセージのサイズを大幅に削減できますが、ランダムな文字シーケンスのサイズを増やすという犠牲を伴います。

モールス信号には別の機能が組み込まれていることに注意してください。ダッシュは3ドットの長さであるため、ダッシュの使用を最小限に抑えるために、上記のコードはこれを念頭に置いて作成されています。1と0(ビルディングブロック)にはこの問題がないため、複製する必要のある機能ではありません。

最後に、モールス信号には2種類の休符があります。短い休符(ドットの長さ)は、ドットとダッシュを区別するために使用されます。より長いギャップ(ダッシュの長さ)は、文字を区切るために使用されます。

では、これは私たちの問題にどのように当てはまりますか?

ハフマン符号化

ハフマン符号化と呼ばれる可変長符号を処理するためのアルゴリズムがあります。ハフマンコーディングは、可変長コード置換を作成します。通常、シンボルの予想される頻度を使用して、より一般的なシンボルに短い値を割り当てます。

ハフマンコードツリー

上記のツリーでは、文字Eは000(または左-左-左)としてエンコードされ、Sは1011です。このエンコード方式が明確であることは明らかです。

これはモールス信号との重要な違いです。モールス信号には文字区切り文字があるため、あいまいな置換を行うことができます(たとえば、4つのドットはHまたは2 Isになります)が、1と0しかないため、代わりに明確な置換を選択します。

以下は簡単な実装です。

private static class Node {
  private final Node left;
  private final Node right;
  private final String label;
  private final int weight;

  private Node(String label, int weight) {
    this.left = null;
    this.right = null;
    this.label = label;
    this.weight = weight;
  }

  public Node(Node left, Node right) {
    this.left = left;
    this.right = right;
    label = "";
    weight = left.weight + right.weight;
  }

  public boolean isLeaf() { return left == null && right == null; }

  public Node getLeft() { return left; }

  public Node getRight() { return right; }

  public String getLabel() { return label; }

  public int getWeight() { return weight; }
}

静的データの場合:

private final static List<string> COLOURS;
private final static Map<string, integer> WEIGHTS;

static {
  List<string> list = new ArrayList<string>();
  list.add("White");
  list.add("Black");
  COLOURS = Collections.unmodifiableList(list);
  Map<string, integer> map = new HashMap<string, integer>();
  for (String colour : COLOURS) {
    map.put(colour + " " + "King", 1);
    map.put(colour + " " + "Queen";, 1);
    map.put(colour + " " + "Rook", 2);
    map.put(colour + " " + "Knight", 2);
    map.put(colour + " " + "Bishop";, 2);
    map.put(colour + " " + "Pawn", 8);
  }
  map.put("Empty", 32);
  WEIGHTS = Collections.unmodifiableMap(map);
}

と:

private static class WeightComparator implements Comparator<node> {
  @Override
  public int compare(Node o1, Node o2) {
    if (o1.getWeight() == o2.getWeight()) {
      return 0;
    } else {
      return o1.getWeight() < o2.getWeight() ? -1 : 1;
    }
  }
}

private static class PathComparator implements Comparator<string> {
  @Override
  public int compare(String o1, String o2) {
    if (o1 == null) {
      return o2 == null ? 0 : -1;
    } else if (o2 == null) {
      return 1;
    } else {
      int length1 = o1.length();
      int length2 = o2.length();
      if (length1 == length2) {
        return o1.compareTo(o2);
      } else {
        return length1 < length2 ? -1 : 1;
      }
    }
  }
}

public static void main(String args[]) {
  PriorityQueue<node> queue = new PriorityQueue<node>(WEIGHTS.size(),
      new WeightComparator());
  for (Map.Entry<string, integer> entry : WEIGHTS.entrySet()) {
    queue.add(new Node(entry.getKey(), entry.getValue()));
  }
  while (queue.size() > 1) {
    Node first = queue.poll();
    Node second = queue.poll();
    queue.add(new Node(first, second));
  }
  Map<string, node> nodes = new TreeMap<string, node>(new PathComparator());
  addLeaves(nodes, queue.peek(), &quot;&quot;);
  for (Map.Entry<string, node> entry : nodes.entrySet()) {
    System.out.printf("%s %s%n", entry.getKey(), entry.getValue().getLabel());
  }
}

public static void addLeaves(Map<string, node> nodes, Node node, String prefix) {
  if (node != null) {
    addLeaves(nodes, node.getLeft(), prefix + "0");
    addLeaves(nodes, node.getRight(), prefix + "1");
    if (node.isLeaf()) {
      nodes.put(prefix, node);
    }
  }
}

考えられる出力の1つは次のとおりです。

         White    Black
Empty          0 
Pawn       110      100
Rook     11111    11110
Knight   10110    10101
Bishop   10100    11100
Queen   111010   111011
King    101110   101111

開始位置の場合、これは32 x 1 + 16 x 3 + 12 x 5 + 4 x 6=164ビットに相当します。

状態の違い

別の可能なアプローチは、最初のアプローチをハフマンコーディングと組み合わせることです。これは、(ランダムに生成されたものではなく)最も期待されるチェスボードが、少なくとも部分的には開始位置に似ている可能性が高いという仮定に基づいています。

つまり、256ビットの現在のボード位置と256ビットの開始位置をXORしてから、それをエンコードします(ハフマンコーディング、またはランレングスエンコードの何らかの方法を使用)。明らかに、これは最初は非常に効率的です(64 0はおそらく64ビットに対応します)が、ゲームが進むにつれて必要なストレージが増えます。

ピースの位置

前述のように、この問題を攻撃する別の方法は、代わりにプレーヤーが持っている各ピースの位置を保存することです。これは、ほとんどの正方形が空になるエンドゲームの位置で特にうまく機能します(ただし、ハフマンコーディングのアプローチでは、空の正方形はとにかく1ビットしか使用しません)。

それぞれの側に王と0-15の他の部分があります。プロモーションのため、これらのピースの正確な構成は十分に異なる可能性があるため、開始位置に基づく数が最大であると想定することはできません。

これを分割する論理的な方法は、2つの側面(白と黒)で構成される位置を保存することです。各サイドには:

  • キング:場所は6ビット。
  • ポーンあり:1(はい)、0(いいえ);
  • はいの場合、ポーンの数:3ビット(0-7 + 1 = 1-8);
  • はいの場合、各ポーンの位置は次のようにエンコードされます。45ビット(以下を参照)。
  • 非ポーンの数:4ビット(0-15);
  • 各ピースの場合:タイプ(クイーン、ルーク、ナイト、ビショップの場合は2ビット)と場所(6ビット)

ポーンの位置に関しては、ポーンは48個の可能な正方形にのみ配置できます(他の正方形のように64個ではありません)。そのため、ポーンごとに6ビットを使用する場合に使用する余分な16個の値を無駄にしない方がよいでしょう。したがって、ポーンが8つある場合 28,179,280,429,056に相当する488の可能性があります。その数の値をエンコードするには、45ビットが必要です。

これは、片側105ビット、つまり合計210ビットです。ただし、開始位置はこの方法の最悪のケースであり、ピースを削除すると大幅に改善されます。

ポーンをすべて同じ正方形に配置することはできないため、可能性は48 8未満であることに注意してください。最初の可能性は48、2番目の可能性は47というように続きます。48 x47x…x41= 1.52e13=44ビットストレージ。

これをさらに改善するには、他のピース(反対側を含む)が占める正方形を削除して、最初に白の非ポーン、次に黒の非ポーン、次に白のポーン、最後に黒のポーンを配置します。開始位置では、これによりストレージ要件が白の場合は44ビット、黒の場合は42ビットに削減されます。

組み合わせたアプローチ

もう1つの可能な最適化は、これらのアプローチのそれぞれに長所と短所があることです。たとえば、最適な4つを選択し、最初の2ビットでスキームセレクターをエンコードし、その後にスキーム固有のストレージをエンコードすることができます。

オーバーヘッドが非常に小さいため、これが最善のアプローチになります。

ゲームの状態

ポジションではなくゲームを保存するという問題に戻ります。3回繰り返されるため、この時点までに発生した移動のリストを保存する必要があります。

注釈

決定しなければならないことの1つは、単に動きのリストを保存するのか、それともゲームに注釈を付けるのかということです。チェスゲームには、多くの場合、次のように注釈が付けられます。

  1. Bb5 !! Nc4?

ホワイトの動きは2つの感嘆符で見事にマークされていますが、ブラックの動きは間違いと見なされています。チェスの句読点を参照してください。

さらに、動きが説明されているときにフリーテキストを保存する必要がある場合もあります。

注釈がないように、移動は十分であると想定しています。

代数表記

ここに移動のテキスト(「e4」、「Bxb5」など)を保存するだけで済みます。終了バイトを含めると、移動ごとに約6バイト(48ビット)が表示されます(最悪の場合)。それは特に効率的ではありません。

次に試すことは、開始位置(6ビット)と終了位置(6ビット)を格納して、移動ごとに12ビットにすることです。それはかなり良いです。

あるいは、予測可能で決定論的な方法で現在の位置からのすべての法的措置を決定し、選択した状態を示すことができます。次に、これは上記の可変ベースエンコーディングに戻ります。白と黒には、最初の動きでそれぞれ20の可能な動きがあり、2番目の動きでさらに多くの動きがあります。

結論

この質問に対する絶対的な正しい答えはありません。上記がほんの数例である多くの可能なアプローチがあります。

この問題や同様の問題について私が気に入っているのは、使用パターンを検討したり、要件を正確に決定したり、コーナーケースについて考えたりするなど、プログラマーにとって重要な能力が必要なことです。

ChessPositionTrainerからスクリーンショットとして取得されたチェスの位置

于 2009-12-02T08:21:55.210 に答える
48

チェスゲームは、人間が読める形式の標準形式で保存するのが最適です。

Portable Game Notationは、標準の開始位置を想定しており(必須ではありませんが)、順番に移動を一覧表示します。コンパクトで人間が読める標準形式。

例えば

[Event "F/S Return Match"]
[Site "Belgrade, Serbia Yugoslavia|JUG"]
[Date "1992.11.04"]
[Round "29"]
[White "Fischer, Robert J."]
[Black "Spassky, Boris V."]
[Result "1/2-1/2"]

1. e4 e5 2. Nf3 Nc6 3. Bb5 {This opening is called the Ruy Lopez.} 3... a6
4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6 8. c3 O-O 9. h3 Nb8  10. d4 Nbd7
11. c4 c6 12. cxb5 axb5 13. Nc3 Bb7 14. Bg5 b4 15. Nb1 h6 16. Bh4 c5 17. dxe5
Nxe4 18. Bxe7 Qxe7 19. exd6 Qf6 20. Nbd2 Nxd6 21. Nc4 Nxc4 22. Bxc4 Nb6
23. Ne5 Rae8 24. Bxf7+ Rxf7 25. Nxf7 Rxe1+ 26. Qxe1 Kxf7 27. Qe3 Qg5 28. Qxg5
hxg5 29. b3 Ke6 30. a3 Kd6 31. axb4 cxb4 32. Ra5 Nd5 33. f3 Bc8 34. Kf2 Bf5
35. Ra7 g6 36. Ra6+ Kc5 37. Ke1 Nf4 38. g3 Nxh3 39. Kd2 Kb5 40. Rd6 Kc5 41. Ra6
Nf2 42. g4 Bd3 43. Re6 1/2-1/2

小さくしたい場合は、zipしてください。仕事は終わりました!

于 2009-12-02T09:51:19.357 に答える
15

素晴らしいパズル!

ほとんどの人が各ピースの位置を保存していることがわかります。もっとシンプルなアプローチをとって、各正方形の内容を保存してみませんか?これにより、プロモーションとキャプチャされたピースが自動的に処理されます。

そしてそれはハフマン符号化を可能にします。実際、ボード上のピースの初期頻度はこれにほぼ完璧です。正方形の半分は空で、残りの正方形の半分はポーンなどです。

各ピースの頻度を考慮して、紙にハフマンツリーを作成しましたが、ここでは繰り返しません。結果、ここでcは色を表します(白= 0、黒= 1):

  • 空の正方形の場合は0
  • ポーンの場合は1c0
  • ルークの場合は1c100
  • 騎士のための1c101
  • ビショップの場合は1c110
  • クイーンの場合は1c1110
  • 王のための1c1111

初期状態のボード全体について、

  • 空の正方形:32*1ビット=32ビット
  • ポーン:16*3ビット=48ビット
  • ルーク/ナイト/ビショップ:12*5ビット=60ビット
  • クイーン/キング:4*6ビット=24ビット

合計:ボードの初期状態で164ビット。現在最も投票数の多い回答の235ビットよりも大幅に少ない。そして、ゲームが進むにつれて(プロモーション後を除いて)小さくなります。

ボード上のピースの位置だけを見ました。追加の状態(その順番、キャスリング、アンパッサン、繰り返しの動きなど)は、個別にエンコードする必要があります。たぶん、最大でさらに16ビットなので、ゲーム状態全体で180ビットになります。可能な最適化:

  • 頻度の低い部分を除外し、それらの位置を別々に保存します。しかし、それは役に立ちません...キングとクイーンを空の正方形に置き換えると、5ビットが節約されます。これは、別の方法で位置をエンコードするために必要な5ビットです。
  • 「後列にポーンがない」は、後列に別のハフマンテーブルを使用することで簡単にエンコードできますが、それが大いに役立つとは思えません。あなたはおそらくまだ同じハフマンツリーで終わるでしょう。
  • 「1つの白、1つの黒のビショップ」は、ビットを持たない追加のシンボルを導入することによってエンコードできますc。これは、ビショップが置かれている正方形から推測できます。(司教に昇進したポーンはこの計画を混乱させます...)
  • 空の正方形の繰り返しは、たとえば「2つの空の正方形が1列に」および「4つの空の正方形が1つに並んでいる」などの追加の記号を導入することにより、ランレングスエンコードできます。しかし、それらの頻度を推定することはそれほど簡単ではありません、そしてあなたがそれを間違えるならば、それは助けるというよりむしろ傷つくでしょう。
于 2009-12-02T09:47:06.100 に答える
9

本当に大きなルックアップテーブルアプローチ

位置-18バイト
有効な位置の推定数は1043単純にそれらすべてを列挙
すると、位置はわずか143ビットで格納できます。次にどちら側を再生するかを示すには、さらに1ビットが必要です

もちろん、列挙は実用的ではありませんが、これは少なくとも144ビットが必要であることを示しています。

移動-1バイト
通常、各位置に約30〜40の合法的な移動がありますが、その数は218にもなる場合があります。各位置のすべての合法的な移動を列挙しましょう。これで、各移動を1バイトにエンコードできます。

辞任を表す0xFFなどの特別な動きの余地はまだ十分にあります。

于 2009-12-03T00:06:06.573 に答える
4

初期位置がエンコードされた後、ステップをエンコードするサブ問題を攻撃します。アプローチは、ステップの「リンクリスト」を作成することです。

ゲームの各ステップは、「古い位置->新しい位置」のペアとしてエンコードされます。あなたはチェスゲームの開始時の初期位置を知っています。リンクされたステップのリストをトラバースすることにより、Xが移動した後の状態に到達できます。

各ステップをエンコードするには、開始位置をエンコードするために64個の値(ボード上の64個の正方形の場合は6ビット-8x8個の正方形)、および終了位置の場合は6ビットが必要です。各側の1つの動きに対して16ビット。

特定のゲームをエンコードするために必要なスペースの量は、移動の数に比例します。

10 x(白の移動の数+黒の移動の数)ビット。

更新:昇格したポーンの潜在的な合併症。ポーンが何に昇格するかを述べることができる必要があります-特別なビットが必要な場合があります(ポーンの昇格は非常にまれであるため、スペースを節約するためにこれにグレイコードを使用します)。

更新2:終了位置の完全な座標をエンコードする必要はありません。ほとんどの場合、移動するピースはXか所までしか移動できません。たとえば、ポーンには、任意の時点で最大3つの移動オプションを設定できます。各ピースタイプの最大移動数を実現することで、「宛先」のエンコードのビットを節約できます。

Pawn: 
   - 2 options for movement (e2e3 or e2e4) + 2 options for taking = 4 options to encode
   - 12 options for promotions - 4 promotions (knight, biship, rook, queen) times 3 squares (because you can take a piece on the last row and promote the pawn at the same time)
   - Total of 16 options, 4 bits
Knight: 8 options, 3 bits
Bishop: 4 bits
Rook: 4 bits
King: 3 bits
Queen: 5 bits

したがって、黒または白の移動ごとの空間的な複雑さは次のようになります。

初期位置の6ビット+(移動するもののタイプに基づく可変ビット数)。

于 2009-12-02T08:27:36.777 に答える
4

各位置で、すべての可能な動きの数を取得します。

次の動きは次のように生成されます

index_current_move =n % num_of_moves //this is best space efficiency
n=n/num_of_moves

ランダムに生成されたゲームを保存するのにおそらく最高のスペース効率であり、30〜40の可能な移動があるため、平均で約5ビット/移動が必要です。ストレージのアセンブルは、逆の順序でnを生成するだけです。

冗長性が高いため、保管位置が割れにくくなっています。(1つのサイトに最大9人のクイーンを乗せることができますが、その場合、ポーンはなく、ボード上にある場合はビショップが反対の色の正方形にあります)が、一般的には残りの正方形の上に同じピースの組み合わせを格納するようなものです。)

編集:

移動を保存する際のポイントは、移動のインデックスのみを保存することです。Kc1-c2を保存してこの情報を減らす代わりに、決定論的なmovegenerator(position)から生成されたmoveのインデックスのみを追加する必要があります。

移動するたびに、サイズの情報を追加します

num_of_moves = get_number_of_possible_moves(postion) ;

プール内で、この数を減らすことはできません

情報プールの生成は

n=n*num_of_moves+ index_current_move

追加

最終位置で使用できる移動が1つしかない場合は、以前に実行された強制移動の数として保存します。例:開始位置に各サイドに1つの強制移動(2つの移動)があり、これを1つの移動ゲームとして保存する場合は、プールnに1を格納します。

情報プールに保存する例

開始位置がわかっていて、3回の移動を行ったとします。

最初の移動では5つの使用可能な移動があり、移動インデックス4を使用します。2番目の移動では6つの使用可能な移動があり、位置インデックス3を取得し、3番目の移動ではその側で使用可能な7つの移動があり、彼は移動インデックスを選択しました。 2.2。

ベクトル形式; index = [4,3,2] n_moves = [5,6,7]

この情報を逆方向にエンコードしているため、n = 4 + 5 *(3 + 6 *(2))= 79(7を掛ける必要はありません)

これをアンループする方法は?最初にポジションがあり、5つの動きが利用可能であることがわかります。それで

index=79%5=4
n=79/5=15; //no remainder

ムーブインデックス4を取り、位置を再度調べます。この時点から、6つの可能なムーブがあることがわかります。

index=15%6=3
n=15/6=2

そして、7つの可能な動きがある位​​置に私たちを連れて行く動きインデックス3を取ります。

index=2%7=2
n=2/7=0

最後の移動インデックス2を実行し、最終位置に到達します。

ご覧のとおり、時間計算量はO(n)であり、空間計算量はO(n)です。編集:乗算する数が増えるため、時間計算量は実際にはO(n ^ 2)ですが、10,000回までのゲームを保存するのに問題はありません。


ポジションの保存

最適に近い状態で行うことができます。

情報を知り、情報を保存するときは、それについてもっと話させてください。一般的な考え方は、冗長性を減らすことです(これについては後で説明します)。昇進もテイクもなかったので、ポーンが8つ、ルークが2つ、ナイトが2つ、ビショップが2つ、キングが1つ、クイーンが1つあると仮定します。

何を保存する必要がありますか:1。各平和の位置2.キャスリングの可能性3.アンパッサンの可能性4.移動可能な側

すべてのピースがどこにでも立つことができるが、同じ場所に2つのピースが立つことはできないと仮定しましょう。同じ色の8つのポーンをボード上に配置できる方法の数は32ビットのC(64/8)(二項)で、2つのルーク2R-> C(56/2)、2B-> C(54/2) 、2N-> C(52/2)、1Q-> C(50/1)、1K-> C(49/1)、他のサイトでも同じですが、8P-> C(48/8)で始まります。 。

両方のサイトでこれを乗算すると、番号4634726695587809641192045982323285670400000が得られます。これは約142ビットです。1つの可能なアンパッサン(アンパッサンポーンは8つの場所のいずれかに配置できます)に8を追加し、キャスリングの制限に16(4ビット)を追加する必要があります。移動したサイトの場合は1ビット。最終的に142+3 + 4 + 1= 150ビットになります

しかし、今度は32個で、テイクなしでボードの冗長性を探しに行きましょう。

  1. 黒と白の両方のポーンが同じ列にあり、向かい合っています。各ポーンは他のポーンに面しています。つまり、白いポーンは最大で6位になります。これにより、C(64/8)* C(48/8)の代わりに8 * C(6/2)がもたらされ、情報が56ビット減少します。

  2. キャスリングの可能性も冗長です。ルークがスタート地点にない場合、そのルークでキャスリングの可能性はありません。したがって、このルークが可能である場合にキャスリングが可能である場合は、追加情報を取得するために4つの正方形をボードに追加し、4つのキャスリングビットを削除することができます。したがって、C(56/2)* C(40/2)* 16の代わりにC(58/2)* C(42/2)があり、3.76ビット(ほぼすべての4ビット)が失われました。

  3. アンパッサン:8つのアンパッサンの可能性の1つを保存すると、黒いポーンの位置がわかり、情報の冗長性が減少します(白い動きで、3番目のポーンがアンパッサンである場合、黒いポーンはc5にあり、白いポーンはどちらかです) c2、c3またはc4)C(6/2)を使用すると、3つになり、2.3ビットが失われます。アンパッサンの数もサイドに保存すると(3つの可能性->左、右、両方)、アンパッサンを受け入れることができるポーンの位置がわかっている場合、冗長性がいくらか減少します。(たとえば、前のアンパッサンの例から、c5で黒く、左、右、または両方に配置できます。1つのサイトにある場合、2 * 3(psissibilitesを格納するための3つと、7または6ランクの黒いポーンのための2つの可能な動き)があります。 )C(6/2)を挿入し、1.3ビット削減し、両側の場合は4.2ビット削減します。これにより、2.3 + 1.3=3削減できます。

  4. ビショップ:ビショップはオポスタイトの正方形にのみ配置できます。これにより、サイトごとに冗長性が1ビット減少します。

合計すると、テイクがなかった場合、チェスの位置を保存するために150-56-4-3.6-2=85ビットが必要です。

そして、考慮されたテイクとプロモーションがあれば、おそらくそれほど多くはありません(しかし、誰かがこの長い投稿が役立つと思うなら、後でそれについて書きます)

于 2009-12-02T09:52:26.687 に答える
4

最悪の場合ではなく、人間がプレイする典型的なゲームの平均的な場合のサイズを最適化することは、興味を追加します。(問題の説明にはどちらが記載されていません。ほとんどの回答は最悪の場合を想定しています。)

移動シーケンスでは、優れたチェスエンジンで各位置から移動を生成します。品質のランク順に並べられた、k個の可能な動きのリストを生成します。人々は一般的にランダムな動きよりも良い動きを選ぶことが多いので、リストの各位置から人々が「良い」動きを選ぶ確率へのマッピングを学ぶ必要があります。これらの確率(インターネットチェスデータベースのゲームのコーパスに基づく)を使用して、算術符号化で動きをエンコードします。(デコーダーは同じチェスエンジンとマッピングを使用する必要があります。)

開始位置については、raluのアプローチが機能します。確率で選択肢に重みを付ける方法があれば、そこで算術符号化を使用してそれを改良することもできます。たとえば、ピースはランダムではなく、互いに防御する構成で表示されることがよくあります。その知識を組み込む簡単な方法を見つけるのは難しいです。1つのアイデア:代わりに、上記の移動エンコーディングにフォールバックし、標準の開始位置から開始して、目的のボードで終了するシーケンスを見つけます。(最終的な位置からのピースの距離の合計に等しいヒューリスティックな距離、またはそれらの線に沿った何かでA *検索を試すことができます。)これは、移動シーケンスを過剰に指定することによる非効率性と、チェスプレイを利用することによる効率性とのトレードオフになります。知識。

また、実際のコーパスからいくつかの統計を収集せずに、これが平均的なケースの複雑さでどれだけの節約をもたらすかを見積もるのはちょっと難しいです。しかし、すべての動きが同じように発生する可能性のある出発点は、ここでの提案のほとんどをすでに打ち負かしていると思います。算術符号化は、動きごとに整数のビット数を必要としません。

于 2009-12-03T06:21:43.370 に答える
4

私は昨夜この質問を見ました、そしてそれは私に興味をそそられたので、私は解決策を考えてベッドに座っていました。私の最終的な答えは、実際にはint3と非常によく似ています。

基本的な解決策

標準のチェスゲームで、ルールをエンコードしないと仮定すると(たとえば、白が常に最初になります)、各ピースの動きだけをエンコードすることで、大幅に節約できます。

合計32個のピース​​がありますが、各移動でどの色が移動しているかがわかるので、心配する必要があるのは16個の正方形だけです。これは、このターンにどのピースが移動するかについて4ビットです。

各ピースには限られたムーブセットしかなく、何らかの方法で列挙します。

  • ポーン:4つのオプション、2ビット(1ステップ進む、2ステップ進む、各対角線に1つ)
  • ルーク:14オプション、4ビット(各方向に最大7)
  • ビショップ:13オプション、4ビット(一方の対角線に7つある場合、もう一方の対角線には6つしかありません)
  • ナイト:8オプション、3ビット
  • クイーン:27オプション、5ビット(ルーク+ビショップ)
  • キング:9オプション、4ビット(8ワンステップムーブとキャスリングオプション)

プロモーションでは、4つのピース(ルーク、ビショップ、ナイト、クイーン)から選択できるため、その移動で2ビットを追加して指定します。他のすべてのルールは自動的にカバーされると思います(例:アンパッサン)。

さらなる最適化

まず、1つの色の8つのピースがキャプチャされた後、ピースのエンコードを3ビットに減らし、次に4つのピースの場合は2ビットに減らすことができます。

ただし、主な最適化は、ゲームの各ポイントで可能な動きのみを列挙することです。ポーンの動きを{00, 01, 10, 11}、それぞれ1歩前進、2歩前進、左斜め、右斜めに保存するとします。一部の移動が不可能な場合は、このターンのエンコーディングからそれらを削除できます。

私たちはすべての段階でゲームの状態を知っているので(すべての動きを追跡することから)、どの部分が動くかを読んだ後、私たちはいつでも読む必要のあるビット数を決定できます。この時点でポーンの唯一の動きが斜めに右にキャプチャされるか、前方に移動することに気付いた場合、1ビットしか読み取れないことがわかります。

要するに、各ピースについて上記にリストされたビットストレージは最大のみです。ほぼすべての動きで、オプションが少なくなり、多くの場合ビットが少なくなります。

于 2009-12-04T13:42:26.660 に答える
3

ボード上の位置は7ビットで定義できます(0〜63、およびボード上にないことを指定する1つの値)。したがって、ボード上のすべてのピースについて、それが配置されている場所を指定します。

32個*7ビット=224ビット

編集:カドリアンが指摘したように...「ポー​​ンからクイーンへの昇格」のケースもあります。どのポーンがプロモートされたかを示すために、最後にビットを追加することをお勧めします。

したがって、昇格されたすべてのポーンについて、昇格されたポーンのインデックスを示す5ビットの224ビットと、リストの最後の場合は11111を追跡します。

したがって、最小の場合(プロモーションなし)は224ビット+ 5(プロモーションなし)です。プロモートされたポーンごとに5ビットを追加します。

編集:毛むくじゃらのカエルが指摘しているように、それが誰の番であるかを示すために、最後にさらにもう1つのビットが必要です; ^)

于 2009-12-02T08:26:47.347 に答える
3

ほとんどの人はボードの状態をエンコードしていますが、動き自体については..ビットエンコードの説明を次に示します。

1個あたりのビット数:

  • ピースID:片側16個を識別するための最大4ビット。白/黒が推測できます。ピースに順序を定義します。ピースの数がそれぞれの2の累乗を下回ると、残りのピースを記述するために使用するビット数が少なくなります。
  • ポーン:最初の移動で3つの可能性があるため、+ 2ビット(1つまたは2つのマスで前進、アンパッサン)。後続の移動では2移動できないため、+1ビットで十分です。ポーンが最後のランクに達したときを記録することにより、デコードプロセスで昇格を推測できます。ポーンがプロモートされていることがわかっている場合、デコーダーは、4つの主要なピースのどれにプロモートされたかを示す別の2ビットを期待します。
  • ビショップ:使用する対角線の場合は+1ビット、対角線に沿った距離の場合は最大+4ビット(16の可能性)。デコーダーは、ピースがその対角線に沿って移動できる最大距離を推測できるため、対角線が短い場合は、使用するビット数を減らします。
  • ナイト: 8つの可能な動き、+3ビット
  • ルーク:水平/垂直の場合は+1ビット、線に沿った距離の場合は+4ビット。
  • キング: 8つの可能な動き、+3ビット。キャスリングを「不可能な」動きで示します。キャスリングはキングが1位のときにのみ可能であるため、この動きを、キングを「後方」に移動するように指示してエンコードします。つまり、ボードの外に移動します。
  • クイーン: 8つの可能な方向、+3ビット。線/対角線に沿った距離の最大+4ビット(ビショップの場合のように、対角線が短い場合は少なくなります)

すべてのピースがボード上にあると仮定すると、これらは移動ごとのビットです。ポーン-最初の移動で6ビット、その後で5ビット。昇格した場合は7。ビショップ:9ビット(最大)、ナイト:7、ルーク:9、キング:7、クイーン:11(最大)。

于 2009-12-02T08:48:26.697 に答える
3

典型的なチェスゲームに最も効率的なエンコーディングを与えるか、それとも最悪の場合のエンコーディングが最も短いエンコーディングを与えるかが問題ですか?

後者の場合、最も効率的な方法は最も不透明でもあります。可能なすべてのペア(最初のボード、法的な一連の移動)の列挙を作成します。これは、3回繰り返される位置で、 -last-pawn-move-or-captureルール以降の50ムーブは、再帰的です。次に、この有限シーケンス内の位置のインデックスは、最悪の場合の最短のエンコーディングを提供しますが、一般的なケースの場合も同様に長いエンコーディングを提供し、計算に非常にコストがかかると思います。可能な最長のチェスゲームは5000ムーブを超えると想定されており、通常、各プレーヤーは各ポジションで20〜30ムーブを利用できます(ただし、残りのピースが少ない場合はそれより少なくなります)。これにより、このエンコーディングに必要な40000ビットのようなものが得られます。

上記のエンコードの動きに関するHenkHoltermanの提案で説明されているように、列挙のアイデアを適用して、より扱いやすいソリューションを提供できます。私の提案:最小限ではありませんが、私が見た上記の例よりも短く、合理的に扱いやすいです:

  1. 占有されている正方形(占有マトリックス)を表す64ビットと、占有されている各正方形にあるピースのリスト(ポーン用に3ビット、その他のピース用に4ビット):これにより、開始位置に190ビットが与えられます。ボードには32個を超えることはできないため、占有マトリックスのエンコードは冗長であり、一般的なボード位置のようなものをエンコードできます。たとえば、33セットビットと一般的なボードリストのボードのインデックスです。

  2. 誰が最初の動きをするかを言う1ビット

  3. ヘンクの提案に従ってコードを移動します。通常、白/黒の移動のペアごとに10ビットですが、プレーヤーに代替の移動がない場合、一部の移動には0ビットが必要です。

これは、典型的な30ムーブのゲームをコーディングするために、490ビットを示唆しており、典型的なゲームにとってはかなり効率的な表現になります。

ドローオンスリーリピートポジションとラストポーンムーブオアキャプチャールール以降の50ムーブ以下のエンコードについて:過去のムーブをエンコードすると、最後のポーンムーブまたはキャプチャーに戻ります。これらのルールが適用されるかどうかを判断するのに十分な情報があります。ゲーム履歴全体は必要ありません。

于 2009-12-02T10:54:05.510 に答える
2

計算時間が問題にならない場合は、決定論的な可能な位置ジェネレーターを使用して、特定の位置に一意のIDを割り当てることができます。

与えられた位置から、最初に決定論的マナーで可能な位置の数を生成します。たとえば、左下から右上に移動します。これにより、次の移動に必要なビット数が決まります。状況によっては、1ビット程度になることもあります。次に、移動が行われると、その移動の一意のIDのみが保存されます。

プロモーションやその他のルールは、決定論的な方法で処理される限り、単に有効な移動としてカウントされます。たとえば、クイーン、ルーク、ビショップなど、それぞれが個別の移動としてカウントされます。

初期位置は最も難しく、約2億5000万の可能な位置を生成する可能性があり(私は思う)、それが誰の動きであるかを決定するために約28ビットと追加のビットが必要になります。

誰がターンするかがわかっていると仮定すると(各ターンが白から黒に反転します)、決定論的ジェネレーターは次のようになります。

for each row
    for each column
        add to list ( get list of possible moves( current piece, players turn) )

「可能な動きのリストを取得」は次のようになります。

if current piece is not null 
    if current piece color is the same as the players turn
        switch( current piece type )
            king - return list of possible king moves( current piece )
            queen - return list of possible queen moves( current piece )
            rook - return list of possible rook moves( current piece )
            etc.

キングがチェックされている場合、「可能なxxx移動のリスト」は、チェック状況を変更する有効な移動のみを返します。

于 2009-12-02T11:57:13.783 に答える
2

ランレングスエンコーディングを使用します。いくつかのピースはユニークである(または2回しか存在しない)ので、それらの後の長さを省略できます。cletusのように、13の固有の状態が必要なので、ニブル(4ビット)を使用してピースをエンコードできます。最初のボードは次のようになります。

White Rook, W. Knight, W. Bishop, W. Queen, W. King, W. Bishop, W. Knight, W. Rook,
W. Pawn, 8,
Empty, 16, Empty, 16
B. Pawn, 8,
B. Rook, B. Knight, B. Bishop, B. Queen, B. King, B. Bishop, B. Knight, B. Rook

これにより、8 + 2 + 4 + 2+8ニブル=24ニブル=96ビットが残ります。16をニブルでエンコードすることはできませんが、「Empty、0」は意味がないため、「0」を「16」として扱うことができます。

ボードが空であるが、左上隅の1つのポーンの場合、「ポーン、1、空、16、空、16、空16、空、15」=10ニブル=40ビットになります。

最悪のケースは、各ピースの間に空の正方形がある場合です。ただし、ピースのエンコードには、16個の値のうち13個が必要なので、別の値を使用して「Empty1」と言うことができます。次に、64ニブル==128ビットが必要です。

ムーブメントには、ピースに3ビット(色は常に白が最初に動くという事実によって与えられます)に加えて、新しい位置に5ビット(0..63)=ムーブメントごとに1バイトが必要です。ほとんどの場合、範囲内にあるのは1つのピースだけなので、古い位置は必要ありません。奇妙なケースでは、単一の未使用のコード(ピースをエンコードするために7つのコードが必要です)を使用し、次に古い位置に5ビット、新しい位置に5ビットを使用する必要があります。

これにより、キャスリングを13バイトでエンコードできます(キングをルークに向かって移動できます。これは、私が意図していることを言うのに十分です)。

[編集]スマートエンコーダーを許可する場合は、初期設定に0ビット(エンコードする必要がないため:静的)に加えて、移動ごとに1バイトが必要です。

[EDIT2]これはポーン変換を残します。ポーンが最後の行に達した場合、「変換」と言うためにポーンを所定の位置に移動してから、置き換えられるピースの3ビットを追加できます(クイーンを使用する必要はありません。ポーンを任意のものに置き換えることができます)しかし王)。

于 2009-12-02T08:43:58.233 に答える
2

ゲームを本や紙にエンコードするのと同じように、すべてのピースにシンボルがあります。これは「合法的な」ゲームであるため、白が最初に移動します。白または黒を個別にエンコードする必要はありません。移動回数を数えて、誰が移動したかを判断します。また、すべての動きは(ピース、終了位置)としてエンコードされ、「終了位置」は、あいまいさを識別できる最小量のシンボルに削減されます(ゼロにすることができます)。ゲームの長さは、移動の数を決定します。すべてのステップで(最後の移動以降の)時間を分単位でエンコードすることもできます。

ピースのエンコードは、それぞれにシンボルを割り当てるか(合計32)、クラスにシンボルを割り当て、終了位置を使用して、どのピースが移動されたかを理解することによって行うことができます。たとえば、ポーンには6つの可能な終了位置があります。しかし、平均して、すべてのターンで利用できるのはカップルだけです。したがって、統計的には、終了位置によるエンコードがこのシナリオに最適な場合があります。

同様のエンコーディングは、計算論的神経科学(AER)のスパイク列に使用されます。

欠点:リンクリストをトラバースするのと同じように、ゲーム全体をリプレイして現在の状態になり、サブセットを生成する必要があります。

于 2009-12-02T09:26:27.307 に答える
2

ハフマン符号化を使ってみます。この背後にある理論は、すべてのチェスゲームで、多くの動きをするものと、あまり動かないか、早期に排除されるものがあります。開始位置にすでにいくつかのピースが削除されている場合は、さらに良いでしょう。同じことが正方形にも当てはまります。正方形の中にはすべてのアクションを見ることができるものもあれば、あまり触れられないものもあります。

したがって、2つのハフマンテーブルがあります。1つはピース用、もう1つは正方形用です。それらは実際のゲームを見ることによって生成されます。ピースと正方形のペアごとに1つの大きなテーブルを作成することもできますが、同じ正方形上を同じピースが移動するインスタンスはあまりないため、これはかなり非効率的だと思います。

すべてのピースにIDが割り当てられます。32の異なるピースがあるので、ピースIDに必要なのは5ビットだけです。ピースIDはゲームごとに変わりません。同じことが正方形のIDにも当てはまり、6ビットが必要になります。

ハフマンツリーは、順番にトラバースされるときに各ノードを書き留めることによってエンコードされます(つまり、最初にノードが出力され、次にその子が左から右に出力されます)。すべてのノードに対して、それがリーフノードであるかブランチノードであるかを指定する1ビットがあります。リーフノードの場合は、IDを与えるビットが後に続きます。

開始位置は、一連のピースと位置のペアによって簡単に指定されます。その後、すべての動きに対して1つのピースと場所のペアがあります。開始位置記述子の終わり(および移動記述子の開始)は、2回言及されている最初のピースを見つけるだけで見つけることができます。ポーンが昇格した場合、ポーンがどうなるかを指定する2つの追加ビットがありますが、ピースIDは変更されません。

ゲームの開始時にポーンが昇格する可能性を説明するために、ハフマンツリーとデータの間に「昇格テーブル」もあります。最初は、アップグレードされるポーンの数を指定する4ビットがあります。次に、ポーンごとに、ハフマンでエンコードされたIDと、ポーンがどのようになったかを指定する2ビットがあります。

ハフマンツリーは、すべてのデータ(開始位置と移動の両方)とプロモーションテーブルを考慮して生成されます。通常、プロモーションテーブルは空であるか、エントリがいくつかあります。

グラフィカルな用語で要約すると、次のようになります。

<Game> := <Pieces huffman tree> <squares huffman tree> <promotion table> <initial position> (<moves> | <1 bit for next move - see Added 2 below>)

<Pieces huffman tree> := <pieces entry 1> <pieces entry 2> ... <pieces entry N>
<pieces entry> := "0" | "1" <5 bits with piece ID>

<squares huffman tree> := <squares entry 1> <squares entry 2> ... <squares entry N>
<Squares entry> := "0" | "1" <6 bits with square ID>

<promotion table> := <4 bits with count of promotions> <promotion 1> <promotion 2> ... <promotion N>
<promotion> := <huffman-encoded piece ID> <2 bits with what it becomes>

<initial position> := <position entry 1> <position entry 2> ... <position entry N>
<moves> := <position entry 1> <position entry 2> ... <position entry N>
<position entry> := <huffman-encoded piece ID> <huffman-encoded squre ID> (<2 bits specifying the upgrade - optional>)

追加:これはまだ最適化できます。すべての作品には、いくつかの法的な動きしかありません。ターゲットの正方形を単純にエンコードする代わりに、すべてのピースの可能な動きに対して0ベースのIDを与えることができます。同じIDがすべてのピースで再利用されるため、合計で21個以下の異なるIDが存在します(クイーンは最大21個の異なる移動オプションを持つことができます)。これをフィールドの代わりにハフマンテーブルに入れます。

ただし、これでは元の状態を表すのが困難になります。各ピースをその場所に配置するために一連の動きを生成する場合があります。この場合、何らかの方法で初期状態の終了と移動の開始をマークする必要があります。

または、非圧縮の6ビットの正方形IDを使用して配置することもできます。

これが全体的なサイズの縮小をもたらすかどうか-私にはわかりません。おそらく、しかし少し実験する必要があります。

追加2:もう1つの特殊なケース。ゲームの状態に動きがない場合、次に動く人を区別することが重要になります。そのために最後にもう1ビット追加します。:)

于 2009-12-02T09:28:08.380 に答える
2

ボードの位置は64ある可能性があるため、位置ごとに6ビットが必要です。最初のピースは32個あるため、これまでに合計192ビットがあり、6ビットごとに特定のピースの位置が示されます。ピースが表示される順序を事前に決定できるため、どちらがどれであるかを言う必要はありません。

ピースがボードから外れている場合はどうなりますか?そうでなければ違法になるので、別のピースと同じ場所にピースを配置して、それがボードから外れていることを示すことができます。しかし、最初のピースがボードに載るかどうかもわかりません。したがって、どのピースが最初のピースであるかを示す5ビットを追加します(32の可能性=最初のピースを表す5ビット)。次に、そのスポットを、ボードから外れた後続のピースに使用できます。これで合計197ビットになります。それが機能するように、ボード上に少なくとも1つのピースがなければなりません。

次に、その順番に1ビットが必要です-198ビットになります。

ポーンのプロモーションはどうですか?ポーンごとに3ビットを追加し、42ビットを追加することで、これを悪い方法で行うことができます。しかし、ほとんどの場合、ポーンは昇格されていないことに気付くことができます。

したがって、ボード上にあるすべてのポーンについて、ビット「0」はそれがプロモートされていないことを示します。ポーンがボード上にない場合は、少しも必要ありません。次に、彼が持っているプロモーション用の可変長ビット文字列を使用できます。ほとんどの場合、それは女王になるので、「10」は女王を意味することができます。次に、「110」はルークを意味し、「1110」はビショップを意味し、「1111」はナイトを意味します。

16個のポーンがすべてボード上にあり、プロモートされていないため、初期状態は198 + 16= 214ビットになります。2つのプロモートされたポーンクイーンを使用したエンドゲームでは、198 + 4 + 4のようなものが必要になる場合があります。つまり、4つのポーンが生きていてプロモートされておらず、2つのクイーンポーンが合計206ビットになります。かなり頑丈なようです!

===

他の人が指摘しているように、ハフマン符号化は次のステップになるでしょう。数百万のゲームを観察すると、各ピースが特定の正方形にある可能性がはるかに高いことに気付くでしょう。たとえば、ほとんどの場合、ポーンは直線、つまり左に1つ、右に1つとどまります。王は通常、ホームベースの周りに固執します。

したがって、個別の位置ごとにハフマン符号化スキームを考案します。ポーンは、6ビットではなく平均3〜4ビットしか取れない可能性があります。キングも数ビットかかるはずです。

また、このスキームでは、可能な位置として「撮影」を含めます。これにより、キャスリングも非常に堅牢に処理できます。各ルークとキングには、追加の「元の位置、移動」状態があります。この方法でポーンにアンパッサンをエンコードすることもできます-「元の位置、アンパッサンができます」。

十分なデータがあれば、このアプローチは本当に良い結果をもたらすはずです。

于 2009-12-02T09:29:31.730 に答える
2

[質問を正しく読んだ後に編集]すべての法的な位置に初期位置(「法的な」の可能な定義)から到達できると仮定すると、任意の位置を最初からの移動のシーケンスとして表すことができます。非標準の位置から始まるプレイのスニペットは、スタートに到達するために必要な一連の動き、カメラをオンにするためのスイッチ、それに続く一連の動きとして表すことができます。

それでは、初期ボード状態をシングルビット「0」と呼びましょう。

任意の位置からの移動は、正方形に番号を付け、移動を(開始、終了)順に並べることで列挙できます。従来の、2つの正方形のジャンプはキャスリングを示します。ボードの位置とルールは常にわかっているので、違法な動きをエンコードする必要はありません。カメラをオンにするフラグは、特別な帯域内移動として表現することも、より適切には帯域外移動番号として表現することもできます。

どちらの側にも24のオープニングムーブがあり、それぞれ5ビットに収まります。後続の移動には多少のビットが必要になる場合がありますが、合法的な移動は常に列挙可能であるため、各移動の幅は喜んで拡大または拡大できます。計算はしていませんが、7ビットの位置はまれだと思います。

このシステムを使用すると、100のハーフムーブゲームを約500ビットでエンコードできます。ただし、オープニングブックを使用するのが賢明かもしれません。100万のシーケンスが含まれているとします。次に、最初の0は標準ボードからの開始を示し、1の後に20ビットの数字が続く場合はそのオープニングシーケンスからの開始を示します。やや従来の開口部を持つゲームは、たとえば20ハーフムーブ、つまり100ビット短縮される可能性があります。

これは可能な限り最大の圧縮ではありませんが、(オープニングブックがなければ)質問で想定されているチェスモデルがすでにある場合は、非常に簡単に実装できます。

さらに圧縮するには、任意の順序ではなく可能性に従って移動を順序付け、可能性のあるシーケンスをより少ないビットでエンコードします(たとえば、人々が言及しているようにハフマントークンを使用します)。

于 2009-12-03T04:30:14.353 に答える
2

答えのほとんどは、3回の繰り返しを見落としていました。残念ながら、3回の繰り返しでは、これまでにプレイしたすべてのポジションを保存する必要があります...

質問では、スペース効率の良い方法で保存する必要があったため、移動のリストから構築できる限り、実際には位置を保存する必要はありません(標準の開始位置がある場合)。PGNを最適化することができ、それで完了です。ベローは単純なスキームです。

ボード上には64個の正方形があり、64 = 2 ^ 6です。12ビットかかる各移動の最初と最後の正方形のみを保存する場合(プロモーションは後で取り組みます)。このスキームは、移動、強調、駒のキャプチャ、キャスリングなどのプレーヤーをすでにカバーしていることに注意してください。これらの時点では、移動リストを再生するだけで作成できます。

昇格のために、「移動NでピースXYZに昇格する」というベクトルの個別の配列を保持できます。(int、byte)のベクトルを保持できます。

これらの(To、From)ベクトルの多くはチェスでは使用できないため、(To、From)ベクトルも最適化するのは魅力的です。例えば。e1からd8などへの移行はありません。しかし、私はどのスキームも思い付くことができませんでした。それ以上のアイデアは大歓迎です。

于 2009-12-23T10:49:44.733 に答える
2

私は長い間(+-2時間)それについて考えてきました。そして、明白な答えはありません。

仮定:

  1. 時間状態を無視する(プレーヤーは時間制限を使用していなかったため、プレイしないことでドローを強制する可能性があります)
  2. ゲームはいつプレイされましたか?!?ルールは時間の経過とともに変化するため、重要です(したがって、次のポイントでモダンゲームを想定します...)たとえば、デッドポーンルール(ウィキペディアには非常に有名な問題があります)を参照してください。昔に戻るには、幸運の司教はゆっくりと動くだけで、サイコロが使われていました。笑。

...最新のルールです。繰り返しと移動の繰り返し制限に関係なく、最初に。

-C 25バイトを四捨五入(64b + 32 * 4b + 5b = 325b)

= 64ビット(何か/何もない)+ 32*4ビット[1bit=color {black / withe} + 3bit = type of piece {King、Queen、Bishop、kNight、Rook、Pawn、MovedPawn} NB:Moved pawn .. ..たとえば、それが前のターンで最後に移動したポーンであった場合、「アンパッサン」が実行可能であることを示します。]実際の状態の+5ビット(ターン、アンパッサン、両側でルークするかどうかの可能性)

ここまでは順調ですね。おそらく強化することができますが、それから考慮に入れるべき可変の長さと昇進があるでしょう!?

現在、以下のルールは、プレーヤーが抽選に応募する場合にのみ適用されますが、自動ではありません。したがって、この90の動きは、キャプチャなしで、またはポーンの動きは、ドローを要求するプレーヤーがいない場合に実行可能であると考えてください。すべての動きを記録する必要があることを意味します...そして利用可能です。

-Dポジションの繰り返し...例えば、上記のボードの状態(Cを参照)またはそうでない...(FIDEルールについては以下を参照)-Eそれは、キャプチャまたはポーンの移動なしで50の移動許容量の複雑な問題を残しますカウンターが必要です...しかし。

それで、あなたはそれをどのように扱いますか?...まあ本当に方法はありません。どちらのプレイヤーも絵を描きたくない、またはそれが起こったことに気づいたくないからです。Eの場合、カウンターで十分かもしれません...しかし、ここにトリックがあり、FIDEルール(http://www.fide.com/component/handbook/?id=124&view=article)を読んでも見つかりません。答え...ルーキングの能力の喪失はどうですか。それは繰り返しですか?私はそうではないと思いますが、これは対処されておらず、明確にされていないぼやけた主題です。

それで、ここに、エンコードしようとしても2つの複雑または未定義の2つのルールがあります...乾杯。

したがって、ゲームを真にエンコードする唯一の方法は、最初からすべてを記録することです...その後、「ボードの状態」の質問と競合します(または競合しませんか?)。

この助けを願っています...あまり数学ではありません:-)いくつかの質問がそれほど簡単ではなく、解釈や事前知識が正しく効率的であるにはあまりにもオープンであることを示すためだけに。ワームの缶が開きすぎるので、インタビューの対象にはなりません。

于 2012-11-03T13:09:01.607 に答える
2

Yacobyのソリューションの開始位置の改善の可能性

各色が16個を超える法的な立場はありません。64個の正方形に最大16個の黒と16個の白のピースを配置する方法の数は約3.63e27です。Log2(3.63e27)=91.55。これは、すべてのピースの位置と色を92ビットでエンコードできることを意味します。これは、Yacobyのソリューションが必要とする位置の64ビット未満+色の最大32ビットです。最悪の場合、エンコーディングがかなり複雑になる代わりに4ビットを節約できます。

一方、5個以上の欠品があるポジションではサイズが大きくなります。これらの位置は、すべての位置の4%未満にすぎませんが、最初の位置とは異なる開始位置を記録する場合の大部分はおそらくこれらです。

これは完全なソリューションにつながります

  1. 上記の方法に従って、ピースの位置と色をエンコードします。 92ビット
  2. 各ピースのタイプを指定するには、ハフマンコード:ポーン:「0」、ルーク:「100」、ナイト:「101」、ビショップ:「110」、クイーン:「1110」、キング:「1111」を使用します。これには、ピースのフルセットに対して(16 * 1 + 12 * 3 + 4 * 4)= 68ビットが必要です。ボード全体の位置は、最大92 + 68=160ビットでエンコードできます。
  3. 追加のゲーム状態を追加する必要があります:ターン:1ビット、キャスリングが可能:4ビット、「アンパッサン」が可能:最大4ビット(1ビットはケースを示し、3ビットはどちらかを示します)。開始位置は=160+ 9= 169ビットでエンコードされます
  4. 移動のリストについては、特定の位置で可能なすべての移動を列挙し、移動の位置をリストに保存します。移動のリストには、すべての特殊なケース(キャスリング、アンパッサン、および辞任)が含まれます。最高位置を格納するために必要な数のビットのみを使用してください。平均して、1回の移動で7ビットを超えてはなりません(平均で16回の可能なピースと8回の合法的な移動)。場合によっては、移動が強制されると、1ビット(移動または辞任)のみが必要になります。
于 2014-08-23T11:29:05.497 に答える
1

最初のボードとその後の移動の基本ケースでは、次のことを考慮してください。

チェスプログラムを使用して、考えられるすべての動きに確率を割り当てます。たとえば、e2-e4の場合は40%、d2-d4の場合は20%というようになります。いくつかの動きが合法であるが、そのプログラムによって考慮されていない場合は、それらに低い確率を与えます。算術符号化を使用して、どの選択が行われたかを保存します。これは、最初の移動では0〜0.4、2番目の移動では0.4〜0.6というようになります。

反対側も同じようにします。たとえば、e2-e4への応答としてe7-e5の可能性が50%である場合、エンコードされた数値は0〜0.2になります。ゲームが終了するまで繰り返します。その結果、範囲が非常に狭くなる可能性があります。その範囲に収まる最小の底を持つ2進分数を見つけます。それが算術符号化です。

これは、フラクショナルビットエンコーディングと考えることができるため、ハフマンよりも優れています(さらに、ゲームの最後にビット全体に切り上げるためのエンコードもあります)。

結果はハフマンよりもコンパクトになるはずであり、チェス評価プログラムによって処理されるため、昇進、アンパッサン、50手ルールなどの詳細についての特別なケースはありません。

再生するには、もう一度チェスプログラムを使用してボードを評価し、すべての確率を各動きに割り当てます。算術エンコードされた値を使用して、実際に再生された移動を判別します。完了するまで繰り返します。

チェスプログラムが十分に優れている場合は、2つの状態のエンコーダーを使用して、より良い圧縮を得ることができます。このエンコーダーでは、黒と白の両方の動きに基づいて確率が定義されます。約200以上の状態の最も極端なケースでは、これはすべての可能なチェスゲームのセット全体をエンコードするため、実行可能ではありません。

これは、算術符号化がどのように機能するかについてのほんの少しの例と、次の動きの確率を評価するのに役立つ既存のチェスプログラムを使用する実際の例だけで、ダリウスがすでに書いたことを言うのとはまったく異なる方法です。

于 2009-12-07T15:52:49.933 に答える
1

ボードには32個あります。各ピースには位置があります(64マスに1つ)。したがって、32個の正の整数が必要です。

私は64の位置が6ビットで保持されることを知っていますが、私はそうしません。私はいくつかの旗の最後のビットを保持します(ドロップされたピース、クイーンのポーン)

于 2009-12-02T08:29:23.950 に答える
1

cletusの答えは良いですが、彼はそれが誰の番かをエンコードすることも忘れていました。これは現在の状態の一部であり、その状態を使用して検索アルゴリズム(アルファ-ベータ派生物など)を駆動する場合に必要です。

私はチェスプレーヤーではありませんが、もう1つのコーナーケースがあると思います。それは、何回の動きが繰り返されたかです。各プレイヤーが同じ動きを3回行うと、ゲームは引き分けになりますね。その場合、3回目の繰り返しの後、状態は終了するため、その情報を状態に保存する必要があります。

于 2009-12-02T08:34:23.680 に答える
1

他の何人かが述べたように、32個のピース​​のそれぞれについて、それらがどの正方形にあるかを保存でき、それらがボード上にあるかどうかにかかわらず、これは32 *(log2(64)+ 1)=224ビットになります。

ただし、ビショップは黒または白の正方形のいずれかしか占有できないため、これらの場合、位置に必要なlog2(32)ビットのみで、28 * 7 + 4 * 6=220ビットになります。

また、ポーンは後ろから開始せず、前にしか移動できないため、56にしかできません。この制限を使用して、ポーンに必要なビット数を減らすことができます。

于 2009-12-02T08:40:16.553 に答える
1

各ピースは4ビット(ポーンからキング、6タイプ)、黒/白=12の値で表すことができます

ボード上の各正方形は、6ビット(x座標、y座標)で表すことができます。

初期位置には最大320ビット(32個、4 + 6ビット)が必要です

後続の各移動は、16ビット(開始位置、終了位置、ピース)で表すことができます。

キャスリングはデュアルムーブであるため、追加の16ビットが必要になります。

クイーンポーンは、4ビットのうち4つのスペア値の1つで表すことができます。

詳細な計算を行わなくても、32 * 7ビット(事前定義されたピースの配列)または64 * 4ビット(事前定義された正方形の割り当て)を格納する場合と比較して、最初の移動後にスペースを節約し始めます。

両側を10回移動した後、必要な最大スペースは640ビットです。

...しかし、繰り返しになりますが、各ピースを一意に識別し(5ビット)、クイーンポーンにフラグを立てるために6番目のビットを追加すると、各移動に必要なのはpiece-id+to-positionだけです。これにより、計算が次のように変更されます...

初期位置=最大384ビット(32個、6 + 6ビット)各移動= 12ビット(to-position、piece-id)

次に、各側で10回移動した後、必要な最大スペースは624ビットです。

于 2009-12-02T09:00:48.523 に答える
1

ボードには64個の正方形があり、正方形が空かどうかを示す64ビットで表すことができます。正方形にピースがある場合にのみ、ピース情報が必要です。プレーヤー+ピースは4ビットを取るので(前に示したように)、64 + 4 * 32=192ビットで現在の状態を取得できます。現在のターンにスローすると、193ビットになります。

ただし、各ピースの法的な動きもエンコードする必要があります。まず、各ピースの合法的な移動の数を計算し、完全な正方形のピース識別子の後にその数のビットを追加します。私は次のように計算しました:

ポーン:フォワード、最初に2ターンフォワード、アンパッサン* 2、プロモーション=7ビット。最初のターンフォワードとプロモーションは同じ位置からは発生しないため、1つのビットに組み合わせることができます。したがって、6になります。ルーク:7つの垂直方向の正方形、7つの水平方向の正方形= 14ビットナイト:8つの正方形= 8ビットのビショップ:2つの対角線* 7 = 14ビットクイーン:7垂直、7水平、7対角、7対角= 28ビットキング:8つの周囲の正方形

これは、現在の位置に基づいてターゲットの正方形をマップする必要があることを意味しますが、それは単純な計算である必要があります。

16個のポーン、4個のルーク/ナイト/ビショップ、2個のクイーン/キングがあるので、これは16 * 6 + 4 * 14 + 4 * 8 + 4 * 14 + 2 * 28 + 2 * 8 = 312ビット多くなり、全体で505ビットになります。

可能な移動のためにピースごとに必要なビット数については、いくつかの最適化を追加することができ、ビット数はおそらく削減されます。私は簡単な数値を使用して作業しました。たとえば、スライドピースの場合、移動できる距離を保存できますが、これには追加の計算が必要になります。

簡単に言うと、正方形が占有されている場合にのみ追加のデータ(ピースなど)を保存し、その合法的な動きを表すために各ピースの最小ビット数のみを保存します。

編集1:キャスリングとポーンのプロモーションを忘れました。これにより、明示的な位置の合計が557移動する可能性があります(ポーンの場合はさらに3ビット、キングの場合は2ビット)。

于 2009-12-02T09:09:30.937 に答える
1

Robert Gのように、PGNは標準であり、さまざまなツールで使用できるため、PGNを使用する傾向があります。

ただし、遠方のスペースプローブ上にあるチェスAIをプレイしている場合、つまりすべてのビットが貴重である場合、これは私が移動のために行うことです。後で初期状態のエンコードに取り掛かります。

動きは状態を記録する必要はありません。デコーダーは、任意の時点でどのような動きが合法であるかだけでなく、状態を追跡することができます。記録する必要があるすべての動きは、さまざまな法的選択肢のどれが選択されるかです。プレーヤーが交代するので、移動はプレーヤーの色を記録する必要はありません。プレイヤーは自分のカラーピースしか動かせないので、最初の選択肢はプレイヤーが動かすピースです(後で別の選択肢を使用する代替案に戻ります)。最大16個の場合、これには最大4ビットが必要です。プレイヤーが駒を失うと、選択肢の数が減ります。また、特定のゲーム状態によって、ピースの選択が制限される場合があります。王が自分自身をチェックせずに移動できない場合、選択肢の数は1つ減ります。キングがチェックされている場合、キングをチェックから外すことができないピースは実行可能な選択ではありません。

作品が指定されると、それは特定の数の合法的な目的地のみを持ちます。正確な数はボードのレイアウトとゲームの履歴に大きく依存しますが、特定の最大値と期待値を把握することができます。騎士以外のすべての人にとって、そしてキャスリングの間、ある部分は別の部分を通り抜けることができません。これは移動制限の大きな原因になりますが、定量化するのは困難です。ピースはボードから移動できません。これにより、宛先の数も大幅に制限されます。

W、NW、N、NE(黒側はN)の順序で線に沿って正方形に番号を付けることにより、ほとんどのピースの宛先をエンコードします。線は、指定された方向に最も遠い正方形から始まり、に移動して、に向かって進みます。邪魔されていない王の場合、移動のリストはW、E、NW、SE、N、S、NE、SWです。騎士の場合、2W1Nから始めて、時計回りに進みます。宛先0は、この順序で最初に有効な宛先です。

  • ポーン:動かないポーンには2つの宛先の選択肢があるため、1ビットが必要です。ポーンが通常またはアンパッサンのいずれかで別のポーンをキャプチャできる場合(状態を追跡しているため、デコーダーが決定できます)、2つまたは3つの移動の選択肢もあります。それ以外は、ポーンは1つの選択肢しかなく、ビットは必要ありません。ポーンが7になると、プロモーションの選択にも取り組みます。ポーンは通常クイーンに昇格し、次にナイトに昇格するため、選択肢を次のようにエンコードします。
    • クイーン:0
    • 騎士:10
    • ビショップ:110
    • ルーク:111
  • ビショップ:4ビットで{d、e}{4,5}の場合は最大13の宛先。
  • ルーク:最大14の宛先、4ビット。
  • 騎士団:最大8つの目的地、3ビット。
  • キングス:キャスリングがオプションの場合、キングはSに戻り、下に移動できません。これにより、合計7つの宛先が得られます。残りの時間、キングは最大8ムーブで、最大3ビットを与えます。
  • クイーン:ビショップまたはルークの選択肢と同じで、合計27の選択肢、つまり5ビットです。

選択肢の数が常に2の累乗であるとは限らないため、上記は依然としてビットを浪費します。選択肢の数がCで、特定の選択肢にcの番号が付けられ、n = ceil(lg(C))(選択肢をエンコードするために必要なビット数)であるとします。次の選択肢の最初のビットを調べることにより、これらの無駄な値を利用します。0の場合は、何もしません。1でc + C <2 nの場合、 Ccに追加します。数値をデコードすると、これが逆になります。受信したc > = Cの場合、 Cを減算し、次の数値の最初のビットを1に設定します。cの場合<2 n --Cの場合、次の数値の最初のビットを0に設定します。2n --C <= c < Cの場合しません。このスキームを「飽和」と呼びます。

エンコーディングを短縮する可能性のある別の潜在的な選択のタイプは、キャプチャする対戦相手のピースを選択することです。これにより、移動の最初の部分であるピースの選択の選択肢の数が増え、最大で1ビット追加されます(正確な数は、現在のプレーヤーが移動できるピースの数によって異なります)。この選択の後には、キャプチャするピースの選択が続きます。これは、特定のプレーヤーのピースの移動数よりもはるかに少ない可能性があります。駒は、どの基本方向からでも1枚の駒と騎士によってのみ攻撃でき、合計で最大10個の攻撃駒になります。これにより、キャプチャ移動の合計で最大9ビットが得られますが、平均して7ビットになると思います。これは、多くの場合、かなりの数の合法的な目的地があるため、女王による捕獲には特に有利です。

飽和状態では、キャプチャエンコーディングにはおそらく利点がありません。使用する初期状態を指定して、両方のオプションを許可することができます。サチュレーションが使用されていない場合、ゲームエンコーディングでは、未使用の選択番号(C <= c <2 n)を使用して、ゲーム中にオプションを変更することもできます。Cが2の累乗であるときはいつでも、オプションを変更できませんでした。

于 2009-12-02T11:50:24.273 に答える
1

トーマスは、ボードをエンコードするための正しいアプローチを持っています。ただし、これは、動きを保存するためのraluのアプローチと組み合わせる必要があります。考えられるすべての動きのリストを作成し、この数を表すために必要なビット数を書き出します。デコーダーは同じ計算を実行しているため、可能な数と読み取るビット数を認識できるため、長さコードは必要ありません。

したがって、ピース用に164ビット、キャスリング情報用に4ビット(ゲームのフラグメントを保存していると仮定します。そうでない場合は再構築可能)、アンパッサン適格性情報用に3ビットを取得します-移動が発生した列を保存するだけです(アンパッサンが不可能な場合は、不可能な場所に列を保存します(そのような列が存在する必要があります)。

移動には通常5ビットまたは6ビットかかりますが、1から8まで変化する可能性があります。

1つの追加のショートカット-エンコードが121ビットで始まる場合(無効な状況-フラグメントでさえ片側に2つのキングがない場合)、デコードを中止し、ボードをワイプして新しいゲームをセットアップします。次のビットは移動ビットになります。

于 2009-12-03T05:09:15.570 に答える
1

アルゴリズムは、各移動で可能なすべての宛先を決定論的に列挙する必要があります。目的地の数:

  • 2人の司教、それぞれ13の目的地= 26
  • 2つのルーク、それぞれ14の目的地= 28
  • 2人の騎士、それぞれ8つの目的地= 16
  • 女王、27の目的地
  • キング、8つの目的地

最悪の場合(列挙に関して)、8つの足がすべてクイーンになる可能性があるため、可能な宛先の最大数は9 * 27 + 26 + 28 + 16 + 8=321になります。したがって、移動のすべての宛先は、9ビットの数値で列挙できます。

両当事者の最大移動数は100です(私が間違っていなければ、チェスプレーヤーではありません)。したがって、どのゲームも900ビットで記録できます。さらに、各ピースの初期位置は、合計32 * 6=192ビットの6ビット番号を使用して記録できます。さらに、「誰が最初に移動するか」レコードの1ビット。したがって、900 + 192 + 1=1093ビットを使用して任意のゲームを記録できます。

于 2009-12-03T08:00:14.443 に答える
1

ボードの状態を保存する

私が考えた最も簡単な方法は、最初に各駒の位置を表す8 * 8ビットの配列を用意することです(つまり、チェスの駒がある場合は1、ない場合は0)。これは固定長なので、ターミネータは必要ありません。

次に、すべてのチェスの駒をその場所の順に表します。1個あたり4ビットを使用すると、32 * 4ビット(合計128)が必要になります。これは本当に無駄です。

二分木を使用すると、ポーンを1バイトで、ナイトとルークとビショップを3で、キングとクイーンを4で表すことができます。また、ピースの色を保存する必要があるため、余分なバイトが必要になります。として(これが間違っている場合は許してください、私はこれまでハフマンコーディングを詳細に調べたことがありません):

  • ポーン:2
  • ルーク:4
  • ナイト:4
  • ビショップ:4
  • キング:5
  • クイーン:5

合計を考えると:

2*16 + 4*4 + 4*4 + 4*4 + 2*5 + 2*5 = 100

28ビットの固定サイズのビットセットを使用してビートします。

したがって、私が見つけた最良の方法は、8 2 +100ビット配列に格納することです。

8*8 + 100 = 164



移動の保存
最初に知っておく必要があるのは、どの部分がどこに移動しているかです。ボード上に最大32個のピース​​があり、正方形を表す整数ではなく、各ピースが何であるかがわかっている場合、ピースのオフセットを表す整数を使用できます。つまり、32個の可能な値を当てはめるだけでピース。

残念ながら、王をキャスリングまたは転覆して共和国を形成するなど、さまざまな特別なルールがあります(テリープラチェット参照)。そのため、移動するピースを保存する前に、それが特別な移動であるかどうかを示す1つのビットが必要です。

したがって、通常の移動ごとに必要な1 + 5 = 6ビットがあります。(1ビットタイプ、ピース用5ビット)

ピース番号がデコードされた後、ピースのタイプがわかり、各ピースは最も効率的な方法でその動きを表す必要があります。たとえば(私のチェスのルールがスクラッチになっている場合)、ポーンには合計4つの可能な動きがあります(左に、右に、1つ前に移動し、2つ前に移動します)。
したがって、ポーンの動きを表すには、「6 + 2=8」ビットが必要です。(最初の移動ヘッダー用に6ビット、どの移動用に2ビット)

女王のために移動することはより複雑であり、方向(8つの可能な方向、つまり3ビット)と各方向に移動する合計8つの可能な正方形(つまり別の3ビット)を持つことが最善です。したがって、クイーンの移動を表すには、6 + 3 + 3 = 12ビットが必要になります。

私が最後に思い浮かぶのは、どのプレイヤーがそれを回すかを保存する必要があるということです。これは1ビットである必要があります(次に移動するには白または黒)



結果の形式したがっ
て、ファイル形式は次のようになります。

[64ビット]最初のピースの位置
[最大100ビット]最初のピース[1ビット]プレーヤーの回転
[nビット]移動

移動の場合
[1ビット]移動タイプ(特殊または通常)
[nビット]移動の詳細

移動が通常の移動である場合、移動の詳細は
[5ビット]ピース
[nビット]特定のピースの移動(通常は2〜6ビットの範囲)のようになります。

それが特別な動きである場合それは
整数型を持ち、それから追加情報(それがキャスリングであるかどうかのように)を持っているべきです。必殺技の回数が思い出せないので、必殺技だと言っても大丈夫かもしれません(1つしかない場合)

于 2009-12-03T10:52:27.533 に答える
1

これが私がゲームのステップをエンコードする方法です。40ステップのゲームの場合、これには約180ビットほどかかります。

まず、すべてのチェスのルールを知っているエンジンを使用して、すべての選択肢のリストを作成します。各ステップで、これを実行します。

  1. 移動可能なすべてのピースを列挙します(最初は、白は8つのポーンと2つのナイト、合計10を移動できます。
  2. 可能な選択肢の数と選択肢自体の両方を保存します。
  3. 可能なすべての移動位置を列挙します。(最初にポーンが選択された場合、1つまたは2つのフィールドを前方に移動できるため、2つの選択肢があります。
  4. ここでも、可能な選択肢の数と選択肢自体を保存します。

これにより、次のようなリストが表示されます。

[[10, 3], # choose white pawn at index #3
 [2, 0],  # move it one step forward
 [10, 2], # choose black pawn #2 
 [2, 1],  # move it two steps forward
 ...
]

等々。それをエンコードするには、可能な移動の数ではなく、選択を保存する必要があります。それを保存する1つの方法は、各選択肢に必要なビット数を調べることです。

[[10, 3], # 10 choices => 4 bits
 [2, 0],  # 2 choices => 1 bit
 [10, 2], # 10 choices => 4 bits
 [2, 1],  # 2 choices => 1 bit
 ...
]

4+1+4+1=10最初の2つの動きのビットを合計します。しかし、数ビットが無駄になり、10個の選択肢に4ビットを使用すると、6個の可能な選択肢が無駄になります。

より良い方法が可能です。リストを逆にして、可能な選択肢と選択した選択肢に基づいて数値を計算します。

n = 0         # last position
n = n*2 + 1   # from [2, 1]   n=1
n = n*10 + 2  # from [10, 2]  n=12
n = n*2 + 0   # from [2, 0]   n=24
n = n*10 + 3  # from [10, 3]  n=243

これで、上記のすべてのステップをわずか8ビットでエンコードする2432進数の数値が得られました。11110011

デコードするために、最初の開始位置には10の可能な選択肢があることがわかっています。計算する

n = 243
choice = n % 10  # we know there are 10 moveable pieces. => choice=3
n /= 10          # n=24
choice = n % 2   # we know 2 possible moves for selected pawn => choice=0
n /= 2           # n=12
choice = n % 10  # 10 moveable pieces for black player. => choice=2
n /= 10          # n=1
choice = n % 2   # 2 possible moves for pawn => choice=1
n /= 2           # n=0, finished decoding

可能な選択肢があまり残っていないため、特にエンドゲームでは、エンコーディングは非常に効率的です。また、可能な移動が1つしかない場合は、その移動のためにストレージはまったく必要ありません。

于 2009-12-27T15:31:33.427 に答える