建立确定性的Go AI


11

这是我前几天想到的一个有趣的问题,它涉及到一些代码位与其他代码位竞争,不仅是在代码具有的属性中,而且是通过与其他代码位进行游戏。

您的任务是构建一个程序,该程序采用Go板的当前状态,并确定要采取或通过的动作。

您的程序将接受以下内容作为输入:

  • 19行,每行19个字符,代表Go板上当前的棋子。的字符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秒来确定要采取的措施。由于计算能力的变化,将不会严格应用此规则,但必须在合理的时间内采取行动。

  • 程序的源代码不得超过1兆字节(1,048,576字节)。

  • 您的程序必须始终采取法律行动。您的程序无法在已经存在宝石的地方移动,也不能放置会导致捕获其自己的宝石的工件。(针对此挑战的规则的一个例外是,允许程序创建最初存在的位置-因为仅给出了董事会的当前位置,所以不能指望存储已经做出的动作之前。)

然后,您提交的内容将与所有其他提交的内容一起参加一场无所不能的锦标赛,在围棋游戏中,棋盘的状态开始为空,每个程序轮流进入棋盘的位置并进行移动。

每对参赛作品将进行两轮比赛-每位选手均为黑人时进行一轮比赛。因为此问题中的AI完全是确定性的,所以两个相同的AI一起玩总是会导致玩完全相同的游戏。

获胜条件如下:

  • 如果您的程序播放到比赛结束,那么Go的中文得分规则将用于确定获胜者。不会应用komi。

  • 如果您的程序播放到达到较早状态的状态,从而导致无限循环,则这两个程序将被声明绑定。

您的提交将根据其相对于其他提交的得分得分。一场胜利值得一分,而平局则值得一分。得分最高的作品是总冠军。


这是一项艰巨的挑战,任何人都可以随时发布新条目,并且在出现这种情况时会定期重新评估排名。


7
好的,因为解决方案是确定性的,所以有可能等待其他所有提交,然后写我自己的来击败他们。
霍华德

1
似乎在ko中进行游戏,允许重复上一个位置,但会导致立即平局(因为这会导致循环)。有趣的...
FireFly 2014年

2
看来您的问题太难了,没有人会努力工作以产生有价值的答案(这确实是很多工作)。这是一个很好的问题,但是走起来太难了。
Victor Stafusa 2014年

1
为什么不使用较小的电路板?9x9对于初学者来说已经足够普遍了。它极大地减少了搜索空间,但是它不算小,以至于被分析“击败”了(我认为已经完全解决的最大问题是5x6)。
Geobits 2014年

1
输入如何工作?标准输入或命令行参数?
Ypnypn

Answers:


7

这是我为克服这一挑战而准备的条目。Python代码:

print "pass"

根据您的规则,始终打“通过”是有效的(尽管很差)策略。


您的代码将永远输给任何与之抗衡的人。仍然是不错的基本案例答案。
Joe Z.

1
@JoeZ。从外观上,他赢得了它:P
David Mulder 2014年

4

Java:选择一个地点,任何地点

只需选择板上的点来测试有效性。它使用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

一些Scala:

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")
  }
}

通过阅读维基百科,我认为这将胜过当前的解决方案。


实际上,在两种情况下,它都会赢361点。
Joe Z.

实际上,我必须收回它,它不符合规范。AI应该是无状态的。给定板的状态,实际上只应该打印件事,而您已经使它打印了两个(1 1pass)。
Joe Z.

@JoeZ。固定它。无论如何都不会编译。
yayestechlab 2014年

实际上,这总是会打印出来的1 1,因为每次更换板子时程序总是重新运行。
JoeZ。14年

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,2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.