Dylemat więźnia z dostępem do przeciwnika


21

W tym wyzwaniu napiszesz bota, który gra dylemat więźnia. Oto haczyk: nie będziesz mieć dostępu do historii poprzednich gier. Zamiast tego będziesz miał dostęp do samego przeciwnika. W tej wersji obaj gracze otrzymują +2 punkty, jeśli obaj ze sobą współpracują, +1 punkty, jeśli obaj wadą, a jeśli jeden współpracuje z jedną wadą, dezerter otrzymuje +3, a drugi nie otrzymuje punktów. Każde zgłoszenie będzie odtwarzane 10 razy względem każdego innego zgłoszenia, w tym samego siebie. Zwycięzcą jest zgłoszenie z największą liczbą punktów.

Kontroler : Powinieneś napisać funkcję javascript w formie

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

Kontroler używa właściwości funkcji namedo wyświetlania wyników, więc jeśli nie jest ona w tym formacie (a zamiast niej f = x => ...lub f = function() { ... }), trudno będzie zobaczyć wynik i nie będzie można uzyskać dostępu do własnej funkcji.

Funkcja zaakceptuje jeden parametr: themfunkcję przeciwnika. Może wtedy wywołać tę funkcję, aby zobaczyć, jaka reakcja przeciwnika otrzyma określone funkcje jako dane wejściowe. Na podstawie tych danych musisz zwrócić „C” lub „D” odpowiednio dla współpracy lub usterki.

Przykłady (będą konkurować):

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

Kontroler jest dostępny tutaj

Zasady :

  • Nie będziesz w stanie zobaczyć samego kodu przeciwnika. Wszystkie funkcje są opakowane, aby wyglądały tak samo, gdy toString()są wywoływane. Jedynym sposobem na zbadanie przeciwnika (który może być sobą) jest przetestowanie go.
  • Twoja funkcja nie musi być deterministyczna. Możesz zapisać stan tylko poprzez ustawienie właściwości dla własnej funkcji, takiej jak submissionName.state = {};. Jednak między meczami (nawet między meczami tych samych graczy) stan jest kasowany przez wywołanie toString()i eval. Dlatego nie ma pamięci o poprzednich meczach.
  • Kolejność wywoływania funkcji w pierwszym dopasowaniu jest losowa.
  • Jeśli Twój kod zgłasza błąd, będzie traktowany tak, jakbyś współpracował, podczas gdy twój przeciwnik jest wadliwy. Jeśli pierwszy biegniesz, kod przeciwnika nawet nie zostanie wywołany. Dzieje się tak nawet wtedy, gdy błąd pojawia się w kodzie przeciwnika podczas twojego sprawdzania them. Uważaj na błędy przepełnienia stosu, szczególnie w przypadku wywołań kodu them(wrap(submissionName)), ponieważ mogą one zrobić to samo.
  • Nie możesz uzyskać dostępu do zmiennejself ani żadnej innej zmiennej, która jest objęta zakresem, gdy evaljest nazywana Z WYJĄTKIEM funkcji wrap. Ta funkcja pozwala na wołanie przeciwnika w sposób nie do odróżnienia od sposobu, w jaki kontroler wywołuje funkcję. Nie możesz pisać Math, windowitd (można użyć funkcji, takich jak Math.random(), jednak).
  • Nie można uzyskać dostępu do śledzenia stosu, tworząc metodę Errorlub inną metodą.

Uwaga dotycząca zbyt długiego czasu: unikaj utknięcia w whilepętla na zawsze. Łączny czas obu zawodników nie powinien przekraczać 1 sekundy w danej rundzie. Aby to wymusić, wybierany jest losowy limit czasu między 1000 ms a 2000 ms (ma to na celu uniknięcie gry przez celowe oczekiwanie znanej ilości czasu), a jeśli proces roboczy trwa dłużej, zostanie zgłoszony błąd. Jeśli tak się stanie, przyczyna błędu zostanie określona w następujący sposób: wykonanie zostanie wstrzymane w losowym momencie po 1000 ms, a stos wywołań w tym momencie zostanie sprawdzony. Oskarżony zostanie ostatnio nazywany konkurent, który jest obecnie w pętli (lub rekurencji podobnej do pętli, w tym sensie, że jest to rekurencja skonfigurowana w celu uniknięcia błędu przepełnienia stosu). Jeśli winny jest ten sam zawodnik za kilkakrotne spowodowanie błędu „zbyt długiego”, zostanie on zdyskwalifikowany.


To wyzwanie przypomina mi aukcję Dollar Bill .
Alion

Czy funkcja użyta do testowania themmusi być deterministyczna / przestrzegać reguł? Na przykład function me(them){let log=0;them(x=>{++log;return 'C';}); return log == 0? 'D': 'C';}
user202729

2
Jeśli obie funkcje wywołują je (zawijaj (coś)), jak możesz zapobiec rekurencji? Czy coś brakuje?
Quintec

@Quintec możesz używać rekurencji i pętli. Po prostu rekurencja musi skutkować StackOverflowbłędem, a nie nieskończoną pętlą, która nigdy się nie kończy. Jeśli może to spowodować StackOverflow, upewnij się, że dodałeś instrukcję try-catch. Na przykład rekurencji, która nie osiągnie błędu
przepełnienia stosu

1
@Quintec niekoniecznie. Na przykład them(() => 'C')nie spowodowałoby to błędu, ponieważ gdy przeciwnik dzwoni them, wywołuje () => 'C'funkcję. Jedyną rzeczą, którą należy zapakować, try-catchbyłoby wywołanie themz parametrem jakiejś funkcji, która wywołuje się themz parametrem funkcji wywołującej themitp. (Nieskończenie). Na przykład, them(t => t(() => 'C'))zagrałby wszystko , co grałby przeciwnik, gdyby przeciwnik myślał, że gra nice. Nie ma możliwości stackoverflowbłędu.
soktinpk

Odpowiedzi:


14

BoomBot

function boom(them) {
  throw 1;
}

Jeśli przeciwnik zostanie uruchomiony jako pierwszy i sprawdzi to bez try..catchtego, bot automatycznie zdobędzie 3 punkty. Zero punktów w każdym innym przypadku.


Jeśli przeciwnik zostanie uruchomiony jako pierwszy i nie sprawdzi tego, straci 3 punkty, prawda?
user202729,

1
@ user202729 Dokładniej, przeciwnik otrzyma 3 punkty. W tej grze nie ma punktów do stracenia.
Bubbler

10

Archeopteryx

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';
}
  • Jeśli przeciwnik współpracuje cooperate, naśladuj ruch przeciwnikadefect .
  • W przeciwnym razie, jeśli przeciwnik współpracuje z defectlub znice , to wada.
  • W przeciwnym razie współpracuj.

Co sprawia, że ​​jest to dobra strategia? Nie mam pojęcia. Wygenerowałem go przy użyciu algorytmu ewolucyjnego, częściowo przeszkolonego w zakresie bieżących zgłoszeń.

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'));
}
  • Jeśli przeciwnik wada przeciwko cooperate, odwróć jego ruch przeciwdefect .
  • W przeciwnym razie, jeśli przeciwnik wada przeciwko defect , to wada.
  • W przeciwnym razie naśladuj ruch przeciwnika notNice.

Kolejna strategia generowana ewolucyjnie.


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 jest dość prosty; po prostu testuje przeciwnika pod kątem tego, co zrobiłby z programem w stanie ustalonym. Jeśli bot woli współpracować, jeśli to możliwe, WWBDB również preferuje współpracę (więc będzie współpracować z ładnym botem). WWBDB nie woli współpracy.


5

Sprawdź stan

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

Jeśli mnie wzywają, to prawdopodobnie są nimi naprawdę. Działamy jako uciekinier. Jeśli mnie nie wzywają, to prawdopodobnie są opakowanym testerem. Zachowalibyśmy się ładniej.


Powyżej jest oryginalna odpowiedź. A może powinienem podjąć współpracę, aby zdobyć więcej punktów.

Sprawdź stan za pomocą self-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;
}

4

RandomBot

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

Bo czemu nie.


3

Złożoność

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

Testy złożoności sprawdzają, czy bot to Cooperate czy Defect. Jeśli tak, to współpracuje, ale jeśli nie, to ma wady. Wszystkie obecne boty, które testują swoich przeciwników, używają prostych funkcji do testowania odpowiedzi, więc w takich przypadkach Złożoność udaje Współpracę.


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

Chcę, aby to działało, aby zawsze mieć wadę, z wyjątkiem gry przeciwko sobie. Próbuje to zrobić, przekazując funkcję „tester”, która nie jest do nich opakowana, i próbuje wykryć, czy „one” są nazwane tester. Jeśli nazywa się tester, zmienia zmienną statyczną aktywowaną na true, a następnie zwraca kooperację. Ale to nie działa. Nie znam się zbyt dobrze na javascript i prawdopodobnie wprowadzę jeszcze kilka zmian.


sprytny pomysł, ale co się stanie, gdy inny brat spełni testerfunkcję: D
V. Courtois

2

Niemiły

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

Naśladuje reakcję przeciwnika na ugięcie



2

Zdrowy rozsądek

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

Uwaga: Nie znam javascript.

Jeśli możesz zarobić na miłej osobie, zrób to. W przeciwnym razie zwróć to, co zwrócą, jeśli staną w obliczu współpracy (przynajmniej tak mi się wydaje ).


2

A ty gdzie chcesz? (zainspirowany zmiennościami w księdze dżungli)

    funkcjonować samemu (im) {
      próbować{
        zwróć je (this);
      } catch (e) {
        zwraca „D”;
      }
    }

   funkcja yourself_no_this (nich) {
      próbować{
        zwróć je (siebie_nie_to);
      } catch (e) {
        zwraca „D”;
      }
    }

Właśnie wygrałem w turnieju, który prowadziłem. Dobra robota!
MegaTom,

Właśnie zauważyłem, że ten bot narusza zasady. „Nie możesz uzyskać dostępu do zmiennej self ...” thisto to samo co self. Myślę, że chciałeś powiedzieć return them(yourself).
MegaTom,

Technicznie ( xkcd.com/1475 );) thisnie jest zmienną, jest słowem kluczowym w kontekście funkcji this!=self. selfoznaczałoby obiekt okna i thissamą funkcję (zawsze odnosi się do kontekstu, w którym się znajduje, dlatego nie jest uważany za zmienną). Dlatego posiadanie var self = this;na początku wielu przykładów kodu można uznać za wprowadzające w błąd. Dodano wersję bez „tego”
TS

1
Nie. thisNie odnosi się do funkcji. yourselfi yourself_no_thisdziałają inaczej. thiszasadniczo nigdy nie odnosi się do funkcji w javascript. Zobacz: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
MegaTom

2

Karać inspektorów

Daj botowi trochę kodu i sprawdź, czy go uruchamia. Jeśli uruchomiono go więcej niż raz, bot jest złym inspektorem i musimy się wycofać! Jeśli uruchomiono go dokładnie raz, zagraj jako niezły bot. Jeśli nigdy nie był uruchamiany, współpracuj.

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

Historia

Co zrobiłby ostatni bot, który widziałem przeciwko temu przeciwnikowi?

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

Wyniki dla turnieju rundy 10000:

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

Mój zmodyfikowany kod turnieju to: jsfiddle.net/eyqL4a8d/2
MegaTom

2

Mal próbuje ustalić, czy jest w symulacji, czy nie. Jeśli tak, zakłada, że ​​ostatecznie otrzyma prawdziwy kod them, i próbuje różnych strategii, aby przekonać ich do współpracy.
Jeśli nie ma pewności, sprawdza, czy może za darmo wykonać defekt, a jeśli nie, próbuje skopiować to them, co zrobiłby, gdy otrzyma współpracownika.

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

1

TrickyBot

Staraj się być nieprzewidywalny

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

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

  return 'C';
}

1

selfapply

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

Nie jestem pewien, czy to ma sens, ale wydaje się interesujące! Rób tak, jak robisz sobie, powtarzaj, aby złapać przypadkowość. Jeśli to nie zadziała, bądź miły.

Nie przetestowany i mój pierwszy kod javascript, i bardziej złożony niż się spodziewałem.


To zdyskwalifikuje się, ponieważ selfapply(selfapply)połączenia selfapply(selfapply)!
Anders Kaseorg

Zastanawiałem się nad własnym zastosowaniem, ale pomyślałem, że będzie dobrze. Mam nadzieję, że tak naprawdę jest teraz.
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];
}

Nauczyłem się więc, jak używać właściwości dla stanu ...


1

Murder Bot # 1

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

Powoduje nieskończoną pętlę, za którą bardziej prawdopodobne jest obwinienie przeciwnika.


1

Bot Platinum Rule

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

Zasada Platinum mówi: „Traktuj innych tak, jak chcą być traktowani”. Mój bot to akceptuje. Cokolwiek zrobiliby sobie, zakładamy, że chcieliby być traktowani, my im to robimy. Jeśli zgłoszą błąd, zakładamy, że chcą współpracować.


Trwałoby to wiecznie, gdyby zostało wezwane przeciwko sobie
Trwałoby

to czy nie zawiesiłoby się (przepełnienie stosu) i nie współpracowało ze sobą? @ mackycheese21
V. Courtois

1

TheGolfedOne (nazwa func: a , 63 bajty

Kod w golfa jest trudny do odczytania. Z tego powodu thempęknie.
Nie w pełni zrozumiałem mechanikę tego KotH, ale przypuszczam, że jeśli przeciwnik jest bezpaństwowcem, muszę go po prostu złamać, kiedy będę się bronił.

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

Wynik jego pierwszego turnieju (przepraszam, nie zawracałem sobie głowy używaniem wszystkich botów)

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

Nie idzie mu tak źle, jak myślałem, 3. miejsce (wśród nich) pierwsza próba.
Druga próba, aznów 260, znów 3 miejsce, z tyłu onlyTrustYourselfi defectznowu. W końcu może być spójne :)

PS: Nie jestem zbyt dobry w golfa, więc żart jest większy niż cokolwiek innego. Tutaj skróciłem tylko nazwy zmiennych, nazwy func i usunąłem jak najwięcej białych znaków.


0

Karma

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

Jeśli przeciwnik będzie z nami współpracował, będziemy współpracować. Jeśli będą próbować się zepsuć, gdy będziemy współpracować, my również to zrobimy.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.