f[j]
입력 이있는 함수 가 x[j]
시스템 상태 s[j]
를 state로 변경 하는 일련의 상태와 함수로 구성된 것처럼 시스템을 볼 수 있습니다 s[j+1]
.
s[j+1] = f[j](s[j], x[j])
상태는 전 세계에 대한 설명입니다. 플레이어의 위치, 적의 위치, 점수, 남은 탄약 등 게임의 프레임을 그리는 데 필요한 모든 것.
기능은 세상에 영향을 줄 수있는 모든 것입니다. 프레임 변경, 키 누르기, 네트워크 패킷.
입력은 함수가받는 데이터입니다. 프레임 변경에는 마지막 프레임이 지난 이후 시간이 걸릴 수 있으며, 키 누름에는 실제 누른 키와 Shift 키의 누르기 여부가 포함될 수 있습니다.
이 설명을 위해 다음과 같은 가정을합니다.
가정 1 :
주어진 게임 실행 상태의 양은 기능의 양보다 훨씬 큽니다. 아마도 수십만 개의 상태가 있지만 수십 가지 기능 (프레임 변경, 키 누르기, 네트워크 패킷 등) 만 있습니다. 물론, 입력량은 상태 수에서 1을 뺀 것과 같아야합니다.
가정 2 :
단일 상태를 저장하는 데 드는 공간 비용 (메모리, 디스크)은 함수 및 입력을 저장하는 것보다 훨씬 큽니다.
가정 3 :
상태를 제시하는 시간적 비용 (시간)은 상태에 대한 함수를 계산하는 것보다 비슷하거나 한두 배 정도 길다.
재생 시스템의 요구 사항에 따라 재생 시스템을 구현하는 몇 가지 방법이 있으므로 가장 간단한 방법으로 시작할 수 있습니다. 또한 종이에 기록 된 체스 게임을 사용하여 작은 예를 만들 것입니다.
방법 1 :
저장 s[0]...s[n]
합니다. 이것은 매우 간단하고 매우 간단합니다. 가정 2 때문에, 이것의 공간 비용은 상당히 높습니다.
체스의 경우, 이것은 각 움직임에 대한 전체 보드를 그려서 달성됩니다.
방법 2 :
순방향 재생 만 필요한 경우 간단히을 저장 s[0]
한 다음 저장 f[0]...f[n-1]
(이것은 함수의 ID 이름 일 뿐임) 및 x[0]...x[n-1]
(이러한 각 함수에 대한 입력 내용 임) 을 저장할 수 있습니다 . 재생하려면 간단하게 시작 s[0]
하고, 계산
s[1] = f[0](s[0], x[0])
s[2] = f[1](s[1], x[1])
등등...
여기에 작은 주석을 만들고 싶습니다. 다른 논평자들은이 게임이 "결정 론적이어야한다"고 말했다. 퀀텀 컴퓨터에서 게임을 실행하지 않는 한 모든 컴퓨터 프로그램은 결정적인 ¹이기 때문에 Computer Science 101을 다시 사용해야한다고 말하는 사람은 누구나 말입니다. 그것이 컴퓨터를 정말 멋지게 만드는 이유입니다.
그러나 프로그램은 라이브러리에서 CPU의 실제 구현에 이르기까지 외부 프로그램에 의존 할 가능성이 크므로 플랫폼간에 기능이 동일하게 작동하는 것이 매우 어려울 수 있습니다.
의사 난수를 사용하는 경우 생성 된 숫자를 입력의 일부로 x
저장하거나 prng 함수의 상태를 상태의 일부로 저장 s
하고 해당 구현을 function의 일부로 저장할 수 있습니다 f
.
체스의 경우, 이것은 초기 보드 (알려진 보드)를 그리고 각 조각이 어디로 갔는지 설명함으로써 달성됩니다. 그건 그렇고 그들이 실제로하는 방법입니다.
방법 3 :
이제, 당신은 아마도 당신의 리플레이를 추구 할 수 있기를 원할 것입니다. 즉, s[n]
임의의을 계산하십시오 n
. 방법 2를 사용하면을 계산 s[0]...s[n-1]
하기 전에 계산 해야합니다. s[n]
가정 2에 따르면 상당히 느릴 수 있습니다.
이를 구현하기 위해 방법 3은 방법 1과 2의 일반화입니다. 방법 2 f[0]...f[n-1]
와 x[0]...x[n-1]
마찬가지로 저장 하고 주어진 상수에 s[j]
대해 모두 저장하십시오 . 더 쉬운 용어로, 이는 모든 주 중 하나에 책갈피를 저장한다는 것을 의미합니다 . 예를 들어, 위해 , 당신은 저장j % Q == 0
Q
Q
Q == 100
s[0], s[100], s[200]...
계산하기 위해서는 s[n]
임의의에 대해 n
, 먼저 이전에 저장된로드 s[floor(n/Q)]
, 다음에서 모든 기능을 계산 floor(n/Q)
에 n
. 기껏해야 Q
함수를 계산하게 됩니다. 값이 작을 Q
수록 계산 속도가 빠르지 만 더 많은 공간을 소비하지만 값이 클수록 Q
공간을 덜 소비하지만 계산하는 데 시간이 더 걸립니다.
사용하는 방법 3 Q==1
은 방법 1과 동일하지만 사용하는 방법 3 Q==inf
은 방법 2와 동일합니다.
체스의 경우, 이것은 모든 움직임과 10 개의 보드마다 하나씩을 그려서 달성 할 수 있습니다 Q==10
.
방법 4 :
당신이 재생을 되돌리고 싶은 경우에, 당신은 방법 3의 작은 변화가 있다고 가정 할 수있다 Q==100
, 당신은 계산할 s[150]
통해 s[90]
역으로. 수정되지 않은 방법 3을 사용하면 50 개의 계산을 수행 s[150]
한 다음 49 개의 계산을 더 많이 수행 s[149]
해야합니다. 그러나 s[149]
get 을 이미 계산 했으므로 처음 계산할 때 s[150]
캐시를 만든 다음 표시해야 할 때 이미 캐시에 있습니다.s[100]...s[150]
s[150]
s[149]
당신은 캐시에게 당신이 계산해야 할 때마다 다시 생성해야 s[j]
들면, j==(k*Q)-1
주어진 어떤을 위해 k
. 이번에는 증가 Q
하면 크기가 작아 지지만 (캐시 전용) 시간이 길어집니다 (캐시 재 작성 용). Q
상태와 함수를 계산하는 데 필요한 크기와 시간을 알고 있으면 최적의 값을 계산할 수 있습니다.
체스의 경우, 이것은 모든 움직임과 10 개의 보드마다 하나씩 ( Q==10
) 을 그려서 달성 할 수 있지만, 마지막으로 계산 한 마지막 10 개의 보드에 별도의 종이로 그려야합니다.
방법 5 :
상태가 단순히 너무 많은 공간을 소비하거나 함수가 너무 많은 시간을 소비하는 경우 실제로 (가짜가 아닌) 리버스 재생을 구현하는 솔루션을 만들 수 있습니다. 이렇게하려면 보유한 각 기능에 대해 역 기능을 작성해야합니다. 그러나이를 위해서는 각 기능이 주입되어야합니다. 이것이 가능하다면, f'
함수의 역 을 나타 내기 위해 f
계산 s[j-1]
은 간단합니다.
s[j-1] = f'[j-1](s[j], x[j-1])
여기에서 함수와 입력은 둘 다 j-1
아니라 j
입니다. 이 동일한 함수와 입력은 계산할 때 사용했던 것과 같습니다.
s[j] = f[j-1](s[j-1], x[j-1])
이러한 함수의 역을 만드는 것은 까다로운 부분입니다. 그러나 일반적으로 게임에서 각 함수 후에 일부 상태 데이터가 손실되므로 일반적으로 할 수 없습니다.
이 메소드는있는 그대로 s[j-1]
만 reverse를 계산할 수 있습니다 s[j]
. 즉, 뒤로 재생하기로 결정한 지점부터 시작하여 뒤로 재생 만 볼 수 있습니다. 임의 지점에서 뒤로 재생하려면이 방법을 방법 4와 혼합해야합니다.
체스의 경우, 주어진 보드와 이전 이동으로 어떤 조각이 이동했는지 알 수 있지만 어디로 이동했는지 알 수 없으므로 구현할 수 없습니다.
방법 6 :
마지막으로, 모든 기능이 주입이라고 보장 할 수 없다면 약간의 트릭을 만들 수 있습니다. 각 함수가 새로운 상태 만 반환하도록하는 대신 폐기 된 데이터를 다음과 같이 반환하도록 할 수도 있습니다.
s[j+1], r[j] = f[j](s[j], x[j])
r[j]
버려진 데이터는 어디에 있습니까 ? 그런 다음 역함수를 만들어 버린 데이터를 다음과 같이 가져옵니다.
s[j] = f'[j](s[j+1], x[j], r[j])
f[j]
및 이외에도 각 기능에 대해 x[j]
저장해야합니다 r[j]
. 다시 한 번 검색하려면 방법 4와 같은 책갈피를 저장해야합니다.
체스의 경우 이것은 방법 2와 동일하지만 방법 2와 달리 각 조각이 어디로 갔는지 만 알려주므로 각 조각의 출처를 저장해야합니다.
이행:
특정 게임에 대해 모든 종류의 기능과 함께 모든 종류의 상태에서 작동하기 때문에 몇 가지 가정을 할 수 있으므로 구현하기가 더 쉽습니다. 실제로 전체 게임 상태에서 방법 6을 구현하면 데이터를 재생할 수있을뿐만 아니라 시간을 거슬러 올라가 특정 시점부터 재생을 재개 할 수 있습니다. 꽤 대단 할 것입니다.
모든 게임 상태를 저장하는 대신 주어진 상태를 그리는 데 필요한 최소값 만 저장하고 고정 된 시간마다이 데이터를 직렬화 할 수 있습니다. 귀하의 상태는 이러한 직렬화이며, 이제 입력이 두 직렬화의 차이가됩니다. 이 작업의 핵심은 세계 상태가 거의 변하지 않으면 직렬화가 거의 바뀌지 않아야한다는 것입니다. 이 차이는 완전히 가역적이기 때문에 책갈피를 사용하여 방법 5를 구현하는 것이 매우 가능합니다.
이벤트 (fps의 조각 또는 스포츠 게임의 점수)가 발생할 때 최근 데이터를 즉시 재생하기 위해 일부 주요 게임 에서이 기능을 구현했습니다.
이 설명이 너무 지루하지 않기를 바랍니다.
¹ 이는 일부 프로그램이 결정적이지 않은 것처럼 작동 함을 의미하지는 않습니다 (예 : MS Windows ^^). 이제 결정 론적 컴퓨터에서 비결정론 적 프로그램을 만들 수 있다면 Fields 메달, Turing 상, 그리고 아마도 Oscar와 Grammy에게도 가치있는 모든 것을 동시에 얻을 수있을 것입니다.