결정적 Go AI 구축


11

내가 요즘에 생각했던 흥미로운 문제가 있는데, 여기에는 코드의 특성뿐만 아니라 다른 코드의 비트에 대해 게임을함으로써 다른 비트의 코드와 경쟁하는 코드가 포함됩니다.

당신의 임무는 Go 보드의 현재 상태를 취하는 프로그램을 구축하고 무엇을 할 것인지 결정하는 것입니다.

프로그램은 다음을 입력으로 받아들입니다.

  • 현재 Go 보드에있는 조각을 나타내는 19 개의 줄로 구성된 19 개의 줄. 의 문자 0는 빈 사각형 을 나타내고 1검은 색 2이며 흰색입니다.

  • 각 플레이어가 가진 포로 수를 나타내는 두 숫자 (검은 색, 흰색).

  • 자신의 차례를 나타내는 숫자 (흑백). 위와 같이 1검은 색 2이며 흰색입니다.

다음 중 하나를 출력하십시오.

  • a b이동할 좌표를 나타내는 한 쌍의 좌표 입니다. 1 1는 왼쪽 위 사각형이며 첫 번째와 두 번째 숫자는 각각 아래로 이동하고 오른쪽으로 이동하는 것을 나타냅니다.

  • pass전달할 이동을 나타내는 문자열

예를 들어, 프로그램은 다음 입력을 수신 할 수 있습니다.

0000000000000000000
0000000000000000000
0000000000000000000
0001000000000002000
0000000000000000000
0000000000000000000
0001210000000000000
0000100000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0002000000000001000
0000000000000000000
0000000000000000000
0000000000000000000
0 0 1

이는 몇 번의 움직임 만 수행 된 게임을 나타냅니다.

그런 다음 프로그램이 출력 될 수 있습니다. 6 5즉, "위에서 6 위, 왼쪽에서 5 위에 검은 돌을 놓습니다". 이것은에서 하얀 돌을 잡을 것입니다 7 5. 그런 다음 보드 상태는 다음과 같이 변경됩니다.

0000000000000000000
0000000000000000000
0000000000000000000
0001000000000002000
0000000000000000000
0000100000000000000
0001010000000000000
0000100000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0002000000000001000
0000000000000000000
0000000000000000000
0000000000000000000
1 0 2

(흰 돌이 포획되었지만 검은 수감자로 간주됩니다.)

코드는 다음 속성을 추가로 만족시켜야합니다.

  • 프로그램에 동일한 입력 상태가 제공되면 항상 동일한 출력을 생성해야합니다. 이것이 Go AI의 결정론입니다. 임의의 구성 요소가 없어야합니다.

  • 수행 할 작업을 결정하는 데 프로그램이 약 60 초 이상 걸리지 않아야합니다. 이 규칙은 컴퓨팅 성능의 변화로 인해 엄격하게 적용되지는 않지만 합리적인 시간 내에 움직여야합니다.

  • 프로그램의 소스 코드는 총 1MB (1,048,576 바이트)를 초과하지 않아야합니다.

  • 귀하의 프로그램은 항상 합법적 인 조치를 취해야합니다. 당신의 프로그램은 이미 돌이 존재하는 곳으로 이동할 수 없으며, 자신의 돌 그룹이 잡히는 조각을 놓을 수 없습니다. (이 과제의 목적에 대한 규칙의 한 가지 예외는 프로그램이 원래 위치를 만들 수 있다는 것입니다. 보드의 현재 위치 만 제공되기 때문에 어떤 동작이 수행되었는지 저장할 수 없습니다. 전에.)

당신의 제출은 보드의 상태가 비어있는 시작 Go의 게임에서 다른 모든 제출에 대한 모든 플레이 -all 토너먼트에서 플레이하고, 각 프로그램은 보드의 위치를 ​​먹이로 이동하고 이동합니다 .

각 제출 쌍은 두 번의 라운드를합니다. 각 플레이어는 검은 색입니다. 이 문제의 AI는 완전히 결정론 적이므로 동일한 AI 중 두 개가 함께 재생하면 항상 정확히 동일한 게임이 재생됩니다.

승리 조건은 다음과 같습니다.

  • 당신의 프로그램이 게임이 끝날 때까지 진행한다면, 중국의 득점 규칙이 승자를 결정하는데 사용될 것입니다. 코미는 적용되지 않습니다.

  • 프로그램이 이전 상태에 도달 한 시점까지 재생되어 무한 루프가 발생하면 두 프로그램이 묶인 것으로 선언됩니다.

귀하의 제출물은 다른 제출물에 대해 몇 점의 점수로 점수가 매겨집니다. 승점은 1 점, 동점은 반점입니다. 점수가 가장 높은 제출물이 전체 우승자입니다.


이것은 언제든지 도전 할 수있는 도전으로, 언제든지 새로운 출품작을 게시 할 수 있으며,이 경우 정기적으로 순위가 재평가됩니다.


7
좋아, 다른 모든 제출을 기다린 다음 이기기 위해 내 자신의 글을 쓰십시오-해결책이 결정적이므로 가능해야합니다.
Howard

1
이전 위치가 반복되는 것처럼 ko에서 재생되는 것처럼 보이지만 (루프가 발생하기 때문에) 즉시 당김으로 이어집니다. 흥미로운 ...
FireFly

2
문제가 너무 어려워서 가치있는 답변을 얻을만큼 열심히 일하지 않는 것처럼 보입니다 (실제로 많은 작업입니다). 좋은 문제이지만 가기가 너무 어렵습니다.
Victor Stafusa

1
더 작은 보드를 사용하지 않는 이유는 무엇입니까? 9x9는 초보자 플레이어에게는 공통입니다. 검색 공간을 획기적으로 줄 였지만 분석에 의해 아직 꺾여 질 정도로 작지는 않습니다 (완전히 해결 된 최대 크기는 5x6이라고 생각합니다).
Geobits

1
입력은 어떻게 작동합니까? stdin 또는 명령 줄 인수?
Ypnypn

답변:


7

이 도전을 시작하기위한 저의 입장입니다. 파이썬 코드 :

print "pass"

당신의 규칙에 따라 항상 "패스"를하는 것은 유효한 (나쁘지만) 전략입니다.


귀하의 코드는 항상 그 코드에 대항하여 행동하는 사람을 잃게됩니다. 여전히 좋은 기본 사례 답변입니다.
Joe Z.

1
@JoeZ. 그리고 그것의 외관에서 그는 그것으로 이겼다 : P
David Mulder

4

자바 : 스팟을 골라라

유효성을 테스트하기 위해 보드에서 반점을 선택하기 만하면됩니다. PRNG를 사용하지만 시드가 설정되어 있으므로 결정적입니다. 통과 한 턴 수에 따라 PRNG 사이클의 다른 청크를 사용합니다.

각 후보 위치에 대해 유효한 이동인지 확인합니다 (그러나 현명한 이동은 아님). 그렇지 않으면 다음 후보로 넘어갑니다. 1000 회 시도 후에 유효한 이동을 찾지 못하면 통과합니다.

import java.util.Random;
import java.util.Scanner;

public class GoNaive {

    int[][] board;
    boolean[] checked;
    int me;

    public static void main(String[] args) {
        new GoNaive().run();
    }

    void run(){
        int turns = init();
        Random rand = new Random(seed);

        for(int i=0;i<turns*tries;i++)
            rand.nextInt(size*size);

        for(int i=0;i<tries;i++){
            int pos = rand.nextInt(size*size);
            for(int c=0;c<size*size;c++)
                checked[c]=false;
            if(board[pos%size][pos/size] == 0)
                if(hasLiberties(pos, me)){
                    System.out.print((pos%size+1) + " " + (pos/size+1));
                    System.exit(0);
                }
        }
        System.out.print("pass");
    }

    boolean hasLiberties(int pos, int color){
        if(checked[pos])
            return false;
        checked[pos] = true;

        int x = pos%size, y=pos/size, n;

        if(x>0){
            n = board[x-1][y];
            if(n==0 || (n==me && hasLiberties(y*size+x-1, color)))
                return true;
        }
        if(size-x>1){
            n = board[x+1][y];
            if(n==0 || (n==me && hasLiberties(y*size+x+1, color)))
                return true;
        }
        if(y>0){
            n = board[x][y-1];
            if(n==0 || (n==me && hasLiberties((y-1)*size+x, color)))
                return true;
        }
        if(size-y>1){
            n = board[x][y+1];
            if(n==0 || (n==me && hasLiberties((y+1)*size+x, color)))
                return true;
        }
        return false;
    }

    int init(){
        int turns = 0;
        board = new int[size][size];
        checked = new boolean[size*size];
        turns = 0;
        Scanner s = new Scanner(System.in);
        String line;
        for(int i=0;i<size;i++){
            line = s.nextLine();
            for(int j=0;j<size;j++){
                board[j][i] = line.charAt(j)-48;
                if(board[j][i] > 0)
                    turns++;
            }
        }
        String[] tokens = s.nextLine().split(" ");
        turns += Integer.valueOf(tokens[0]);
        turns += Integer.valueOf(tokens[1]);
        me = Integer.valueOf(tokens[2]);
        s.close();
        return turns;
    }

    final static int size = 19;
    final static int seed = 0xdeadface;
    final static int tries = 1000;
}

2

일부 스칼라 :

package go;

class Go {
  def main(args : Array[String]) {
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    System.out.printLn("1 1")
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    readLine()
    System.out.printLn("pass")
  }
}

Wikipedia를 읽으면 이것이 현재 솔루션을 능가 할 것이라고 생각합니다.


사실, 두 경우 모두 361 포인트로 이길 것입니다.
Joe Z.

실제로, 나는 그것을 다시 가져 가야 할 것입니다. 사양을 따르지 않습니다. AI는 상태가 없어야합니다. 실제로 보드의 상태에 따라 가지만 인쇄해야하며 두 개 ( 1 1pass)로 인쇄했습니다 .
Joe Z.

@JoeZ. 고쳤다. 어쨌든 컴파일하지 않았을 것입니다.
yayestechlab

즉 것이다 항상 인쇄 1 1프로그램이 항상 새롭게 보드가 변경 때마다 실행되기 때문에, 실제로.
Joe Z.

1

자바

public class Go {
  public static void main(String[] args) {
    Scanner s = new Scanner(System.in);
    for (int i = 0; i < 361;) {
      char c = s.nextChar();
      if (c != '\n') {
        if (c == '0') {
          System.out.println((i % 19 + 1) + " " + (i / 19 + 1));
          System.exit(0);
        }
        i++;
      }
    }
  }
}

첫 번째 빈 공간을 선택합니다. 게시 시점에 모든 AI에 대해 승리합니다.


2
이것은 법적 조치를 보장하지 않습니다. 사용 가능한 첫 번째 공간에 자유 공간이 없으면 재생할 수 없습니다. 예를 들어,이 AI가 스스로 연주 한 경우 : 첫 번째 행이 번갈아 가면 1 1흰색 (현재 비어 있음)으로 캡처되고 다음 차례에는 검은 색으로 재생할 수 없습니다.
Geobits
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.