Gardez vos distances sur un cercle

9

Ceci est basé sur ce défi et l'idée de Geobits / CarpetPython de l'améliorer:

Garde tes distances!

Pour ce défi, la distance entre deux nombres est mesurée sur une boucle, donc, par exemple, la distance entre 0 et 999 est 1. Cela devrait empêcher des stratégies comme de toujours choisir le numéro le plus bas ou le plus élevé de gagner presque à chaque fois. Le seul autre changement est que le nombre le plus bas qui peut être choisi est désormais 0 au lieu de 1.

Je vais le résumer ici:

  • Écrivez une fonction en Java, Python ou Ruby qui prend trois arguments:
    • le nombre de tours joués jusqu'à présent
    • le nombre de joueurs
    • les nombres choisis dans les tours précédents, comme un tableau de chaînes séparées par des espaces
  • Il doit renvoyer un entier de 0 à 999, inclus
  • Le score d'un programme à chaque tour est la somme des racines carrées des distances par rapport aux nombres choisis par chaque autre programme
  • Le programme avec le score le plus élevé après 100 rounds gagne.
  • Une réponse par personne

Le programme de contrôle est ici:

https://github.com/KSFTmh/src/

Classement

NumberOne, de TheBestOne, gagne.

  • NumberOne - 9700
  • NumberOnePlusFourNineNine - 9623
  • AncientHistorian - 9425
  • FindCampers - 9259
  • WowThisGameIsSoDeep - 9069
  • Échantillonneur - 9014
  • SabotageCampers - 8545

Apparemment, mon sabotage de campeur ... euh (?) Ne fonctionne pas très bien.

Voici les résultats complets: https://github.com/KSFTmh/src/blob/master/results-3

Je pense que c'est assez différent pour ne pas être un doublon.

Au fait, c'est la première fois que je pose une question sur Stack Exchange, alors faites-moi savoir si je fais quelque chose de mal.

KSFT
la source
4
Voulons-nous vraiment une question aussi similaire?
Optimizer
5
@Optimizer Quelques personnes dans les commentaires semblaient penser que c'était une bonne idée. Les réponses de l'original fonctionneront très différemment ici, donc je ne pense pas que ce soit un doublon.
KSFT
1
Le mérite d'avoir suggéré le défi devrait aller à @Geobits. Je suis juste d'accord avec lui.
Logic Knight
1
Mmm. Il semble qu'un nombre constant gagne à nouveau. Je suis curieux de savoir pourquoi. Pourrions-nous voir les 600 numéros de sortie dans la question, ou sur github ou pastebin? Je soupçonne que certains de nos prédicteurs ont des bogues. Peut-être le mien :-(
Logic Knight
1
@CarpetPython Un changement simple serait de calculer la distance entre les points du dernier tour en plus des points de ce tour.
TheNumberOne

Réponses:

3

Python 2, échantillonneur

Cette entrée est basée sur le même code pour Gardez vos distances, entrée Sampler . J'espère qu'il fera mieux ici où les avantages 1 et 999 n'existent pas.

Dans une liste de lieux, choisissez celui qui est le plus éloigné des numéros récemment utilisés, en ignorant le tour précédent (car d'autres entrées peuvent prédire sur la base du seul tour précédent).

def choose(turn, players, history):
    sample = map(int, (' '.join( history[-5:-1] )).split())
    def distance(x):
        return sum(min(1000-abs(x-y), abs(x-y))**0.5 for y in sample)
    score, place = max((distance(x), x) for x in range(1000))
    return place
Logic Knight
la source
Il semble que celui-ci soit gagnant, mais c'est peut-être parce que je ne compile pas correctement le contrôleur et que les autres plantent.
KSFT
2

Number OnePlusFourNineNine, Java

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

La logique est vraiment simple. À moins que quelqu'un ne trouve un véritable algorithme qui prenne en compte les scores précédents, cette réponse est assez optimisée.

Maintenant que nous comptons la distance dans un cercle, la distance maximale de deux points peut être de 500. Maintenant, si toutes les entrées généraient des nombres aléatoires (ou pseudo-aléatoires en fonction d'un algorithme), cette réponse n'aurait aucun avantage du tout . Mais il y a au moins 1 entrée qui produit une réponse constante dont une distance presque maximale. Cela fait que le score est en faveur de 500 car il y a une source fixe de distance maximale possible à chaque tour :)

Optimiseur
la source
Vous avez optimisé ma réponse. ;)
TheNumberOne
@TheBestOne haha
Optimizer
2

AncientHistorian - Python

Il s'agit du même algorithme que le précédent, sauf lors du calcul des scores potentiels, il utilise la distance circulaire. Comme je perds horriblement et que je n'arrive pas à compiler le contrôleur, j'essaie simplement une nouvelle stratégie, où j'utilise le pire des tours précédents.

def choose(round, players, scores):
    calc = lambda n, scores: sum([min(abs(int(i)-n), 1000-max(int(i),n)+min(int(i),n))**.5 for i in scores.split(' ')])
    return min(range(1000), key=lambda n: sum([calc(n, j) for j in scores[1:]])) if round>1 else 250
Maltysen
la source
Ça ne marche pas. iest un élément de scores.split(' '), ce qui signifie que c'est une chaîne, pas un entier.
KSFT
@KSFT oh shoot, j'aurais vraiment dû tester, mettre à jour.
Maltysen
2

SabotageCampers - Python

def choose(rounds, players, previous):
    if rounds<3:
        return 1
    prevchoices=[int(i) for i in " ".join(previous[-5:]).split(" ")]
    remove=[]
    for i in prevchoices:
        if prevchoices.count(i)<3:
            remove.append(i)
    campers=[i for i in prevchoices if i not in remove]
    return random.choice(campers)

Les campeurs gagnent toujours. Faites-moi savoir si vous avez des suggestions à ce sujet.

KSFT
la source
2

FindCampers - Python 2

Trouvez tous les campeurs des 10 derniers tours et restez loin d'eux. J'espère que les prédicteurs vont fuir de moi. Je vais maintenant ignorer mes anciens choix.

def choose(rounds, players, previous):
    from collections import Counter

    def distance(x, y):
        return min(1000 - abs(x-y), abs(x-y))

    pastRounds = list(map(lambda x: Counter(map(int, x.split())), previous))
    me = 751
    for (index, round) in enumerate(pastRounds):
        round.subtract((me,))
        pastRounds[index] = set(round.elements())
        campers = reduce(lambda x,y: x.intersection(y), pastRounds[max(1, index-9):index], pastRounds[max(0,index-10)])
        if campers:
            dist, me = max(min((distance(x, y), x) for y in campers) for x in range(1000))
        else:
            me = 751
    return me
Jmac
la source
Aww ... J'espérais que ça irait vers les campeurs quand j'ai vu le nom ...
KSFT
Lol. Je pourrais ajouter une entrée qui sabotera les campeurs.
Jmac
Malheureusement, je n'ai autorisé qu'une seule entrée par personne.
KSFT
Je viens de publier moi-même une entrée pour saboter les campeurs.
KSFT
Le mien ne fonctionne pas parce que je ne savais pas que les résultats précédents avaient été triés. Comment le vôtre détecte-t-il les campeurs?
KSFT
1

Numéro un, Java

La première réponse. Copié de ma réponse précédente .

public static int choose(int round, int players, String[] args) {
    return 1;
}
Le numéro un
la source
Quelqu'un semble avoir dévalorisé toutes les réponses.
KSFT
1

WowThisGameIsSoDeep, Java

J'ai analysé le jeu pendant 10 ans sur un cluster à 1 million de cœurs et trouvé la solution optimale.

public static int choose(int round, int players,String[]spam) { return(int)(Math.random()*1e3); }
feersum
la source
Ce n'est pas un code-golf
Optimizer
5
Cette solution n'est pas optimale. Si vous voulez une distribution uniforme, vous devez utiliser Random.nextInt(int).
Peter Taylor
Cela semble toujours revenir 1.
KSFT
@KSFT Je l'ai testé et j'ai obtenu de nombreux numéros différents. Peut-être que c'est du sabotage après tout?
feersum
4
Ah! Je l'ai corrigé! J'ai accidentellement tapé "WowThisGameIsSoDeep.py", et il essayait de l'exécuter en tant que fichier Python.
KSFT
1

Extrapolateur circilinéaire, Ruby

def choose(round, players, previous_choices)
  previous_rounds = previous_choices.map{ |round| round.split.map(&:to_i) }
  optimal_past_choices = previous_rounds.map do |choices|
    (0..999).max_by { |i| choices.map{ |c| root_distance(i,c) }.inject(:+) }
  end
  if (last_round = optimal_past_choices.last)
    (last_round + average_delta(optimal_past_choices).round) % 1000
  else
    750
  end
end

def root_distance(i,j)
  dist = (i-j).abs
  dist = [dist, 1000 - dist].min
  dist ** 0.5
end

def directed_distance(i,j)
  dist = j - i
  if dist > 500
    dist - 1000
  elsif dist < -500
    dist + 1000
  else
    dist
  end
end

def average_delta(ary)
  ary.each_cons(2).map{ |x,y| directed_distance(x,y) }.inject(0,:+)/ary.count
end
histocrate
la source
Cela donne cette erreur:NoMethodError: undefined method `split' for #<Array:0x720f56e2> choose at CircilinearExtrapolator.rb:2
KSFT
Oh, est previous_choicesun tableau de valeurs comme ["1 6 500","2 8 503"]?
histocrate
C'est. Pensiez-vous que c'était autre chose? Sinon, je viens de gâcher quelque chose en le faisant fonctionner.
KSFT
Je pensais que c'était juste une chaîne plate, désolé. Je vais éditer.
histocrate
Édité. Maintenant, tout le monde sait que j'ai posté quelque chose sans le tester ...
histocrat