프로그래머 퍼즐 : 게임 내내 체스 판 상태 인코딩


95

엄격하게 질문이 아니라 퍼즐에 가깝습니다 ...

수년에 걸쳐 저는 신입 사원에 대한 몇 가지 기술 인터뷰에 참여했습니다. 표준 "X 기술을 알고 계십니까"질문을하는 것 외에, 그들이 문제에 어떻게 접근하는지에 대한 느낌을 얻으려고 노력했습니다. 일반적으로 인터뷰 전날 이메일로 질문을 보내고 다음 날까지 해결책을 찾을 수 있기를 기대합니다.

종종 결과는 매우 흥미 롭습니다. 틀렸지 만 흥미로울 것입니다. 그리고 그 사람이 왜 특정한 접근 방식을 취했는지 설명 할 수 있다면 제 추천을받을 것입니다.

그래서 저는 Stack Overflow 청중을 위해 제 질문 중 하나를 던질 것이라고 생각했습니다.

질문 : 체스 게임 (또는 그 하위 집합)의 상태를 인코딩하기 위해 생각할 수있는 가장 공간 효율적인 방법은 무엇입니까? 즉, 합법적으로 배열 된 조각이있는 체스 판이 주어지면이 초기 상태와 게임에서 플레이어가 취하는 모든 후속 법적 동작을 모두 인코딩합니다.

답변에 필요한 코드는 없으며 사용할 알고리즘에 대한 설명 만 있으면됩니다.

편집 : 포스터 중 하나가 지적했듯이 나는 움직임 사이의 시간 간격을 고려하지 않았습니다. 추가 옵션으로도 고려하십시오. :)

EDIT2 : 추가 설명을 위해 ... 기억하십시오, 인코더 / 디코더는 규칙을 인식합니다. 실제로 저장해야하는 유일한 것은 플레이어의 선택입니다. 다른 것은 인코더 / 디코더가 알고 있다고 가정 할 수 있습니다.

EDIT3 : 여기서 우승자를 선택하는 것은 어려울 것입니다. :) 많은 훌륭한 답변!


4
체스 게임의 초기 상태가 잘 정의되어 있지 않습니까? 왜 인코딩해야합니까? 각 턴 (= 움직임) 사이의 차이 만 인코딩하는 것으로 충분하다고 생각합니다.
tanascius

1
그는 게임이 합법적 인 초기 설정으로 시작할 수 있다고 가정합니다 (신문에서 찾을 수있는 체스 게임 퍼즐 에서처럼).
Aaron Digulla 2009

6
엄격하게하려면 모든 과거 위치를 인코딩해야합니다. 동일한 위치가 세 번 나타나면 무승부이기 때문입니다. en.wikipedia.org/wiki/Threefold_repetition
flybywire 2009

4
제안 : 사람들이 프로그램으로 출품작을 제출하는 실제 대회를 만드십시오. 프로그램은 체스 게임을 입력으로 취하고 (이에 대해 사람이 읽을 수 있고 최적화되지 않은 기본 형식을 정의 할 수 있음) 압축 된 게임을 출력합니다. 그런 다음 매개 변수를 사용하여 압축 된 게임을 가져와 일치해야하는 원래 입력을 다시 생성합니다.
Vilx-

2
요점은 지침을 따를 수 없다는 것을 보여줄 것입니다. 심지어 대부분의 우버 코더도 어느 시점에서 지침을 따를 필요가 있습니다. 나는 그것이 어리석은 구현이라고 생각했지만 (그리고 말 했음에도) 특정 방식으로 무언가를 구현하라는 지시를받은 상황에 부딪혔다. 그렇게 구현하는 데에는 (내가 알거나 이해하지 못했던) 아주 좋은 이유가있었습니다.
Andrew Rollings

답변:


132

업데이트 : 저는 프로그래밍 퍼즐, 체스 포지션, 허프만 코딩을 썼습니다 . 이 글을 읽어 보면 완전한 게임 상태를 저장하는 유일한 방법은 전체 동작 목록을 저장하는 것이라고 판단했습니다 . 이유는 계속 읽어보십시오. 그래서 저는 조각 레이아웃에 대해 약간 단순화 된 버전의 문제를 사용합니다.

문제

이 이미지는 시작 체스 위치를 보여줍니다. 체스는 8x8 보드에서 발생하며 각 플레이어는 8 개의 폰, 2 개의 루크, 2 개의 기사, 2 개의 비숍, 1 개의 퀸, 1 개의 킹으로 구성된 동일한 16 개 조각 세트로 시작합니다.

시작 체스 위치

위치는 일반적으로 열의 문자와 행의 숫자로 기록되므로 White의 여왕은 d1에 있습니다. 이동은 대부분의 경우 대수 표기법으로 저장되며 , 이는 모호하지 않으며 일반적으로 필요한 최소한의 정보 만 지정합니다. 이 오프닝을 고려하십시오.

  1. e4 e5
  2. Nf3 Nc6

다음으로 번역됩니다.

  1. White는 king 's pawn을 e2에서 e4로 이동합니다 (e4에 도달 할 수있는 유일한 조각이므로 "e4").
  2. Black은 왕의 폰을 e7에서 e5로 이동합니다.
  3. 흰색은 기사 (N)를 f3으로 이동합니다.
  4. 검은 색은 기사를 c6로 이동합니다.

보드는 다음과 같습니다.

조기 개장

모든 프로그래머에게 중요한 능력 은 문제정확하고 명확하게 지정할 수 있다는 입니다.

그래서 무엇이 누락되었거나 모호합니까? 밝혀진대로 많이.

보드 상태 대 게임 상태

가장 먼저 결정해야 할 것은 게임의 상태를 저장할 것인지 아니면 보드에있는 조각의 위치를 ​​저장할 것인지입니다. 단순히 조각의 위치를 ​​인코딩하는 것은 하나이지만 문제는 "모든 후속 법적 이동"이라고 말합니다. 문제는 또한이 시점까지의 움직임을 아는 것에 대해 아무것도 말하지 않습니다. 제가 설명 하겠지만 실제로 문제입니다.

캐슬 링

게임은 다음과 같이 진행되었습니다.

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

보드는 다음과 같이 보입니다.

나중에 개봉

흰색에는 캐슬 링 옵션이 있습니다. 이것에 대한 요구 사항 중 일부는 왕과 관련 루크가 결코 움직일 수 없기 때문에 왕이나 양쪽의 루크가 이동했는지 여부를 저장해야한다는 것입니다. 분명히 그들이 그들의 시작 위치에 있지 않다면, 그들은 움직이지 않았다면 그것을 지정해야합니다.

이 문제를 처리하는 데 사용할 수있는 몇 가지 전략이 있습니다.

첫째, 그 조각이 움직 였는지 여부를 나타 내기 위해 6 비트의 추가 정보 (각 루크와 킹에 대해 1 개)를 저장할 수 있습니다. 올바른 조각이있는 경우 6 개의 사각형 중 하나에 대해 약간만 저장하여이를 간소화 할 수 있습니다. 또는 움직이지 않은 각 조각을 다른 조각 유형으로 취급 할 수 있으므로 각면에 6 개의 조각 유형 (폰, 루크, 나이트, 비숍, 퀸 및 킹) 대신 8 개 (움직이지 않은 루크 및 움직이지 않은 킹 추가)가 있습니다.

En Passant

Chess에서 독특하고 자주 무시되는 또 다른 규칙은 En Passant 입니다.

en passant

게임이 진행되었습니다.

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

b4에있는 Black의 폰은 이제 b4에있는 그의 폰을 c4에있는 White 폰을 c3으로 옮기는 옵션이 있습니다. 이것은 첫 번째 기회에서만 발생합니다. 즉, Black이 옵션을 통과하면 다음 이동을 수행 할 수 없습니다. 그래서 우리는 이것을 저장해야합니다.

이전 움직임을 알고 있다면 En Passant가 가능한지 확실히 대답 할 수 있습니다. 또는 4 순위에있는 각 폰이 두 번 앞으로 이동하여 방금 이동했는지 여부를 저장할 수 있습니다. 또는 우리는 보드에서 가능한 각 En Passant 위치를보고 가능한지 여부를 나타내는 플래그를 가질 수 있습니다.

프로모션

폰 프로모션

화이트의 움직임입니다. White가 자신의 폰을 h7에서 h8로 옮기면 다른 말로 승격 될 수 있습니다 (왕은 아님). 99 %의 경우 여왕으로 승진되지만 때로는 그렇지 않은 경우도 있습니다. 일반적으로 그렇지 않으면 승리 할 때 교착 상태가 될 수 있기 때문입니다. 이것은 다음과 같이 작성됩니다.

  1. h8 = Q

이것은 우리가 각면에 고정 된 수의 조각이 있다는 것을 믿을 수 없다는 것을 의미하기 때문에 우리 문제에서 중요합니다. 8 개의 폰이 모두 승격되면 한 쪽이 9 명의 퀸, 10 명의 루크, 10 명의 비숍 또는 10 명의 기사로 끝날 가능성은 전적으로 가능합니다.

수가 막히게 하다

당신이 이길 수없는 위치에있을 때 당신의 최선의 전술은 교착 상태 를 시도하는 것 입니다. 가장 가능성이 높은 변형은 합법적 인 이동을 할 수없는 경우입니다 (일반적으로 킹을 체크 할 때 이동하기 때문에). 이 경우 무승부를 청구 할 수 있습니다. 이것은 음식을 제공하기 쉽습니다.

두 번째 변형은 3 중 반복 입니다. 같은 보드 위치가 게임에서 세 번 발생하면 (또는 다음 이동에서 세 번 발생) 무승부가 청구될 수 있습니다. 위치는 특정 순서로 발생할 필요가 없습니다 (즉, 동일한 순서의 동작을 세 번 반복 할 필요가 없음). 이것은 이전의 모든 보드 위치를 기억해야하기 때문에 문제를 크게 복잡하게 만듭니다. 이것이 문제의 요구 사항 인 경우 문제에 대한 유일한 해결책은 이전의 모든 이동을 저장하는 것입니다.

마지막으로 50 개의 이동 규칙이 있습니다. 플레이어는 폰이 움직이지 않았고 이전 50 개 연속 이동에서 조각을 가져 오지 않은 경우 무승부를 청구 할 수 있으므로 폰이 이동 된 이후 또는 조각을 가져온 이후에 몇 개의 움직임을 저장해야합니다 (두 개 중 가장 최근의 것). 6 비트 (0-63).

누구의 차례인가?

물론 우리는 누구의 차례인지 알 필요가 있으며 이것은 하나의 정보입니다.

두 가지 문제

교착 상태로 인해 게임 상태를 저장하는 유일하고 현명한 방법은이 위치로 이어진 모든 동작을 저장하는 것입니다. 그 한 가지 문제를 해결하겠습니다. 보드 상태 문제는 다음과 같이 단순화됩니다. 캐슬 링, en passant, 교착 상태 및 차례를 무시하고 보드에있는 모든 조각의 현재 위치를 저장합니다 .

조각 레이아웃은 각 사각형의 내용을 저장하거나 각 조각의 위치를 ​​저장하는 두 가지 방법 중 하나로 광범위하게 처리 할 수 ​​있습니다.

간단한 내용

6 가지 유형 (폰, 루크, 나이트, 비숍, 퀸, 킹)이 있습니다. 각 조각은 흰색 또는 검은 색일 수 있으므로 사각형에는 12 개의 가능한 조각 중 하나가 포함될 수 있거나 비어있어 13 개의 가능성이 있습니다. 13은 4 비트 (0-15)로 저장 될 수 있으므로 가장 간단한 해결책은 각 제곱에 대해 4 비트를 64 제곱 또는 256 비트 정보로 저장하는 것입니다.

이 방법의 장점은 조작이 매우 쉽고 빠르다는 것입니다. 저장 공간 요구 사항을 늘리지 않고 3 개의 가능성을 더 추가하여 확장 할 수도 있습니다. 이전에 언급 된 문제의

하지만 우리는 더 잘할 수 있습니다.

Base 13 인코딩

이사회 위치를 매우 많은 수로 생각하면 도움이됩니다. 이것은 종종 컴퓨터 과학에서 수행됩니다. 예를 들어, 중지 문제 는 컴퓨터 프로그램을 (올바르게) 많은 수로 취급합니다.

첫 번째 솔루션은 위치를 64 자리 16 진수로 처리하지만이 정보에 중복성이 있으므로 ( "숫자"당 사용되지 않은 3 가지 가능성) 숫자 공간을 64 진수 13 자리로 줄일 수 있습니다. 물론 이것은 기본 16만큼 효율적으로 수행 할 수 없지만 저장 요구 사항을 절약 할 수 있습니다 (저장 공간 최소화가 목표입니다).

베이스 (10)의 수 (234)는 2 × 동등 2 + 3 × 10 1 + 4 × 10 0 .

16 진법에서 숫자 0xA50은 10 x 16 2 + 5 x 16 1 + 0 x 16 0 = 2640 (십진수)과 같습니다.

따라서 위치를 p 0 x 13 63 + p 1 x 13 62 + ... + p 63 x 13 0 으로 인코딩 할 수 있습니다. 여기서 p i 는 제곱 i 의 내용을 나타냅니다 .

2 256 등호 약 1.16e77. 13 64는 약 1.96e71과 같으며 237 비트의 저장 공간이 필요합니다. 7.5 % 만 절약 하면 조작 비용 이 크게 증가합니다.

가변베이스 인코딩

법적 게시판에서는 특정 조각이 특정 사각형에 나타날 수 없습니다. 예를 들어, 폰은 첫 번째 또는 여덟 번째 랭크에서 발생할 수 없으므로 해당 사각형의 가능성을 11로 줄입니다. 그러면 가능한 보드가 11 16 x 13 48 = 1.35e70 (대략)으로 줄어들어 233 비트의 저장 공간이 필요합니다.

실제로 이러한 값을 십진수 (또는 이진수)로 인코딩하고 디코딩하는 것은 좀 더 복잡하지만 안정적으로 수행 할 수 있으며 독자에게 연습으로 남겨 둡니다.

가변 폭 알파벳

앞의 두 가지 방법은 모두 고정 너비 알파벳 인코딩 으로 설명 할 수 있습니다 . 알파벳의 11, 13 또는 16 멤버 각각은 다른 값으로 대체됩니다. 각 "문자"는 너비가 같지만 각 문자의 가능성이 같지 않다는 점을 고려하면 효율성이 향상 될 수 있습니다.

모스 식 부호

모스 부호를 고려하십시오 (위 그림 참조). 메시지의 문자는 일련의 대시와 점으로 인코딩됩니다. 이러한 대시와 점은 라디오 (일반적으로)를 통해 전송되며 그 사이에 일시 중지되어 구분됩니다.

문자 E ( 영어에서 가장 일반적인 문자 )가 단일 점, 가능한 가장 짧은 시퀀스 인 반면 Z (최소 빈도)는 대시 2 개와 경고음 2 개입니다.

이러한 방식은 예상되는 메시지 의 크기를 크게 줄일 수 있지만 무작위 문자 시퀀스의 크기를 증가시키는 비용이 발생합니다.

모스 코드에는 또 다른 내장 기능이 있다는 점에 유의해야합니다. 대시는 점 3 개만큼 길기 때문에 대시 사용을 최소화하기 위해이를 염두에두고 생성 된 코드입니다. 1과 0 (빌딩 블록)에는이 문제가 없기 때문에 복제해야 할 기능이 아닙니다.

마지막으로 모스 부호에는 두 가지 종류의 쉼표가 있습니다. 짧은 쉼표 (점의 길이)는 점과 대시를 구분하는 데 사용됩니다. 더 긴 간격 (대시 길이)은 문자를 구분하는 데 사용됩니다.

그렇다면 이것이 우리 문제에 어떻게 적용됩니까?

허프만 코딩

Huffman 코딩 이라는 가변 길이 코드를 처리하는 알고리즘이 있습니다 . Huffman 코딩은 일반적으로 기호의 예상 빈도를 사용하여 더 일반적인 기호에 더 짧은 값을 할당하는 가변 길이 코드 대체를 생성합니다.

허프만 코드 트리

위의 트리에서 문자 E는 000 (또는 left-left-left)으로 인코딩되고 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);
    }
  }
}

가능한 출력은 다음과 같습니다.

         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 비트와 같습니다.

국가 차이

또 다른 가능한 접근 방식은 첫 번째 접근 방식을 Huffman 코딩과 결합하는 것입니다. 이것은 (무작위로 생성 된 것이 아니라) 대부분의 예상 체스 보드가 적어도 부분적으로는 시작 위치와 비슷하지 않을 가능성이 더 높다는 가정을 기반으로합니다.

그래서 여러분이하는 일은 256 비트 시작 위치로 256 비트 현재 보드 위치를 XOR 한 다음이를 인코딩합니다 (Huffman 코딩 또는 실행 길이 인코딩 방법 사용 ). 분명히 이것은 (64 비트에 해당하는 64 0s) 시작하는 데 매우 효율적이지만 게임이 진행됨에 따라 필요한 저장 공간이 증가합니다.

조각 위치

앞서 언급했듯이이 문제를 해결하는 또 다른 방법은 플레이어가 가지고있는 각 조각의 위치를 ​​저장하는 것입니다. 이것은 대부분의 사각형이 비어있는 엔드 게임 위치에서 특히 잘 작동합니다 (그러나 Huffman 코딩 방식에서는 빈 사각형이 어쨌든 1 비트 만 사용합니다).

각면에는 킹과 0-15 개의 다른 조각이 있습니다. 승진으로 인해 이러한 조각의 정확한 구성은 시작 위치를 기반으로 한 숫자가 최대라고 가정 할 수 없을 정도로 다양 할 수 있습니다.

이것을 분할하는 논리적 방법은 두 개의면 (흰색과 검은 색)으로 구성된 위치를 저장하는 것입니다. 각 측면에는 다음이 있습니다.

  • 킹 : 위치에 대해 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에 해당 하는 48 8 개의 가능성 이 있습니다 . 많은 값을 인코딩하려면 45 비트가 필요합니다.

이는 측면 당 105 비트 또는 총 210 비트입니다. 시작 위치는이 방법의 경우 최악의 경우이며 조각을 제거할수록 훨씬 좋아집니다.

폰이 모두 같은 사각형에있을 수 없기 때문에 48 8 개 미만의 가능성 이 있다는 점을 지적해야합니다 . 첫 번째는 48 개, 두 번째는 47 개 등입니다. 48 x 47 x… x 41 = 1.52e13 = 44 비트 저장.

다른 조각 (다른면 포함)이 차지하는 사각형을 제거하여이를 더욱 개선 할 수 있으므로 먼저 흰색 비폰을 배치 한 다음 검정색 비폰을 배치 한 다음 흰색 폰을 배치하고 마지막으로 검은 폰을 배치 할 수 있습니다. 시작 위치에서 이것은 저장 요구 사항을 흰색의 경우 44 비트, 검은 색의 경우 42 비트로 줄입니다.

결합 된 접근 방식

또 다른 가능한 최적화는 이러한 접근 방식 각각에 강점과 약점이 있다는 것입니다. 예를 들어, 가장 좋은 4 개를 선택한 다음 처음 2 비트에서 체계 선택기를 인코딩 한 다음 그 이후에 체계 별 저장소를 인코딩 할 수 있습니다.

오버 헤드가 너무 작기 때문에 이것이 최고의 접근 방식이 될 것입니다.

게임 상태

나는 위치 보다는 게임 을 저장하는 문제로 돌아 간다 . 3 중 반복 때문에이 지점까지 발생한 동작 목록을 저장해야합니다.

주석

결정해야 할 한 가지는 단순히 동작 목록을 저장하는 것입니까, 아니면 게임에 주석을 달고 있습니까? 체스 게임에는 종종 주석이 추가됩니다. 예를 들면 다음과 같습니다.

  1. Bb5 !! Nc4?

White의 움직임은 두 개의 느낌표가 훌륭하다고 표시되는 반면 Black은 실수로 간주됩니다. Chess 구두점을 참조하십시오 .

또한 이동이 설명 된대로 자유 텍스트를 저장해야 할 수도 있습니다.

나는 움직임이 충분하여 주석이 없을 것이라고 가정합니다.

대수 표기법

여기에 이동 텍스트 (“e4”,“Bxb5”등)를 간단히 저장할 수 있습니다. 종료 바이트를 포함하여 이동 당 약 6 바이트 (48 비트)를보고 있습니다 (최악의 경우). 특히 효율적이지 않습니다.

두 번째 시도는 시작 위치 (6 비트)와 끝 위치 (6 비트)를 저장하여 이동 당 12 비트를 저장하는 것입니다. 훨씬 낫습니다.

또는 우리가 선택한 예측 가능하고 결정적인 방식과 상태로 현재 위치에서 모든 법적 이동을 결정할 수 있습니다. 그런 다음 위에서 언급 한 가변 기본 인코딩으로 돌아갑니다. 화이트와 블랙은 첫 번째 이동에서 각각 20 개의 이동이 가능하고 두 번째 이동에서 더 많은 이동이 가능합니다.

결론

이 질문에 절대적으로 정답은 없습니다. 위의 몇 가지 가능한 접근 방식이 많이 있습니다.

이 문제와 유사한 문제에 대해 내가 좋아하는 점은 사용 패턴을 고려하고 요구 사항을 정확하게 결정하고 코너 케이스에 대해 생각하는 것과 같이 모든 프로그래머에게 중요한 능력이 필요하다는 것입니다.

Chess Position Trainer 에서 스크린 샷으로 찍은 체스 위치 .


3
그리고 나중에 결과를 gzip으로 압축합니다 (헤더가 결과를 증가시키지 않으면); ^)
Toad

흑백을 나타 내기 위해 공간을 두 배로 늘릴 필요가 없습니까?
Daniel Elliott

5
좋은 게시물입니다. 작은 수정 : 캐슬 링에는 각 캐슬 링 방식 (흰색 및 검정색, 킹 사이드 및 퀸 사이드)에 대해 하나씩 4 비트가 필요합니다. 루크가 이동 한 다음 다시 돌아 왔을 수 있기 때문입니다. 좀 더 중요합니다. 누구의 움직임인지 포함시켜야합니다. =)
A. Rex

9
기사로의 승급에 관해서는 한 번 해봤습니다. 정말 거친 상황-그는 나와 짝짓기에서 한 가지 움직임이었고 나는 그것을 멈출 수 없었습니다. 그는 내 폰을 무시했다. 왜냐하면 그것이 승진시키는 동안 그것은 늦게 움직일 것이기 때문이다. 대신 기사로 승진하고 짝짓기를 할 때 카메라가 있으면 좋겠다!
Loren Pechtel

2
나는 등 핸들 옆모습 가용성 도중, 캐슬 링 [FEN] [1], [1] 언급하지 않았다 당신의 기사를 놀라게하고 있습니다 en.wikipedia.org/wiki/FEN
로스

48

체스 게임을 사람이 읽을 수있는 표준 형식으로 저장하는 것이 가장 좋습니다.

휴대용 게임 표기법은 (는 있지만 표준 시작 위치를 가정 할 필요가 없습니다 ) 그냥 움직임을 나열 회전에 의해 전원을 켭니다. 사람이 읽을 수있는 컴팩트 한 표준 형식입니다.

[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

더 작게 만들고 싶다면 압축 하세요. 완료되었습니다!


23
2 개의 반대표에 대한 저의 변호에서 이것은 다음과 같습니다. 1) 원하는대로 수행합니다. 2) thedailywtf.com/articles/riddle-me-an-interview.aspx 테스트를 통과했습니다 . "... 해결할 수있는 사람들 중 일부 이 수수께끼는 프로그래머로서 원하지 않는 유형의 사람들입니다. 물 변위 스케일 / 바지선을 만들고 747을 부두로 택시로 이동 한 다음이를 사용하여 점보 제트기에 가중치를 부여하는 사람과 함께 작업하고 싶습니까? 단순히 보잉에게 전화하는 대신에? " 인터뷰에서 무작위 인코딩을 발명하는 사람을 고용하지 않습니다. 그들은 코드에서도 그렇게 할 것이기 때문입니다.
Rob Grant

1
글쎄, 내가 그들에게 문제 해결 기술을 얻기 위해 문제를 풀도록 특별히 요청한다면, 다른 질문으로 다른 문제를 다루
겠다고

7
@reinier : 정보 밀도 문제에 대해 완전히 단서가 없다고 말하는 것이 아닙니다 (내 대답이 무능함을 인정하는 것으로 잘못 진단하셨습니다). 확실히 기존 데이터 저장 표준에 따라 코딩하는 사람을 고용하고 싶고, 자신의 도구를 사용하는 것보다 적절한 기존 도구를 사용하는 것이 좋은 생각이 될 수 있음을 인식하는 사람을 고용하고 싶을 것입니다. 이상하게도 라이브러리 기능을 사용하는 것이 약점의 신호라고 생각하는 사람을 고용하고 싶지는 않습니다.
Rob Grant

18
이것은 인터뷰에서이 질문에 대한 나의 첫 번째 대답이 될 것입니다. 첫 번째 본능은 준비된 해결책을 찾는 것임을 보여주고 싶습니다. 면접관이 스스로 생각 해낼 수있는 내용을 듣고 싶다고 말하면 비트 패킹 솔루션으로 이동할 수 있습니다.
Bill the Lizard

2
저는 Robert와 함께이 문제를 해결했습니다. 기존 솔루션은 실용적이고 사람이 읽을 수 있으며 충분히 컴팩트합니다. 복잡한 알고리즘을 사용하여 디코딩하는 맞춤형 슈퍼 팩 솔루션과 비교할 때 모두 주요 업적입니다. 면접에 관한 것이라면 반드시 실용적인 면도 고려할 것입니다! 정말 똑똑한 사람들이 매우 복잡하고 비실용적 인 솔루션을 몇 번이나 생각해 냈는지 놀랄 것입니다. 그것은 일반적으로 그들이 머리 속의 복잡성을 처리 할 수 ​​있다는 사실에 기인합니다. 그러나 나머지 우리는
어떻습니까

15

멋진 퍼즐!

나는 대부분의 사람들이 각 조각의 위치를 ​​저장하고있는 것을 봅니다. 좀 더 단순한 접근 방식을 취하고 각 사각형의 내용을 저장하는 것은 어떻습니까? 승진을 처리하고 조각을 자동으로 캡처합니다.

그리고 그것은 Huffman 인코딩을 허용합니다 . 실제로 보드에있는 조각의 초기 주파수는 거의 완벽합니다. 사각형의 절반은 비어 있고 나머지 사각형의 절반은 폰입니다.

각 조각의 빈도를 고려하여 종이에 허프만 나무 를 만들었는데 여기서는 반복하지 않겠습니다. 결과 c는 색상을 나타냅니다 (흰색 = 0, 검은 색 = 1).

  • 빈 사각형의 경우 0
  • 폰의 경우 1c0
  • 루크의 경우 1c100
  • 기 사용 1c101
  • 비숍 용 1c110
  • 여왕의 경우 1c1110
  • 왕을위한 1c1111

초기 상황의 전체 이사회에 대해

  • 빈 사각형 : 32 * 1 비트 = 32 비트
  • 폰 : 16 * 3 비트 = 48 비트
  • 루크 / 나이츠 / 비숍 : 12 * 5 비트 = 60 비트
  • queens / kings : 4 * 6 비트 = 24 비트

전체 : 초기 보드 상태의 경우 164 비트 . 현재 가장 많이 투표 된 답변의 235 비트보다 훨씬 적습니다. 그리고 게임이 진행됨에 따라 더 작아 질 것입니다 (프로모션 이후 제외).

나는 칠판에있는 조각들의 위치만을 보았다. 추가 상태 (턴, 캐슬 링 한 사람, 패전트, 반복 동작 등)는 별도로 인코딩해야합니다. 최대 16 비트가 추가 될 수 있으므로 전체 게임 상태에 대해 180 비트 입니다. 가능한 최적화 :

  • 자주 사용하지 않는 부분은 제외하고 위치를 별도로 저장합니다. 그러나 그것은 도움이되지 않을 것입니다. 왕과 여왕을 빈 사각형으로 바꾸면 5 비트를 절약 할 수 있습니다. 이는 다른 방식으로 위치를 인코딩하는 데 필요한 정확히 5 비트입니다.
  • "뒷줄에 폰 없음"은 뒷줄에 다른 Huffman 테이블을 사용하여 쉽게 인코딩 할 수 있지만 많은 도움이되지는 않습니다. 당신은 아마도 여전히 같은 Huffman 나무로 끝날 것입니다.
  • "하나의 흰색, 하나의 검정 비숍"은 c비트 가없는 추가 기호를 도입하여 인코딩 할 수 있으며 , 그런 다음 비숍이있는 사각형에서 추론 할 수 있습니다. (주교로 승진 한 폰은이 계획을 방해합니다 ...)
  • 빈 사각형의 반복은 "행에 빈 사각형 2 개"및 "행에 빈 사각형 4 개"에 대한 추가 기호를 도입하여 실행 길이로 인코딩 될 수 있습니다. 그러나 그 빈도를 추정하는 것은 그리 쉽지 않으며, 잘못 이해하면 도움이되기보다는 상처를 입을 것입니다.

은행 순위에있는 폰은 조금도 절약 할 수 없습니다. 다른 모든 패턴 중에서 3 번 비트를 잘라낼 수 있습니다. 따라서 실제로 은행 순위에서 조각 당 1 비트를 절약 할 수 있습니다.
Loren Pechtel

2
일부는 다른 것보다 더 자주 일부 조각을 가질 가능성이 있으므로 64 사각형 각각에 대해 별도의 Huffman 트리를 만들 수 있습니다.
Claudiu

9

정말 큰 조회 테이블 접근 방식

Position -18 bytes
합법적 인 위치의 예상 수는 10입니다. 43
단순히 모든 위치를 열거하면 위치가 143 비트에 저장 될 수 있습니다. 다음에 플레이 할 팀을 표시하려면 1 비트가 더 필요합니다.

물론 열거 형은 실용적이지 않지만 최소한 144 비트가 필요하다는 것을 보여줍니다.

이동 -1 바이트
일반적으로 각 위치에 대해 약 30-40 개의 합법적 인 이동이 있지만 그 수는 218 개까지있을 수 있습니다. 각 위치에 대한 모든 합법적 인 이동을 열거합니다. 이제 각 이동을 1 바이트로 인코딩 할 수 있습니다.

우리는 여전히 사임을 나타 내기 위해 0xFF와 같은 특별한 움직임을위한 충분한 여지를 가지고 있습니다.


3
"체스 게임의 상태를 인코딩하기 위해 생각할 수있는 가장 공간 효율적인 방법"이라는 요구 사항의 핵심입니다. 사전보다 더 좋은 것은 없습니다. 여기에는 파리도 포함됩니다.
Andrew

1
그런 사전을 생성하는 데 걸리는 시간에 대한 흥미로운 링크를 찾았습니다. :) ioannis.virtualcomposer2000.com/math/EveryChess.html
앤드류 익스펜더를

Shannons 추정치는 약간 구식입니다. :-) 그는 승진이나 캡처를 포함하지 않았으며, 이는 상당한 금액으로 숫자를 날려 버렸습니다. 5x10 ^ 52의 상한선은 Victor Allis 1994에 의해 주어졌습니다.
Gunther Piez

확실히 가변 길이 인코딩으로 평균은 적어도 10 ^ 43입니까? 더 많은 위치로 편향된 인코딩은 특히 많은 위치가 불가능하기 때문에이를 줄여야합니다.
필 H

EveryChess 링크, '판매'archive.org 링크 지금 : web.archive.org/web/20120303094654/http://...
oPless

4

최악의 경우 대신 인간이 플레이하는 일반적인 게임의 평균 케이스 크기 를 최적화하는 데 관심이 추가 됩니다. (문제 진술은 어느 것을 말하지 않습니다. 대부분의 응답은 최악의 경우를 가정합니다.)

이동 시퀀스의 경우 좋은 체스 엔진이 각 위치에서 이동을 생성하도록합니다. 퀄리티 순위에 따라 순서대로 k 개의 가능한 이동 목록을 생성합니다. 사람들은 일반적으로 무작위 동작보다 좋은 동작을 더 자주 선택하므로 목록의 각 위치에서 사람들이 '좋은'동작을 선택할 확률에 대한 매핑을 배워야합니다. 이러한 확률 (일부 인터넷 체스 데이터베이스의 게임 코퍼스 기반)을 사용하여 산술 코딩으로 동작을 인코딩합니다 . (디코더는 동일한 체스 엔진과 매핑을 사용해야합니다.)

시작 위치의 경우 ralu의 접근 방식이 효과적입니다. 확률에 따라 선택에 가중치를 부여하는 방법이 있다면 산술 코딩으로이를 다듬을 수 있습니다. 예를 들어, 조각은 종종 무작위가 아닌 서로를 방어하는 구성에 나타납니다. 그 지식을 통합하는 쉬운 방법을 찾기가 더 어렵습니다. 한 가지 아이디어는 위의 이동 인코딩으로 돌아가서 표준 개방 위치에서 시작하여 원하는 보드에서 끝나는 시퀀스를 찾는 것입니다. (마지막 위치에서 조각의 거리를 합한 것과 같은 휴리스틱 거리로 A * 검색을 시도 할 수 있습니다.) 이것은 이동 순서를 과도하게 지정하는 것과 체스 플레이를 활용하는 효율성의 비 효율성을 교환합니다. 지식.

실제 말뭉치에서 일부 통계를 수집하지 않고 평균 사례 복잡성에서 얼마나 많은 절감 효과를 얻을 수 있는지 추정하는 것도 어렵습니다. 그러나 모든 움직임의 시작점은 이미 여기에서 대부분의 제안을 능가 할 것이라고 생각합니다. 산술 코딩에는 움직임 당 정수 비트 수가 필요하지 않습니다.


이 정보를 풀에 저장하는 복잡성은 O (n)입니다. 수정 된 답변을 확인하십시오.
Luka Rahne

ralu, 나는 당신이 무슨 말을하는지 잘 모르겠습니다.하지만 당신이 일련의 움직임을 표현하는 것이 최악의 경우 최적의 공간을 사용한다는 것을 의미한다면, 나는 그것을 모순하지 않습니다. 여기서 아이디어는 일부 동작이 다른 동작보다 더 가능성이 있음을 활용하는 것입니다.
Darius Bacon

좀 더 likley 인 포지션을 찾기 위해 필요한 것은 주어진 포지션 결정적인 방식으로 유효한 움직임을 정렬하는 결정 론적 (그리고 강력한) 체스 엔진을 사용하는 것입니다.
Luka Rahne

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 비트.


방금 업데이트 한 것은 128 개의 조합을 의미했습니다. 분명히 128 비트 미만입니다. :) :)
Alex Weinstein

1
게임 상태는 이동과 동일하지 않습니다. 주어진 위치는 정점 또는 노드로 생각할 수 있으며 법적 이동은 방향성 모서리 또는 화살표로 생각할 수 있으며 (방향성 비순환) 그래프를 형성합니다.
Shaggy Frog

왜 반대표를 받았는지 잘 모르겠습니다. 업데이트 된 아이디어에 대한 사람들의 의견을 듣고 싶습니다.
Alex Weinstein

1
이것은 당신의 추론에 영향을주지 않지만 약간의 수정입니다. e2의 폰 예시 : e3, e4, exd3, exf3. e7의 폰 예시 : e8Q, e8N, e8R, e8B, exd8Q, exd8N, exd8R, exd8B, exf8Q, exf8N, exf8R, exf8B.
A. Rex

1
한 가지 사소한 문제-5 비트는 32 개의 값만 인코딩합니다. 보드의 사각형을 지정하려면 6 비트가 필요합니다.
Chris Dodd

4

나는 어제 밤에이 질문을 보았고 그것이 나를 흥미롭게해서 해결책을 생각하면서 침대에 앉았다. 내 최종 답변은 실제로 int3와 매우 유사합니다.

기본 솔루션

표준 체스 게임을 가정하고 규칙을 인코딩하지 않는다고 가정하면 (예 : White가 항상 먼저 진행됨) 각 조각이 만드는 동작 만 인코딩하여 많은 비용을 절약 할 수 있습니다.

총 32 개의 조각이 있지만 각 이동에서 어떤 색이 움직이는 지 알 수 있으므로 걱정할 사각형은 16 개뿐입니다 .이 조각은 이번 턴에 이동하는 4 비트 입니다.

각 조각에는 제한된 이동 세트 만 있으며 어떤 식 으로든 열거 할 수 있습니다.

  • 폰 : 4 개 옵션, 2 비트 (1 단계 앞으로, 2 단계 앞으로, 각 대각선 1 개)
  • 루크 : 14 개 옵션, 4 비트 (각 방향으로 최대 7 개)
  • Bishop : 13 개 옵션, 4 비트 (하나의 대각선에 7 개가있는 경우 다른 대각선에 6 개만 있음)
  • Knight : 8 가지 옵션, 3 비트
  • 퀸 : 27 개 옵션, 5 비트 (Rook + Bishop)
  • King : 9 개 옵션, 4 비트 (8 개의 한 단계 이동 및 캐슬 링 옵션)

승진을 위해 선택할 수있는 4 개의 조각 (Rook, Bishop, Knight, Queen)이 있으므로 해당 이동에 2 비트 를 추가 하여 지정합니다. 다른 모든 규칙은 자동으로 적용됩니다 (예 : en passant).

추가 최적화

먼저 한 가지 색상의 8 개 조각을 캡처 한 후 조각 인코딩을 3 비트로 줄인 다음 4 조각에 대해 2 비트 등으로 줄일 수 있습니다.

그러나 주요 최적화 는 게임의 각 지점에서 가능한 이동 열거 하는 것입니다. Pawn의 움직임 {00, 01, 10, 11}을 각각 1 단계 앞으로, 2 단계 앞으로, 대각선 왼쪽 및 대각선 오른쪽으로 저장한다고 가정합니다 . 일부 이동이 불가능한 경우 이번 턴에 인코딩에서 제거 할 수 있습니다.

우리는 모든 단계의 게임 상태를 알고 있으므로 (모든 동작을 따라 가면서), 어떤 조각이 움직일 것인지 읽은 후 항상 읽어야하는 비트 수를 결정할 수 있습니다. 이 시점에서 폰의 유일한 움직임이 대각선으로 오른쪽으로 캡처되거나 앞으로 이동하는 것을 인식하면 1 비트 만 읽는다는 것을 알고 있습니다.

요컨대, 각 조각에 대해 위에 나열된 비트 스토리지는 최대 값 입니다. 거의 모든 움직임에는 더 적은 수의 옵션과 종종 더 적은 비트가 있습니다.


4

각 위치에서 가능한 모든 이동 수를 얻습니다.

다음 이동은 다음과 같이 생성됩니다.

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

무작위로 생성 된 게임을 저장하기위한 최고의 공간 효율성을 입증 하고 30-40 개의 이동이 가능하기 때문에 평균적으로 약 5 비트 / 이동이 필요합니다. 스토리지를 조립하면 n이 역순으로 생성됩니다.

중복성이 높기 때문에 위치를 저장하는 것이 더 어렵습니다. (한 사이트에 최대 9 명의 퀸이 탑승 할 수 있지만이 경우 폰이없고 보드에있는 경우 비숍이 반대 색상의 사각형에 있음) 그러나 일반적으로 나머지 사각형 위에 동일한 조각을 조합하여 저장하는 것과 같습니다.)

편집하다:

무브 저장의 포인트는 무브 인덱스 만 저장하는 것입니다. Kc1-c2를 저장하고이 정보를 줄이려고하는 대신 결정 론적 movegenerator (position)에서 생성 된 이동 인덱스 만 추가해야합니다.

움직일 때마다 크기 정보를 추가합니다.

num_of_moves = get_number_of_possible_moves(postion) ;

이 수는 줄일 수 없습니다.

정보 풀 생성은

n=n*num_of_moves+ index_current_move

특별한

최종 위치에 사용 가능한 이동이 하나만있는 경우 이전에 수행 한 강제 이동 수로 저장합니다. 예 : 시작 위치에 각 측면에 대해 1 개의 강제 이동 (2 개 이동)이 있고이를 하나의 이동 게임으로 저장하려면 1 개를 풀 n에 저장합니다.

정보 풀에 저장하는 예

우리가 시작 위치를 알고 있고 3 개의 동작을한다고 가정 해 봅시다.

첫 번째 행마에는 5 개의 사용 가능한 이동이 있고, 우리는 이동 인덱스 4를 취합니다. 두 번째 이동에는 6 개의 사용 가능한 이동이 있고, 우리는 포지션 인덱스 3을 취하고, 3 번째 수에는 그 편에 대해 7 개의 이동이 가능하며, 그는 이동 인덱스를 선택하기로 선택했습니다. 2.

벡터 형태; 인덱스 = [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. 유효한 이동이있는 쪽

모든 조각이 같은 위치에 두 조각이 아닌 아무 곳에 나 설 수 있다고 가정 해 봅시다. 같은 색상의 폰 8 개를 보드에 배치 할 수있는 방법의 수는 C (64/8) (이항)로 32 비트, 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) 등 .

두 사이트에 대해이 값을 곱하면 약 142 비트 인 4634726695587809641192045982323285670400000이됩니다. 가능한 en-passant (en-passant 폰은 8 개 중 하나에있을 수 있음)에 대해 8을 더해야합니다. 이동이있는 사이트의 경우 1 비트입니다. 우리는 142 + 3 + 4 + 1 = 150 비트로 끝납니다.

하지만 이제는 32 개 조각을 가지고있는 보드에서 중복성을 찾아 보겠습니다.

  1. 흑백 폰은 모두 같은 기둥에 있고 서로 마주보고 있습니다. 각 폰은 다른 폰을 향하고 있으며 이는 흰색 폰이 기껏해야 6 위가 될 수 있음을 의미합니다. 이것은 정보를 56 비트 감소시키는 C (64/8) * C (48/8) 대신 8 * C (6/2)를 가져옵니다.

  2. 캐슬 링 가능성도 중복됩니다. 루크가 시작 장소에 없으면 그 루크의 캐슬 링 가능성이 없습니다. 그래서 우리는 상상으로이 루크를 캐슬 링이 가능하고 캐슬 링 비트 4 개를 제거하면 추가 정보를 얻기 위해 보드에 4 개의 사각형을 추가 할 수 있습니다. 따라서 C (56/2) * C (40/2) * 16 대신 C (58/2) * C (42/2)가 있고 3.76 비트가 손실되었습니다 (거의 4 비트).

  3. en-passant : 8 개의 en passant possibilites 중 하나를 저장할 때, 우리는 black pawn의 위치를 ​​알고 정보 용 redindancy를 줄입니다. c2, c3 또는 c4) C (6/2)를 삽입하면 3 개가 있고 2.3 비트가 손실되었습니다. 우리가 수행 할 수있는 측면 (3 가지 가능성-> 왼쪽, 오른쪽, 둘 다)과 함께 whit en-passant 번호를 저장하면 약간의 중복성을 줄이고, en-passant를 취할 수있는 pawn의 가능성을 알고 있습니다. (예를 들어 이전 en passant 예에서 c5의 whit black on 왼쪽, 오른쪽 또는 둘 다에있을 수 있습니다. 한 사이트에 있으면 2 * 3 (psissibilites를 저장하는 데 3 개, 7 또는 6 랭크에서 검은 폰에 대해 2 개의 이동 가능) ) insted of C (6/2) 그리고 1.3 비트로 줄이고 양쪽에서 4.2 비트로 줄이면 2.3 + 1.3 = 3으로 줄일 수 있습니다.

  4. bishops : bisop은 오 포스 타이트 사각형에만있을 수 있습니다. 이렇게하면 각 사이트에 대해 중복성이 1 비트 씩 줄어 듭니다.

요약하면 체스 위치를 저장하기 위해 150-56-4-3.6-2 = 85 비트 가 필요합니다.

그리고 고려할 수있는 고려와 승진이 있다면 아마 그다지 많지 않을 것입니다.


흥미로운 접근 방식. 좀 더 자세히 추가 :)
Andrew Rollings 2009-12-02

나는 또한 위치를 저장하기 위해 앞치마를 추가했습니다. 나는 복용하지 않는 위치에서 85bits까지 내려 갔고 얼마나 멀리 갈 수 있는지 좋은 ilustration입니다. 가장 좋은 아이디어는 거의 모든 4 비트가 중복되는 캐슬 링 가능성을 줄이는 것입니다.
Luka Rahne

3

대부분의 사람들은 보드 상태를 인코딩했지만 이동 자체에 대해서는 .. 여기에 비트 인코딩 설명이 있습니다.

조각 당 비트 :

  • Piece-ID : 한 면당 16 개 조각을 식별하기위한 최대 4 비트. 흰색 / 검정을 유추 할 수 있습니다. 조각에 정의 된 순서가 있습니다. 조각의 수가 각 2의 거듭 제곱 아래로 떨어지면 나머지 조각을 설명하는 데 더 적은 비트를 사용합니다.
  • Pawn : 첫 번째 이동에서 3 가지 가능성이 있으므로 +2 비트 (1 개 또는 2 개의 사각형 앞으로 이동, 통과) 이후 이동은 2 개씩 앞으로 이동하는 것을 허용하지 않으므로 +1 비트이면 충분합니다. 승진은 폰이 마지막 순위에 도달했을 때를 기록함으로써 디코딩 과정에서 추론 할 수 있습니다. 폰이 승격 된 것으로 알려진 경우 디코더는 4 개의 주요 부분 중 어느 것이 승격되었는지를 나타내는 또 다른 2 비트를 예상합니다.
  • Bishop : 사용되는 대각선의 경우 +1 비트, 대각선을 따른 거리의 경우 최대 +4 비트 (16 가지 가능성). 디코더는 조각이 해당 대각선을 따라 이동할 수있는 최대 가능한 거리를 추론 할 수 있으므로 더 짧은 대각선이면 더 적은 비트를 사용합니다.
  • 기사 : 8 개 이동 가능, +3 비트
  • 루크 : 수평 / 수직의 경우 +1 비트, 선을 따른 거리의 경우 +4 비트.
  • 킹 : 8 개의 이동 가능, +3 비트. 캐슬 링을 '불가능한'움직임으로 표시하십시오. 캐슬 링은 왕이 1 순위에있을 때만 가능하므로,이 움직임을 킹을 '뒤로'이동하라는 지시 (예 : 보드 밖으로)로 인코딩하십시오.
  • 퀸 : 8 가지 방향, +3 비트. 선 / 대각선을 따라 거리에 대해 최대 +4 비트 추가 (비숍의 경우와 같이 대각선이 더 짧은 경우 더 적음)

모든 조각이 보드에 있다고 가정 할 때, 다음은 이동 당 비트입니다. Pawn-첫 번째 이동시 6 비트, 이후 5 비트. 승진하는 경우 7입니다. Bishop : 9 비트 (최대), Knight : 7, Rook : 9, King : 7, Queen : 11 (최대).


조각을 식별하는 32 비트 ??? 나는 당신이 5 (32 조각)를 의미한다고 생각합니다. 또는 '종료'상태를 인코딩해야하는 경우 6,
Toad

폰은 루크, 나이트 또는 비숍으로 승격 될 수도 있습니다. 이것은 Stalemate를 피하거나 대립을 피하기 위해 일반적입니다.
Kobi

이것은 추론에 영향을 미치지 않지만 약간의 수정입니다. 폰은 승진을 포함하지 않는 4 개의 동작을 가질 수 있고 승진을 포함하여 12 개의 동작을 가질 수 있습니다. e2의 폰 예시 : e3, e4, exd3, exf3. e7의 폰 예시 : e8Q, e8N, e8R, e8B, exd8Q, exd8N, exd8R, exd8B, exf8Q, exf8N, exf8R, exf8B.
A. Rex

내가 잘못 읽었을지도 모르지만, 폰은 첫 번째 움직임에 대해 엉뚱한 행동을 할 수 없습니다. 실제로 게임 규칙에 있기 때문에 특별한 "en passant"표기법이 필요하지 않습니다. 단지 대각선 이동일 것입니다. 첫 번째 이동은 4 가지 옵션 중 하나이며 후속 이동은 최대 3 가지 옵션입니다.
DisgruntledGoat

3

일반적인 체스 게임에 가장 효율적인 인코딩을 제공하는 것이 문제입니까? 아니면 최악의 경우 인코딩이 가장 짧은 것입니까?

후자의 경우 가장 효율적인 방법은 가장 불투명 한 방법이기도합니다. 가능한 모든 쌍 (초기 보드, 합법적 인 이동 순서)의 열거 형을 생성합니다. -마지막 전당포 이동 또는 캡처 규칙 이후 50 번 이동은 재귀 적입니다. 그런 다음이 유한 시퀀스의 위치 인덱스는 가장 짧은 최악의 경우 인코딩을 제공하지만 일반적인 경우에도 동일하게 긴 인코딩을 제공하며 계산하는 데 매우 비쌉니다. 가능한 가장 긴 체스 게임은 5000 개 이상의 이동이어야하며, 일반적으로 각 플레이어에게 각 위치에서 20 ~ 30 개의 이동이 가능합니다 (조각이 거의 남지 않은 경우 더 적지 만). 이는이 인코딩에 필요한 40000 비트와 같은 것을 제공합니다.

위의 인코딩 동작에 대한 Henk Holterman의 제안에 설명 된대로 열거 개념을 적용하여보다 다루기 쉬운 솔루션을 제공 할 수 있습니다. 내 제안 : 최소한은 아니지만 위의 예보다 짧고 합리적으로 다루기 쉽습니다.

  1. 점유 된 사각형 (점유 행렬)을 나타내는 64 비트와 각 점유 된 사각형에있는 조각 목록 (폰의 경우 3 비트, 다른 조각의 경우 4 비트) : 시작 위치에 190 비트를 제공합니다. 보드에 32 개 이상의 조각이있을 수 없기 때문에 점유 행렬의 인코딩이 중복되므로 공통 보드 위치와 같은 것을 인코딩 할 수 있습니다 (예 : 공통 보드 목록의 보드 인덱스 33 세트 비트).

  2. 누가 먼저 움직 일지 1 비트

  3. Henk의 제안에 따라 코드 이동 : 일반적으로 흰색 / 검정 이동 쌍당 10 비트이지만, 플레이어가 대체 이동이없는 경우 일부 이동은 0 비트를 사용합니다.

이것은 일반적인 30 개 이동 게임을 코딩하는 데 490 비트를 제안하며 일반적인 게임에 대해 합리적으로 효율적인 표현입니다.

마지막 전당포 이동 또는 캡처 규칙 이후로 세 번 반복되는 위치와 50 개 이하의 움직임을 인코딩하는 방법 : 과거를 인코딩하면 마지막 폰 이동 또는 캡처로 돌아갑니다. 이 규칙의 적용 여부를 결정할 수있는 충분한 정보가 있어야합니다. 전체 게임 기록이 필요하지 않습니다.


내가 많은 게임을 선택하고 그 결과의 평균을 취한다고 가정하자.
Andrew Rollings

3

보드의 위치는 7 비트로 정의 할 수 있습니다 (0-63 및 더 이상 보드에 없음을 지정하는 1 값). 따라서 보드의 모든 조각에 대해 위치를 지정하십시오.

32 개 * 7 비트 = 224 비트

편집 : Cadrian이 지적했듯이 ... 우리는 또한 '승진 된 전당포에서 여왕으로'케이스가 있습니다. 어떤 폰이 승격되었는지 표시하기 위해 끝에 추가 비트를 추가하는 것이 좋습니다.

따라서 승격 된 모든 폰에 대해 승격 된 폰의 인덱스를 나타내는 5 비트와 목록의 끝인 경우 11111로 224 비트를 따릅니다.

따라서 최소 케이스 (프로모션 없음)는 224 비트 + 5 (프로모션 없음)입니다. 승격 된 모든 폰에 대해 5 비트를 추가합니다.

편집 : 얽히고 설킨 개구리가 지적했듯이, 우리는 그것이 누구의 차례인지를 나타 내기 위해 끝에 또 다른 비트가 필요합니다; ^)


그리고 나중에 결과를 gzip으로 압축합니다 (헤더가 결과를 증가시키지 않으면); ^)
Toad

특정 정사각형 색상에서 일부 조각을 찾을 수 없다는 점을 고려하여 개선 할 수 있습니까?
Andrew Rollings

앤드류 : 실제로는 할 수 없습니다. 나는 승진 된 폰을 여왕으로 간주하는 것을 잊었다 (cadrian의 대답이 제안하는 것처럼). 보이는 그래서 같은 사실은 또 다른 여분의 비트가 필요합니다
두꺼비

흑인과 백인 감독이 어떻게 함께 정의 될 수 있는지 알 수 있습니다. 나는 기사에 대해 궁금해 ..
int3

1
여왕이 아닌 프로모션을 놓치고 있습니다.
Loren Pechtel

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"으로 취급 할 수 있습니다.

보드가 비어 있지만 왼쪽 상단 모서리에있는 단일 폰의 경우 "Pawn, 1, Empty, 16, Empty, 16, Empty 16, Empty, 15"= 10 nibbles = 40 bits입니다.

최악의 경우는 각 조각 사이에 빈 사각형이있을 때입니다. 그러나 조각을 인코딩하려면 16 개 값 중 13 개만 필요하므로 다른 값을 사용하여 "Empty1"이라고 말할 수 있습니다. 그런 다음 64 니블 == 128 비트가 필요합니다.

움직임의 경우 조각에 3 비트 (흰색이 항상 먼저 이동한다는 사실에 의해 색상이 지정됨)와 새 위치에 대해 5 비트 (0..63)가 필요합니다 = 움직임 당 1 바이트. 대부분의 경우 한 조각 만 범위 내에 있기 때문에 이전 위치가 필요하지 않습니다. 이상한 경우에는 사용하지 않은 단일 코드 (조각을 인코딩하는 데 7 개의 코드 만 필요)를 사용한 다음 이전 위치에는 5 비트, 새 위치에는 5 비트를 사용해야합니다.

이렇게하면 캐슬 링을 13 바이트로 인코딩 할 수 있습니다 (내가 의도 한 바를 말할 수있는 Rook쪽으로 King을 이동할 수 있음).

[편집] 스마트 인코더를 허용하는 경우 초기 설정에 0 비트가 필요합니다 (어떤 식 으로든 인코딩 할 필요가 없기 때문입니다. 정적 임) + 이동 당 1 바이트.

[EDIT2] 폰 변환을 남깁니다. 폰이 마지막 행에 도달하면 "변형"이라고 말한 다음 교체 할 조각에 3 비트를 추가 할 수 있습니다 (퀸을 사용할 필요가 없습니다. 폰을 다른 것으로 교체 할 수 있습니다. 그러나 왕).


스마트 인코더는 그것이 전체 게임이라고 가정 할 수 없습니다. 게임의 일부일 수 있습니다. 여전히 시작 위치를 인코딩해야한다고 생각합니다.
Andrew Rollings

음, 최악의 경우 128 비트가 필요하거나 게임이 아직 초기 단계 인 경우 최대 15 개의 동작을 사용하여 시작 위치 = 120 비트로 가져올 수 있습니다.
Aaron Digulla 2009

초기 보드 상태뿐만 아니라 모든 상태를 인코딩해야하므로 조각 자체도 인코딩해야합니다. 따라서 조각 당 최소 5 비트가 필요합니다. 따라서 이렇게하면 최소한 32 * 5 비트가 추가로 제공됩니다
Toad

@reiner : 당신이 틀렸어요. 조각 / 빈 사각형 당 4 비트 만 필요합니다. 그리고 나는 이미 내 대답의 첫 부분에서 이것을 다루었으므로 "32 * 5 비트 추가"는 없습니다. 초기 상태의 경우 96 비트가 필요하고 다른 시작 상태의 경우 최대 128 비트가 필요합니다.
Aaron Digulla 2009

Aaron : 말했듯이 최악의 시나리오는이 인코딩에서 정말 최악의 경우입니다. 시작 보드에서 3 ~ 4 번 이동 한 후에는 더 많은 빈 항목을 추가함에 따라 인코딩에 훨씬 더 많은 비트가 필요합니다.
Toad

2

책과 종이에 게임을 인코딩하는 것처럼 모든 조각에는 기호가 있습니다. "합법적 인"게임이므로 흰색이 먼저 이동합니다. 흰색 또는 검은 색을 별도로 인코딩 할 필요가 없습니다. 이동 횟수를 세어 누가 이동했는지 확인하세요. 또한 모든 움직임은 '종료 위치'가 모호함을 식별 할 수있는 최소한의 기호 (0 일 수 있음)로 축소되는 (조각, 종료 위치)로 인코딩됩니다. 게임의 길이는 이동 횟수를 결정합니다. 또한 모든 단계에서 시간 (마지막 이동 이후)을 분 단위로 인코딩 할 수도 있습니다.

조각의 인코딩은 각각에 기호를 할당하거나 (총 32 개) 클래스에 기호를 할당하여 수행 할 수 있으며, 끝 위치를 사용하여 어떤 조각이 이동되었는지 이해합니다. 예를 들어, 폰은 6 개의 가능한 종료 위치를 가지고 있습니다. 그러나 평균적으로 매 턴마다 몇 명만 사용할 수 있습니다. 따라서 통계적으로 끝 위치 별 인코딩이이 시나리오에 가장 적합 할 수 있습니다.

유사한 인코딩이 계산 신경 과학 (AER)의 스파이크 트레인에 사용됩니다.

단점 : 연결 목록을 순회하는 것처럼 현재 상태에 도달하고 하위 집합을 생성하려면 전체 게임을 재생해야합니다.


게임 조각 일 수도 있습니다. 당신은 흰색 움직임이 처음이라고 가정 할 수 없습니다.
Andrew Rollings

2

64 개의 가능한 보드 위치가 있으므로 위치 당 6 비트가 필요합니다. 32 개의 초기 조각이 있으므로 지금까지 총 192 비트가 있습니다. 여기서 6 비트마다 주어진 조각의 위치를 ​​나타냅니다. 조각이 나타나는 순서를 미리 결정할 수 있으므로 어느 것이 무엇인지 말할 필요가 없습니다.

조각이 보드에서 벗어난다면? 글쎄, 우리는 다른 조각과 같은 위치에 조각을 놓아 보드에서 벗어 났음을 나타낼 수 있습니다. 그렇지 않으면 불법입니다. 그러나 우리는 또한 첫 번째 작품이 보드에 올지 여부도 모릅니다. 그래서 우리는 어떤 조각이 첫 번째 조각인지 나타내는 5 비트를 추가합니다 (32 개 가능성 = 첫 번째 조각을 나타내는 5 비트). 그런 다음 보드에서 벗어난 후속 조각에 해당 지점을 사용할 수 있습니다. 총 197 비트가됩니다. 보드에 적어도 하나의 조각이 있어야 작동합니다.

그 다음 우리는 198 비트 가 될 차례 인 1 비트가 필요합니다 .

폰 프로모션은 어떻습니까? 폰당 3 비트를 추가하고 42 비트를 추가하여 나쁜 방법으로 할 수 있습니다. 그러나 대부분의 경우 폰이 승격되지 않는다는 것을 알 수 있습니다.

따라서 보드에있는 모든 폰에 대해 비트 '0'은 승격되지 않았 음을 나타냅니다. 폰이 보드에 없으면 우리는 조금도 필요하지 않습니다. 그런 다음 그가 승진 한 가변 길이 비트 문자열을 사용할 수 있습니다. 대부분의 경우 여왕이 될 것이므로 "10"은 여왕을 의미 할 수 있습니다. "110"은 루크, "1110"은 비숍, "1111"은 나이트를 의미합니다.

16 개의 폰이 모두 보드에 있고 승격되지 않았으므로 초기 상태는 198 + 16 = 214 비트 를 사용합니다. 2 명의 승격 된 폰 퀸이있는 최종 게임은 198 + 4 + 4와 같은 것을 취할 수 있습니다. 즉, 승격되지 않은 4 개의 폰과 2 개의 퀸 폰을 의미하며 총 206 비트 입니다. 꽤 튼튼한 것 같습니다!

===

다른 사람들이 지적했듯이 Huffman 인코딩은 다음 단계가 될 것입니다. 수백만 개의 게임을 관찰하면 각 조각이 특정 사각형에있을 가능성이 훨씬 더 높다는 것을 알 수 있습니다. 예를 들어, 대부분의 경우 폰은 직선으로 유지되거나 하나는 왼쪽 / 오른쪽으로 유지됩니다. 왕은 일반적으로 홈베이스에 붙어 있습니다.

따라서 각각의 개별 위치에 대해 Huffman 인코딩 체계를 고안하십시오. 폰은 6 비트가 아닌 평균 3-4 비트 만 가져갈 것입니다. 킹도 몇 비트를 가져 가야합니다.

또한이 계획에서 가능한 위치로 "취득"을 포함하십시오. 이것은 또한 캐슬 링을 매우 견고하게 처리 할 수 ​​있습니다. 각 루크와 킹은 추가 "원래 위치, 이동"상태를 갖게됩니다. 또한 이런 방식으로 폰에서 패전트를 인코딩 할 수 있습니다- "원래 위치, 패전트 가능".

데이터가 충분하면이 방법을 사용하면 정말 좋은 결과를 얻을 수 있습니다.


2
제거 된 조각을 왕과 같은 사각형에 할당하기 만하면됩니다. 왕이 제거 될 수 없기 때문에 모호하지 않을 것입니다
John La Rooy

그것은 좋은 의견입니다. :)이 솔루션에도 좋은 측면이 있습니다. 승자를 선택하는 것이 그렇게 어려울 줄은 몰랐습니다.
Andrew Rollings

2

Huffman 인코딩 을 사용하려고합니다 . 이것의 배후에있는 이론은-모든 체스 게임에는 많이 움직일 수있는 부분이 있고 많이 움직이지 않거나 일찍 제거되는 부분이 있다는 것입니다. 시작 위치에 이미 일부 조각이 제거되어 있으면 더 좋습니다. 사각형의 경우도 마찬가지입니다. 일부 사각형은 모든 동작을 볼 수있는 반면, 일부는 별 영향을받지 않습니다.

따라서 나는 두 개의 Huffman 테이블을 갖게 될 것입니다. 하나는 조각 용이고 다른 하나는 사각형 용입니다. 실제 게임을보고 생성됩니다. 나는 모든 조각 정사각형 쌍에 대해 하나의 큰 테이블을 가질 수 있지만 동일한 조각이 다시 같은 정사각형에서 움직이는 인스턴스가 많지 않기 때문에 매우 비효율적이라고 생각합니다.

모든 조각에는 할당 된 ID가 있습니다. 32 개의 다른 조각이 있기 때문에 조각 ID로 5 비트 만 필요합니다. 조각 ID는 게임마다 변경되지 않습니다. 6 비트가 필요한 정사각형 ID도 마찬가지입니다.

Huffman 트리는 순서대로 순회 될 때 각 노드를 기록하여 인코딩됩니다 (즉, 먼저 노드가 출력 된 다음 하위에서 왼쪽에서 오른쪽으로). 모든 노드에는 리프 노드인지 분기 노드인지를 지정하는 1 비트가 있습니다. 리프 노드 인 경우 ID를 제공하는 비트가 뒤 따릅니다.

시작 위치는 일련의 조각 위치 쌍으로 지정됩니다. 그 후 모든 이동에 대해 하나의 조각 위치 쌍이 있습니다. 두 번 언급 된 첫 번째 조각을 찾는 것만으로 시작 위치 설명 자의 끝 (및 이동 설명 자의 시작)을 찾을 수 있습니다. 폰이 승격되는 경우 그것이 될 것을 지정하는 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 : 하나 더 특별한 경우. 게임 상태에 이동이 없으면 다음으로 이동하는 사람을 구별하는 것이 중요합니다. 이를 위해 끝에 하나 더 추가하십시오. :)


2

[질문을 제대로 읽은 후 편집] 모든 법적 위치가 초기 위치 ( "legal"의 가능한 정의)에서 도달 할 수 있다고 가정하면 시작부터 이동 순서로 모든 위치를 표현할 수 있습니다. 비표준 위치에서 시작하는 플레이 스 니펫은 시작에 도달하는 데 필요한 일련의 동작, 카메라를 켜는 스위치, 후속 동작으로 표현할 수 있습니다.

따라서 초기 보드 상태를 단일 비트 "0"이라고합시다.

어떤 위치에서든 이동은 정사각형에 번호를 매기고 이동 순서를 (시작, 끝) 순으로 나열 할 수 있으며, 기존의 2 제곱 점프는 캐슬 링을 나타냅니다. 보드 위치와 규칙이 항상 이미 알려져 있기 때문에 불법 이동을 인코딩 할 필요가 없습니다. 카메라를 켜는 플래그는 특수 대역 내 이동으로 표현하거나 대역 외 이동 번호로 더 현명하게 표현할 수 있습니다.

양쪽에 24 개의 오프닝 무브가 있으며, 각각 5 비트에 맞습니다. 후속 이동에는 다소 비트가 필요할 수 있지만 합법적 인 이동은 항상 열거 가능하므로 각 이동의 너비는 행복하게 증가하거나 확장 할 수 있습니다. 계산하지 않았지만 7 비트 위치가 드물다고 생각합니다.

이 시스템을 사용하면 100 개의 반 동작 게임을 약 500 비트로 인코딩 할 수 있습니다. 그러나 시작 책을 사용하는 것이 현명 할 수 있습니다. 백만 개의 시퀀스가 ​​포함되어 있다고 가정합니다. 그러면 이니셜 0은 표준 보드에서 시작을 나타내고 1 뒤에 20 비트 번호는 해당 시작 시퀀스에서 시작을 나타냅니다. 다소 전통적인 오프닝이있는 게임은 예를 들어 20 개 반 동작 또는 100 비트로 단축 될 수 있습니다.

이것은 가능한 가장 큰 압축은 아니지만 (개봉 책없이) 이미 체스 모델을 가지고 있다면 구현하기가 매우 쉬울 것입니다.

더 압축하려면 임의의 순서가 아닌 가능성에 따라 이동 순서를 지정하고 가능한 시퀀스를 더 적은 비트로 인코딩해야합니다 (예 : 사람들이 언급 한대로 Huffman 토큰 사용).


초기 위치가 반드시 알려지는 것은 아닙니다. 게임 조각 일 수 있습니다.
Andrew Rollings

@ 앤드류 : 네. 내 실수. 게임 조각을 허용하도록 편집했습니다.
Douglas Bagnall

2

계산 시간이 문제가되지 않는 경우 결정 가능한 위치 생성기를 사용하여 주어진 위치에 고유 한 ID를 할당 할 수 있습니다.

주어진 위치에서 먼저 결정 론적 매너에서 가능한 위치의 수를 생성합니다 (예 : 왼쪽 아래에서 시작하여 오른쪽 위로 이동). 이는 다음 동작에 필요한 비트 수를 결정하며 일부 상황에서는 1만큼 작을 수 있습니다. 그런 다음 이동이 이루어지면 해당 이동에 대한 고유 ID 만 저장합니다.

승진 및 기타 규칙은 예를 들어 퀸, 루크, 비숍과 같이 결정적인 방식으로 처리되는 한 유효한 이동으로 간주됩니다.

초기 위치는 가장 어렵고 약 2 억 5 천만 개의 가능한 위치를 생성 할 수 있습니다 (내 생각에).이 위치는 이동을 결정하기 위해 약 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 이동 목록'은 체크 상황을 변경하는 유효한 이동 만 반환합니다.


은밀한 솔루션입니다 ... 그러니이 경우에는 결정 론적 숫자를 생성하는 알고리즘을 설명하세요.
Andrew Rollings

나는 :)는 체스 판의 모든 위치를 생성하는 데 걸리는 시간에 흥미있는 링크를 찾을했다 ioannis.virtualcomposer2000.com/math/EveryChess.html
앤드류 익스펜더

2

대부분의 답변은 3 배 반복을 간과했습니다. 안타깝게도 3 겹 반복의 경우 지금까지 플레이 한 모든 포지션을 저장해야합니다 ...

이 질문은 공간 효율적인 방식으로 저장해야하므로 이동 목록에서 구성 할 수있는 한 실제로 위치를 저장할 필요가 없습니다 (표준 시작 위치가있는 경우). PGN을 최적화 할 수 있습니다. Bellow는 간단한 계획입니다.

보드에는 64 개의 사각형이 있습니다. 64 = 2 ^ 6입니다. 12 비트를 사용하는 각 이동의 초기 및 마지막 사각형 만 저장하면 (프로모션은 나중에 다룹니다). 이 계획은 이미 플레이어의 이동, emphassant, 조각 캡처, 캐슬 링 등을 포함합니다. 이것들은 이동 목록을 재생하여 구성 할 수 있습니다.

승진을 위해 우리는 "이동 N 승격에서 조각 XYZ"라는 별도의 벡터 배열을 유지할 수 있습니다. (int, byte)의 벡터를 유지할 수 있습니다.

(To, From) 벡터도 최적화하려는 유혹이 있습니다. 이러한 (To, From) 벡터 중 상당수가 체스에서는 불가능하기 때문입니다. 예. e1에서 d8 등으로의 이동은 없을 것입니다. 그러나 나는 어떤 계획도 생각할 수 없었습니다. 추가 아이디어는 가장 환영받습니다.


2

나는 그것에 대해 오랫동안 (+-2 시간) 생각했습니다. 그리고 분명한 답은 없습니다.

가정 :

  1. 시간 상태 무시 (플레이어가 시간 제한을 사용하지 않았으므로 플레이하지 않음으로써 강제로 무승부 할 수 있음)
  2. 언제 게임을 했습니까?!? 규칙이 시간이 지남에 따라 변경 되었기 때문에 중요합니다 (이후 현대 게임은 현대 게임이라고 가정합니다 ...) 예를 들어 죽은 폰 규칙을 참조하세요 (위키피디아에는이를 보여주는 매우 유명한 문제가 있습니다). 시간을 거슬러 올라가는 행운을 빕니다 감독은 천천히 움직이고 주사위를 사용했습니다. 롤.

... 그래서 최신의 현대적인 규칙입니다. 첫 번째는 반복에 관계없이 반복 제한을 이동합니다.

-C 25 바이트 반올림 (64b + 32 * 4b + 5b = 325b)

= 64 비트 (무언가 / 무) + 32 * 4 비트 [1bit = color {black / withe} + 3bit = 조각 유형 {King, Queen, Bishop, kNight, Rook, Pawn, MovedPawn} NB : Moved pawn ... 예를 들어 이전 턴에서 마지막으로 이동 한 폰이었던 경우 'en passant'가 가능함을 나타냅니다. ] 실제 상태에 대해 +5 비트 (누가 차례, en passant, 루킹 가능성 여부)

여태까지는 그런대로 잘됐다. 아마도 향상 될 수 있지만 고려해야 할 가변 길이와 프로모션이있을 것입니다!?

이제 다음 규칙은 플레이어가 추첨에 응모 할 때만 적용됩니다. 자동이 아닙니다! 따라서 캡처하지 않고 90 개의 동작을 수행하거나 플레이어가 무승부를 요청하지 않으면 폰 이동이 가능하다고 생각하십시오! 모든 동작을 기록하고 사용할 수 있어야 함을 의미합니다.

-D 위치 반복 ... 예 : 위에서 언급 한 보드 상태 (C 참조) 여부 ... (FIDE 규칙에 대한 다음 참조) -E 포획 또는 폰 이동없이 50 이동 허용이라는 복잡한 문제를 남깁니다. 카운터가 필요합니다 ...하지만.

그래서 어떻게 처리합니까? ... 음, 정말 방법이 없습니다. 어느 플레이어도 그리기를 원하지 않거나 그것이 발생했음을 깨닫고 싶지 않기 때문입니다. 이제 E의 경우 카운터로 충분할 수 있지만 여기에 트릭이 있으며 FIDE 규칙 (http://www.fide.com/component/handbook/?id=124&view=article)도 읽을 수 없습니다. 대답 ... 루킹 능력 상실은 어떻습니까? 반복인가요? 나는 그렇지 않다고 생각하지만 이것은 다루지 않고 명확하지 않은 흐린 주제입니다.

그래서 여기에 인코딩을 시도하는 것조차 복잡하거나 정의되지 않은 두 가지 규칙이 있습니다. 건배.

따라서 게임을 진정으로 인코딩하는 유일한 방법은 처음부터 모든 것을 기록하는 것입니다. 그러면 "보드 상태"질문과 충돌 (또는 그렇지 않습니까?)됩니다.

이 도움이되기를 바랍니다 ... 너무 많은 수학이 아닙니다. :-) 어떤 질문이 정확하고 효율적 이기에는 해석이나 사전 지식이 너무 개방적이지 않다는 것을 보여주기 위해서입니다. 웜 캔을 너무 많이 열었 기 때문에 인터뷰를 고려할 사람은 없습니다.


2

Yacoby 솔루션의 시작 위치에서 가능한 개선

법적 지위는 각 색상의 조각이 16 개를 초과하지 않습니다. 64 개의 정사각형에 최대 16 개의 검은 색 조각과 16 개의 흰색 조각을 배치하는 방법의 수는 약 3.63e27입니다. Log2 (3.63e27) = 91.55. 즉, 모든 조각의 위치와 색상을 92 비트로 인코딩 할 수 있습니다. 이는 위치의 경우 64 비트보다 작으며 Yacoby의 솔루션에 필요한 색상의 경우 최대 32 비트입니다. 인코딩이 상당히 복잡해지면서 최악의 경우 4 비트를 절약 할 수 있습니다.

반면에 5 개 이상의 조각이 누락 된 위치의 경우 크기가 증가합니다. 이러한 위치는 모든 위치의 4 % 미만에 불과하지만 초기 위치와 다른 시작 위치를 기록하려는 경우의 대부분 일 것입니다.

이것은 완전한 솔루션으로 이어집니다

  1. 위의 방법에 따라 조각의 위치와 색상을 인코딩하십시오. 92 비트 .
  2. 각 조각의 유형을 지정하려면 Huffman 코드 : pawn : '0', rook : '100', knight : '101', bishop : '110', queen : '1110', king : '1111'을 사용하십시오. 전체 조각 세트에 대해 (16 * 1 + 12 * 3 + 4 * 4) = 68 비트가 필요합니다. 전체 보드 위치는 최대 92 + 68 = 160 비트로 인코딩 할 수 있습니다 .
  3. 추가 게임 상태 추가 : turn : 1 비트, 어떤 캐슬 링이 가능한지 : 4 비트, "en passant"가능 : 최대 4 비트 (1 비트는 경우를 나타내고 3 비트는 어느 것을 나타냄). 시작 위치는 = 160 + 9 = 169 비트로 인코딩됩니다.
  4. 이동 목록의 경우 주어진 위치에 대해 가능한 모든 이동을 열거하고 이동 위치를 목록에 저장합니다. 이동 목록에는 모든 특수 사례 (캐슬 링, en passant 및 사임)가 포함됩니다. 가장 높은 위치를 저장하는 데 필요한만큼만 비트를 사용하십시오. 평균적으로 이동 당 7 비트를 초과하지 않아야합니다 (평균 16 개 가능한 조각과 조각 당 8 개의 합법적 인 이동). 어떤 경우에는 강제로 이동하면 1 비트 만 필요합니다 (이동 또는 사임).

1

보드에는 32 개의 조각이 있습니다. 각 조각에는 위치가 있습니다 (64 사각형 중 하나). 따라서 32 개의 양의 정수만 있으면됩니다.

64 개의 포지션이 6 비트에 있다는 것을 알고 있지만 그렇게하지 않을 것입니다. 나는 몇 개의 깃발을 위해 마지막 비트를 보관할 것입니다 (드롭 된 조각, 여왕의 폰)


상태를 유지하기 위해 플래그를 사용할 필요가 없습니다. 인코더가 "규칙을 이해"할만큼 똑똑하다고 가정 할 수 있습니다. 따라서 폰이 갑자기 여왕으로 변경되면 반드시 인코딩에서 특별히 플래그를 지정할 필요가 없습니다 (플레이어가 승격하지 않기로 선택하지 않는 한).
Andrew Rollings

예, 폰이 승격되었는지 여부를 폰의 초기 위치로 알 수 없기 때문에 그래야합니다! 따라서 초기 설정에서 인코딩됩니다
Toad

아, 그런데 이미 홍보되었는지 왜 알아야하나요? 그것은 단지 조각입니다. 이 경우 과거 상태는 관련이 없습니다.
Andrew Rollings

나는 폰이 여전히 폰이거나 여왕으로 승진했다면 게임의 나머지 부분과 거의 관련이 없다고 생각합니다. 당신이 그렇게 생각하지 않는다면, 나는 당신과 함께 체스 게임을하고 싶습니다; ^)
Toad

@reinier : 그는 현재 여왕 이 원래 여왕 이었거나 원래 폰 이었는지 상관이 없다고 주장하고 있습니다.
A. Rex

1

cletus 의 대답은 좋지만 그는 누구의 차례인지 인코딩하는 것을 잊었습니다. 현재 상태의 일부이며 해당 상태를 사용하여 검색 알고리즘 (예 : 알파-베타 파생물)을 구동하는 경우 필요합니다.

나는 체스 선수는 아니지만, 또 하나의 코너 케이스가 있다고 믿습니다. 얼마나 많은 동작이 반복되었는지입니다. 각 플레이어가 같은 동작을 세 번하면 게임은 무승부입니다. 그렇다면 해당 정보를 상태에 저장해야합니다. 세 번째 반복 후에는 상태가 이제 터미널이되기 때문입니다.


실제 체스 게임에서는 두 플레이어가 총 1 ~ 2 시간 만 생각하므로 두 플레이어의 플레이 시간도 추가해야합니다.
Toad

2
실제 데이터에서 규칙을 인코딩 할 필요가 없습니다. 인코더 자체가 필요한 규칙을 알고 있다고 가정 할 수 있습니다.
Andrew Rollings

아 .. 노는 시간을 고려하지 않았어요. 좋은 전화 ... :)
앤드류 익스펜더

@Andrew Rollings : 규칙은 상태 기반이며 특정 전제 조건이 충족 될 때만 트리거됩니다. 전제 조건의 상태를 추적하는 것도 상태의 일부입니다. :)
Shaggy Frog

이 경우에는 관련이 없습니다. 필요한 경우 디코더는 상태를 검사하여 승자를 결정할 수 있습니다. 인코더 / 디코더는 규칙을 인식합니다. 실제로 인코딩해야하는 유일한 것은 플레이어의 선택입니다. 다른 것은 인코더 / 디코더가 알고 있다고 가정 할 수 있습니다.
Andrew Rollings

1

몇몇 다른 사람들이 언급했듯이 32 개 조각 각각에 대해 어떤 사각형이 있는지 저장할 수 있으며, 보드에 있는지 여부에 따라 32 * (log2 (64) + 1) = 224 비트가됩니다.

그러나 비숍은 검은 색 또는 흰색 사각형 만 차지할 수 있으므로 위치에 대해 log2 (32) 비트 만 필요하며 28 * 7 + 4 * 6 = 220 비트가됩니다.

그리고 폰은 뒤쪽에서 시작하지 않고 앞으로 만 이동할 수 있기 때문에 56 개에만있을 수 있습니다. 폰에 필요한 비트 수를 줄이기 위해이 제한을 사용할 수 있습니다.


감독도 이사회에서 벗어날 수 있으므로 추가 비용이 필요합니다. 또한 승진 된 폰과 먼저 시작할 사람을 잊고 있습니다. 당신은 기본적으로 내 대답에 결국 계정으로 모든 촬영 ^)
두꺼비

감독에 대한 6 비트는 log2 (32) + 1 = 6이지만 모든 세부 사항을 고려할 때 이것은 확실히 복잡한 질문입니다. :)
Andreas Brinck 2009

나는이 라인을 따라 생각했지만 도움이되지 않습니다. Thomas의 대답을보고 허프만 인코딩을 수정하여 빈 공간 개념을 제거하십시오. 64 비트를 사용하여 제곱이 차지하는 행렬을 저장하고 각 인코딩에서 1 비트를 제거하여 동일한 64 비트를 정확하게 복구합니다.
Loren Pechtel

1

보드에는 64 개의 사각형이 있으며 사각형이 비어 있는지 여부를 나타내는 64 비트로 나타낼 수 있습니다. 사각형에 조각이있는 경우에만 조각 정보가 필요합니다. 플레이어 + 조각이 4 비트를 사용하므로 (앞서 보셨 듯이) 현재 상태를 64 + 4 * 32 = 192 비트로 얻을 수 있습니다. 현재 턴에 던지면 193 비트가 있습니다.

그러나 각 조각에 대한 법적 이동도 인코딩해야합니다. 먼저 각 조각에 대한 합법적 인 이동 수를 계산하고 전체 사각형의 조각 식별자 뒤에 해당 비트를 추가합니다. 다음과 같이 계산했습니다.

폰 : 앞으로, 먼저 두 번 앞으로, en passant * 2, 프로모션 = 7 비트. 첫 번째 턴 포워드와 프로모션은 같은 위치에서 발생할 수 없기 때문에 단일 비트로 결합 할 수 있으므로 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 비트입니다.

가능한 이동을 위해 조각 당 필요한 비트 수에 관해서는 일부 최적화를 추가 할 수 있으며 비트 수는 아마도 감소 할 수 있습니다. 저는 작업하기 위해 쉬운 숫자를 사용했습니다. 예를 들어 슬라이딩 조각의 경우 이동할 수있는 거리를 저장할 수 있지만 추가 계산이 필요합니다.

간단히 말해서 : 사각형이 점유 된 경우에만 추가 데이터 (조각 등)를 저장하고, 합법적 인 이동을 나타 내기 위해 각 조각에 대한 최소 비트 수만 저장합니다.

EDIT1 : 어떤 조각에 대한 캐슬 링과 전당포 승진을 잊어 버렸습니다. 이것은 명시적인 위치를 가진 합계를 557 개의 이동으로 가져올 수 있습니다 (폰의 경우 3 비트, 킹의 경우 2 비트).


1

각 조각은 4 비트 (폰 투 킹, 6 가지 유형), 블랙 / 화이트 = 12 개 값으로 표현 될 수 있습니다.

보드의 각 사각형은 6 비트 (x 좌표, y 좌표)로 나타낼 수 있습니다.

초기 위치에는 최대 320 비트 (32 개, 4 + 6 비트)가 필요합니다.

이후의 각 이동은 16 비트 (from-position, to-position, piece)로 표현 될 수 있습니다.

Castling은 이중 이동이므로 추가 16 비트가 필요합니다.

Queened 폰은 4 비트 중 4 개의 예비 값 중 하나로 표현 될 수 있습니다.

계산을 자세히 수행하지 않으면 32 * 7 비트 (미리 정의 된 조각 배열) 또는 64 * 4 비트 (미리 정의 된 사각형 할당)를 저장하는 것과 비교하여 첫 번째 이동 후 공간을 절약하기 시작합니다.

양쪽에서 10 번 이동 한 후 필요한 최대 공간은 640 비트입니다.

...하지만 다시 말하지만, 각 조각을 고유하게 식별하고 (5 비트) 여왕 된 폰을 표시하기 위해 여섯 번째 비트를 추가하면 각 이동에 대해 조각 ID + 위치 지정 만 필요합니다. 이것은 계산을 다음과 같이 변경합니다.

초기 위치 = 최대 384 비트 (32 개 조각, 6 + 6 비트) 각 이동 = 12 비트 (위치로, 조각 ID)

그런 다음 각 측면에서 10 번 이동 한 후 필요한 최대 공간은 624 비트입니다.


두 번째 옵션은 스토리지를 12 비트 레코드 (각 레코드 = 위치 및 조각)로 읽을 수 있다는 추가 이점이 있습니다. 첫 번째 이동 캡은 피스에 사전 입력이 있다는 사실에 의해 감지됩니다.
Steve De Caux

이동 사이의 시간 동안 카운터의 x 비트를 각 레코드에 추가합니다. 설정 기록의 경우 0으로 설정됩니다.
Steve De Caux

이것이 제가 작성하려고했던 접근 방식입니다. 한 가지 최적화는 표준 게임의 경우 초기 위치를 전혀 인코딩 할 필요가 없다는 것입니다. "이것은 표준 게임입니다"라는 머리 부분 하나만으로도 충분합니다. 또한, 캐슬 링은 이중 이동을 취하지 않습니다. 캐슬 링 이동은 항상 분명하고, 주어진 킹 반이 발생했을 때 루크가 이동할 수있는 유효한 방법은 하나뿐이므로 중복 정보입니다. 승진을 위해 폰이 마지막 행으로 이동 한 후 4 비트를 사용하여 새로운 조각 유형을 지정할 수 있습니다.
kyoryu

따라서 일반적인 게임의 경우 10 개의 이동 후 승진이 없다고 가정하면 121 비트가됩니다. 비정형 게임은 깃발에 1 비트, 조각 * 10 비트, 첫 번째 플레이어를 나타내는 다른 비트가 필요합니다. 또한 주어진 사각형의 조각은 게임의 이전 이동에서 암시 적이므로 각 이동에는 12 비트 만 필요합니다. 이것은 제안 된 방법 중 일부보다 덜 효율적일 수 있지만 "표준"게임에 대해 꽤 깨끗하고 합리적으로 효율적입니다.
교류 2009.12.03

@kyoro-이동 당 12 비트를 이길 수 있다고 확신하지 않습니다. 표준 설정을 위해 null이라는 아이디어를 사용하여 (나는 여전히 bin 0으로 설정된 12 비트를 사용합니다)-각면에서 1000 개 이동 후 이것은 일명 24012 비트입니다. 3002 바이트 (반올림) 어떤 형태의 압축을 사용하더라도이를 이길 수있는 치트가 필요합니다. 사전을 하드 코딩 (또는 논리적으로 파생 가능)으로 선언함으로써
Steve De Caux

1

Robert G와 마찬가지로 PGN은 표준이고 다양한 도구에서 사용할 수 있기 때문에 사용하는 경향이 있습니다.

그러나 만약 내가 먼 우주 탐사선에있는 체스 AI를 플레이하고 있고 따라서 모든 부분이 소중하다면 이것이 내가 움직임을 위해 할 일입니다. 나중에 초기 상태를 인코딩하는 방법에 대해 알아 보겠습니다.

움직임은 상태를 기록 할 필요가 없습니다. 디코더는 주어진 지점에서 합법적 인 움직임뿐만 아니라 상태를 추적 할 수 있습니다. 기록해야 할 모든 움직임은 다양한 법적 대안 중 어느 것이 선택되었는지입니다. 플레이어가 번갈아 가며 움직이기 때문에 플레이어 색상을 기록 할 필요가 없습니다. 플레이어는 자신의 색상 조각 만 이동할 수 있으므로 첫 번째 선택은 플레이어가 이동하는 조각입니다 (나중에 다른 선택을 사용하는 대안으로 돌아올 것입니다). 최대 16 개 조각으로 최대 4 비트가 필요합니다. 플레이어가 조각을 잃으면 선택의 수가 줄어 듭니다. 또한 특정 게임 상태는 말의 선택을 제한 할 수 있습니다. 왕이 자신을 체크하지 않고 움직일 수 없다면 선택의 수가 1 개 줄어 듭니다. 킹이 체크에 있다면 킹을 체크에서 빼낼 수없는 조각은 실행 가능한 선택이 아닙니다.

조각이 지정되면 특정 수의 법적 목적지 만 갖게됩니다. 정확한 숫자는 보드 레이아웃과 게임 이력에 따라 크게 다르지만 특정 최대 값과 예상 값을 파악할 수 있습니다. 기사를 제외한 모든 사람과 캐슬 링 중에는 한 조각이 다른 조각을 통과 할 수 없습니다. 이것은 이동 제한의 큰 원천이 될 것이지만 정량화하기는 어렵습니다. 조각은 보드 밖으로 이동할 수 없으며, 이는 또한 목적지 수를 크게 제한합니다.

우리는 W, NW, N, NE 순서로 줄을 따라 사각형에 번호를 매겨 대부분의 조각의 대상을 인코딩합니다 (검은면은 N). 선은 이동하기에 합법적 인 방향으로 가장 먼 정사각형에서 시작하여쪽으로 진행합니다. 방해받지 않는 왕의 경우 이동 목록은 W, E, NW, SE, N, S, NE, SW입니다. 기사의 경우 2W1N으로 시작하여 시계 방향으로 진행합니다. destination 0은이 순서에서 첫 번째 유효한 목적지입니다.

  • 폰 : 움직이지 않은 폰은 목적지를 2 개 선택할 수 있으므로 1 비트가 필요합니다. 폰이 정상적으로 또는 en passant (디코더가 상태를 추적하고 있기 때문에 결정할 수 있음)를 캡처 할 수있는 경우 2 개 또는 3 개의 이동 선택이 있습니다. 그 외에는 폰은 하나의 선택 만 할 수 있으며 비트가 필요하지 않습니다. 폰이 7에있을 때 순위, 우리는 또한 홍보의 선택에 압정. 폰은 일반적으로 여왕으로 승진 한 후 기사로 승격되기 때문에 선택 항목을 다음과 같이 인코딩합니다.
    • 여왕 : 0
    • 기사 : 10
    • 비숍 : 110
    • 루크 : 111
  • Bishop : 4 비트에 대해 {d, e} {4,5}에있을 때 최대 13 개의 대상.
  • Rook : 최대 14 개의 목적지, 4 비트.
  • 기사 : 최대 8 개의 목적지, 3 비트.
  • Kings : 캐슬 링이 옵션 일 때, 킹은 S로 돌아가서 아래로 이동할 수 없습니다. 이것은 총 7 개의 목적지를 제공합니다. 나머지 시간 동안 킹은 최대 8 개의 동작을 수행하여 최대 3 비트를 제공합니다.
  • Queen : 비숍 또는 루크의 선택과 동일하며 총 27 개의 선택 항목 (5 비트)

선택의 수가 항상 2의 거듭 제곱이 아니기 때문에 위는 여전히 비트를 낭비합니다. 선택 항목의 수가 C 이고 특정 선택 항목의 번호 가 c 이고 n = ceil (lg ( C )) (선택 항목을 인코딩하는 데 필요한 비트 수)이라고 가정합니다. 우리는 다음 선택의 첫 번째 비트를 검사하여 이러한 낭비되는 값을 사용합니다. 0이면 아무 작업도하지 않습니다. 1이고 c + C <2 n 이면 Cc에 추가 합니다. 다수의 디코딩이 역으로 상기 수신한다면 C > = C는 , 감산 C를 하고있는 경우 (1)에 다음 번호의 첫번째 비트를 설정 C<2n - C 이면 다음 숫자의 첫 번째 비트를 0으로 설정합니다. 2 n - C <= c < C 이면 아무 작업도 수행하지 않습니다. 이 구성표를 "포화"라고합니다.

인코딩을 단축 할 수있는 또 다른 잠재적 유형은 캡처 할 상대 조각을 선택하는 것입니다. 이것은 기껏해야 추가 비트 (현재 플레이어가 움직일 수있는 조각의 수에 따라 달라짐)에 대해 조각을 고르는 동작의 첫 번째 부분에 대한 선택의 수를 증가시킵니다. 이 선택 뒤에는 캡처 조각이 선택되는데, 이는 주어진 플레이어 조각의 이동 수보다 훨씬 적을 것입니다. 말은 어떤 추기경에서든 하나의 말과 최대 10 개의 공격 말에 대해 기사로만 공격 할 수 있습니다. 평균적으로 7 비트를 예상하지만 캡처 이동에 대해 총 최대 9 비트를 제공합니다. 이것은 종종 합법적 인 목적지가 많기 때문에 여왕에 의한 캡처에 특히 유리합니다.

포화 상태에서는 캡처 인코딩이 이점을 제공하지 못할 수 있습니다. 사용되는 초기 상태를 지정하여 두 옵션을 모두 허용 할 수 있습니다. 채도를 사용하지 않으면 게임 인코딩에서 사용하지 않은 선택 번호 ( C <= c <2 n )를 사용하여 게임 중에 옵션을 변경할 수도 있습니다. 모든 시간 C는 우리가 옵션을 변경할 수 2의 거듭 제곱이다.


1

Thomas는 보드 인코딩에 대한 올바른 접근 방식을 가지고 있습니다. 그러나 이것은 동작을 저장하는 ralu의 접근 방식과 결합되어야합니다. 가능한 모든 움직임의 목록을 만들고이 숫자를 표현하는 데 필요한 비트 수를 기록하십시오. 디코더는 동일한 계산을 수행하기 때문에 얼마나 많은 것이 가능한지 알고 있고 얼마나 많은 비트를 읽을 수 있는지 알 수 있으므로 길이 코드가 필요하지 않습니다.

따라서 조각에 대해 164 비트, 캐슬 링 정보에 대해 4 비트 (게임의 조각을 저장한다고 가정하고 그렇지 않으면 재구성 할 수 있다고 가정), en passant 자격 정보에 대해 3 비트를 얻습니다. 이동이 발생한 열을 저장하기 만하면됩니다 ( en passant가 가능하지 않은 경우 불가능한 곳에 열을 저장하고 (이러한 열이 있어야 함) 이동할 사람에 대해 1을 저장합니다.

이동은 일반적으로 5 또는 6 비트를 사용하지만 1에서 8까지 다양 할 수 있습니다.

하나의 추가 단축키 (인코딩이 12 1 비트로 시작하는 경우 (잘못된 상황-조각도 한쪽에 두 개의 킹이 없음)) 디코딩을 중단하고 보드를 지우고 새 게임을 설정합니다. 다음 비트는 이동 비트입니다.


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 비트 번호를 사용하여 기록 할 수 있습니다. "누가 먼저 움직 일지"기록에 대한 추가 정보. 따라서 900 + 192 + 1 = 1093 비트를 사용하여 모든 게임을 녹화 할 수 있습니다.


1

보드 상태 저장

내가 생각한 가장 간단한 방법은 너무 먼저 각 조각의 위치를 ​​나타내는 8 * 8 비트 배열을 갖는 것입니다 (따라서 체스 조각이 있으면 1이고 없으면 0). 길이가 고정되어 있으므로 종결자가 필요하지 않습니다.

다음은 위치 순서대로 모든 체스 조각을 나타냅니다. 조각 당 4 비트를 사용하면 32 * 4 비트 (총 128 비트)가 필요합니다. 정말 낭비입니다.

바이너리 트리를 사용하면 폰을 1 바이트로, 나이트와 루크와 비숍을 3으로, 킹과 퀸을 4로 표현할 수 있습니다. 조각의 색상도 저장해야하므로 추가 바이트가 필요합니다. (이것이 틀렸다면 용서하십시오 . 이전 에 Huffman 코딩 을 자세히 살펴본 적이 없습니다 .)

  • 폰 : 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 개 조각이 있고 사각형을 나타내는 정수가 아니라 각 조각이 무엇인지 알고 있으므로 조각 오프셋을 나타내는 정수를 가질 수 있습니다. 즉, 조각.

안타깝게도 왕을 성세 시키거나 전복시키고 공화국을 형성하는 것과 같은 다양한 특수 규칙이 있으므로 (Terry Pratchett 참조) 이동하기 위해 조각을 저장하기 전에 특수 이동인지 여부를 나타내는 단일 비트가 필요합니다.

따라서 각 정상적인 움직임에 대해 필요한 1 + 5 = 6비트가 있습니다. (1 비트 유형, 조각 용 5 비트)

조각 번호가 해독 된 후 우리는 조각의 유형을 알고 있으며 각 조각은 가장 효율적인 방법으로 이동을 나타내야합니다. 예를 들어 (내 체스 규칙이 처음부터 끝났다면) 폰은 총 4 개의 이동이 가능합니다 (왼쪽으로 이동, 오른쪽으로 이동, 한 번 앞으로 이동, 두 번 앞으로 이동).
따라서 폰 이동을 나타내려면 '6 + 2 = 8'비트가 필요합니다. (초기 이동 헤더의 경우 6 비트, 이동 대상의 경우 2 비트)

여왕을 위해 이동하는 것은 방향 (8 개의 가능한 방향, 따라서 3 비트)과 각 방향에 대해 총 8 개의 가능한 사각형 (따라서 다른 3 비트)을 갖는 것이 가장 좋다는 점에서 더 복잡 할 것입니다. 따라서 여왕을 움직이는 것을 나타내려면 6 + 3 + 3 = 12비트 가 필요 합니다.

저에게 마지막으로 발생하는 것은 어떤 플레이어가 턴을했는지 저장해야한다는 것입니다. 단일 비트 여야합니다 (다음으로 이동하려면 흰색 또는 검정색)



결과 형식
따라서 파일 형식은 다음과 같습니다.

[64 비트] 초기 조각 위치
[최대 100 비트] 초기 조각 [1 비트] 플레이어 턴
[n 비트] 이동

이동이
[1 비트] 인 경우 이동 유형 (특수 또는 일반)
[n 비트] 이동 세부 정보

이동이 일반 이동 인 경우 이동 세부 정보는
[5 비트] 조각
[n 비트] 특정 조각 이동 (일반적으로 2 ~ 6 비트 범위) 과 유사합니다 .

특수 이동 인
경우 정수 유형과 추가 정보 (예 : 캐슬 링)가 있어야합니다. 필살기 횟수가 기억 나지 않아서 필살기라고 표시하는 것만으로도 괜찮을지도 모른다 (하나만있는 경우)


1

초기 보드와 후속 이동의 기본 사례에서 다음을 고려하십시오.

체스 프로그램을 사용하여 가능한 모든 동작에 확률을 할당하십시오. 예를 들어 e2-e4의 경우 40 % d2-d4의 경우 20 % 등입니다. 일부 이동이 합법적이지만 해당 프로그램에서 고려되지 않는 경우 낮은 확률을 제공합니다. 산술 코딩을 사용하여 선택한 항목을 저장하십시오. 첫 번째 이동에는 0과 0.4 사이, 두 번째 이동에는 0.4와 0.6 사이의 숫자가됩니다.

다른 쪽도 똑같이하십시오. 예를 들어 e2-e4에 대한 응답으로 e7-e5의 확률이 50 %이면 인코딩 된 숫자는 0에서 0.2 사이가됩니다. 게임이 끝날 때까지 반복하십시오. 결과는 잠재적으로 매우 작은 범위입니다. 그 범위에 맞는 가장 작은 밑을 가진 이진 분수를 찾으십시오. 그것은 산술 코딩입니다.

이것은 부분적인 비트 인코딩으로 생각할 수 있기 때문에 Huffman보다 낫습니다 (게임이 끝날 때 일부는 전체 비트로 반올림 됨).

결과는 Huffman보다 더 간결해야하며 승진, en passant, 50 규칙 이동 및 기타 세부 사항에 대한 특별한 경우는 없습니다. 이는 체스 평가 프로그램에서 처리되기 때문입니다.

다시 플레이하려면 체스 프로그램을 다시 사용하여 보드를 평가하고 각 동작에 모든 확률을 할당합니다. 산술로 인코딩 된 값을 사용하여 실제로 재생 된 동작을 확인합니다. 끝날 때까지 반복하십시오.

체스 프로그램이 충분히 좋다면 2 상태 인코더를 사용하여 더 나은 압축을 얻을 수 있습니다. 여기서 확률은 흑백의 움직임을 기반으로 정의됩니다. 약 200 개 이상의 상태 중 가장 극단적 인 경우에는 가능한 모든 체스 게임의 전체 세트를 인코딩하므로 실행 가능하지 않습니다.

이것은 Darius가 이미 작성한 것을 말하는 것과 거의 다른 방식으로 산술 코딩이 어떻게 작동하는지에 대한 약간의 예와 기존 체스 프로그램을 사용하여 다음 움직임 (들)의 확률을 평가하는 데 도움이되는 실제 예를 통해서만 가능합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.