Wythoff의 님 님을 완벽하게 플레이하십시오


16

당신의 목표는 Wythoff의 Nim 게임을위한 완벽한 플레이어를 작성하는 것입니다 .

Wythoff의 님의 규칙

Wythoff의 님 (Nim)은 결정적인 2 인용 게임으로 두 개의 동일한 카운터로 쌓입니다. 플레이어는 다음 중 하나를 수행하는 교대 차례입니다.

  1. 첫 번째 더미에서 하나 이상의 카운터 제거
  2. 두 번째 더미에서 하나 이상의 카운터 제거
  3. 첫 번째 파일과 두 번째 파일 모두에서 같은 수의 카운터 (하나 이상)를 제거하십시오.

물론, 더미는 음수가 될 수 없지만, 0이 될 수 있습니다. 마지막 카운터를 제거하는 사람이 게임에서 승리합니다.

보다 기하학적 인 생각을 위해이 애플릿에서 재생할 수있는 게임의 동등한 구성이 있습니다 . 단일 여왕은 왼쪽 아래에 모서리가있는 1/4 무한 체스 판의 사각형에서 시작합니다. 플레이어는 여왕을 교대로 움직이며 체스 여왕처럼 움직이지만 세 방향으로 제한됩니다.

  1. 내려가는
  2. 왼쪽
  3. 대각선 아래로 그리고 왼쪽

여왕을 모퉁이로 옮기는 사람이 이깁니다.

여왕의 좌표 (코너 포함 (0,0))를 각 더미의 크기 와 연관 시키면 두 게임이 동일하다는 것을 쉽게 알 수 있습니다.

완벽한 플레이

(완벽한 플레이와이기는 움직임의 개념에 익숙하다면 이것을 건너 뛸 수 있습니다.)

Wythoff의 님은 유한하고 결정적인 게임이므로 완벽한 플레이 라는 개념을 가지고 있습니다 . 퍼펙트 플레이어는 항상 이론적으로이긴 위치에서 승리하는 전략으로, 승리를 보장하는 전략이 존재하는 위치를 의미합니다.

승리 전략이 되려면, 방금 이사 한 플레이어의 이론적 인 승리 위치로 이동하기에 충분하므로 플레이어는 다음에 가지 않습니다. 이 우승 포지션 중 첫 번째 포지션 ( 콜드 포지션 이라고도 함 )은 다음과 같습니다 (0,0), (1,2), (2,1), (3,5), (5,3). Wythoff의 Nim에 대한 승리 전략과 승리 위치를 생성하는 공식을 찾는 알고리즘에 대한 설명은 Wikipedia 기사 를 참조하십시오 .

프로그램 요구 사항

프로그램이나 함수를 작성하면 위치를 입력으로 받아 이동 후 위치의 형태로 우승 이동을 출력합니다. 가장 적은 바이트가 이깁니다.

이기는 움직임이 존재하지 않는 경우, 즉 위치가 이론상 손실 인 경우 프로그램은이를 표시하고 몰수해야합니다.

프로그램은 적절한 시간 내에 실행되어야합니다. 따라서 지수 재귀 게임 트리 검색으로는 충분하지 않습니다. 전략을 미리 계산하고 하드 코딩하려면 괜찮습니다.

입력

(i,j)파일 크기를 나타내는 음이 아닌 숫자 쌍 입니다 99. 튜플, 목록 또는 원하는 컨테이너 등 두 가지 숫자가 될 수 있습니다.

산출

이동 후 위치를 다시 두 개의 숫자 또는 컨테이너로 인쇄하거나 출력하십시오. 이것은 우승 위치로 합법적으로 이동해야합니다. 그러한 움직임이 여러 개인 경우 어느 것이나 괜찮습니다.

이기는 움직임이 없으면 출력에이를 표시해야합니다. 모든 출력은 같은 False, None0, 또는 (-1,-1)그 법적 위치 아니라, 모든지는 입력에 대해 동일만큼, 할 것입니다.

예제 실행

f(5,0)   = (0,0)
f(2,2)   = (1,2)   # Or (2,1) or (0,0) 
f(1,2)   = False
f(13,9)  = (13,8)  # Or (10,6)
f(10,6)  = False
f(5,10)  = (5,3)
f(25,30) = (8,13)    

2
+1, 부분적으로 무한의 1/4이라는 아이디어가 좋아서.
Level River St

"합리적인 시간"을 정의하십시오. (100,50)에 몇 초가 적당한 시간입니까?
John Dvorak

오. 기다림. 입력은 ... 30 ??? 조금 낮지 않습니까?
John Dvorak

@JanDvorak 당신이 옳습니다, 저렴한 지름길을 허용 할 수도 있습니다. 99로 변경-충분하다고 생각합니까? 게시 후 사양을 수정하기위한 사과
xnor

@PeterTaylor 감사합니다.
xnor

답변:


6

하스켈, 167165

c p=o p:c(o p:p)
o p=[(a,b)|a<-[0..],b<-[0..a],(a,b)?p==[]]!!0
(a,b)?p=[y|y@(c,d)<-p,c==a||c==b||d==b||a+d==b+c]
f x@(a,b)|a<b=f(b,a)|x?c[]!!0==x=(0,-1)|1>0=x?c[]!!0

알고리즘은 비효율적이지만 입력 <100의 경우 1 초 내에 (대화식 콘솔에는 없지만) 여전히 실행됩니다.

설명:

c p=o p:c(o p:p)

이전 콜드 위치 세트가 제공된 콜드 위치 목록은 하나의 콜드 위치 다음에이 위치와 이전 콜드 위치가 제공된 콜드 위치 목록이 이어집니다 (비효율 :이 위치는 두 번 생성됨).

o p=[(a,b)|a<-[0..],b<-[0..a],(a,b)?p==[]]!!0

하나의 콜드 위치는 첫 번째 쌍이므로 해당 쌍에서 도달 할 수있는 콜드 위치가 없습니다 (비효율 : 대신 이전 쌍에서 검색해야 함)

(a,b)?p=[y|y@(c,d)<-p,c==a||c==b||d==b||a+d==b+c]

쌍에서 도달 할 수있는 위치는 첫 번째 요소가 일치하고 두 번째 요소가 일치하거나 차이가 일치하거나 제거 전의 작은 힙이 제거 후 더 큰 힙인 위치입니다.

f x@(a,b)|a<b=f(b,a)
         |x?c[]!!0==x=(0,-1)
         |1>0=x?c[]!!0

(주된 방법) 힙의 순서가 잘못된 경우 교환하십시오. 그렇지 않으면, 위치에서 도달 할 수있는 첫 번째 냉기 위치가 위치 자체 인 경우 실패를 표시하십시오 (이상적으로는 Maybe (Int,Int)대신 돌아올 것임 ). 그렇지 않으면 콜드 위치를 반환합니다 (비효율 : 해당 쌍이 두 번 조회됩니다. 더 나쁜 것은 콜드 위치 목록이 두 번 생성됨).


" 지수 적 재귀 게임 트리 검색은 충분하지 않습니다 "는 낙관적 인 것 같습니다. 왜냐하면 당신이 묘사하는 것이 정확히 그렇게 들리기 때문입니다.
피터 테일러

@PeterTaylor 이것은 O (n ^ 4)입니다. 각 콜드 페어는 O (n ^ 3) 시간이 걸리고 O (n) 개가 있습니다. 생성을 최적화하면 O (n ^ 2)가됩니다 (시퀀스를 올바르게 읽으면). 지수 시간 알고리즘이 훨씬 느려집니다. 몇 가지 테스트를 실행해야합니까?
John Dvorak

괜찮아, 난 널 믿어
피터 테일러

x@에서 제거 할 수 있습니다x@(a,b)?p=...
자랑스러운 haskeller

그것이 어떻게 도착했는지 확실하지 않습니다. 고마워요
John Dvorak

5

GolfScript ( 63 57 바이트)

{\]zip{~-}%0|$(!*,1=}+1,4*{..,,^[(.@,2/+.2$]+}38*2/?0]0=`

형식으로 stdin의 입력을 예상 [a b]하고 해당 형식으로 stdout에 출력을 남겨 두거나0 위치를 잃어버린 경우 . 온라인 데모

개요

,4*{..,,^[(.@,2/+.2$]+}38*2/

를 사용하여 냉기 위치 목록 ( [b a]각 냉기 위치에 대한 뒤집힌 버전 포함 [a b])을 계산합니다.Beatty sequence 속성을 .

그런 다음 ?생성 된 블록을 만족하는 첫 번째 냉기 위치를 검색합니다.

{\]zip{~-}%0|$(!*,1=}+

기본적으로 벡터 차이를 계산 한 다음 입력 위치 [0 x]에서 [x 0], 또는 [x x]일부 인지 확인하여 입력 위치에서 위치에 도달 할 수 있는지 확인합니다 x > 0. : IMO 그 테스트 해결사 비트 인 0|$형태로 이들 형식 중 어떤 배열 힘을 [0 x]매핑 반면 [0 0][0], [a b]어느 쪽 ab이다 0세 요소의 배열로, 그리고 [-x 0]또는 [-x -x][-x 0]. 그런 다음 (!*,1=우리가 있는지 확인합니다 [0 x].

마지막으로 0]0=`대체 사례와 출력 형식을 수행합니다.


4

피스 57 58 61 62

K1.618Jm,s*dKs*d*KKU39M<smf|}TJ}_TJm,-Ghb-Hebt^,0hk2U99 1

온라인으로 사용해보십시오.

다른 답변과 매우 유사하지만 위키 백과 페이지에는 더 많은 내용이 나와 있지 않습니다.) 마법 숫자 39는 값이있는 차가운 위치 수입니다99 .

g처럼 호출 할 수 있는 함수 를 정의합니다 g 30 25. []실패에 대한 반품[(13,8)]성공 .

설명

K1.618                            : K=phi (close enough for first 39 values)
      Jm,s*dKs*d*KKU39            : J=cold positions with the form (small,big)
M<s                              1: Define g(G,H) to return this slice: [:1] of the list below 
   mf|}TJ}_TJ                     : map(filter: T or reversed(T) in J, where T is each member of..
             m,-Ghb-Hebt^,0hk2    : [(G H) - (0 x+1),(x+1 0) and (x+1 x+1)]
                              U99 : for each x from 0 - 98

sint로 캐스트-몇 문자 이상을 저장합니다 /____1. 단항 범위를 사용하여 rZ39로 대체 할 수 있습니다 U39. 마찬가지로, 당신은 대체 할 수 r99)와 함께 U99.
isaacg

@isaacg 감사합니다! 나는 완전히 잊었다 U. 나는 설명을 정말로 업데이트해야한다 : P
FryAmTheEggman

@isaacg Pyth에 대한 생각, @두 번째 논쟁이 이제 목록이라면 교차점을 만들 수 있다고 생각합니다 . aP
FryAmTheEggman

좋은 생각입니다. 구현했습니다. 또한 두 목록 목록의 교차를 포함하여 이전에는 불가능했던 몇 가지 트릭을 허용하도록 교차 코드를 변경했습니다.
isaacg 2013

2

자바 스크립트 ES6-280 바이트

축소

r=x=>~~(x*1.618);g=(y,x)=>y(x)?g(y,x+1):x;s=A=>A?[A[1],A[0]]:A;f=(a,b)=>j([a,b])||j([a,b],1);j=(A,F)=>l(A,F)||s(l(s(A),F));l=(A,F)=>([a,b]=A,c=(F&&a+b>=r(b)&&(e=g(x=>a+b-2*x-r(b-x),0))?[a-e,b-e]:(e=g(x=>r(a+x)-2*a-x,0))+a<b?[a,a+e]:(e=r(b)-b)<a?[e,b]:0),c&&r(c[1]-c[0])==c[0]?c:0)

넓히는

r = x => ~~(x*1.618);
g = (y,x) => y(x) ? g(y,x+1) : x;
s = A =>A ? [A[1],A[0]] : A;
f = (a,b) => j([a,b]) || j([a,b],1);
j = (A,F) => l(A,F) || s(l(s(A),F));
l = (A,F) => (
    [a,b] = A,
    c = (
        F && a+b >= r(b) && (e = g( x => a+b - 2*x - r(b - x), 0 )) ? [a-e,b-e] :
        (e = g( x => r(a+x) - 2*a - x, 0)) + a < b ? [a,a+e] :
        (e = r(b) - b) < a ? [e,b] : 0
    ),
    c && r(c[1] - c[0]) == c[0] ? c : 0
);

멋지고 빠른 알고리즘. O (n)에서 실행되지만 바이트 절약 루프가 아닌 경우 일정한 시간에 실행됩니다. 루프는 재귀 증분기로 구현되므로 스크립트는 n에 대한 재귀 오류와 함께 결국 실패합니다. 수백 또는 수천의 에 합니다. Taylor 씨가 언급 한 것과 동일한 Beatty 시퀀스 속성을 사용하지만 시퀀스를 계산하는 대신 올바른 용어로 간단히 넘어갑니다.

내가 테스트 한 것 외에도 모든 테스트 입력과 수십 가지에서 올바르게 실행됩니다.

호출 할 함수는 f입니다. 성공시와 0포기시 배열을 반환 합니다.


잠깐, 배열을 출력해도 괜찮습니까?
John Dvorak

@ JanDvorak : xnor는 유효한 출력 목록에 튜플이 있으므로 그렇게 생각했습니다. 그는 문제를 분명히 할 수 있습니다. 어쨌든 사소한 수정입니다.
COTO

쌍의 배열 또는 싱글 톤 배열은 괜찮습니다. 여러 번이기는 동작은 아닙니다.
xnor

1

Perl 5-109 (2 개 플래그 포함)

#!perl -pl
for$a(@v=0..99){for$b(@v){$c=$a;$d=$b;${$:="$a $b"}||
map{$$_||=$:for++$c.$".++$d,"$a $d","$c $b"}@v}}$_=$$_

용법:

$ perl wyt.pl <<<'3 5'

$ perl wyt.pl <<<'4 5'
1 2

가능한 각 입력에 대한 솔루션을 계산 한 다음 단일 조회 만 수행하면됩니다.

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