틱택 토를 연주하고 잃지 마십시오


14

(최고의 전략을 사용해야하는 몇 가지 과제가 있지만 여기서는 그렇지 않습니다. 이길 수 있어도 동점을 만들 수 있습니다)

도전

틱택 토 게임을하는 프로그램을 작성하십시오. 패배해서는 안됩니다 (따라서 넥타이로 또는 승리로 게임을 끝내야합니다).

허용 된 I / O 방법

  1. 입력은 현재 보드 일 수 있습니다. 두 번째 플레이어의 모든 이전 동작이 엔진에서 재생되었다고 가정 할 수 있습니다.
  2. 입력은 첫 번째 플레이어의 이동일 수 있으며 함수는 과거에 발생한 이동을 저장합니다. 이 경우 함수는 각 이동마다 한 번씩 여러 번 호출됩니다. 또는 여러 번 기능 / 프로그램 프롬프트 입력.
  3. 첫 번째 플레이어 인 경우 추가 입력을 받거나 첫 번째 플레이어 문제와 두 번째 플레이어 문제를 해결하기 위해 두 가지 (아마도 관련된) 기능을 작성할 수 있습니다. 프로그램에서 입력 방법 2 (다중 호출)를 사용해야하는 경우 첫 번째 호출에서 전달되는 항목을 결정할 수 있습니다.
  4. 차례가 지나면 보드가 출력 될 수 있습니다.
  5. 출력이 당신의 움직임 일 수 있습니다.
  6. 이동은 한 쌍의 숫자 (0 인덱싱 또는 1 인덱싱 일 수 있음), 0 ~ 8 범위의 숫자 또는 1 ~ 9 범위의 숫자로 표시 될 수 있습니다.
  7. 보드는 3 × 3 배열 또는 길이 9의 배열로 표현 될 수 있습니다. 언어에 0- 인덱싱 배열이 있더라도 1- 인덱싱을 사용할 수 있습니다.
  8. 그리드의 세포를 나타 내기 위해 모든 3 개 가지 값을 사용할 수 있습니다 X, O그리고 비 웁니다.

우승 기준

각 언어에서 가장 짧은 코드가 승리합니다.


패배가 당신에게 주어지면 당신의 해결책은 유효하지 않습니다. 당신은 다른 게임을하고 있기 때문에 체스 판은 즉시 바뀌지 않을 것입니다.we can assume that all previous moves of the 2nd player were also played by our engine
l4m2


1
@ l4m2 인터프리터를 다시 시작하십시오. 끝난. 왜 귀찮게합니까? 바이트 수를 불필요하게 증가시킵니다.
user202729


4
보너스를하지 마십시오. 필요하거나 제거하거나 선택하지 마십시오. 보너스는 도전을
망칠

답변:


4

비 펀지, 181 168 바이트

>>4&5pp20555>>03>16p\::5g8%6p5v
 ^p5.:g605$_ #!<^_|#:-1g61+%8g<
543217539511|:_^#->#g0<>8+00p3+5%09638527419876
v<304p$_v#:->#$$:2`#3_:^
>#\3#13#<111v124236478689189378

보드의 위치는 1에서 9까지입니다. 기본적으로 첫 번째 이동이 이루어 지지만 컴퓨터가 먼저 이동하도록하려면 첫 번째 이동에 0을 입력하면됩니다. 이동하면 컴퓨터는 이동을 나타내는 숫자로 응답합니다.

유효한 이동을 입력하지 않았는지 확인하는 사람은 없으며, 누군가 이겼는지 잃었는지 확인하는 사람도 없습니다. 일단 더 이상 움직이지 않으면 프로그램은 무한 루프로 들어갑니다.

대화식 입력 기능이있는 온라인 통역사가 없기 때문에 온라인으로 테스트하기가 약간 어렵습니다. 그러나 어떤 동작을 사전에 알고 있는지 (컴퓨터가 어떻게 반응 할 것인지를 가정 할 경우) 사전 프로그래밍 된 동작으로 TIO를 테스트 할 수 있습니다.

사용자가 먼저 플레이 : 온라인으로 사용해보십시오!
컴퓨터가 먼저 재생됩니다 : 온라인으로 사용해보십시오!

진행 상황을 쉽게 확인할 수 있도록 이동 사이에 보드를 출력하는 버전도 있습니다.

사용자가 먼저 플레이 : 온라인으로 사용해보십시오!
컴퓨터가 먼저 재생됩니다 : 온라인으로 사용해보십시오!

결과를 보려면 TIO가 시간 초과 될 때까지 기다려야합니다.

설명

이 보드는 Befunge 메모리 영역에 1에서 9까지 색인 된 9 개의 값으로 구성된 평면 배열로 저장됩니다. 이렇게하면 컴퓨터를 처음 재생할 때 제로 오프셋을 특수한 경우 "무 이동"으로 사용할 수 있습니다. 플레이어 이동은 4로 저장되고 컴퓨터는 5로 이동합니다. 모든 위치에서 시작하려면 32 (Befunge 메모리 기본값)로 초기화되므로 보드에 액세스 할 때마다 8로 수정하므로 0, 4로 돌아갑니다. 또는 5.

이러한 배열을 감안할 때, 보드에서 3 개의 포지션의 값을 합하면, 합계가 10이면 컴퓨터가 승리에서 한 번 멀어지고, 합계가 8이면 플레이어는 승리에서 한 번 멀어지고, 총계가 9 인 경우 컴퓨터와 플레이어간에 위치가 공유되지만 여전히 하나의 위치는 무료입니다.

우리의 전체 전략은이 개념을 기반으로합니다. 우리는 보드에 세 위치의 세트를 나타내는 트리플의 목록을 취하는 루틴을 가지고 있으며, 그 위치의 합계를 계산하고, 합계가 특정 총계와 같으면 컴퓨터는 세트의 위치 중 어느 위치가 비어 있는지 이동합니다.

우리가 테스트하는 트리플의 주요 목록은 우승 조합 (1/2/3, 1/5/9, 1/4/7 등)입니다. 먼저 총 10 점 (컴퓨터가 이길 예정)을 찾은 다음 총 8 명 (플레이어가 이길 예정이므로 해당 움직임을 차단해야 함)을 찾습니다. 덜 분명하게, 우리는 또한 총 9를 확인합니다 (플레이어와 컴퓨터 각각에 위치가 하나 있으면 컴퓨터가 세 번째를 취하는 것이 좋습니다).

마지막 시나리오 이전에 우리가하는 또 다른 전략적 움직임은 모든 코너 세트 (1/2/4, 2/3/6 등)와 두 개의 반대 코너 조합 (1/8/9 및 3)을 확인하는 것입니다. / 7 / 8). 이러한 조합 중 하나가 8로 합쳐지면 (즉, 플레이어가 두 포지션을 차지한 경우), 컴퓨터가 나머지 자유 포지션을 취하는 것이 좋은 전략입니다.

마지막으로 두 가지 특별한 경우가 있습니다. 첫째, 우리는 항상 다른 움직임 전에 중심 위치를 시도합니다. 이것은 다른 모든 동작과 동일한 루틴으로 달성되며, 단일 트리플, 5/5/5 및 목표 합계 0을 전달합니다. 또한 다른 모든 테스트에서 이동을 찾지 못하면 최후의 수단으로 상단 모서리 중 하나입니다. 다시 한번 이것은 1/1/1과 3/3/3의 트리플을 테스트하고 목표 합계는 0입니다.

나는 이것이 반드시 완벽한 전략이라고 생각하지는 않는다-컴퓨터가 이길 가능성이있는 게임이 있을지도 모른다. 나는 컴퓨터에 대해 가능한 모든 움직임을 시도하는 테스트 스크립트를 실행했으며 유효한 모든 동작 순서에 대해 컴퓨터가 게임에서 승리하거나 그렸습니다.


나는 Befunge를 잘 모르지만 아마도 가능한 모든 입력을 테스트 할 수 있습니다 ( 샘플 )
l4m2

@ l4m2 참고로, 이제 컴퓨터에 대해 가능한 모든 이동을 시도한 테스트 스크립트를 실행했으며 절대 잃지 않는 것을 확인할 수 있습니다.
James Holderness

2

파이썬 2 : 399 401 349 333 317 370 바이트

2x 버그 수정 : l4m2의 크레딧

-52 자 : 지하 모노레일 크레딧

-16 자 : Jonathan Frech의 신용

-26 자 : 사용자의 신용

def f(b):
 t=4,9,2,3,5,7,8,1,6;n=lambda k:[t[i]for i,j in enumerate(b)if j==k];p,o,a,I=n(2),n(1),n(0),t.index
 for i in p:
    for j in p:
     for k in a:
        if i+j+k==15and-j+i:return I(k)
 for i in o:
    for j in o:
     for k in a:
        if i+j+k==15and-j+i:return I(k)
 for i in 9,3,7,1:
    if i in a and 5 in p:return I(i)
 for i in 5,4,2,8,6:
    if i in a:return I(i)
 return I(a[0])

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

선형 대수 과정의 첫 날에 지난 학기를 치렀습니다. 저의 훌륭한 대학원생 강사는 틱택 토 보드를 행렬로 표현하면 다음과 같이 제안했습니다.

4 | 9 | 2
--+---+--
3 | 5 | 7
--+---+--
8 | 1 | 6

그런 다음 연속으로 3을 얻는 것은 [1,9] 범위에서 15를 더하는 3 개의 숫자를 선택하는 것과 같습니다.이 답변은이 아이디어를 이용합니다. 이 함수는 보드를 나타내는 9 개의 숫자가 포함 된 목록을 가져옵니다. 0은 빈 공간을 나타내고 1은 상대방이 차지하고 2는 프로그램이 수행 한 이전 플레이를 나타냅니다. 처음 3 줄은 프로그램이 어떤 숫자를 고른 지 (p), 반대가 고른 지 (o), 여전히 유효한지 (a)를 알아냅니다. 그런 다음 사용 가능한 숫자를 살펴보고 이미 선택한 두 개의 숫자와 함께 15 개가 추가되는지 확인합니다. 만약 그렇다면, 그 광장을 골라서 이길 것입니다. 즉시이기는 움직임이 없으면 상대방이 같은 방법으로 이길 수 있는지 확인합니다. 그들이 할 수 있다면, 승리하는 광장을 차지할 것입니다. 승리 또는 블로킹 이동이없는 경우 코너에서 움직입니다. 이것은 바보 친구를 방지합니다 :

- - - 
- X -
- - -

- O -             # Bad Move
- X -
- - -

- O X
- X -
- - -

- O X
- X -
O - -

- O X
- X -
O - X

이러한 상황이 발생하지 않으면 임의로 사각형을 선택합니다. 이 함수는 알고리즘에 의해 선택된 0 인덱스 사각형을 나타내는 숫자 [0,8]을 출력합니다.

편집 : 알고리즘은 이제 대각선보다 중심을 우선시하여 다른 바보가 l4m2 및 관련 전략으로 지적 될 가능성을 방지합니다.

편집 : 명확히하기 위해, 함수는 보드 형태로 보드를 가져 와서 [0,8]에서 정수로 이동을 출력합니다. 이 I / O 전략이 너무 복잡하기 때문에보다 대화식으로 만드는 래퍼 스크립트가 있습니다. 단일 명령 행 인수가 필요합니다. 플레이어가 먼저 가면 1이되고 프로그램이 먼저 가면 0이됩니다.

import sys

def f(b):
 t=4,9,2,3,5,7,8,1,6;n=lambda k:[t[i]for i,j in enumerate(b)if j==k];p,o,a,I=n(2),n(1),n(0),t.index
 for i in p:
    for j in p:
     for k in a:
        if i+j+k==15and-j+i:return I(k)
 for i in o:
    for j in o:
     for k in a:
        if i+j+k==15and-j+i:return I(k)
 for i in 9,3,7,1:
    if i in a and 5 in p:return I(i)
     for i in 5,4,2,8,6:
        if i in a:return I(i)
 return I(a[0])

board = [0,0,0,0,0,0,0,0,0]
rep = {0:"-",1:"X",2:"O"}

turn = int(sys.argv[1])
while True:
    for i in range(3):
        print rep[board[i*3]]+" "+rep[board[i*3+1]]+" "+rep[board[i*3+2]]
        print
    if turn:
        move = int(raw_input("Enter Move [0-8]: "))
    else:
        move = f(board)
    board[move] = turn+1
    turn = (turn+1)%2 


1
return마지막 줄을 제외한 모든 줄을 줄 앞에 놓아 공백을 절약 할 수 있습니다
undergroundmonorail

1
또한 나는 도움이되지만 대신 일을, 바이트를 저장할 것인지 궁금 할 수없는 e=enumerate수행 f=lambda n:[t[i]for i,j in enumerate(b)if j==n]및 할당 p, oa기능을 사용하여. 비록 그것을 계산하지 않았다
undergroundmonorail

3
아직도 해킹했습니다 . xkcd.com/832 정말 도와드립니다
l4m2

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