Bleib auf Abstand!

15

Jeder Spieler hat eine Nummer. Kann deins am weitesten von allen entfernt sein?

Bedarf

Schreiben Sie eine Java-, Python 2- oder Ruby-Funktion mit dem Namen choose(), die drei Argumente akzeptiert:

  • eine ganze Zahl - die Anzahl der bereits abgeschlossenen Runden
  • eine ganze Zahl - die Anzahl der Spieler
  • eine Reihe von Zeichenfolgen - die Ergebnisse jeder vorherigen Runde
    • Jede Zeichenfolge ist eine durch Leerzeichen getrennte Liste von Ganzzahlen, die vom niedrigsten zum höchsten Wert sortiert sind

Zum Beispiel choose(2, 4, ["4 93 93 174", "1 84 234 555"])bedeutet:

  • Es gab bereits zwei Runden (dies ist die dritte Runde)
  • Es gibt insgesamt vier Spieler
  • In der ersten Runde wurden die Zahlen 4, 93, 93, 174 gewählt
  • In der zweiten Runde wurden die Zahlen 1, 84, 234, 555 gewählt

Sie müssen eine ganze Zahl von 1 bis 999 (einschließlich) zurückgeben.

Für jeden anderen Spieler ist Ihre Punktzahl die Quadratwurzel des Abstandes zwischen Ihrer und ihrer Zahl. Ihre Punktzahl für die Runde ist die Summe aller dieser Punkte.

Es werden 100 Runden gespielt. Die höchste Gesamtpunktzahl gewinnt!

Regeln

  • Ihr Code verwendet möglicherweise keine E / A, einschließlich Konsole, Dateien, Netzwerk usw.
  • Sie dürfen weder das Steuerungsprogramm noch andere Spieler stören.
  • Programme, die gegen die oben genannten Regeln verstoßen, werden ausgeschlossen.
  • Jeder Aufruf einer Funktion sollte auf meinem Computer (Intel Core i5 2450M mit 8 GB RAM) weniger als fünf Sekunden dauern.
  • Wenn ein Programm eine Ausnahme auslöst oder einen ungültigen Wert zurückgibt, wird es so behandelt, als ob es 1 zurückgibt.
  • Jeder Benutzer darf höchstens ein Programm einreichen.

Sonstiges

Bestenliste

Der Gewinner ist Conservator .

Lobende Erwähnung an Gustav , den Spieler mit der höchsten Punktzahl und einer nicht konstanten Strategie.

  • Konservator - 36226
  • Hoch - 36115
  • FloorHugger - 35880
  • NumberOne - 35791
  • Overestimator - 35791
  • Gustav - 35484
  • Historiker - 35201
  • Sampler - 34960
  • Inkrementierer - 34351
  • JumpRightIn - 34074
  • Vickrey - 34020
  • Teenager - 33907
  • Randu - 33891
  • Gewichtheber - 33682
  • Middleman - 33647
  • BounceInwards - 33529
  • NastyMathematician - 33292
  • Jumper - 33244
  • Nachahmer - 33049

Die vollständigen Ergebnisse finden Sie hier . (Ich empfehle, den Zeilenumbruch zu deaktivieren.)

Ypnypn
quelle
Habe ich irgendeine Möglichkeit zu sagen, welche Nummer in den vorherigen Runden meine eigene war?
Martin Ender
@ MartinBüttner Nr.
Ypnypn
1
Ich kenne keine dieser Sprachen :( Könnten Sie JavaScript hinzufügen? Wie, führen Sie es mit node.js?
Cilan
1
@TheWobbuffet, ich kenne auch keinen von ihnen. Hielt mich nicht davon ab, einen Python-Eintrag zu machen.
Mark
7
Ich denke, es wäre interessanter gewesen, wenn der Raum ein Kreis / eine Schleife gewesen wäre, so dass der Abstand zwischen 1 und 999 gleich 1 wäre. Das würde verhindern, dass "jede Runde eine einzelne Zahl erraten" dominiert, da es keine "Kanten" gibt. zum parken auf. Offensichtlich zu spät, um jetzt zu wechseln;)
Geobits

Antworten:

9

Python, Konservator

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

Da jede Ausnahme 1 wirft, bleibt sie so weit wie möglich davon entfernt. Macht sein Vermögen auf Kosten der Schwachen.

Witzige Tatsache: Ich dachte darüber nach, es zu verbessern, konnte aber keinen besseren Weg finden, als mich nur in einer Ecke zu verstecken.

Clabacchio
quelle
1
Sieht so aus, als hätte ich die falsche Ecke gewählt. :(
TheNumberOne
Es ist aus einem einfachen Grund gut: Andere versuchen, die Entfernung zu Ihnen zu minimieren. Sie verbessern automatisch Ihre Punktzahl. Ein Game Changer wäre ein Gegner, der versucht, so nah wie möglich an dich heranzukommen.
Martin Thoma
1
Eww ... ein Semikolon in Python?
KSFT
@KSFT hehe Ich bin rostig auf Python, und ich war sowieso noch nie so Experte
Clabacchio
6

Nummer eins, Java

Der Name erklärt dies vollständig.

public static int choose(int round, int players, String[] args) {
    return 1;
}
Die Nummer eins
quelle
1
Warum abstimmen?
TheNumberOne
5
Mir gefällt besonders, wie der Benutzername mit dem Beitrag zusammenhängt
Brian J
5

Python, AncientHistorian

Ist der festen Überzeugung, dass die Zukunft genau wie die Vergangenheit sein wird, glaubt jedoch, dass die letzte Runde zu aktuell ist, um noch nicht abgeschlossen zu sein. Sie durchläuft also nur 1 - 999 und wählt aus, welche der vorherigen Runden mit Ausnahme der letzten die besten gewesen wären. Die ersten 2 Runden bringen 500 zurück.

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
quelle
4

Python, Vickrey

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)

Erstellt eine Liste mit häufig gespielten Zahlen, setzt voraus, dass alle anderen optimal spielen, und entscheidet sich für die zweite beste Wahl die Liste gegeben.

Wenn zum Beispiel die häufigsten Zahlen sind [1, 990, 999], fügt Vickrey das optimale Spiel 200 ein, um es zu geben [1, 200, 990, 999], und wählt dann die beste Option für das neue Array aus (das ist 556).

Sp3000
quelle
4

Java, Overestimator

Wie der Name schon sagt, geht dieses Programm davon aus, dass alle anderen Programme versuchen werden, "gut" zu spielen, indem sie die beste Antwort basierend auf der letzten Runde auswählen. Daher wählt dieser "Überschätzer" immer die schlechteste Position basierend auf der vorherigen Runde.

 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;
 }
Alex Walker
quelle
Wie kommt es, dass dies eine konstante "1" spielte? Gab es einen Fehler? Wohlgemerkt, "1" zu spielen erwies sich als ziemlich erfolgreich. :)
Emil
Leider hat der Code einen Fehler, ja - er analysiert niemals die Ergebnisse, die er in der letzten Runde gelesen hat. (Aber ich habe es zu spät gemerkt und es schien falsch, eine Einsendung bis dahin zu bearbeiten, und wie Sie sagten, lief es ziemlich gut, so ... wie auch immer: p)
Alex Walker
4

Java - Gewichtheber

Durchläuft 1-999, um herauszufinden, welches für jede Runde das Beste ist. Wiegt sie nach Aktualität (die letzten Runden haben mehr Gewicht) und gibt die beste Gesamtschätzung zurück. Wenn sich später Muster bilden, können diese hoffentlich aufgreifen.

Edit: Jetzt mit + Inf% mehr Rekursion! Nicht in der Lage zu sein, zu speichern oder zu sehen, was Sie in früheren Runden ausgewählt haben, ist ein Hindernis. Wenn Sie Ihre eigenen Eingaben berücksichtigen, werden Sie durcheinander gebracht, wenn Sie versuchen, herauszufinden, was andere tun werden. Also, lasst es uns berechnen! Dies wird nun wiederkehren, um herauszufinden, was es in der vorherigen Runde gewählt hat, und dies ignorieren, wenn der nächste Zug berechnet wird.

Beachten Sie, dass es nur seine eigenen Eingaben aus der letzten Runde wirklich ignoriert, aber da diese am höchsten gewichtet sind, scheint es in Ordnung zu funktionieren. Dies könnte mit ein bisschen mehr Arbeit behoben werden, aber ich werde auf die Bestenliste warten, um zu sehen, ob sie benötigt wird.

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
quelle
Hinweis: Selbst in Runde 100 dauert es auf meinem etwas langsamen PC weniger als eine Sekunde. Wenn es Ihnen aus irgendeinem Grund zu lange dauert, lassen Sie es mich wissen, damit ich die Rekursion einschränken kann.
Geobits
Es ist auch sehr schnell auf meiner Maschine.
Ypnypn
3

Ruby, Nachahmer

Gibt einfach die Zahl zurück, die beim letzten Mal gewonnen wurde.

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
Türknauf
quelle
1
Was kehrt es für die erste Runde zurück? Vergiss es. Ausnahmen würden 1 zurückgeben.
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

Es ist wahrscheinlich die einfachste Strategie. Es findet die größte Lücke in der letzten Runde und wählt die Zahl genau in der Mitte dieser Lücke.

Martin Ender
quelle
Was kehrt es für die erste Runde zurück? 1?
mbomb007
@ mbomb007 Oh, ich vergesse immer diese lästigen ersten Runden. Danke, es gibt jetzt 500 zurück.
Martin Ender
3

Gustav (Python 2)

Dies ist eine ziemlich direkte Metastrategie , die schamlos von einer meiner alten Antworten in einer ähnlichen KotH-Herausforderung kopiert wurde. Es werden ein paar einfache Strategien betrachtet, wie sie sich in allen vorherigen Runden entwickelt hätten, und dann die höchste Punktzahl für die nächste Runde.

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]

Mir ist jetzt klar, dass der Algorithmus noch einige Fehler aufweist. ZB könnte es "sich selbst jagen", weil es seine eigenen Züge nicht von denen der Gegner unterscheidet. Ich lasse es aber erstmal so.

Emil
quelle
1

Die folgenden drei Programme sind integriert.

Hoch (Rubin)

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

Inkrementierer (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
quelle
1

Python, Sampler

Wählen Sie aus der Liste der Orte den aus, der von den zuletzt verwendeten Zahlen am weitesten entfernt ist, und ignorieren Sie dabei den vorherigen Zug.

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
Logik-Ritter
quelle
1

Java, BounceInwards

Ab 1 nähert es sich allmählich dem Wert 500, während zwischen der höheren und der niedrigeren Option gewechselt wird.

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

NastyMathematician (Java)

Untersucht die letzten beiden Runden (wenn die besten Zahlen 70 und 80 waren, wird 90 ausgegeben). Es ist böse, weil es versucht, so viele Zahlen wie möglich zu sammeln, um gegen seine Gegner zu gewinnen.

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
quelle
1

Python - Ich möchte nicht an einen Namen denken ...

Wenn der Durchschnitt der in den letzten Runden gewählten Zahlen weniger als 500 beträgt, werden 999 ausgewählt. Andernfalls wird 1 ausgewählt.

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
quelle
0

Python, Middleman (basierend auf Conservator von @clabacchio)

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

Nachdem ich gemerkt hatte, dass die obere Kante hoch abschneidet (und die untere Kante übertrifft), fragte ich mich, ob es etwas Schlimmeres geben könnte, als nur in der Mitte hängen zu bleiben.

Dennis Jaheruddin
quelle
0

Jumper (Rubin)

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

Wechselt zwischen unten, Mitte und oben. (5.500.995)

MegaTom
quelle