保持距离!


15

每个玩家都有一个号码。您能离他们最远吗?

要求

编写一个名为Java,Python 2或Ruby的函数choose(),该函数接受三个参数:

  • 整数-已完成的回合数
  • 整数-玩家人数
  • 字符串数组-前一轮的结果
    • 每个字符串都是用空格分隔的整数列表,从最低到最高排序

例如,choose(2, 4, ["4 93 93 174", "1 84 234 555"])表示:

  • 已经有两轮了(这是第三轮)
  • 一共有四个玩家
  • 在第一轮中,选择的数字是4,93,93,174
  • 在第二轮中,选择的数字是1,84,234,555

您必须返回1到999(含)之间的整数。

对于每个其他玩家,您的得分是您的数字与其数字之间的距离的平方根。您在该回合中的分数是所有这些分数的总和。

将进行100轮比赛。最高总分获胜!

规则

  • 您的代码可能不使用任何I / O,包括控制台,文件,网络等。
  • 您不得干扰控制程序或任何其他播放器。
  • 看起来违反上述规则的程序将被排除。
  • 在我的计算机(带8GB RAM的Intel Core i5 2450M)上,每次调用函数应花费不到5秒的时间。
  • 如果程序引发异常或返回无效值,则将其视为返回1。
  • 每个用户最多可以提交一个程序。

  • 控制程序在GitHub上
  • 有三个内置播放器。在此答案中可以找到它们。
  • 获奖者将于1月28日入选。

排行榜

获胜者是保管人

值得一提的是古斯塔夫(Gustav),他是采用非固定策略的得分最高的球员。

  • 柜子-36226
  • 高-36115
  • 地板抱抱-35880
  • 一号-35791
  • 高估-35791
  • 古斯塔夫-35484
  • 历史学家-35201
  • 取样器-34960
  • 增量器-34351
  • JumpRightIn-34074
  • 维克雷-34020
  • 少年-33907
  • 兰杜-33891
  • 举重运动员-33682
  • 中间人-33647
  • BounceInwards-33529
  • 讨厌的数学家-33292
  • 跳线-33244
  • 模仿者-33049

完整的结果可以在这里找到。(我建议禁用文本换行。)


我有什么办法告诉我前几轮比赛中我自己的号码吗?
马丁·恩德

@MartinBüttner号
Ypnypn,2015年

1
我不懂这些语言:(您能添加JavaScript吗?例如,使用node.js运行它吗?
Cilan 2015年

1
@TheWobbuffet,我也都不认识。并没有阻止我编写Python条目。
2015年

7
我认为,如果空间是一个圆/环,从而使1和999之间的距离为1,那会更有趣。这将使“猜测每转一个数字”不再占主导地位,因为没有“边缘”停车。显然现在已经来不及改变;)
Geobits'1

Answers:


9

Python,保管人

def choose(round, players, scores):
    return 999

因为每个异常都抛出1,所以它尽可能地远离它。以牺牲软弱者为生。

有趣的事实:我曾想过要改进它,但找不到比躲在角落里更好的方法了。


1
看来我选错了角落。:(
TheNumberOne 2015年

这样做有一个简单的理由,这是件好事:其他人试图尽量减少与您的距离。他们会自动使您的成绩更好。改变游戏规则的人将是一个试图与您尽可能接近的对手。
Martin Thoma 2015年

1
Eww ... Python中的分号?
KSFT

@KSFT嘿嘿,我对Python感到生疏,无论如何我从来都不是专家
clabacchio 2015年

6

Java第一

名称完全说明了这一点。

public static int choose(int round, int players, String[] args) {
    return 1;
}

1
为什么要投反对票?
TheNumberOne

5
我特别喜欢用户名如何与提交相关联
Brian J

5

Python,古代历史

坚信未来将与过去完全相同,但相信最后一轮比赛太过历史而已,因此它只能循环显示1-999,并选择上一轮比赛中表现最好的那一轮。前2回合返回500。

def choose(round, players, scores):
    calc = lambda n, scores: sum([abs(int(i)-n)**.5 for i in scores.split(' ')])
    return max(range(1, 1000), key=lambda n: sum([calc(n, j) for j in scores[1:]])) if round>1 else 500

4

Python,维克瑞

def choose(rounds, players, results):        
    if not results:
        return (id(0)/7)%999 + 1

    def best(array):
        score = lambda x: sum(abs(x-y)**.5 for y in array)
        m = max(score(x) for x in range(1, 1000))
        return [x for x in range(1, 1000) if score(x) == m]

    def second_best(array):
        array.extend(best(array))
        options = best(array)
        return options[(id(0)/7) % len(options)]

    results = [map(int, s.split()) for s in results]
    counts = {}

    for round_ in results:
        for number in round_:
            counts[number] = counts.get(number, 0) + 1

    most_common = sorted([(c, n) for n,c in counts.items()], reverse=True)
    to_avoid = [t[1] for t in most_common[:players]]

    return second_best(to_avoid)

列出经常播放的号码,并假设其他所有人都将发挥最佳状态,并选择第二个给定的列表中选择佳的选择。

例如,如果最常见的数字是[1, 990, 999],则Vickrey插入最佳剧本200给予[1, 200, 990, 999],然后为新数组选择最佳选项(即556)。


4

Java,高估器

顾名思义,该程序假定所有其他程序都将根据上一轮选择最佳答案来尝试“打好”-因此,此“高估”总是根据前一轮选择最差的位置。

 public static int choose(int round, int players, String[] args) {
     String[] lastRoundStrings = args[args.length - 1].split(" ");
     int[] lastRound = new int[lastRoundStrings.length];
     int worstSelection = 0;
     for (int i = 0; i < lastRound.length; i++) {
         double worstScore = Double.MAX_VALUE;
         for (int j = 1; j < 999; j++) {
             double computedScore = score(j, lastRound);
             if (computedScore < worstScore) {
                 worstScore = computedScore;
                 worstSelection = j;
             }
         }
     }
     return worstSelection;
 }

 public static double score(int position, int[] otherPositions) {
     double total = 0;
     for (int i = 0; i < otherPositions.length; i++) {
         total += Math.sqrt(Math.abs(otherPositions[i] - position));
     }
     return total;
 }

这怎么打成常数“ 1”?是否有错误?提醒您,打“ 1”非常成功。:)
Emil

遗憾的是,代码中有一个错误,是的-它从未真正解析过上一轮读取的分数。(但我意识到为时已晚,到那时编辑提交似乎是错误的,再加上您说做得很好,所以...:p)
Alex Walker

4

Java-举重运动员

循环播放1-999以找出哪一轮最适合。根据新近度对它们进行称重(最近几轮的权重更大),并返回其最佳总体猜测。希望如果模式在以后的回合中形成,那么它将能够继续进行下去。

编辑:现在有了+ Inf%更多的递归! 不能存储/保存/查看您在前一轮中选择的内容是一件麻烦事。在尝试找出其他因素时,将您自己的输入考虑在内会使您陷入困境将要做。所以,让我们计算一下!现在将进行递归,以找出在上一轮中选择的内容,并在计算下一步时忽略它。

请注意,它实际上只忽略了上一回合的输入,但由于该输入的权重最高,因此看起来还可以。可以通过一些更多的工作来解决此问题,但是我将等待排行榜查看是否需要这样做。

int choose(int rounds, int players, String[] hist){
    if(rounds < 1)
        return 1;

    int lastChoice = choose(rounds-1,players,java.util.Arrays.copyOf(hist, hist.length-1));

    int[][] history = new int[hist.length][players];
    for(int i=0;i<hist.length;i++){
        String[] tokens = hist[i].split(" ");
        boolean flag = false;
        for(int j=0;j<tokens.length;j++){
            history[i][j] = Integer.parseInt(tokens[j]);
            if(i==history.length-1 && history[i][j]==lastChoice && !flag){
                flag = true;
                history[i][j] = -1;
            }
        }
    }

    double best = 0;
    int guess = 1;
    for(int i=1;i<1000;i++){
        double score = 0;
        for(int j=0;j<history.length;j++){
            double weight = (double)(j+1)/history.length;
            for(int k=0;k<history[j].length;k++){
                if(history[j][k] > 0)
                    score += Math.sqrt(Math.abs(history[j][k]-i)) * weight;
            }
        }
        if(score > best){
            best = score;
            guess = i;
        }
    }
    return guess;
}

注意:即使在第100回合,它也可以在我速度稍慢的PC上在一秒钟内完成。如果由于某种原因花费您的时间太长,请告诉我,以便限制递归。
Geobits,2015年

在我的机器上也非常快。
Ypnypn

3

Ruby,模仿者

只需返回上一次赢得的号码即可。

def choose r, p, hist
  last = hist.last.split.map &:to_i
  scores = last.map{|n| last.map{|m| (n-m).abs ** 0.5 }.inject :+ }
  last[scores.index scores.max]
end

1
第一轮返回什么?哦,没关系。例外会返回1
mbomb007

3

Ruby,JumpRightIn

def choose(round, players, args)
    return 500 if args.size == 0
    last_round = args[-1].split.map(&:to_i) + [1000]
    max_gap = 0
    last = 0
    move = 1
    last_round.each { |i|
        gap = i - last - 1
        if gap > max_gap
            max_gap = gap
            move = (i + last)/2
        end
        last = i
    }
    move
end

这可能是最直接的策略。它在上一轮中找到最大的缺口,并在该缺口的中间选择数字。


第一轮返回什么?1?
mbomb007

@ mbomb007哦,我总是忘记这些讨厌的初始回合。谢谢,现在返回500
马丁安德

3

古斯塔夫(Python 2)

这是一个非常简单明了的元策略,在类似的KotH挑战中无耻地从我的一个旧答案中复制而来。它考虑了一些简单的策略,研究了它们在之前所有回合中的表现,然后按照得分最高的方式进行下一回合。

def choose(k, N, h):
    if k<2: return 999
    H = [[int(x) for x in l.split()] for l in h]
    score = lambda x,l: sum(abs(x-y)**.5 for y in l)
    S = [range(1,1000)
         + [max(range(1,1000), key=lambda x: score(x, H[i-1]))]
         + [max(range(1,1000), key=lambda x: score(x, H[i-2]))]
         + [min(range(1,1000), key=lambda x: score(x, H[i-1]))]
         + [min(range(1,1000), key=lambda x: score(x, H[i-2]))]
         for i in range(2,k+1)]
    scores = [sum(score(s[j],l) for s,l in zip(S[:-1], H[2:]))
              for j in range(len(S[0]))]
    return max(zip(scores, S[-1]))[1]

我现在意识到该算法仍然存在一些缺陷。例如,它可能会保持“追逐自己”,因为它没有将自己的举动与对手的举动区分开。但是,我暂时将其保留下来。



1

内置以下三个程序。

高(红宝石)

def choose(round, players, args)
    return 990
end

增量器(Java)

public static int choose(int round, int players, String[] args) {
    return round * 10 + 5;
}

FloorHugger(Python)

def choose(round, players, args):
    if len(args) == 0:
        return 10
    last = args[-1].split();

# next line from http://stackoverflow.com/a/7368801/3148067
    last = map(int, last)

    dist = 0
    for i in range(1, 999):
        if i in last:
            dist = 0
        else:
            dist = dist + 1
            if dist == 10:
                return i
    return 500

1

Python,采样器

在位置列表中,选择距最近使用的数字最远的位置,而忽略上一个转向。

def choose(turn, players, history):
    sample = map(int, (' '.join( history[-5:-1] )).split())
    def distance(x): return sum(abs(x-y)**0.5 for y in sample)
    places = range(1, 1000, 13)
    score, place = max((distance(x), x) for x in places)
    return place

1

Java,BounceInwards

从1开始,它逐渐接近500,同时在较高和较低选项之间反弹。

public static int choose(int round, int players, String[] args) {
    return round%2 == 0 ? round * 5 : 1000 - round * 5;
}

1

讨厌的数学家(Java)

检查最后两轮(如果最佳数字是70和80,则将输出90)。这太讨厌了,因为它试图以尽可能多的数字来击败他的对手。

public static int choose(int round, int players, String[] args) {
    if (round == 0) {
        return 999;
    }

    int[][] results = new int[args.length][players];

    // parse input
    for (int i = 0; i < args.length; i++) {
        String[] rounds = args[i].split(" ");
        for (int j = 0; j < rounds.length; j++) {
            results[i][j] = Integer.parseInt(rounds[j]);
        }
    }

    int bestNumber = 0;
    double bestScore = -1;

    // get the best number for the last round
    for (int i = 1; i < 1000; i++) {
        double score = 0;
        for (int result : results[results.length - 1]) {
            score += Math.sqrt(Math.abs(i - result));
        }
        if (score >= bestScore) {
            bestScore = score;
            bestNumber = i;
        }
    }

    if (round == 1) {
        return bestNumber;
    }

    int bestNumber2 = 0;
    double bestScore2 = -1;

    // get the best number for the second last round
    for (int i = 1; i < 1000; i++) {
        double score = 0;
        for (int result : results[results.length - 2]) {
            score += Math.sqrt(Math.abs(i - result));
        }
        if (score > bestScore2) {
            bestScore2 = score;
            bestNumber2 = i;
        }
    }

    // add the difference between last round and second last round to get this rounds best number
    int difference = bestNumber - bestNumber2;
    bestNumber = bestNumber + difference;

    return bestNumber > 999 ? 999 : bestNumber;
}

1

Python-我不想想到一个名字...

如果在前几轮中选择的数字的平均值小于500,则选择999。否则,选择1。

def choose(a,b,c):
    total=0
    for i in c:
        for j in i.split(" "):
            total+=int(i)
    average=total/(a*b)
    if average<500:
        return 999
    return 1

0

Python,Middleman(基于@clabacchio的保护者)

def choose(round, players, scores):
    return 500;

当我注意到上边缘得分较高(并超过下边缘)之后,我想知道是否有什么比仅被中间位置捕获更糟糕的事情了。


0

跳线(红宝石)

def choose(round, players, args)
    495*(round%3)+5
end

在底部,中间和顶部之间切换。(5,500,995)

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.