1P5: Итеративная дилемма заключенного

35

Эта задача является частью первого периодического премьер - программирования головоломка Пуш и предназначена как демонстрация нового вызов типа предложения .

Задача состоит в том, чтобы написать программу, которая сыграет дилемму повторного заключенного лучше, чем другие участники.

Смотри, Винни. Мы знаем твоего сокамерника --- как его зовут? Да, МакВонгски, иппо-ирландско-украинский бандит - что-то замышляет, и вы знаете, что это такое.

Мы стараемся быть милыми здесь, Винни. Предоставляю тебе шанс.

Если вы скажете нам, что он планирует, мы увидим, что вы получите хорошую работу.

И если ты не ...

Правила игры

  • Конкурс состоит из полной круговой игры (все возможные пары) двух участников одновременно (включая самостоятельные игры).
  • Между каждой парой сыграно 100 раундов
  • В каждом раунде каждого игрока просят выбрать между сотрудничеством с другим игроком или предательством, не зная намерений других игроков в этом вопросе, но имея в виду результаты предыдущих раундов, сыгранных против этого противника.
  • Очки начисляются за каждый раунд на основе комбинированного выбора. Если оба игрока сотрудничают, они получают по 2 очка. Взаимное предательство приносит 1 очко каждому. В смешанном случае предающему игроку присуждается 4 очка, а соучастнику штрафуется 1.
  • «Официальный» матч будет проведен не ранее, чем через 10 дней после публикации всех заявок, которые я смогу получить на работу и использовать для выбора «принятого» победителя. У меня есть Mac OS 10.5, поэтому решения POSIX должны работать, но есть linuxisms, которые не работают. Кроме того, у меня нет поддержки Win32 API. Я готов приложить основные усилия, чтобы установить вещи, но есть предел. Пределы моей системы никоим образом не представляют собой пределы приемлемых ответов, просто те, которые будут включены в «официальный» матч.

Интерфейс программиста

  • Записи должны быть в форме программ, которые можно запускать из командной строки; Решение должно (единственный!) вывод программы на стандартный вывод. История предыдущих раундов с этим противником будет представлена ​​в качестве аргумента командной строки.
  • Вывод либо «с» (для моллюска ) или «т» (для все ).
  • История представляет собой единую строку символов, представляющую предыдущие раунды, причем самые последние раунды будут самыми ранними в строке. Персонажи
    • «К» (для сохранения веры означает взаимное сотрудничество)
    • "R" (для крысы b @ st @ rd продал меня! )
    • «S» (для присоски! Означает, что вы выиграли от предательства)
    • «Е» (потому что каждый ищет взаимного предательства)

Кронштейн

Четыре игрока будут предоставлены автором

  • Ангел - всегда сотрудничает
  • Дьявол - всегда говорит
  • TitForTat - сотрудничает в первом раунде, затем всегда делает то, что сделал в последнем раунде
  • Случайный - 50/50

к которому я добавлю все записи, которые я могу запустить.

Общая оценка будет суммой очков против всех оппонентов (включая самостоятельные игры только один раз и с использованием средней оценки).

Абитуриенты

(по состоянию на 2 мая 2011 г. 7:00)

Тайное рукопожатие | Анти-Т42Т Ракета | Недоверие (вариант) | Анти-рукопожатие | Маленький Лиспер | Сходимость | Акула | Вероятностный | Павлов - Win Stay, Lose Switch | Честь среди воров | Помогите вампиру | Друид | Маленький интриган | Прошлое | Синица для двух татов | Простак |

маркер

#! /usr/bin/python
#
# Iterated prisoner's dilemma King of Hill Script Argument is a
# directory. We find all the executables therein, and run all possible
# binary combinations (including self-plays (which only count once!)).
#
# Author: dmckee (https://codegolf.stackexchange.com/users/78/dmckee)
#
import subprocess 
import os
import sys
import random
import py_compile

###
# config
PYTHON_PATH = '/usr/bin/python' #path to python executable

RESULTS = {"cc":(2,"K"), "ct":(-1,"R"), "tc":(4,"S"), "tt":(1,"E")}

def runOne(p,h):
    """Run process p with history h and return the standard output"""
    #print "Run '"+p+"' with history '"+h+"'."
    process = subprocess.Popen(p+" "+h,stdout=subprocess.PIPE,shell=True)
    return process.communicate()[0]

def scoreRound(r1,r2):
    return RESULTS.get(r1[0]+r2[0],0)

def runRound(p1,p2,h1,h2):
    """Run both processes, and score the results"""
    r1 = runOne(p1,h1)
    r2 = runOne(p2,h2)
    (s1, L1), (s2, L2) = scoreRound(r1,r2), scoreRound(r2,r1) 
    return (s1, L1+h1),  (s2, L2+h2)

def runGame(rounds,p1,p2):
    sa, sd = 0, 0
    ha, hd = '', ''
    for a in range(0,rounds):
        (na, ha), (nd, hd) = runRound(p1,p2,ha,hd)
        sa += na
        sd += nd
    return sa, sd


def processPlayers(players):
    for i,p in enumerate(players):
        base,ext = os.path.splitext(p)
        if ext == '.py':
            py_compile.compile(p)
            players[i] = '%s %sc' %( PYTHON_PATH, p)
    return players

print "Finding warriors in " + sys.argv[1]
players=[sys.argv[1]+exe for exe in os.listdir(sys.argv[1]) if os.access(sys.argv[1]+exe,os.X_OK)]
players=processPlayers(players)
num_iters = 1
if len(sys.argv) == 3:
    num_iters = int(sys.argv[2])
print "Running %s tournament iterations" % (num_iters)
total_scores={}
for p in players:
    total_scores[p] = 0
for i in range(1,num_iters+1):
    print "Tournament %s" % (i)
    scores={}
    for p in players:
        scores[p] = 0
    for i1 in range(0,len(players)):
        p1=players[i1];
        for i2 in range(i1,len(players)):
            p2=players[i2];
#        rounds = random.randint(50,200)
            rounds = 100
            #print "Running %s against %s (%s rounds)." %(p1,p2,rounds)
            s1,s2 = runGame(rounds,p1,p2)
            #print (s1, s2)
            if (p1 == p2):
                scores[p1] += (s1 + s2)/2
            else:
                scores[p1] += s1
                scores[p2] += s2

    players_sorted = sorted(scores,key=scores.get)
    for p in players_sorted:
        print (p, scores[p])
    winner = max(scores, key=scores.get)
    print "\tWinner is %s" %(winner)
    total_scores[p] += 1
print '-'*10
print "Final Results:"
players_sorted = sorted(total_scores,key=total_scores.get)
for p in players_sorted:
    print (p, total_scores[p])
winner = max(total_scores, key=total_scores.get)
print "Final Winner is " + winner
  • Жалобы на мой ужасный питон приветствуются, так как я уверен, что это отстой более чем один способ
  • Исправления ошибок приветствуются

История изменений бомбардира:

  • Распечатайте отсортированных игроков и результаты и объявите победителя (4/29, Кейси)
  • При желании можно запустить несколько турниров (по ./score warriors/ num_tournaments)умолчанию = 1), обнаружить и скомпилировать исходники Python (4/29, Кейси)
  • Исправлена ​​ошибка, из-за которой второму игроку передавали неверную историю. (4/30, dmckee; спасибо, Джош)

Начальные воины

В качестве примера и так, чтобы результаты могли быть проверены

ангел

#include <stdio.h>
int main(int argc, char**argv){
  printf("c\n");
  return 0;
}

или

#!/bin/sh
echo c

или

#!/usr/bin/python
print 'c'

дьявол

#include <stdio.h>
int main(int argc, char**argv){
  printf("t\n");
  return 0;
}

случайный

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int main(int argc, char**argv){
  srandom(time(0)+getpid());
  printf("%c\n",(random()%2)?'c':'t');
  return 0;
}

Обратите внимание, что бомбардир может повторно вызывать воина много раз за одну секунду, поэтому необходимо предпринять серьезные усилия для обеспечения случайности результатов, если время используется для посева PRNG.

TitForTat

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char**argv){
  char c='c';
  if (argv[1] && (
          (argv[1][0] == 'R') || (argv[1][0] == 'E')
          ) ) c='t';
  printf("%c\n",c);
  return 0;
}

Первый, который действительно что-то делает с историей.

Запуск бомбардира только на предоставленных воинах

Finding warriors in warriors/
Running warriors/angel against warriors/angel.
Running warriors/angel against warriors/devil.
Running warriors/angel against warriors/random.
Running warriors/angel against warriors/titfortat.
Running warriors/devil against warriors/devil.
Running warriors/devil against warriors/random.
Running warriors/devil against warriors/titfortat.
Running warriors/random against warriors/random.
Running warriors/random against warriors/titfortat.
Running warriors/titfortat against warriors/titfortat.
('warriors/angel', 365)
('warriors/devil', 832)
('warriors/random', 612)
('warriors/titfortat', 652)

Этот дьявол, он мастерский, и хорошие парни, очевидно, приходят последними.

Полученные результаты

"официального" забега

('angel', 2068)
('helpvamp', 2295)
('pavlov', 2542)
('random', 2544)
('littleschemer', 2954)
('devil', 3356)
('simpleton', 3468)
('secrethandshake', 3488)
('antit42t', 3557)
('softmajo', 3747)
('titfor2tats', 3756)
('convergence', 3772)
('probabimatic', 3774)
('mistrust', 3788)
('hyperrationalwasp', 3828)
('bygones', 3831)
('honoramongthieves', 3851)
('titfortat', 3881)
('druid', 3921)
('littlelisper', 3984)
('shark', 4021)
('randomSucker', 4156)
('gradual', 4167)
        Winner is ./gradual
dmckee
источник
2
Если мой сокамерник - ниппо-ирландско-украинский, почему его имя выглядит как хиберно-китайско-русский?
Питер Тейлор
2
@Peter: LOL. Правда? Ну, (1) генеалогия не ясна, но я, вероятно, пришел благодаря своей микрофонности через шотландско-ирландцев; (2) после того, как я написал «Ниппо», я испробовал разные фрагменты имен моих друзей из страны восходящего солнца, и мне не понравилось, как они сканировали, поэтому я пошел дальше и использовал китайскую фамилию, которая звучала вместо этого хорошо, и (3) я бы не почувствовал разницу, если бы они по очереди избивали меня шинами. Что кажется вероятным в данных обстоятельствах.
dmckee
1
@ Джош: Было бы просто изменить return (s1, L1+h1), (s2, L2+h1)на return (s1, L1+h1), (s2, L2+h2)[Примечание, L2+h2а L2+h1не в конце]? // Ошибка «вырезать и вставить» или что-то такое же идиотское. Sheesh!
dmckee
2
Я потратил некоторое время на тестовый сценарий, и я рад сообщить об обновлении здесь . Это обновление добавляет простую оболочку к тестовому сценарию, которая позволяет пользователю вручную запускать этот бот против этого бота, запускать турниры с ограниченными полями и некоторые другие интересные вещи. Не стесняйтесь вносить предложения! Ой. И я должен @josh за идею «бот-бот». Это на самом деле просто более изящная реализация его сценария "тренер".
arrdem
2
Интересно: было 23 участника, поэтому каждый играл по 22 раунда. Если бы все играли в «Ангела», каждый счет был бы 4400, но даже лучший результат 4167 не соответствовал этому. Если бы мы жили в идеальном мире ... :)
Briguy37

Ответы:

11

постепенный

Эта стратегия основана на документе Бофилса, Делахэ и Матье . Мой C действительно не самый лучший, так что если у кого-то есть предложения по улучшению / ускорению кода, дайте мне знать!

[Править] Стоит отметить, что Gradual был разработан, чтобы быть стратегией, которая превосходит Tit for Tat. Он имеет схожие свойства в том, что он готов сотрудничать и принимает ответные меры против дезертирующего противника. В отличие от Tit for Tat, в котором есть память только о последнем сыгранном раунде, Gradual запомнит полное взаимодействие и укажет количество раз, которое оппонент уже преодолел. Впрочем, после этого он снова предложит взаимное сотрудничество.

Как обычно, эффективность стратегии зависит от ряда других стратегий. Кроме того, в оригинальной статье не совсем ясно некоторые детали.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char* argv[]) {
    if(argc == 1){
        printf("c\n");
        return 0;
    }

    size_t l = strlen(argv[1]);
    int i;
    size_t currentSequence = 0;
    size_t totalDefects = 0;
    size_t lastDefects = 0;

    for(i = l-1; i >= 0; i--){
        if(argv[1][i] == 'E' || argv[1][i] == 'R'){
            totalDefects++;
            currentSequence = 0;
        } else if(argv[1][i] == 'S') {
            currentSequence++;
        }
    }

    if(currentSequence < totalDefects)
        // continue defect sequence
        printf("t\n");
    else if(argv[1][0] == 'S' || argv[1][0] == 'E' ||
            argv[1][1] == 'S' || argv[1][1] == 'E')
        // blind cooperation
        printf("c\n");
    else if(argv[1][0] == 'R')
        // start new defect sequence
        printf("t\n");
    else
        printf("c\n");

    return 0;
}
Ventero
источник
11

Тайное рукопожатие

#!/usr/bin/python
import sys
import random

def main():
    if len(sys.argv) == 1:
        hist = ""
    else:
        hist = sys.argv[1]
    if len(hist) <= len(TAG) and hist == TAGMATCH[len(TAG) - len(hist):]:
        print TAG[len(TAG) - len(hist) - 1]
        return
    if hist[-len(TAG):] == TAGMATCH:
        print 'c'
        return
    print "t"

def getTag():
    global TAG
    filename = sys.argv[0]
    filename = filename.replace(".pyc", ".py")
    f = open(filename, 'r')
    code = f.read().split('\n')
    f.close()
    if len(code[1]) == 0 or code[1][0] != '#':
        random.seed()
        newtag = 't' * 10
        cs = 0
        while cs < 3:
            pos = random.randint(0, 8)
            if newtag[pos] == 't':
                newtag = newtag[:pos] + 'c' + newtag[pos+1:]
                cs += 1
        code.insert(1, '#%s' % newtag)
        f = open(filename, 'w')
        f.write('\n'.join(code))
        f.close()
        TAG = newtag
    else:
        TAG = code[1][1:]
    global TAGMATCH
    TAGMATCH = TAG.replace('c', 'K').replace('t', 'E')

if __name__ == "__main__":
    getTag()
    main()

Стратегия здесь состоит в том, чтобы пожертвовать первые 10 раундов ради выполнения «секретного» рукопожатия. Если у меня есть я, я узнаю историю первых 10 ходов и надеваю кепку Ангела до конца игры. Как только я осознаю, что мой сокамерник не я, я превращаюсь в дьявола, пытаясь использовать в своих интересах чрезмерно кооперативных сокамерников.

Позволит ли я пожертвовать первыми 10 раундами, чтобы вытеснить самого дьявола, сильно зависит от того, сколько там записей. Чтобы минимизировать урон, в рукопожатии отображаются только 3 сотрудника.

Изменить: TAGMATCH теперь динамический, чтобы предотвратить глупые ошибки, такие как изменение только одной из них, и поэтому я могу сделать TAG динамическим в какой-то момент в будущем.

Редактировать 2: Теперь случайным образом генерирует тег при первом запуске и сохраняет его в указанном файле sys.argv[0]( .pycзаменяется на .pyтак, чтобы он переходил к коду, а не к байт-коду, файлу). Я думаю, что это единственная информация, которую имеют все мои экземпляры, которой никто не имеет, так что, похоже, это единственный способ избежать паразитов.

Аарон Дюфур
источник
Но откуда твой двойник узнает, как стать дьяволом?
arrdem
1
(Я чувствую себя как попугай, все время говоря «Тит для Тата» ...) Обратите внимание, что T4T превзойдет вашу стратегию в паре: T4T (сотрудничает ранее) и Devil (меньше результатов по Крысе), и свяжет с вашим стратегия. Конечно, в итоге важен общий итог, а не общее количество. Как вы говорите, население важно.
Джош Касвелл
1
О, нет, вы получаете еще один S из Tit for Tat. Ницца. Я не осознавал, TAGчто меня играли задом наперед. Тем не менее, вы не должны TAGMATCHбыть «KEEEKEEEKE»? "".join({('c', 'c'):'K', ('t', 't'): 'E'}[moves] for moves in zip(TAG, TAG))
Джош Касвелл
@ Джон Хороший вопрос - у меня изначально был другой тег, и когда я изменил его, чтобы минимизировать сотрудничество, я забыл обновить TAGMATCH. @Arrdem Идея состоит в том, что, если я играю против себя, лучшее, что можно сделать, - это постоянно сотрудничать, чтобы максимизировать сумму своих очков.
Аарон Дюфур
1
Оу, черт побери. Так что теперь я должен найти во всех .pyфайлах ваш код и извлечь TAG. Я не буду делать это в C, хотя ...
Джои
6

Маленький Лиспер

(setf *margin* (/ (+ 40 (random 11)) 100))
(setf *r* 0.0)
(setf *s* 0.0)
(setf *k* 0.0)
(setf *e* 0.0)

;; step 1 - cout up all the games results

(loop for i from 1 to (length(car *args*)) do
    (setf foo (char (car *args*) (1- i)))
    (cond 
        ((equal foo #\R) (setf *r* (1+ *r*)))
        ((equal foo #\S) (setf *s* (1+ *s*)))
        ((equal foo #\K) (setf *k* (1+ *k*)))
        ((equal foo #\E) (setf *e* (1+ *e*)))
    )
)

(setf *sum* (+ *r* *s* *k* *e*))

;; step 2 - rate trustworthiness
(if (> *sum* 0)
    (progn
        (setf *dbag* (/ (+ *r* *e*) *sum*)) ; percentage chance he rats
        (setf *trust* (/ (+ *s* *k*) *sum*)); percentage chance he clams
    )
    (progn
        (setf *dbag* 0) ; percentage chance he rats
        (setf *trust* 0); percentage chance he clams
    )
)



;; step 3 - make a decision (the hard part....)

(write-char
    (cond
        ((> *sum* 3) (cond 
                    ((or (= *dbag* 1) (= *trust* 1)) #\t) ; maximizes both cases
                                                          ; takes advantage of the angel, crockblocks the devil
                    ((> (+ *dbag* *margin*) *trust*) #\t) ; crockblock statistical jerks
                    ((< *dbag* *trust*) #\c)              ; reward the trusting (WARN - BACKSTABBING WOULD IMPROVE SCORE)
                    ((and
                        (= (floor *dbag* *margin*) (floor *trust* *margin*))
                        (not (= 0 *dbag* *trust*)))
                        #\t)                              ; try to backstab a purely random opponent, avoid opening w/ a backstab
                    )
        )
        (t #\c)                                            ; defalt case - altruism
    )
)

Дьявол

Рассмотрим следующий формат (Player1, Player2)

  • (С, Т) - получает P2 FOUR POINTS за его измены, в то время как Р1 россыпей ONE
  • (T, T) - P2 И P1 ПОЛУЧАЮТ 1

Предполагая, что P2 - это дьявол, он никогда не сможет потерять очки, на самом деле худшее, что он может сделать, - это набрать только одно очко. Поэтому по сравнению с чисто случайным противником наихудший возможный счет дьявола будет точно (5/2) * n, где n - количество сыгранных «игр». Его абсолютный наихудший случай - против него самого, где его счет будет n, а его лучший случай - против ангела, который будет 4 * n

Утвердить: оптимальный_страт = дьявол

это турнир Удар в спину моему сокамернику - намного лучшая стратегия, чем сотрудничество, потому что это помогает МОЙ СЧЕТ больше (+4). БОНУС - его хлопают (-1)! Если я высовываю ему шею, я стою, чтобы получить (+2) и потерять (-1). Поэтому статистически удары в спину вознаграждаются.

Но оптимально ли это?

Нет никаких причин НИКОГДА (по этой системе подсчета очков) сотрудничать.

  • Если вы выбрали неправильное время, чтобы замолчать, вы проиграете.
  • Если вы крысы, по крайней мере, вы ничего не потеряете.
  • Если вы крысы, а он тупой, вы получаете в 2 раза больше, чем если бы вы были хорошим подопечным.

В системе KOTH максимизация прибыли имеет важное значение. Даже если у вас есть два бота, которые отлично синхронизируются и сотрудничают, их индивидуальные результаты будут только повышены на 200 баллов за их спортивное мастерство. Дьявол, с другой стороны, заработает как минимум 100 очков, в среднем 200 и максимум 400, а его противникам будет стоить до 100 очков каждый! Практически, дьявол действительно выигрывает в среднем 300 игр, достигая 500.

Итог - время покажет

Мне кажется, что подсчет очков следует пересмотреть, чтобы дьявол не занял день. Увеличение показателя сотрудничества до 3 может сделать все. Однако, как показывают Павлов и Злоба, возможно обнаружить дьяволов и помешать им набрать 400 очков. Могу ли я доказать, что любой из них наберет достаточно очков для своего сотрудничества, чтобы оправдать свою веру? нет. Все это зависит от финальной области претендентов.

GL, HF!

И, пожалуйста, сделайте все возможное, чтобы этот пост. Я хочу написать мой старший документ по этому вопросу, когда все сказано и сделано.

История версий

  1. Добавлена ​​переменная поля, которая случайным образом меняет допуск Лиспера к герцогиню.
  2. Обновлен лиспер для моллюска в течение первых двух раундов, чтобы встать на правую ногу с кооперативными противниками
  3. Использовал генетический алгоритм, чтобы найти наиболее надежные значения для генератора случайных порогов, основываясь на их максимальном совокупном балле по сравнению со стандартным набором противников. Выложено обновление, включающее их.

ОФИЦИАЛЬНАЯ ВЕРСИЯ ЛИСПЕРА

РАЗРАБОТАТЬ ВЕРСИЮ ЛИСПЕРА

arrdem
источник
Подсчет очков варьируется в разных вариантах игры. Я же поиграться с увеличением стимул сотрудничества, и я согласен , что это будет иметь влияние на выбранных стратегий. Хорошая новость: вы можете взять бомбардира, установить свои собственные правила и попробовать его. В принципе, вы могли бы даже предложить награду.
dmckee
fink install clisp :: постукивая пальцами несколько раз ::
dmckee
1
@josh - спасибо за ссылку. Я прочитал некоторые другие страницы Википедии по этой дилемме, но я пропустил этот раздел. Ошибка правил, которую я только что заметил, нет никаких правил против записей, использующих файловую систему. это создает потенциал для гораздо более эффективного сотрудничества по линии рукопожатия.
arrdem
3
There is no reason to EVER (under this scoring system) co-operateтолько наполовину правильно. Если вы знаете, что ваш оппонент не принимает во внимание историю (ангел, дьявол, случайный), то вы всегда должны отступать. Если ваш оппонент принимает во внимание историю, и вы можете синхронизировать, то вы можете сделать лучше. У меня есть пара идей, которые вращаются вокруг определения, является ли противник рациональным или суперрациональным.
Питер Тейлор
1
Разве вы не получаете ошибки деления на ноль в 3/20 раз с последней версией? Всякий раз, когда (random 20)дает 2, 5 или 8, (/ (+1 rand-num) 10)равен 0,3, 0,6, 0,9, а остаток от деления с 0,3 равен 0; так (floor *dbag* *margin*)умирает.
Джош Касуэлл
5

Недоверие (вариант)

Этот тест вышел первым в моих собственных тестах несколько лет назад (тогда я был в 11-м классе и сделал небольшую диссертацию именно об этом, используя стратегии, разработанные и другими учениками). Начинается с последовательностиtcc (и после этого играет как Tit for Tat.

Извинения за ужасный код; если кто-то может сделать это короче, не точно играя в гольф, я был бы благодарен :-)

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]) {
    if (argc == 1)
        printf("t\n");
    else switch (strlen(argv[1])) {
        case 0:
            printf("t\n");
            break;
        case 1:
        case 2:
            printf("c\n");
            break;
        default:
            if (argv[1][0] == 'R' || argv[1][0] == 'E')
                printf("t\n");
            else
                printf("c\n");
            break;
    }

    return 0;
}
детеныш
источник
Нет необходимости дублировать код на длину 1 и 2. Используйте провалиться: case 1: case2: printf(...); break;. И gcc хочет явного объявления об string.hиспользовании strlen. В любом случае у меня это работает.
dmckee
Ах, это правда. Я не был уверен, как определить самый первый раунд, есть ли пустой первый аргумент (история) или просто нет.
Джои
Я не уверен. Это то, что Python делает с Popen(p+" "+h,stdout=subprocess.PIPE,shell=True)когда h = ''. Я предполагаю argc=1.
dmckee
1
Эта начальная последовательность довольно хорошая идея, направленная прямо на Тита за слабость Тата. Вы получаете крошечное лидерство на этом, затем играете его путь после этого.
Джош Касвелл
1
@ Джош, а где крошечный поводок? Против T4T начинается SRK, а затем продолжается K. Но SR приносит 3 очка каждому игроку.
Питер Тейлор
5

Ракета Анти-Т42Т

#!/usr/bin/python

"""
Anti-T42T Missile, by Josh Caswell

That Tit-for-two-tats, what a push-over!
  T42T: ccctcctcc...
AT42TM: cttcttctt...
        KSSRSSRSS...
"""
import sys
try:
    history = sys.argv[1]
except IndexError:
    print 'c'
    sys.exit(0)

if history[:2] == 'SS':
    print 'c'
else:
    print 't'

Удачно справляется с базовым набором воинов: убивает Ангела, слегка побеждённого Дьяволом (но держит свой счет на низком уровне), обычно бьет Рэнда ловко и едва ли бьет Тита за Тата. Плохо работает при игре против себя.

Джош Касвелл
источник
Я отправил правку, которая делает эту работу действительно полезной :) Она должна быть одобрена.
Кейси
@Casey: Господи, я делаю так много глупых ошибок в моем увлечении этой проблемой! Спасибо, но почему вы устранили ш-бэнг?
Джош Касвелл
Э-э, это был несчастный случай. Я добавлю это обратно.
Кейси
@Casey: нет проблем. Я сделаю это. В любом случае нужно добавить строку документа.
Джош Касвелл
4

конвергенция

Вначале приятно, потом играет случайным образом с прицелом на историю противника.

/* convergence
 *
 * A iterated prisoners dilemma warrior for
 *
 * Strategy is to randomly chose an action based on the opponent's
 * history, weighting recent rounds most heavily. Important fixed
 * point, we should never be the first to betray.
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char**argv){
  srandom(time(0)+getpid()); /* seed the PRNG */
  unsigned long m=(1LL<<31)-1,q,p=m;
  if (argc>1) {
    size_t i,l=strlen(argv[1]);
    for (i=l; --i<l; ){
      switch (argv[1][i]) {
      case 'R':
      case 'E':
    q = 0;
    break;
      case 'K':
      case 'S':
    q = m/3;
    break;
      }
      p/=3;
      p=2*p+q;
    }
  }
  /* printf("Probability of '%s' is %g.\n",argv[1],(double)p/(double)m); */
  printf("%c\n",(random()>p)?'t':'c'); 
  return 0;
}

Я пытался немного утяжелить историю, но не оптимизировал ее должным образом.

dmckee
источник
4

Акула

#!/usr/bin/env python

"""
Shark, by Josh Caswell

Carpe stultores.
"""

import sys

HUNGER = 12

try:
    history = sys.argv[1]
except IndexError:
    print 'c'
    sys.exit(0)

if history.count('S') > HUNGER:
    print 't'
else:
    print 'c' if history[0] in "SK" else 't'

Хорошо справляется с базовым составом.

Джош Касвелл
источник
... захватить моллюска?
arrdem
:) хватайся за дураков.
Джош Касвелл
+1 за постоянное 2-е место в текущем поле.
arrdem
3

Павлов - Win Stay, Lose Switch

На первом ходу он сотрудничает, а затем сотрудничает тогда и только тогда, когда оба игрока выбрали предыдущий ход.

#!/usr/bin/python
import sys

if len(sys.argv) == 1:
    print 'c'
else:
    hist = sys.argv[1]
    if hist[0] == 'K' or hist[0] == 'E':
        print 'c'
    else:
        print 't'
Casey
источник
Разве это не должно использовать hist[0]( hist[-1]это всегда первый ход раунда)?
Джош Касвелл
Ого, ты прав. Я предположил, что у входной строки были самые последние раунды в конце строки, а не в начале. Исправлена.
Кейси
3

Честь среди воров

#!/usr/bin/env python

"""
Honor Among Thieves, by Josh Caswell

I'd never sell out a fellow thief, but I'll fleece a plump mark,
and I'll cut your throat if you try to cross me.
"""

from __future__ import division
import sys

PLUMPNESS_FACTOR = .33
WARINESS = 10

THIEVES_CANT = "E" + ("K" * WARINESS)

try:
    history = sys.argv[1]
except IndexError:
    history = ""

if history:
    sucker_ratio = (history.count('K') + history.count('S')) / len(history)
    seem_to_have_a_sucker = sucker_ratio > PLUMPNESS_FACTOR


# "Hey, nice t' meetcha."
if len(history) < WARINESS:
    #"Nice day, right?"
    if not set(history).intersection("RE"):
        print 'c'
    # "You sunnuvab..."
    else:
        print 't'

# "Hey, lemme show ya this game. Watch the queen..."
elif len(history) == WARINESS and seem_to_have_a_sucker:
    print 't'

# "Oh, s#!t, McWongski, I swear I din't know dat were you."
elif history[-len(THIEVES_CANT):] == THIEVES_CANT:

    # "Nobody does dat t' me!"
    if set(history[:-len(THIEVES_CANT)]).intersection("RE"):
        print 't'
    # "Hey, McWongski, I got dis job we could do..."
    else:
        print 'c'

# "Do you know who I am?!"
elif set(history).intersection("RE"):
    print 't'

# "Ah, ya almos' had da queen dat time. One more try, free, hey? G'head!"
elif seem_to_have_a_sucker:
    print 't'

# "Boy, you don't say much, do ya?"
else:
    print 'c'

Обратите внимание, что по THIEVES_CANTсути это рукопожатие, хотя оно появится только при игре против кооператора. Тем не менее, он позволяет избежать проблемы паразитов, проверяя наличие более поздних скрещиваний. Хорошо справляется с базовым составом.

Джош Касвелл
источник
+1 за то, что был первым стратом, который надежно потрепал Лиспера. Средний запас победы - 300 баллов.
arrdem
Кажется, самый сильный в турнирном забеге текущего поля.
Питер Тейлор
На самом деле, нет, Друид теперь, когда я исправил ошибку в бомбардире.
Питер Тейлор
@rmckenzie, @Peter: Боже, правда? Я просто собирался на личность.
Джош Касвелл
@josh - больше нет .... в новом коде оценки @ код оценки Кейси Лиспер снова на вершине, а затем акула.
arrdem
3

"Probabimatic"

Начинается с сотрудничества, затем выбирается тот параметр, который дает наибольшее ожидаемое значение. Просто.

#include <stdio.h>

void counts(char* str, int* k, int* r, int* s, int* e) {
    *k = *r = *s = *e = 0;
    char c;
    for (c = *str; c = *str; str++) {
        switch (c) {
            case 'K': (*k)++; break;
            case 'R': (*r)++; break;
            case 'S': (*s)++; break;
            case 'E': (*e)++; break;
        }
    }
}

// Calculates the expected value of cooperating and defecting in this round. If we haven't cooperated/defected yet, a 50% chance of the opponent defecting is assumed.
void expval(int k, int r, int s, int e, float* coop, float* def) {
    if (!k && !r) {
        *coop = .5;
    } else {
        *coop = 2 * (float)k / (k + r) - (float)r / (k + r);
    }
    if (!s && !e) {
        *def = 2.5;
    } else {
        *def = 4 * (float)s / (s + e) + (float)e / (s + e);
    }
}

int main(int argc, char** argv) {
    if (argc == 1) {
        // Always start out nice.
        putchar('c');
    } else {
        int k, r, s, e;
        counts(argv[1], &k, &r, &s, &e);
        float coop, def;
        expval(k, r, s, e, &coop, &def);
        if (coop > def) {
            putchar('c');
        } else {
            // If the expected values are the same, we can do whatever we want.
            putchar('t');
        }
    }
    return 0;
}

Раньше все начиналось с сотрудничества, но теперь кажется, что дефекты на самом деле работают лучше. РЕДАКТИРОВАТЬ: Ой, подождите, это на самом деле не так.

Lowjacker
источник
1
Еще один статистик! Давайте посмотрим, как это играет против своих коллег- калькуляторов !
Джош Касвелл
Кстати, если вы измените for (char c = *str;в char c; for (c = *str;то GCC будет собирать это , не жалуясь , что он должен быть переведен в режим C99.
Питер Тейлор
3

Гиперрациональная оса

Реализовано в Java, потому что я не был уверен, насколько сложными будут структуры данных. Если для кого-то это проблема, то я думаю, что могу портировать его на bash без особых проблем, потому что в конце он использует только простые ассоциативные массивы.

Примечание : я удалил это из пакета в соответствии с последней версией моего патча для счетчика для обработки Java. Если вы хотите опубликовать Java-решение, которое использует внутренние классы, вам придется патчить патч.

import java.util.*;

public class HyperrationalWasp
{
    // I'm avoiding enums so as not to clutter up the warriors directory with extra class files.
    private static String Clam = "c";
    private static String Rat = "t";
    private static String Ambiguous = "x";

    private static final String PROLOGUE = "ttc";

    private static int n;
    private static String myActions;
    private static String hisActions;

    private static String decideMove() {
        if (n < PROLOGUE.length()) return PROLOGUE.substring(n, n+1);

        // KISS - rather an easy special case here than a complex one later
        if (mirrorMatch()) return Clam;
        if (n == 99) return Rat; // This is rational rather than superrational

        int memory = estimateMemory();
        if (memory == 0) return Rat; // I don't think the opponent will punish me
        if (memory > 0) {
            Map<String, String> memoryModel = buildMemoryModel(memory);
            String myRecentHistory = myActions.substring(0, memory - 1);
            // I don't think the opponent will punish me.
            if (Clam.equals(memoryModel.get(Rat + myRecentHistory))) return Rat;
            // I think the opponent will defect whatever I do.
            if (Rat.equals(memoryModel.get(Clam + myRecentHistory))) return Rat;
            // Opponent will cooperate unless I defect.
            return Clam;
        }

        // Haven't figured out opponent's strategy. Tit for tat is a reasonable fallback.
        return hisAction(0);
    }

    private static int estimateMemory() {
        if (hisActions.substring(0, n-1).equals(hisActions.substring(1, n))) return 0;

        int memory = -1; // Superrational?
        for (int probe = 1; probe < 5; probe++) {
            Map<String, String> memoryModel = buildMemoryModel(probe);
            if (memoryModel.size() <= 1 || memoryModel.values().contains(Ambiguous)) {
                break;
            }
            memory = probe;
        }

        if (memory == -1 && isOpponentRandom()) return 0;

        return memory;
    }

    private static boolean isOpponentRandom() {
        // We only call this if the opponent appears not have have a small fixed memory,
        // so there's no point trying anything complicated. This is supposed to be a Wilson
        // confidence test, although my stats is so rusty there's a 50/50 chance that I've
        // got the two probabilities (null hypothesis of 0.5 and observed) the wrong way round.
        if (n < 10) return false; // Not enough data.
        double p = count(hisActions, Clam) / (double)n;
        double z = 2;
        double d = 1 + z*z/n;
        double e = p + z*z/(2*n);
        double var = z * Math.sqrt(p*(1-p)/n + z*z/(4*n*n));
        return (e - var) <= 0.5 * d && 0.5 * d <= (e + var);
    }

    private static Map<String, String> buildMemoryModel(int memory) {
        // It's reasonable to have a hard-coded prologue to probe opponent's behaviour,
        // and that shouldn't be taken into account.
        int skip = 0;
        if (n > 10) skip = n / 2;
        if (skip > 12) skip = 12;

        Map<String, String> memoryModel = buildMemoryModel(memory, skip);
        // If we're not getting any useful information after skipping prologue, take it into account.
        if (memoryModel.size() <= 1 && !memoryModel.values().contains(Ambiguous)) {
            memoryModel = buildMemoryModel(memory, 0);
        }
        return memoryModel;
    }

    private static Map<String, String> buildMemoryModel(int memory, int skip) {
        Map<String, String> model = new HashMap<String, String>();
        for (int off = 0; off < n - memory - 1 - skip; off++) {
            String result = hisAction(off);
            String hypotheticalCause = myActions.substring(off+1, off+1+memory);
            String prev = model.put(hypotheticalCause, result);
            if (prev != null && !prev.equals(result)) model.put(hypotheticalCause, Ambiguous);
        }
        return model;
    }

    private static boolean mirrorMatch() { return hisActions.matches("c*ctt"); }
    private static String myAction(int idx) { return myActions.substring(idx, idx+1).intern(); }
    private static String hisAction(int idx) { return hisActions.substring(idx, idx+1).intern(); }
    private static int count(String actions, String action) {
        int count = 0;
        for (int idx = 0; idx < actions.length(); ) {
            int off = actions.indexOf(action, idx);
            if (off < 0) break;
            count++;
            idx = off + 1;
        }
        return count;
    }

    public static void main(String[] args) {
        if (args.length == 0) {
            hisActions = myActions = "";
            n = 0;
        }
        else {
            n = args[0].length();
            myActions = args[0].replaceAll("[KR]", Clam).replaceAll("[SE]", Rat);
            hisActions = args[0].replaceAll("[KS]", Clam).replaceAll("[RE]", Rat);
        }

        System.out.println(decideMove());
    }

}

Изменения, которые я внес в счетчик для запуска этого:

17a18
> import re
22a24
> GCC_PATH = 'gcc'                #path to c compiler
24c26
< JAVA_PATH = '/usr/bin/java'   #path to java vm
---
> JAVA_PATH = '/usr/bin/java'     #path to java vm
50,55c52,59
<         elif ext == '.java':
<             if subprocess.call([JAVAC_PATH, self.filename]) == 0:
<                 print 'compiled java: ' + self.filename
<                 classname = re.sub('\.java$', '', self.filename)
<                 classname = re.sub('/', '.', classname);
<                 return JAVA_PATH + " " + classname
---
>         elif ext == '.class':
>             # We assume further down in compilation and here that Java classes are in the default package
>             classname = re.sub('.*[/\\\\]', '', self.filename)
>             dir = self.filename[0:(len(self.filename)-len(classname))]
>             if (len(dir) > 0):
>                 dir = "-cp " + dir + " "
>             classname = re.sub('\\.class$', '', classname);
>             return JAVA_PATH + " " + dir + classname
196c200,201
<         if os.path.isdir(sys.argv[1]):
---
>         warriors_dir = re.sub('/$', '', sys.argv[1])
>         if os.path.isdir(warriors_dir):
198,200c203,211
<             for foo in os.listdir("./src/"): # build all c/c++ champs first.
<                 os.system(str("gcc -o ./warriors/" + os.path.splitext(os.path.split(foo)[1])[0] + " ./src/" + foo ))
<                 #print str("gcc -o ./warriors/" + os.path.splitext(os.path.split(foo)[1])[0] + " ./src/" + foo )
---
>             for foo in os.listdir("./src/"): # build all c/c++/java champs first.
>                 filename = os.path.split(foo)[-1]
>                 base, ext = os.path.splitext(filename)
>                 if (ext == '.c') or (ext == '.cpp'):
>                     subprocess.call(["gcc", "-o", warriors_dir + "/" + base, "./src/" + foo])
>                 elif (ext == '.java'):
>                     subprocess.call([JAVAC_PATH, "-d", warriors_dir, "./src/" + foo])
>                 else:
>                     print "No compiler registered for ", foo
202,203c213,214
<             print "Finding warriors in " + sys.argv[1]
<             players = [sys.argv[1]+exe for exe in os.listdir(sys.argv[1]) if os.access(sys.argv[1]+exe,os.X_OK)]
---
>             print "Finding warriors in " + warriors_dir
>             players = [warriors_dir+"/"+exe for exe in os.listdir(warriors_dir) if (os.access(warriors_dir+"/"+exe,os.X_OK) or os.path.splitext(exe)[-1] == '.class')]

Спасибо @rmckenzie за то, что я сложил свою функцию претендента.

Питер Тейлор
источник
Просто вопрос стиля .... следует ли считать файл .java «исходным» и перемещать его в каталог ./src, а окончательный .class помещать в папку ./warriors с помощью того же индекса, который используется в файлах .c, или интерпретируется ли Java, и как таковые .java и .class остаются вместе? Хорошие изменения в бомбардире в любом случае ... будут иметь их в статистике репо.
arrdem
@rmckenzie, хорошая мысль: да, технически это скомпилировано. Причина, по которой у меня был исходный файл в каталоге warriors, в том, что там есть и файлы python - и они скомпилированы. Если вы хотите, я могу проверить, какие изменения необходимы для компиляции из ./src в ./warriors - но для этого потребуется несколько аргументов компилятора, потому что Java по умолчанию предполагает, что структура каталогов отражает пакет (пространство имен).
Питер Тейлор
@peter, мне просто интересно ... воины находятся в ./warriors в силу того, что они * nix 777 или иным образом исполняемые. Скрипты Python и Lisp НОМИНАЛЬНО скомпилированы для производительности, но исполняются в своем естественном (исходном) состоянии. К МОИМ ЗНАНИЯМ, КАК ЧЕЛОВЕК НЕ-JAVA, файлы .java не имеют таких разрешений и, следовательно, не будут отображаться. Вот для чего существует хакерство ... потому что компиляция - это отдельный шаг. Так что да. Я был бы очень признателен, если бы вы посмотрели на это изменение. РЕПО ЛИНК
arrdem
Используя ваш код и осу chmod 777, JVM бросила эту красоту. Exception in thread "main" java.lang.NoClassDefFoundError: //warriors/HyperrationalWasp Caused by: java.lang.ClassNotFoundException: ..warriors.HyperrationalWasp at java.net.URLClassLoader$1.run(URLClassLoader.java:217) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:205) at java.lang.ClassLoader.loadClass(ClassLoader.java:321) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294) at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
arrdem
@rmckenzie, это странно. Во всяком случае, я думаю, что у меня будет патч для вас очень скоро. Мне пришлось взломать код загрузки, потому что файлы классов не являются исполняемыми. И если любые другие записи Java используют внутренние классы, это сломается.
Питер Тейлор
3

Soft_majo

Ах, хорошо, еще одна из стандартных стратегий, просто чтобы завершить состав.

Этот выбирает ход, который противник сделал больше всего; при равных он сотрудничает.

#include <stdio.h>
#include <string.h>

int main(int argc, char * argv[]) {
    int d = 0, i, l;

    if (argc == 1) {
        printf("c\n");
    } else {
        l = strlen(argv[1]);

        for (i = 0; i < l; i++)
            if (argv[1][i] == 'R' || argv[1][i] == 'E')
                d++;

        printf("%c\n", d > l/2 ? 't' : 'c');
    }
}
детеныш
источник
Ваш код - soft_majo, но ваше описание - hard_majo.
Питер Тейлор
Питер: Эх, прости; исправлено.
Джои
3

Случайный присоски

Этот будет дефект, если оппонент слишком часто (порог), но будет время от времени пытаться нанести удар в спину.

Работает довольно хорошо против всех, кроме игроков Java и Lisp (которые я не могу запустить из-за того, что на тестовой машине нет ни Java, ни Lisp); большую часть времени по крайней мере.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#define THRESHOLD 7
#define RAND 32

int main(int c, char * a []) {
    int r;
    char * x;
    int d = 0;

    srandom(time(0) + getpid());

    if (c == 1) {
        printf("c\n");
        return 0;
    }

    for (x = a[1]; *x; x++)
        if (*x == 'R' || *x == 'E') d++;

    if (d > THRESHOLD || random() % 1024 < RAND || strlen(a[1]) == 99)
        printf("t\n");
    else
        printf("c\n");

    return 0;
}
детеныш
источник
Против HyperrationalWasp, как правило, это будет примерно так же, как против дьявола. Он начинает просто сотрудничать все время, поэтому я предполагаю, что это ангел, и приступаю к атаке. Затем, когда он достигнет порога, вы переключитесь в режим дьявола, а я переключусь на t4t. Если это произойдет случайным ударом в спину в первые 6 ходов, я переключусь на t4t, прежде чем вы перейдете в дьявола, но вероятность этого невелика.
Питер Тейлор
1
Питер: Ну, я редко проверяю стратегии непосредственно друг против друга, так как общая область довольно сильно влияет на эффективность стратегии. В настоящее время это в основном борьба с постепенным и друидом за первое место в моих тестах.
Джои
Постепенно и друид оба набрали около 200 против Оса; случайная присоска забьет около 83.
Питер Тейлор
2

былое

#!/usr/bin/env python

"""
BYGONES, entry to 1P5 Iterated Prisoner's Dilemma, by Josh Caswell

Cooperates at first, plays as Tit for Tat for `bygones * 2` rounds, then checks 
history: if there's too much ratting, get mad and defect; too much 
suckering, feel bad and cooperate.
"""

bygones = 5

import sys

# React to strangers with trust.
try:
    history = sys.argv[1]
except IndexError:
    print 'c'
    sys.exit(0)

replies = { 'K' : 'c', 'S' : 'c',
            'R' : 't', 'E' : 't' }

# Reply in kind.
if len(history) < bygones * 2:
    print replies[history[0]]
    sys.exit(0)

# Reflect on past interactions.
faithful_count = history.count('K')
sucker_count = history.count('S')
rat_count = history.count('R')

# Reprisal. 
if rat_count > faithful_count + bygones:
    # Screw you!
    print 't'
    sys.exit(0)

# Reparation.
if sucker_count > faithful_count + bygones:
    # Geez, I've really been mean.
    print 'c'
    sys.exit(0)

# Resolve to be more forgiving.
two_tats = ("RR", "RE", "ER", "EE")
print 't' if history[:2] in two_tats else 'c'

Не нашли лучшего значения для bygones . Я не ожидаю, что это будет выигрышная стратегия, но я заинтересован в том, чтобы стратегия выглядела как то, что я считаю «хорошим» в реальной жизни. Будущий пересмотр может также включать проверку количества взаимных отступлений.

Джош Касвелл
источник
2

Помогите вампиру

#!/usr/bin/env python

"""
Help Vampire, entry to 1P5 Iterated Prisoner's Dilemma,
by Josh Caswell.

1. Appear Cooperative 2. Acknowledge Chastisement 
3. Act contritely 4. Abuse charity 5. Continual affliction
"""

import sys
from os import urandom

LEN_ABASHMENT = 5

try:
    history = sys.argv[1]
except IndexError:
    print 'c'    # Appear cooperative
    sys.exit(0)

# Acknowledge chastisement
if history[0] in "RE":
    print 'c'
# Act contritely
elif set(history[:LEN_ABASHMENT]).intersection(set("RE")):
    print 'c'
# Abuse charity
elif history[0] == 'S':
    print 't'
# Continual affliction
else:
    print 't' if ord(urandom(1)) % 3 else 'c'

Имеет забавно асимметричный результат, когда настроен против самого себя. Если бы только это решение могло быть применено в реальной жизни.

Джош Касвелл
источник
2

друид

#!/usr/bin/env python

"""
Druid, by Josh Caswell

Druids are slow to anger, but do not forget.
"""

import sys
from itertools import groupby

FORBEARANCE = 7
TOLERANCE = FORBEARANCE + 5

try:
    history = sys.argv[1]
except IndexError:
    history = ""

# If there's been too much defection overall, defect
if (history.count('E') > TOLERANCE) or (history.count('R') > TOLERANCE):
    print 't'
# Too much consecutively, defect
elif max([0] + [len(list(g)) for k,g in     # The 0 prevents dying on []
                groupby(history) if k in 'ER']) > FORBEARANCE:
    print 't'
# Otherwise, be nice
else:
    print 'c'

Достаточно хорошо против базового состава.

Джош Касвелл
источник
2

простак

#!/usr/bin/env python

"""
Simpleton, by Josh Caswell

Quick to anger, quick to forget, unable to take advantage of opportunity.
"""

import sys
from os import urandom

WHIMSY = 17

try:
    history = sys.argv[1]
except IndexError:
    if not ord(urandom(1)) % WHIMSY:
        print 't'
    else:
        print 'c'
    sys.exit(0)

if history[0] in "RE":
    print 't'
elif not ord(urandom(1)) % WHIMSY:
    print 't'
else:
    print 'c'

Хорошо против базового состава.

Джош Касвелл
источник
2

Маленький интриган

#!/usr/bin/env python

"""
The Little Schemer, by Josh Caswell

No relation to the book. Keeps opponent's trust > suspicion 
by at least 10%, trying to ride the line.
"""

from __future__ import division
import sys
from os import urandom

out = sys.stderr.write

def randrange(n):
    if n == 0:
        return 0
    else:
        return ord(urandom(1)) % n

try:
    history = sys.argv[1]
except IndexError:
    print 'c'
    sys.exit(0)

R_count = history.count('R')
S_count = history.count('S')
K_count = history.count('K')
E_count = history.count('E')

# Suspicion is _S_ and E because it's _opponent's_ suspicion
suspicion = (S_count + E_count) / len(history)
# Likewise trust
trust = (K_count + R_count) / len(history)

if suspicion > trust:
    print 'c'
else:
    projected_suspicion = (1 + S_count + E_count) / (len(history) + 1)
    projected_trust = (1 + K_count + R_count) / (len(history) + 1)

    leeway = projected_trust - projected_suspicion
    odds = int(divmod(leeway, 0.1)[0])

    print 't' if randrange(odds) else 'c'

Плохо справляется с базовым набором, но довольно хорошо против своей цели. Очевидно, не написано на схеме.

Джош Касвелл
источник
Почему я чувствую вызов?
arrdem
Победил этого педераста .... Рандомизировал порог в Лиспере.
arrdem
@rmckenzie: но как это повлияло на твою игру против остальной части поля? С достаточным количеством кооператоров, работающих друг с другом, параноидальные или завистливые стратегии начнут ухудшаться. У вас все еще есть фиксированный верхний предел, который можно использовать.
Джош Касвелл
Если вы прочитаете текущий шепот, это скорее защита, чем зависть. Он пытается обнаружить противников, которые преследуют статистически коварные страты, как это, и только потом возвращает огонь. Это открытие CC предназначено, чтобы встать на правую ногу с Ворами, и имеет дополнительное преимущество, заключающееся в том, чтобы убедить большинство кооперативных слоев играть вместе.
arrdem
@rmckenzie: Очень хорошо! Я сделаю это.
Джош Касвелл
1

Синица для двух татов

еще один старый любимый

#!/usr/bin/env python

"""
Tit For Two Tats, entry to 1P5 Iterated Prisoner's Dilemma, 
    by Josh Caswell (not an original idea).

Cooperates unless opponent has defected in the last two rounds.
"""

import sys
try:
    history = sys.argv[1]
except IndexError:
    history = ""

two_tats = ("RR", "RE", "ER", "EE")

if len(history) < 2:
    print 'c'
else:
    print 't' if history[:2] in two_tats else 'c'
Джош Касвелл
источник
Вы не можете сделать возврат, если вы не внутри функции. Может быть, использовать sys.exit(0)? Или просто дайте ему закончить. Изменить: Также первый вызов вашей программы без истории, которая вызывает, IndexErrorкогда вы делаете argv[1].
Кейси
Возможно, вы пропустили len(history)<2предложение, потому что последнее выглядит как elseчасть.
dmckee
@Casey @dmckee Спасибо за исправленные ошибки. "Дух" на меня, returnособенно!
Джош Касвелл
@dmckee: Это началось как часть более сложной вещи, и затем я понимаю, что переписал «Тит для двух татов» и решил принять это. Скопируйте и вставьте ошибку пользователя.
Джош Касвелл
@Josh: я кратко видел твою запись в Bygones, ты ее удалил? Выглядело интересно.
Кейси