Тримайте дистанцію!


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 січня.

Таблиця лідерів

Переможець - Консерватор .

Почесна згадка про Густава , гравця з найвищими оцінками , що має нестабільну стратегію.

  • Консерватор - 36226
  • Високий - 36115
  • FloorHugger - 35880
  • Кількістьодин - 35791
  • Переоцінка - 35791
  • Густав - 35484
  • Історик - 35201
  • Пробовідбірник - 34960
  • Інкрементер - 34351
  • JumpRightIn - 34074
  • Вікрі - 34020
  • Підліток - 33907
  • Ранду - 33891
  • Важка атлетика - 33682
  • Посередник - 33647
  • BounceInwards - 33529
  • NastyMathematician - 33292
  • Джемпер - 33244
  • Копікат - 33049

Повні результати можна знайти тут . (Я рекомендую вимкнути обгортку тексту.)


Чи є у мене якийсь спосіб сказати, який був мій власний номер у тих попередніх раундах?
Мартін Ендер

@ MartinBüttner No.
Ypnypn

1
Я не знаю жодної з цих мов :( Чи можете ви додати JavaScript? Як, запустіть його з node.js?
Cilan

1
@TheWobbuffet, я не знаю жодного з них. Це не завадило мені зробити запис на Python.
Марк

7
Я думаю, що було б цікавіше, якби пробіл був колом / циклом, щоб відстань між 1 і 999 дорівнювала 1. Це дозволило б "здогадатися про одне число кожного кроку" від домінування, оскільки немає "ребер" припаркуватися на. Очевидно, що занадто пізно, щоб змінити зараз;)
Геобіц

Відповіді:


9

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

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

Оскільки кожен виняток кидає 1, він тримається подалі від нього якомога більше. Заробляє свої статки за рахунок слабких.

Факт забави: я думав про вдосконалення, але не зміг знайти кращого способу, ніж просто сховатися у кутку.


1
Схоже, я вибрав неправильний кут. :(
TheNumberOne

Це добре з простої причини: інші намагаються мінімізувати відстань до вас. Вони автоматично покращать ваш рахунок. Змінник гри буде противником, який намагається максимально наблизитися до вас.
Мартін Тома

1
Eww ... крапка з комою в Python?
KSFT

@KSFT hehe Я іржавий на Python, і я ніколи не був таким експертом
clabacchio

6

Номер один, Java

Назва пояснює це повністю.

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

1
Чому голосування "за"?
TheNumberOne

5
Мені особливо подобається, як ім’я користувача зв’язується з поданням
Brian J

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

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).


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" виявилася досить успішною. :)
Еміль

На жаль, у коді є помилка, так - він ніколи насправді не аналізує бали, прочитані в останньому раунді. (Але я зрозумів це занадто пізно, і мені здалося неправильним редагувати подання до того часу, плюс, як ви кажете, це було дуже добре, так що ... як би там не було: p)
Алекс Уокер

4

Java - важкоатлет

Проведіть петлі через 1-999, щоб визначити, що було б найкращим для кожного раунду. Зважує їх відповідно до залишковості (останні раунди мають більшу вагу) та дає найкращі загальні здогадки. Сподіваємось, якщо візерунки формуватимуться в подальшому раунді, це вдасться підібрати на ньому.

Редагувати: Тепер з + інф% більше рекурсії! Неможливість зберігати / зберігати / бачити те, що ви вибрали у попередніх раундах - це тягар. Беручи свої власні входи до уваги столових вас при спробі з'ясувати , що інші будуть робити. Отже, давайте обчислимо це! Тепер це повториться, щоб зрозуміти, що він обрав у попередньому раунді, і проігнорувати це під час обчислення наступного кроку.

Зауважте, що він дійсно ігнорує свій власний внесок з останньої черги, але оскільки цей показник зважений найвищим, він, здається, працює нормально. Це може бути виправлено трохи більше роботи, але я зачекаю, поки таблиця лідерів побачить, чи потрібно.

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 раунді він закінчується за секунду на моєму дещо повільному ПК. Якщо з певних причин у вас буде занадто багато часу, дайте мені знати, щоб я міг обмежити рекурсію.
Геобіц

Це дуже швидко і на моїй машині.
Ypnypn

3

Рубі, Копікат

Просто повертає той номер, який виграв останній раз.

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

Наступні три програми вбудовані.

Високий (Ruby)

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

Пітон, пробник

Зі списку місць виберіть те, що знаходиться найдалі від останніх використаних номерів, ігноруючи попередній поворот.

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

NastyMathematician (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 500995)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.