Mantieni le distanze!


15

Ogni giocatore ha un numero. Il tuo può essere il più lontano da tutti?

Requisiti

Scrivi una funzione Java, Python 2 o Ruby denominata choose()che accetta tre argomenti:

  • un numero intero: il numero di round già completati
  • un numero intero - il numero di giocatori
  • una matrice di stringhe: i risultati di ogni round precedente
    • ogni stringa è un elenco di numeri interi separati da spazio, ordinati dal più basso al più alto

Ad esempio, choose(2, 4, ["4 93 93 174", "1 84 234 555"])significa:

  • c'erano già due round (questo è il terzo round)
  • ci sono un totale di quattro giocatori
  • nel primo turno, i numeri scelti erano 4, 93, 93, 174
  • nel secondo turno, i numeri scelti erano 1, 84, 234, 555

È necessario restituire un numero intero compreso tra 1 e 999 (incluso).

Per ogni altro giocatore, il tuo punteggio è la radice quadrata della distanza tra il tuo numero e il loro. Il tuo punteggio per il round è il totale di tutti questi punteggi.

Verranno giocati 100 round. Il punteggio totale più alto vince!

Regole

  • Il codice non può utilizzare alcun I / O, inclusi console, file, rete, ecc.
  • Non puoi interferire con il programma di controllo o con altri giocatori.
  • I programmi che sembrano violare le regole di cui sopra saranno esclusi.
  • Ogni chiamata di una funzione dovrebbe richiedere meno di cinque secondi sul mio computer (Intel Core i5 2450M con 8 GB di RAM).
  • Se un programma genera un'eccezione o restituisce un valore non valido, verrà trattato come se avesse restituito 1.
  • Ogni utente può presentare al massimo un programma.

miscellaneo

  • Il programma di controllo è su GitHub .
  • Ci sono tre giocatori integrati. Si possono trovare in questa risposta .
  • Il vincitore sarà scelto il 28 gennaio.

Classifica

Il vincitore è Conservator .

Menzione d'onore a Gustav , il giocatore con il punteggio più alto con una strategia non costante.

  • Conservatore - 36226
  • Alta - 36115
  • FloorHugger - 35880
  • NumberOne - 35791
  • Sovrastimatore - 35791
  • Gustav - 35484
  • Storico - 35201
  • Campionatore - 34960
  • Incrementatore - 34351
  • JumpRightIn - 34074
  • Vickrey - 34020
  • Adolescente - 33907
  • Randu - 33891
  • Sollevatore di pesi - 33682
  • Middleman - 33647
  • BounceInwards - 33529
  • Cattivo matematico - 33292
  • Maglione - 33244
  • Copione - 33049

I risultati completi possono essere trovati qui . (Consiglio di disabilitare la disposizione del testo.)


Posso dire qual era il mio numero in quei round precedenti?
Martin Ender,

@ MartinBüttner No.
Ypnypn,

1
Non conosco nessuna di quelle lingue :( Potresti aggiungere JavaScript? Ad esempio, eseguirlo con node.js?
Cilan,

1
@TheWobbuffet, neanche io ne conosco nessuno. Non mi ha impedito di scrivere Python.
Segna il

7
Penso che sarebbe stato più interessante se lo spazio fosse un cerchio / anello in modo che la distanza tra 1 e 999 sia 1. Ciò impedirebbe al dominio di "indovinare un singolo numero ogni giro", poiché non ci sono "bordi" per parcheggiare. Ovviamente è troppo tardi per cambiare adesso;)
Geobits il

Risposte:


9

Python, Conservatore

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

Poiché ogni eccezione genera 1, si allontana il più possibile da essa. Fa fortuna a spese dei deboli.

Curiosità: ho pensato di migliorarlo, ma non sono riuscito a trovare un modo migliore di nascondermi in un angolo.


1
Sembra che abbia scelto l'angolo sbagliato. :(
TheNumberOne

È buono per un semplice motivo: gli altri cercano di ridurre al minimo la distanza da te. Miglioreranno automaticamente il tuo punteggio. Un punto di svolta sarebbe un avversario che cerca di avvicinarsi il più possibile a te.
Martin Thoma,

1
Eww ... un punto e virgola in Python?
KSFT,

@KSFT hehe Sono arrugginito su Python e non sono mai stato così esperto
clabacchio

6

Numero uno, Java

Il nome lo spiega completamente.

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

1
Perché il voto negativo?
TheNumberOne il

5
Mi piace soprattutto come il nome utente si lega alla presentazione
Brian J

5

Python, AncientHistorian

Crede fermamente che il futuro sarà esattamente come il passato, ma crede che l'ultimo round sia troppo recente per essere histiry, quindi passa da 1 a 999 e sceglie quale sarebbe stato il migliore dei round precedenti se non l'ultimo. Il primo 2 round restituisce 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, 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)

Crea un elenco di numeri che sono stati giocati spesso, presume che tutti giocheranno in modo ottimale e opta per il secondo scelta migliore data l'elenco.

Ad esempio, se i numeri più comuni sono [1, 990, 999], allora Vickrey inserisce il gioco ottimale 200 da dare [1, 200, 990, 999], quindi seleziona l'opzione migliore per il nuovo array (che è 556).


4

Java, sovrastimatore

Come suggerisce il nome, questo programma presume che tutti gli altri programmi proveranno a giocare "bene" selezionando la risposta migliore in base all'ultimo round - quindi questo "sovrastimatore" sceglie sempre la peggiore posizione possibile in base al round precedente.

 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;
 }

Come mai questo ha giocato un "1" costante? C'è stato un bug? Intendiamoci, suonare "1" ha avuto molto successo. :)
Emil,

Purtroppo il codice ha un bug, sì - non analizza mai realmente i punteggi che legge dall'ultimo round. (Ma me ne sono reso conto troppo tardi e a quel punto mi è sembrato sbagliato modificare una proposta, più come dici che stava andando abbastanza bene quindi ... qualunque cosa: p)
Alex Walker,

4

Java - Sollevatore di pesi

Passa attraverso 1-999 per capire quale sarebbe la migliore per ogni round. Li pesa in base alla recency (i round recenti hanno più peso) e restituisce la migliore ipotesi generale. Spero che se si formano dei modelli in un secondo momento, questo sarà in grado di riprenderlo.

Modifica: ora con + Inf% ricorsione in più! Non essere in grado di memorizzare / salvare / vedere ciò che hai scelto nei round precedenti è un trascinamento. Prendere in considerazione i tuoi input ti incasina quando cerchi di capire cosa faranno gli altri . Quindi, calcoliamolo! Questo ora riporterà a capire cosa ha scelto nel round precedente e lo ignorerà quando calcolerà la mossa successiva.

Nota che ignora davvero il proprio input dall'ultimo turno, ma dato che quello è ponderato più in alto, sembra funzionare bene. Questo potrebbe essere risolto con un po 'più di lavoro, ma aspetterò la classifica per vedere se è necessario.

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;
}

Nota: anche al round 100, si completa in meno di un secondo sul mio PC un po 'lento. Se per qualche motivo è necessario troppo tempo per il tuo, fammi sapere in modo da poter limitare la ricorsione.
Geobits il

È molto veloce anche sulla mia macchina.
Ypnypn,

3

Rubino, Copione

Restituisce semplicemente il numero vinto l'ultima volta.

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
Cosa restituisce per il primo round? Oh non importa. Le eccezioni restituirebbero 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

È probabilmente la strategia più diretta. Trova il gap più grande nell'ultimo round e sceglie il numero proprio nel mezzo di quel gap.


Cosa restituisce per il primo round? 1?
mbomb007,

@ mbomb007 Oh, dimentico sempre questi fastidiosi round iniziali. Grazie, ora restituisce 500.
Martin Ender,

3

Gustav (Python 2)

Questa è una meta strategia piuttosto semplice, copiata senza vergogna da una delle mie vecchie risposte in una sfida KotH simile. Considera alcune semplici strategie, osserva come si sarebbero comportati in tutti i round precedenti, quindi segue il punteggio più alto per il round successivo.

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]

Mi rendo conto ora che l'algoritmo presenta ancora alcuni difetti. Ad esempio, potrebbe continuare a "rincorrere se stesso" perché non distingue le sue mosse da quelle degli avversari. Tuttavia, lo lascerò così per ora.



1

I seguenti tre programmi sono integrati.

Alta (Rubino)

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

Incrementatore (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, Sampler

Da un elenco di luoghi, scegli quello più lontano dai numeri utilizzati di recente, ignorando il turno precedente.

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

A partire da 1, si avvicina gradualmente a 500 mentre rimbalza tra l'opzione superiore e quella inferiore.

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

1

NastyMathematician (Java)

Esamina gli ultimi due round (se i numeri migliori erano 70 e 80, produrrà 90). È brutto perché cerca di prendere il maggior numero possibile per vincere contro i suoi avversari.

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 - Non voglio pensare a un nome ...

Se la media dei numeri scelti nei round precedenti è inferiore a 500, seleziona 999. Seleziona 1 altrimenti.

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 (basato sul conservatore di @clabacchio)

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

Dopo aver notato che il bordo superiore ha un punteggio alto (e ha sovraperformato il bordo inferiore), mi chiedevo se potesse esserci qualcosa di peggio che rimanere intrappolati nel mezzo.


0

Maglione (Ruby)

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

Si alterna tra basso, medio e alto. (5.500.995)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.