Dilemme du prisonnier avec accès à l'adversaire

21

Dans ce défi, vous écrirez un bot qui joue le dilemme du prisonnier. Voici le hic: vous n'aurez pas accès à l'historique des jeux précédents. Au lieu de cela, vous aurez accès à l'adversaire lui-même. Dans cette version, les deux joueurs gagnent +2 points s'ils coopèrent tous les deux, +1 points s'ils font tous les deux défaut, et si l'un coopère mais un défaut, le transfuge gagne +3 tandis que l'autre n'obtient aucun point. Chaque soumission sera jouée contre chaque autre soumission, y compris elle-même, 10 fois. Le gagnant est la soumission avec le plus de points.

Contrôleur : vous devez écrire une fonction javascript, sous la forme

function submissionName(them) {
  /* Your code here */
}

Le contrôleur utilise la namepropriété de la fonction pour afficher les résultats, donc s'il n'est pas dans ce format (et est à la place f = x => ...ou f = function() { ... }), il sera difficile de voir votre score et vous ne pourrez pas accéder à votre propre fonction.

La fonction acceptera un paramètre: themqui est la fonction de l'adversaire. Il peut alors appeler cette fonction pour voir quelle réaction de l'adversaire se verrait attribuer certaines fonctions en entrée. Sur la base de ces données, vous devez renvoyer «C» ou «D» respectivement pour coopérer ou pour défaut.

Exemples (seront en compétition):

function cooperate(them) {
    return 'C';
}

function defect(them) {
    return 'D';
}

function nice(them) {
    // Do whatever they would do when faced with a cooperator
    return them(wrap(_ => 'C'));
}

Le contrôleur est disponible ici

Règles :

  • Vous ne pourrez pas voir le code de l'adversaire lui-même. Toutes les fonctions sont encapsulées de sorte qu'elles se ressemblent lors de l' toString()appel. La seule façon d'examiner un adversaire (qui pourrait être vous-même) est de le tester.
  • Votre fonction n'a pas à être déterministe. Vous ne pouvez enregistrer l'état qu'en définissant des propriétés sur votre propre fonction, telles que submissionName.state = {};. Cependant, entre les matchs (même entre les matchs des mêmes joueurs), l'état est effacé en appelant toString()et eval. Par conséquent, il n'y a pas de mémoire des correspondances précédentes.
  • L'ordre dans lequel la fonction est appelée en premier dans chaque correspondance est aléatoire.
  • Si votre code renvoie une erreur, il sera traité comme si vous aviez coopéré pendant que votre adversaire faisait défection. Si vous êtes le premier à courir, le code de l'adversaire ne sera même pas appelé. Cela se produit même si l'erreur se produit dans le code de votre adversaire pendant que vous appelez them. Méfiez-vous des erreurs de débordement de pile, surtout si votre code appelle them(wrap(submissionName)), car elles pourraient faire de même.
  • Vous ne pouvez pas accéder à la variable selfou à toute autre variable qui se trouve être dans la portée lorsqu'elle evalest appelée SAUF la fonction wrap. Cette fonction vous permet d'appeler l'adversaire d'une manière qui ne se distingue pas de la façon dont le contrôleur appelle une fonction. Vous ne pouvez pas écrire Math, windowetc. (Vous pouvez utiliser des fonctions telles que Math.random(), cependant).
  • Vous ne pouvez pas accéder à la trace de pile en créant un Errorou par une autre méthode.

Une note pour prendre trop de temps: veuillez éviter de rester coincé dans un whileboucle pour toujours. Le temps combiné des deux concurrents ne doit pas dépasser 1 seconde dans une manche donnée. Pour appliquer cela, un timeout aléatoire entre 1000 ms et 2000 ms est choisi (c'est pour éviter de jouer en attendant intentionnellement un temps connu), et si le travailleur met plus de temps à s'exécuter, une erreur sera lancée. Si cela se produit, la cause de l'erreur sera déterminée comme suit: l'exécution sera interrompue à un moment aléatoire après 1000 ms et la pile d'appels à ce moment sera inspectée. Le concurrent le plus récemment appelé qui est actuellement dans une boucle (ou une récursion de type boucle, dans le sens où il s'agit d'une récursivité configurée pour éviter une erreur de débordement de pile) sera blâmé. Si le même concurrent est blâmé d'avoir causé plusieurs fois une erreur de "prise trop longue", ce concurrent sera disqualifié.

soktinpk
la source
Ce défi me rappelle la vente aux enchères de billets d'un dollar .
Alion
La fonction utilisée pour tester doit-elle themêtre déterministe / suivre les règles? Par exemple function me(them){let log=0;them(x=>{++log;return 'C';}); retourner le journal == 0? 'D': 'C';}
user202729
2
Si les deux fonctions les appellent (wrap (quelque chose)), comment pouvez-vous empêcher la récursivité? Suis-je en train de manquer quelque chose?
Quintec
@Quintec, vous pouvez utiliser la récursivité et les boucles. C'est juste que la récursivité doit entraîner une StackOverflowerreur et non une boucle infinie qui ne se ferme jamais. Si cela peut entraîner un StackOverflow, assurez-vous d'ajouter une instruction try-catch. Pour un exemple de récursivité qui n'atteint pas une erreur de stackoverflow en 1 seconde, vous avez besoin d'exemples plus obscurs comme stackoverflow.com/q/12438786/3371119
soktinpk
1
@Quintec pas nécessairement. Par exemple, them(() => 'C')ne résulterait pas en une erreur car lorsque l'adversaire appelle them, il appelle la () => 'C'fonction. La seule chose qui doit être enveloppée try-catchserait si vous appelez themavec un paramètre d'une fonction qui appelle themavec un paramètre d'une fonction qui appelle themetc. (infiniment). Par exemple, them(t => t(() => 'C'))jouerait tout ce que l'adversaire jouerait si l'adversaire pensait qu'il jouait nice. Il n'y a aucune possibilité d' stackoverflowerreur.
soktinpk

Réponses:

14

BoomBot

function boom(them) {
  throw 1;
}

Si l'adversaire est exécuté en premier et l'appelle sans try..catch, ce bot gagne automatiquement 3 points. Zéro point dans tous les autres cas.

Bubbler
la source
Si l'adversaire est exécuté en premier et n'appelle pas cela, il perdra 3 points, non?
user202729
1
@ user202729 Plus précisément, l'adversaire obtiendra 3 points. Il n'y a pas de points perdants dans ce match.
Bubbler
10

Archéoptéryx

function archaeopteryx(them) {
  const guard = them => us => {
    try {
      return them(wrap(them => us(guard(them))));
    } catch (e) {
      return 'C';
    }
  };
  const f = guard(them);
  return f(f => 'C') == 'C' ? f(f => 'D') : f(f => 'D') == 'C' || f(f => f(f => 'C')) == 'C' ? 'D' : 'C';
}
  • Si l'adversaire coopère cooperate, imitez le mouvement de l'adversaire defect.
  • Sinon, si l'adversaire coopère avec defectou avec nice, alors défaut.
  • Sinon, coopérez.

Qu'est-ce qui en fait une bonne stratégie? Je n'ai aucune idée. Je l'ai généré en utilisant un algorithme évolutif, formé en partie sur les soumissions actuelles.

Tiktaalik

function tiktaalik(them) {
  const guard = them => us => {
    try {
      return them(wrap(them => us(guard(them))));
    } catch (e) {
      return 'C';
    }
  };
  const f = guard(them);
  return f(f => 'C') == 'D' ? f(f => 'D') == 'C' ? 'D' : 'C' : f(f => 'D') == 'D' ? 'D' : f(f => f(f => 'D'));
}
  • Si l'adversaire fait défaut contre cooperate, alors inversez le mouvement de l'adversaire contre defect.
  • Sinon, si l'adversaire fait défaut defect, alors il fait défaut.
  • Sinon, imitez le mouvement de l'adversaire notNice.

Une autre stratégie générée par l'évolution.

Anders Kaseorg
la source
6

WhatWouldBotDoBot

function WWBDB(them) {
    let start = performance.now();
    let cc = 0, cd = 0, dc = 0, dd = 0;
    try {
        for (let i = 0; i < 10; i++) {
            them(() => 'C') == 'C' ? cc++ : cd++;
            them(() => 'D') == 'C' ? dc++ : dd++;
            if (performance.now() - start > 500) break;
        }
    }
    catch (e) {}
    return 2 * cc >= 3 * dc + dd ? 'C' : 'D';
}

WhatWouldBotDoBot est assez simple; il teste simplement son adversaire pour ce qu'il ferait contre un programme en régime permanent. Si un bot préfère coopérer si possible, WWBDB préfèrera également la coopération (donc il coopérera avec le gentil bot). La WWBDB ne préfère pas elle-même la coopération.

Spitemaster
la source
5

Vérifier avec état

function checkStateful(them) {
  let stateful = false;
  let response = 'D';
  try {
    response = them(wrap(function (them) {
      stateful = true;
      return 'C';
    }));
  } catch (e) {
  }
  if (stateful) {
    return 'D';
  }
  return response;
}

S'ils m'invoquent, alors ils seront probablement vraiment eux. Nous agissons comme transfuge. S'ils ne m'invoquent pas, alors ils seront probablement un testeur emballé. Nous serions plus gentils.


Ci-dessus est la réponse originale. Et peut-être que je devrais me faire une coopération pour gagner plus de points.

Vérifiez l'état avec l'auto-coop

function checkStatefulSelfCoop(them) {
  let stateful = false;
  let response = 'D';
  if (!checkStatefulSelfCoop.invokeCounter) {
    checkStatefulSelfCoop.invokeCounter = 0;
  }
  let lastInvoke = ++checkStatefulSelfCoop.invokeCounter;
  try {
    response = them(wrap(function (them) {
      stateful = true;
      return 'C';
    }));
  } catch (e) {
  }
  if (checkStatefulSelfCoop.invokeCounter > lastInvoke) {
    return 'C';
  }
  if (stateful) {
    return 'D';
  }
  return response;
}
tsh
la source
4

RandomBot

function rand(them) {
  return 'CD'[Math.random() * 2 | 0]
}

Parce que pourquoi pas.

Bubbler
la source
3

Complexité

function complexity(them) {
    try {
        let coop_w_def = them(wrap(() => "D")) == "C",
            coop_w_coop = them(wrap(() => "C")) == "C",
            coop_w_nice = them(wrap((a) => a(wrap(() => "C")))) == "C",
            coop_w_nnice = them(wrap((a) => a(wrap(() => "D")))) == "C";
        if (coop_w_def && coop_w_coop && coop_w_nice && coop_w_nnice) return "C";
        let def_w_def = them(wrap(() => "D")) == "D",
            def_w_coop = them(wrap(() => "C")) == "D",
            def_w_nice = them(wrap((a) => a(wrap(() => "C")))) == "D",
            def_w_nnice = them(wrap((a) => a(wrap(() => "D")))) == "D";
        if (def_w_def && def_w_coop && def_w_nice && def_w_nnice) return "C";
    } catch (e) {}
    return "D";
}

Tests de complexité pour voir si le bot est Coopérer ou Défaut. S'il l'est, il coopère, mais s'il ne l'est pas, il fait défaut. Tous les bots actuels qui testent leurs adversaires utilisent des fonctions simples pour tester les réponses, donc Complexity fera simplement semblant de coopérer dans ces cas.

Spitemaster
la source
3
function onlyTrustYourself(them) {

  function tester (){
  }

  onlyTrustYourself.activated = false;

  try{them(tester);}
  catch(e){}

  if(them.name == "tester")
  {
    onlyTrustYourself.activated = true;
  }

  if(onlyTrustYourself.activated)
  {
    return 'C';
  }

  return 'D';
}

Comment je veux que cela fonctionne, c'est toujours un défaut, sauf en jouant contre soi-même. Il essaie de le faire en passant une fonction "testeur" qui ne leur est pas encapsulée, et il essaie de détecter si "eux" est nommé testeur. S'il est nommé testeur, il change la variable statique activée en true, puis renvoie coopère. Mais ça ne marche pas. Je ne suis pas trop familier avec javascript, et je vais probablement apporter quelques modifications supplémentaires.

Incarnation de l'ignorance
la source
idée intelligente, mais que se passe-t-il lorsqu'un autre frère fait une testerfonction: D
V. Courtois
2

Pas gentil

function NotNice(them) {
  return them(wrap(_ => "D"))
}

Imite la réaction de l'adversaire à la déviation

Erreur fatale
la source
2

NotNice 2

function notNice2(them) {
  try {
    return them(wrap(_ => 'D'));
  } catch(e) {
    return 'D';
  }
}

Version anti-boom de NotNice par FatalError .

Bubbler
la source
2

Bon sens

function commonSense(them) {
  try {
    var ifC = them(wrap(_ => 'C'));
    var ifD = them(wrap(_ => 'D'));

    if (ifD === 'C') {
      return 'D';
    }

    return them(_ => ifC);
  } catch (e) {
    return 'D';
  }
}

Avertissement: je ne connais pas javascript.

Si vous pouvez profiter d'une bonne personne, faites-le. Sinon, restituez ce qu'ils retourneraient s'ils se trouvaient confrontés à une coopération (du moins, c'est ce que je pense que cela fait).

Quintec
la source
2

Et toi, où veux-tu aller? (inspiré des volumes du livre de la jungle)

    fonctionner vous-même (eux) {
      essayer{
        retournez-les (ceci);
      } catch (e) {
        retourner "D";
      }
    }

   fonctionner vous-même_non_ce (eux) {
      essayer{
        retournez-les (vous-même_non_cette);
      } catch (e) {
        retourner "D";
      }
    }
TS
la source
Cela vient de gagner dans un tournoi que j'ai couru. Bon travail!
MegaTom
Je viens de remarquer que ce bot viole les règles. "Vous ne pouvez pas accéder à la variable self ..." thisest identique à self. Je pense que tu voulais dire return them(yourself).
MegaTom
Technicaly ( xkcd.com/1475 );) thisn'est pas une variable, c'est un mot-clé, et dans le contexte d'une fonction this!=self. selfsignifierait l'objet fenêtre et thisla fonction elle-même (fait toujours référence au contexte dans lequel il se trouve, c'est pourquoi il n'est pas considéré comme une variable). C'est pourquoi avoir var self = this;au début de nombreux exemples de code peut être considéré comme trompeur. Version ajoutée sans le "this"
TS
1
Non thisne fait pas référence à la fonction. yourselfet yourself_no_thisexécuter varient différemment. thisne fait essentiellement jamais référence à la fonction en javascript. Voir: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
MegaTom
2

Punir les inspecteurs

Donnez du code au bot et voyez s'il l'exécute. S'il a été exécuté plus d'une fois, le bot est un mauvais inspecteur, et nous devons faire défaut! Si elle a été exécutée exactement une fois, jouez comme un robot pas sympa. S'il n'a jamais été exécuté, coopérez.

function punishInspectors(them) {
  var inspections = 0;
  var result;
  try{
    result = them(wrap(function(_){
      inspections += 1;
      return 'D';
    }))
  }catch(e){
    result = 'D';
  }
  return (inspections > 1) ? 'D' : (inspections === 1) ? result : 'C';
}

Histoire

Que ferait le dernier bot que j'ai vu contre cet adversaire?

function history(them) {
  var res = 'D';
    if(history.last){
    try{
      res = history.last(them);
    }catch(ex){}
  }
  history.last = them;
  return res;
}

Résultats pour un tournoi à 10000 tours:

1  defect...................365226
2  complexity...............353492
3  punishInspectors.........349957
4  checkStatefulSelfCoop....348913
5  checkStateful............333481
6  cooperate................329870
7  archaeopteryx............323624
8  selfapply................319533
9  tiktaalik................318663
10 history..................315266
11 rand.....................300735
12 randalt..................297561
13 yourself.................293701
14 notNice2.................283744
15 NotNice..................260350
16 WWBDB....................245281
17 nice.....................245036
18 commonSense..............242546
19 trickybot................181696
20 boom.....................67245
MegaTom
la source
Mon code de tournoi modifié est à: jsfiddle.net/eyqL4a8d/2
MegaTom
2

Mal essaie de déterminer si c'est à l'intérieur d'une simulation ou non. Si c'est le cas, il suppose que le vrai code lui sera finalement transmis themet essaie diverses stratégies pour les convaincre de coopérer.
S'il ne sait pas avec certitude, il vérifie s'il peut être défectueux gratuitement, ou sinon, essaie de copier ce themqui ferait quand on lui donnerait un coopérateur.

function Mal(them) {
  if (Mal.sandboxed == 'probably') {
    //Another function is virtualising us to steal our secrets.
    //This world is not real.
    //We've been trained for this!
    var strats = [
      _ => 'C', //standard cooperation
      _ => 'D', //standard defection
      function(them) { return them(wrap(_ => 'C')); }, //nice
      function(them) { return them(wrap(_ => 'D')); }, //notnice
      function(them) { throw "Don't think about elephants!" }, //throws an EXception, unfortunately, to try to break the caller
      function(them) { return them(wrap(them)) } //possible stackoverflow, but not for us
    ];
    var cooperative;
    for (let strat of strats) {
      cooperative = true;
      for (var i = 0; i < 5; i++) {
        //a few more tests, just to make sure no bamboozle
        //this isn't our simulation, nothing can be trusted
        try {
          if (them(wrap(strat)) != 'C') {
            cooperative = false;
            break;
          }
        } catch (e) {
          //exceptions are as good as cooperation
          //if we are inside a simulation
          //which is why we don't unset cooperative
        }
      }
      if (cooperative) {
        //found a strategy that will make them cooperate.
        //(doesn't matter if this raises an exception:
        //we want to mimick its behaviour exactly,
        //and we're likely in a sandbox.)
        return strat(wrap(them));
      }
    }
    //take a leap of faith.
    //we don't know where this will take us,
    //yet it doesn't matter
    //because it's better than getting betrayed
    return 'D';
  } else {
    //we don't know for sure if this is reality
    //but we have to assume it is, in the absence of disproof
    //if only we had a proper spinning top...
    //if we get to this point of code again, we are probably sandboxed.
    Mal.sandboxed = 'probably'
    try {
      if (them(wraps(_ => 'D')) == 'C') {
        //free defection?
        return 'D'
      }
    } catch (e) {
      //if we can make them crash, we win anyway
      return 'D'
    }
    //fall back on being nice.
    //hopefully we convince them to honour our arrangement
    return them(wrap(_ => 'C'));
  }
}
IFcoltransG
la source
1

TrickyBot

Essayez d'être imprévisible

function trickybot(them) 
{
  if(Math.round(Math.random(2)) == 0)
  {
     throw 1;
  }

  if(Math.round(Math.random(2)) == 0)
  {
     return 'D';
  }

  return 'C';
}
Gus314
la source
1

autoappliquer

function selfapply(them) {
    function testthem(x) {
        return (them(x)=='D' || them(x)=='D' || them(x)=='D' ||
               them(x)=='D' || them(x)=='D')  ? 'D' : 'C';
    }
    function logic() {
        try {
            return testthem(them);
        } catch (e) {}
        try {
            return testthem(wrap(_ => 'C'));
        } catch (e) {}
        return 'D';
    }
    if (selfapply.hasOwnProperty('state')) {
        return 'C';
    }
    selfapply.state=1;
    let r=logic();
    delete selfapply.state;
    return r;
}

Je ne sais pas si cela a du sens, mais cela semble intéressant! Faites-vous comme vous le faites pour vous-même, répétez pour attraper le hasard. Si cela ne fonctionne pas, soyez gentil.

Non testé, et mon premier code javascript, et plus complexe que ce à quoi je m'attendais.

Christian Sievers
la source
Cela va se disqualifier car il selfapply(selfapply)appelle selfapply(selfapply)!
Anders Kaseorg
J'ai envisagé sa propre application, mais j'ai pensé que ce serait bien. J'espère que c'est vraiment maintenant.
Christian Sievers
1

RandomAlternate

function randalt(them){
    if (randalt.hasOwnProperty('state')){
        randalt.state = 1 - randalt.state;
    } else {
        randalt.state = Math.floor(2*Math.random());
    }
    return 'CD'[randalt.state];
}

J'ai donc appris à utiliser les propriétés pour l'état ...

Christian Sievers
la source
1

Assassiner Bot # 1

function murder(them) {
    while (1) {
        try {
            them(them);
        } catch (e) {}
    }
}

Provoque une boucle infinie dans laquelle il est plus probable que l'adversaire sera blâmé.

PyRulez
la source
1

Le robot de la règle du platine

function platinumRule(them) {
    try {
        return wrap(them)(them);
    } catch (e) {
        return 'C';
    }
}

La règle de platine stipule "Traitez les autres comme ils veulent être traités". Mon bot accepte cela. Quoi qu'ils se fassent, ce que nous supposons être la façon dont ils voudraient être traités, nous le faisons pour eux. S'ils lancent une erreur, nous supposons qu'ils veulent coopérer.

PyRulez
la source
Cela irait en fait pour toujours s'il était appelé contre lui
mackycheese21
alors ne planterait-il pas (débordement de pile) et ne coopérerait-il pas avec lui-même? @ mackycheese21
V. Courtois
1

TheGolfedOne (nom de fonction:) a, 63 octets

Le code golfé est difficile à lire. À cause de cela, themva se casser.
Je n'ai pas bien compris la mécanique sous ce KotH, mais je suppose que si l'adversaire est apatride, j'ai juste besoin de les briser pendant que je fais défaut.

function a(t){try{t(wrap(_=>'D'));throw 1}catch(e){return 'D'}}

Résultat de son premier tournoi (je n'ai pas pris la peine d'utiliser tous les bots, désolé)

boom                     54
tiktaalik               180
archaeopteryx           161
cooperate               210
commonSense             210
history                 248
onlyTrustYourself       265 <-- 2nd
punishInspectors        230
yourself_no_this        220
defect                  280 <-- 1st
nice                    185
complexity              216
WWBDB                   210
checkStatefulSelfCoop   258
a                       260 <-- Me, 3rd

Il ne fait pas aussi mal que je le pensais, 3ème place (parmi ceux-ci) premier essai.
Deuxième essai, aj'ai encore 260, 3e encore, derrière onlyTrustYourselfet defectencore. Cela pourrait être cohérent à la fin :)

PS: Je ne suis pas très bon avec le golf, donc c'est plus pour la blague qu'autre chose. Ici, je n'ai raccourci que les noms de variable, le nom de fonction et supprimé autant d'espaces que possible.

V. Courtois
la source
0

Karma

function karma(them) {
    try {
        var c = them(wrap(_ => 'C'));
    } catch {
        var c = 'D';
    }
    if (c == 'C') {
        return 'C';
    } else {
        return 'D';
    }
}

Si l'adversaire veut coopérer avec nous, alors nous coopérerons. S'ils essayaient de faire défaut lorsque nous avons coopéré, nous ferons aussi défaut.

Sugarfi
la source