답변:
체스 엔진 프로그래밍은 매우 복잡한 영역이므로, 바로이 주제에 대한 많은 정보를 가지고있는 Chess Programming Wiki 를 알려 드리겠습니다 .
체스 계산 (및 많은 유사한 것들)은 일반적으로 "게임 트리"또는 " 결정 트리 " 로 모델링되고 생각됩니다 . 일반적으로이 트리는 맨 위에 하나의 노드 (현재 위치)가있는 유향 그래프로, 가능한 각 이동에 대한 노드로 연결되며 각 노드는 다음 가능한 각 이동 에 대해 더 많은 노드로 연결됩니다 .
가장 단순하고 무차별적인 형태로 체스 엔진은이 트리의 모든 위치를 깊이 한계 ( "ply")까지 생성하여 복잡한 기준 1 에 따라 각 결과 위치를 평가합니다 . 그런 다음 최상의 결과를 가져 오는 것처럼 보입니다. 요즘엔 엔진이보아야 할 위치의 수를 제한하기 위해 많은 복잡한 기술 이 개발되었지만 실제 문제를 변경하지 않기 때문에이 답변의 목적으로 기술을 무시할 것입니다. 손.
엔진이 일반적으로 각 이동을 고려하는 데 거의 동일한 시간이 걸리는 기본 이유는 의사 결정 트리의 크기가 깊이 ( k
)에 따라 기하 급수적으로 증가하기 때문 입니다.
시작 위치를 고려하십시오. 트리 상단 ( k=0
)은 하나의 노드입니다. White에는 20 개의 가능한 첫 움직임이 있으므로 깊이에 20 개의 노드가 k=1
있습니다. 그런 다음 Black은 각 White 옵션에 대해 20 개의 동작을 사용할 수 있습니다. 따라서에서 가능한 위치 k=2
가 20 * 20 = 400
있습니다! 그리고 플레이어가 조각을 개발할 때만 악화됩니다!
예를 들어, 주어진 시간에 각 플레이어마다 항상 20 개의 가능한 움직임이 있다고 가정합시다 2 . 컴퓨터는 각 플레이어에 대해 다섯 번의 움직임을 미리 보도록 지시합니다 (10 회). 각 레벨에서 무차별 트리의 크기를 살펴 보겠습니다. 재미를 위해 트리의 전체 위치 수 (위에서 지정된 레벨까지)도 살펴 봅니다.
Ply | Positions | Total Tree Size
----------------------------------------
0 | 1 | 1
1 | 20 | 21
2 | 400 | 421
3 | 8000 | 8421
4 | 160000 | 168421
5 | 3200000 | 3368421
6 | 64000000 | 67368421
7 | 1280000000 | 1347368421
8 | 25600000000 | 26947368421
9 | 512000000000 | 538947368421
10 | 10240000000000 | 10778947368421
각 레벨이 이전 레벨보다 기하 급수적으로 큰 결과는 전체 트리의 크기가 맨 아래 레벨에 의해 지배된다는 것 입니다. 위의 예를 고려하십시오. 마지막 레벨에만 10 조 개의 노드가 있습니다. 나무의 나머지 전체는 오천 억만 포함합니다. 열 번째 플라이에는 전체 트리에서 노드의 약 95 %가 포함됩니다 (이는 실제로 각 레벨에서 적용됩니다). 실제로 이것이 의미하는 것은 모든 검색 시간이 "마지막"이동을 평가하는 데 소비 된다는 것입니다.
그렇다면 이것이 귀하의 질문과 어떤 관련이 있습니까? 위와 같이 컴퓨터가 10 겹으로 설정되어 있고 평가 결과를 "기억"한다고 가정하겠습니다. 이동을 계산하고 재생 한 다음 이동합니다. 이제 두 번의 이동이 이루어 졌으므로 발생하지 않은 이동과 관련된 메모리에서 모든 위치를 제거하고 이미 계산 된 나머지 8 개의 이동 (26,947,368,421 위치)을 내려가는 트리가 남습니다!
괜찮아! 따라서 마지막 두 가닥 만 계산하면됩니다! 각각의 깊이에서 20 개의 움직임을 사용하여, 여기에서 계산해야하는 총 움직임 수는 여전히 10 조가 넘습니다. 우리가 이미 계산 한 위치는 가능성의 2.5 %만을 차지합니다! 따라서 마지막 움직임의 결과를 캐싱하더라도 2.5 %의 속도 향상이 기대됩니다. 핵심은 이것이 프로그램이 이전 결과를 캐시하더라도 이동 사이에 상당한 속도 향상을 보이지 않는 이유입니다 (컴퓨터가 물론 강제 메이트 또는 무언가를 발견하는 경우는 제외)!
이 많은 내가 맨 위에 프로그래밍 위키에 연결 만 폭 넓은 수학적 관점에서 답을 설명하려고 시도 이유는이 질문에 참여 복잡성은. 실제로, 프로그램 은 일반적으로 트리의 일부를 이동에서 캐시로 이동하며 그 자체로는 불충분 한 다른 이유도 있습니다. 몇 가지 간단한 이유 (예 : 특정 라인은 8 개의 움직임으로보기에는 좋지만 뒤로는 끝납니다) 9 번 이동시 랭크 메이트!) 및 매우 복잡한 것들 (일반적으로 다양한 영리한 가지 치기 방법과 관련됨). 따라서 컴퓨터는 이전 이동의 컷오프 깊이를 기반으로 잘못된 가정을 피하기 위해 계속해서 앞을 내다 봐야합니다.
1 여기서는 휴리스틱 함수를 다루지 않겠습니다. 왜냐하면 그 자체가 매우 복잡한 영역이기 때문입니다. 그러나 여기에서도 위치 캐싱 체계를 통해 얻을 수있는 몇 가지 이점이 있습니다.
2 평균 분기 계수 20은 아마도 너무 낮을 것 입니다.
일반적인 체스 엔진은 위치와 브라케팅 알파-베타 점수를 전치 테이블 에 저장하여 후속 검색 중에 참조 할 수 있습니다. 이 표는 다음 이동을 선택하기 위해 직접 참조되지 않지만 두 가지 방법으로 해당 이동을보다 효율적으로 검색합니다.
검색 트리에서 위치가 여러 번 발생할 수 있으며 이동 순서의 전치 또는 치환에 의해 도달합니다. 테이블을 참조 할 수 있기 때문에 이러한 위치는 위치를 방문하고 다시 방문 할 때 수십 번이 아니라 몇 번 (다른 고정 검색 깊이에 대해) 평가해야합니다.
알파-베타 검색의 표준 기술은 반복 심화 를 사용 하여 터미널 깊이에 도달 할 때까지 트리를 더 큰 검색 깊이에서 반복적으로 탐색하는 것입니다. 이전 반복에서 계산 된 평가 점수는 이후 반복에서 검색된 이동을 정렬하는 데 사용됩니다. 알파-베타는 나쁜 움직임 전에 좋은 움직임이 검색되면 더 잘 수행되는 것으로 알려져 있습니다 (즉, 더 많은 검색 트리를 정리).
엔진의 메모리를 증명하는 예 :
깊은 이론적 참신함, 특히 Caruana vs Topalov 게임이 올해에 진행된 곳을 찾아보십시오. 엔진이 12 번 이동 후 위치를 분석하여 짧은 시간 (예 : 10-15 분) 동안 제안 된 이동을 확인하고 TN (
13.Re2!
)이 나타나지 않는 것을 확인할 수 있습니다. 이동을 직접 소개하고, 이동으로 돌아가 엔진이 거의 동일한 시간 동안 동일한 위치를 다시 분석하도록합니다. 놀랍게도, 어떤 생각을 한 후에, 엔진은 TN을 최고의 움직임으로 간주하고 승인합니다.
편집 : 원래 답변 (아래에 표시)이 잘못되었지만 맨 위에 인용 된 엔진 메모리의 유용한 예를 제공합니다.
내가 아는 한, 그들은하지 않습니다. 즉, 거의 모든 움직임에서 처음부터 나무 검색을 시작합니다.
그러나 각 이동에 대한 값을 실현하는 일종의 기능이 있어야 하며이 기능에는 반드시 단기 메모리가 있습니다. 몇 가지 예는 깊은 이론적 참신함이 발견되는 위치, 특히 Caruana vs Topalov 게임이 올해에 한 게임 입니다. 엔진이 12 번 이동 후 위치를 분석하여 짧은 시간 (예 : 10-15 분) 동안 제안 된 이동을 확인하고 TN ( 13.Re2!
)이 나타나지 않는 것을 확인할 수 있습니다. 이동을 직접 소개하고, 이동으로 돌아가 엔진이 거의 동일한 시간 동안 동일한 위치를 다시 분석하도록합니다. 놀랍게도, 어떤 생각을 한 후에, 엔진은 TN을 최고의 움직임으로 간주하고 승인합니다.
저는 체스 소프트웨어 전문가가 아니지만 이런 일이 발생합니다. 위치에 대한 움직임을 평가하는 함수가 메모리를 가지고 있다면 이것은 적어도 부분적으로 설명 될 수 있습니다.
헨리 키터 (Henry Keiter)는 이미 일반적인 답변을 제공했습니다.보다 자세한 답변을 드리겠습니다. 전치 테이블, 검색 깊이 및 컷오프에 관한 것입니다. 여기서 논의한 내용은 다른 답변보다 훨씬 기술적이지만 체스 프로그래밍을 배우려는 사람에게는 도움이 될 것입니다.
위치를 이전에 평가 한 경우 이동을 저장할 메모리가 충분하면 평가 점수를 재사용 할 수 있다는 것은 일반적으로 오해입니다. 체스 프로그래밍은 그보다 더 복잡합니다. 메모리가 무한하더라도 위치를 다시 검색해야합니다. 각 움직임에 대해 평가 점수는 그 깊이와 한계와 함께 첨부됩니다. 예를 들어, 엔진이 높은 고장으로 이동을 저장하는 경우 테이블 항목의 하한이 있습니다. 즉, 직책을 찾고 있다면 이전 평가 점수를 사용할 수 있는지 여부를 여전히 확인해야합니다.
그 외에도 각 평가에는 깊이가 있습니다. 반복 심화 프레임 워크에서 각 반복에 대한 깊이를 증가 시키면 이전 반복에서 이미 검색 한 위치를 계속 검색해야합니다.
귀하의 질문에 대한 짧은 대답 은 엔진이 이전에 분석 한 모든 위치를 저장하지만 (메모리가 충분한 한) 저장된 결과를 생각만큼 쉽게 재사용 할 수 없다는 것 입니다. 반복이 적은 오프닝 단계에서 저장된 결과는 이동 순서와 12 가지 이동 감소 휴리스틱에 가장 유용합니다. 예를 들어, 마지막 깊이에서 가장 잘 움직이는 것이 현재 깊이에서 가장 잘 움직이는 것으로 가정하므로 이동 목록을 정렬하고 다른 움직임 전에 가장 좋은 움직임을 검색합니다. 잘만되면, 우리는 초기의 높은 실패율을 얻게 될 것입니다.
우리는 위치를 저장하기 위해 무한한 메모리를 가지고 있지 않습니다. 해싱 알고리즘을 정의해야합니다. Zobrist 해싱 알고리즘은 의사 랜덤 분포를 제공하지만 조만간 기존 항목을 대체해야합니다.
각 엔진에는 자체 시간 관리 체계가 있습니다. 일부 엔진 및 GUI를 사용하면 엔진 속도를 설정할 수 있습니다. 엔진은 항상 시간 관리 서브 루틴 또는 사용자 설정에 의해 부과 된 제한을 제공 할 수있는 한 계산 / 평가 / 최소한도입니다. 엔진이 오랫동안 생각하면 게임의 시간 제어가 느리거나 사용자가 느리게 재생하도록 설정했기 때문일 수 있습니다.
엔진이 계산 한 위치 및 평가는 해시 테이블에 저장됩니다. 사용자는 대부분의 UCI 엔진 설정에서 사용 가능한 해시의 크기를 설정할 수 있습니다. 엔진 자체는 특정 양의 RAM을 사용하며, 해시 테이블 크기를 너무 높게 설정하면 컴퓨터가 가상 RAM 형태로 하드 드라이브에 해시를 저장하기 시작합니다. 하드 드라이브 메모리는 RAM보다 느리게 액세스되며 일반적으로 하드 드라이브가 떨리는 소리를들을 수 있습니다. 많은 사용자가 사용 가능한 RAM에 맞도록 해시 테이블 크기를 설정합니다.
고려 된 다른 위치가 더 이상 관련이 없기 때문에 엔진과 상대방이 이동 한 후 해시 테이블의 상당 부분이 쓸모 없게됩니다. 엔진은 해시에 저장된 평가를 재사용하지만 엔진이 같은 줄을 더 깊게 넘어 가면 수평선 효과로 인해 일부 평가가 올바르지 않은 것으로 판명되기 때문에 종종 후보 이동 순서를 다시 지정해야합니다.
해시의 양은 한정되어 있기 때문에 엔진은 새로운 정보를 추가 할 때 해시에서 어떤 정보를 삭제할지 결정해야합니다. 엔진은 어떤 움직임이 재생 될지 미리 알지 못하기 때문에 새로운 데이터를 추가 할 때 유용한 정보를 실수로 삭제할 수 있습니다.
일반적으로 엔진은 모든 법적 움직임을 특정 깊이로 검사하지 않습니다. 정방향 및 역방향 가지 치기를 기반으로 트리의 특정 분기를 고려하지 않습니다. 또한 리프 노드 위치에 캡처 또는 점검이 아직 수행되지 않은 경우 엔진은 조용한 (정지) 위치에 도달 할 때까지 해당 라인을 계속 진행합니다. 실제 트리는 일부 위치에서 상당히 깊을 수 있지만, 적은 수의 움직임으로 인해 다른 줄이 잘릴 수 있습니다.