Держи дистанцию!

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 раундов. Самый высокий общий балл выигрывает!

правила

  • Ваш код не может использовать любые операции ввода-вывода, включая консоль, файлы, сеть и т. Д.
  • Вы не можете вмешиваться в программу управления или любых других игроков.
  • Программы, которые выглядят так, как будто они нарушают вышеуказанные правила, будут исключены.
  • Каждый вызов функции должен занимать на моем компьютере менее пяти секунд (Intel Core i5 2450M с 8 ГБ ОЗУ).
  • Если программа выдает исключение или возвращает недопустимое значение, оно будет обрабатываться так, как будто оно вернуло 1.
  • Каждый пользователь может представить не более одной программы.

Разнообразный

  • Управляющая программа есть на GitHub .
  • Есть три встроенных игрока. Их можно найти в этом ответе .
  • Победитель будет выбран 28 января.

Leaderboard

Победитель - консерватор .

Похвальная грамота Густаву , игроку с самым высоким счетом и непостоянной стратегией.

  • Консерватор - 36226
  • Высокий - 36115
  • FloorHugger - 35880
  • NumberOne - 35791
  • Завышенный показатель - 35791
  • Густав - 35484
  • Историк - 35201
  • Пробоотборник - 34960
  • Инкрементатор - 34351
  • JumpRightIn - 34074
  • Викри - 34020
  • Подросток - 33907
  • Ранду - 33891
  • Тяжелоатлет - 33682
  • Посредник - 33647
  • BounceInwards - 33529
  • Настя Математик - 33292
  • Джемпер - 33244
  • Подражатель - 33049

Полные результаты можно найти здесь . (Я рекомендую отключить перенос текста.)

Ypnypn
источник
Есть ли у меня какой-нибудь способ сказать, каким был мой номер в предыдущих раундах?
Мартин Эндер
@ MartinBüttner Нет.
Ypnypn
1
Я не знаю ни одного из этих языков :( Не могли бы вы добавить JavaScript? Например, запустить его с помощью node.js?
Килан
1
@ TheWobbuffet, я тоже не знаю ни одного из них. Не помешало мне сделать запись Python.
Марк
7
Я думаю, что было бы более интересно, если бы пространство представляло собой круг / петлю, чтобы расстояние от 1 до 999 равнялось 1. Это не позволило бы «угадать одно число за ход» доминирующему положению, поскольку «ребер» нет парковаться на. Очевидно, что уже слишком поздно, чтобы измениться сейчас;)
Geobits

Ответы:

9

Питон, консерватор

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

Так как каждое исключение выбрасывает 1, оно как можно дальше от него. Делает свое состояние за счет слабых.

Забавный факт: я думал об улучшении этого, но не мог найти лучший способ чем просто скрыться в углу.

clabacchio
источник
1
Похоже, я выбрал не тот угол. :(
TheNumberOne
Это хорошо по простой причине: другие пытаются минимизировать расстояние до вас. Они автоматически сделают ваш счет лучше. Изменителем игры будет противник, который пытается подобраться как можно ближе к вам.
Мартин Тома
1
Фуу ... точка с запятой в Python?
KSFT
@KSFT хе-хе Я на Python ржавый, и я никогда не был таким экспертом
Клабаккио
6

Номер один, Java

Название объясняет это полностью.

public static int choose(int round, int players, String[] args) {
    return 1;
}
Номер один
источник
1
Почему голосование против?
TheNumberOne
5
Мне особенно нравится, как имя пользователя связывается с представлением
Брайан Дж
5

Питон, древнеисторический

Твердо верит, что будущее будет точно таким же, как и прошлое, но верит, что последний раунд слишком недавний, чтобы быть его историческим, поэтому он просто перебирает 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
Maltysen
источник
4

Питон, Викри

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], то Викри вставляет оптимальную игру 200, чтобы дать [1, 200, 990, 999], а затем выбирает лучший вариант для нового массива (который 556).

Sp3000
источник
4

Ява, Заверитель

Как следует из названия, эта программа предполагает, что все другие программы будут пытаться играть «хорошо», выбирая лучший ответ на основе последнего раунда - так что этот «переоценщик» всегда выбирает наихудшую возможную позицию на основе предыдущего раунда.

 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» оказалась довольно успешной. :)
Эмиль
К сожалению, в коде есть ошибка, да - на самом деле он никогда не анализирует результаты, прочитанные в последнем раунде. (Но я понял это слишком поздно, и к тому времени казалось, что редактировать представление было неправильно, к тому же, как вы говорите, дела шли довольно хорошо, так что ... что угодно: p)
Алекс Уокер,
4

Ява - Тяжелоатлет

Выполните циклы по 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;
}
Geobits
источник
Примечание: даже на 100 раунде это завершается менее чем за секунду на моем несколько медленном ПК. Если по какой-то причине это займет у вас слишком много времени, дайте мне знать, чтобы я мог ограничить рекурсию.
Geobits
Это очень быстро на моей машине.
Ypnypn
3

Ruby, Copycat

Просто возвращает тот номер, который выиграл в прошлый раз.

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

Рубин, 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

Густав (Питон 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
Ypnypn
источник
1

Python, Sampler

Из списка мест выберите тот, который находится дальше всего от недавно использованных номеров, игнорируя предыдущий ход.

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

НастяМатематик (Ява)

Исследует последние два раунда (если лучшие числа были 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;
}
CommonGuy
источник
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
KSFT
источник
0

Питон, посредник (по материалам консерватора @clabacchio)

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

После того, как я заметил, что верхний край получил высокие баллы (и превзошел нижний), я подумал, может ли быть что-нибудь хуже, чем просто попасть в середину.

Деннис Джаэруддин
источник
0

Джемпер (Рубин)

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

Чередуется между нижней, средней и верхней. (5500995)

MegaTom
источник