1П5: Ітераційна дилема в'язня


35

Це завдання є частиною першого періодичного прем'єр - програмування головоломка Пуш і призначена як демонстрація нового виклик типу пропозиції .

Завдання - написати програму, щоб відтворити повторену дилему в'язня краще, ніж інші учасники.

Подивися, Вінні. Ми знаємо вашого співмешканця --- як його звати? Так, Маквонгський, ніпопо-ірландсько-український гангстер - щось до чого, і ви знаєте, що це таке.

Ми намагаємось бути приємно тут, Вінні. Дай вам шанс.

Якщо ви скажете нам, що він планує, ми побачимо, що ви отримаєте хорошу роботу.

А якщо ви цього не зробите ...

Правила гри

  • Конкурс складається з повноцінного кругообігу (усі можливі пари) одночасно з двома учасниками (включаючи самостійні ігри).
  • Між кожною парою проводиться 100 раундів
  • У кожному раунді кожному гравцеві пропонується вибирати співпрацювати з іншим гравцем або зраджувати їх, не знаючи намірів інших гравців у цьому питанні, але пам’ятаючи про результати попередніх раундів, зіграних проти цього суперника.
  • Очки присвоюються за кожен раунд на основі комбінованого вибору. Якщо обидва гравці співпрацюють, кожен отримує 2 бали. Взаємна зрада дає 1 бал кожній. У змішаному випадку гравцеві, який зраджує, присуджується 4 бали, а кооператор накладається штраф 1.
  • "Офіційний" матч буде проведений не раніше ніж через 10 днів після публікації з усіма поданнями, які я можу взяти на роботу, і буду використаний для вибору "прийнятого" переможця. У мене є Mac OS 10.5 вікно, тому рішення POSIX повинні працювати, але є Linuxx, які цього не роблять. Так само я не підтримую API Win32. Я готовий докласти основних зусиль для встановлення речей, але є обмеження. Межі моєї системи жодним чином не представляють межі прийнятних відповідей, просто тих, які будуть включені у "офіційну" відповідність.

Інтерфейс програміста

  • Записи повинні бути у вигляді програм, які можна запустити з командного рядка; рішення повинно бути (єдиним!) результатом програми на стандартному виході. Історія попередніх раундів з цим опонентом буде представлена ​​як аргумент командного рядка.
  • Вихідні дані є "c" (для підключення ) або "t" (для всіх ).
  • Історія - це єдиний рядок символів, що представляє попередні раунди, причому останні раунди виходять найчастіше в рядку. Персонажі є
    • "K" (бо зберегли віру, що означає взаємну співпрацю)
    • "R" (для щура b @ st @ rd мене продали! )
    • "S" (для присосок! Означає, що ви виграли від зради)
    • "Е" (бо всі шукають номер один про взаємну зраду)

Кронштейн

Чотири гравці будуть надані автором

  • Ангел - завжди співпрацює
  • Чорт - завжди розмовляє
  • TitForTat - Співпрацює в першому раунді, тоді завжди робить так, як це робилося в останньому раунді
  • Випадкові - 50/50

до якого я додам усі записи, які можу отримати для запуску.

Загальний бал буде підсумовувати бал проти всіх супротивників (включаючи самостійні ігри лише один раз та використання середнього балу).

Вступники

(чинний станом на 2 травня 2011 р. 7:00)

Таємне рукостискання | Ракета проти Т42Т | Недовіра (варіант) | Анти-рукостискання | Маленький Лиспер | Конвергенція | Акула | Імовірний | Павлов - Виграй, залишайся, програй перемикач | Честь серед злодіїв | Допомога Вампіру | Друїд | Маленький Шемер | Тимчасові | Синиця на двох татів | Простий |

Бомбардир

#! /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, виявляти та компілювати джерела пітона (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

2
Якщо мій співкамерник - ніппо-ірландсько-український, чому його ім’я виглядає гіберно-китайсько-російським?
Пітер Тейлор

2
@ Петер: LOL. Правда? Що ж, (1) генеалогії не зрозумілі, але я, мабуть, прийшов своєю мізерністю через шотландсько-ірландський; (2) після того, як я написав "Nippo", я випробував різні шматочки імен моїх друзів з країни висхідного сонця і мені не сподобалось те, як вони сканували, тому я пішов вперед і використав китайське прізвище, яке звучало добре натомість, і (3) я б не знав різниці, якби вони по черзі б'ють мене шинами. Що здається ймовірним за обставин.
dmckee

1
@Josh: Чи було б просто змінити return (s1, L1+h1), (s2, L2+h1)на return (s1, L1+h1), (s2, L2+h2)[Примітка L2+h2замість L2+h1кінця]? // Помилка вирізання-вставки або щось настільки ж ідіотське. Sheesh!
dmckee

2
Я витратив деякий час на тестовий сценарій, і я радий повідомити про оновлення тут . Це оновлення додає просту оболонку до тестового сценарію, що дозволяє користувачеві вручну запускати цього бота проти цього бота, проводити турніри з обмеженими полями та деякі інші цікаві речі. Не соромтеся робити пропозиції! Ой. І я завдячую @josh за ідею bot-vs-bot. Це насправді просто більш фантазійне виконання його «тренерського» сценарію.
arrdem

2
Цікаво: Було 23 учасники, тож кожен грав 22 раунди. Якби всі грали в "Ангел", кожен рахунок був би 4400, але навіть найкращий результат 4167 не відповідав би цьому. Якби ми жили в ідеальному світі ... :)
Briguy37

Відповіді:


11

Поступовий

Ця стратегія ґрунтується на роботі Beaufils, Delahaye та Mathieu . Мій C насправді не найкращий, тому якщо у когось є якісь пропозиції щодо вдосконалення / пришвидшення коду, дайте мені знати!

[Редагувати] Варто зазначити, що "Градіал" був розроблений як стратегія, яка перевершує Тит для Тата. Він має подібні властивості тим, що готовий співпрацювати і мститься проти опонента, який зазнає поразки. На відміну від Тіта для Тата, який має лише пам’ять про останній відіграний раунд, "Поступово" запам'ятає повну взаємодію та зазнає дефектів, скільки разів перемогла противник. Однак він знову запропонує взаємну співпрацю.

Як завжди, ефективність стратегії дещо залежить від складання інших стратегій. Крім того, оригінальний папір не був дуже зрозумілий у деяких деталях.

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

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 для Tat. Приємно. Я не здогадувався, що TAGйого грають заднім числом. Однак, чи не повинен бути ваш TAGMATCH"KEEEKEEEKE"? "".join({('c', 'c'):'K', ('t', 't'): 'E'}[moves] for moves in zip(TAG, TAG))
Джош Касвелл

@John Добре - я спочатку мав іншу TAG, і коли я змінив її, щоб мінімізувати співпрацю, я забув оновити TAGMATCH. @Arrdem Ідея полягає в тому, що якщо я граю проти себе, найкраще зробити, щоб обидва постійно співпрацювали, щоб максимально збільшити суму своїх балів.
Аарон Дюфур

1
Ах, чорт забирай. Тому тепер мені доведеться шукати всі .pyфайли для вашого коду та витягувати TAG. Я не буду цього робити на З ...
Джої,

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)

  • (C, T) - P2 отримує ЧЕТВЕРТИННІ БУНКИ за свою зраду, тоді як P1 ВІДБУВАЄ ОДИН
  • (T, T) - P2 І P1 НАЗАД 1

Якщо припустити, що P2 - диявол, то немає можливості, щоб диявол коли-небудь міг втратити очки, насправді найгірше, що він може зробити, це отримати лише один бал. Тому проти чисто випадкового супротивника, найгірший можливий рахунок диявола буде точно (5/2) * n, де n - кількість "ігор", що граються. Його абсолютний найгірший випадок - проти самого себе, де його оцінка буде n, а його найкращий випадок - проти ангела, який буде 4 * n

Стверджувати: optim_strat = чорт

це турнір. Задній удар мого напарника - це набагато краща стратегія, ніж співпраця, оскільки це допомагає МОЄМУ СКОРОМУ (+4). БОНУС - він грюкає (-1)! Якщо я висуну йому шию, я виграю (+2) і розпушую (-1). З цього приводу статистичний показник винагороджується.

Але чи оптимально це?

Немає жодних підстав для того, щоб EVER (за цією системою підрахунків балів) співпрацював.

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

У системі KOTH максимізація віддачі є важливою. Навіть якщо у вас є два боти, які прекрасно синхронізуються та співпрацюють, їхні індивідуальні бали все одно отримають лише 200 балів за спортивне майстерність. Диявол з іншого боку заробить щонайменше 100 очок, середній випадок - 200 і максимум 400, - і коштуватиме його опонентам до 100 очок кожен! Тож практично диявол насправді набирає середню гру в 300, прискорюючи до 500.

Підсумок - час покаже

Для мене, схоже, забивання слід переглядати, щоб чорт не зайняв день. Підвищення показника співпраці до 3, все це може зробити. Однак можливо виявити чортів і не допустити їх забивати їх повних 400, як показують павлов і злобні. Чи можу я довести, що хтось із них набере достатньо балів для співпраці, щоб виправдати свою віру? ні. Все це залежить від остаточного поля претендентів.

GL, HF!

І будь ласка, зробіть найгірше на цій посаді. Я хочу написати свою статтю, коли все сказано і зроблено.

Історія версій

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

ОФІЦІЙНА ВЕРСІЯ ЛІЗПЕРА

РОЗВИТОК ВЕРСІЇ ЛІЗПЕРА


Рахунок різниться в різних варіантах гри. Я ж погратися зі збільшенням стимул співпраці, і я згоден , що це буде мати вплив на обраних стратегій. Хороша новина: ви можете схопити бомбардира, встановити власні правила і спробувати його. В принципі, ви навіть можете запропонувати щедроту.
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 для 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

Ах, правда, що. Я не був впевнений, як виявити перший раунд, чи є порожній перший аргумент (історія) чи просто жоден.
Joey

Я не впевнений. Це все, що пітон робить, Popen(p+" "+h,stdout=subprocess.PIPE,shell=True)коли h = ''. Я припускаю argc=1.
dmckee

1
Ця початкова послідовність є досить хорошою ідеєю, прямо націленою на Тіта на слабкість Тата. Ви отримуєте на ньому крихітний привід, а потім відтворюєте його шлях.
Джош Касвелл

1
@Josh, куди крихітна ведуча? Проти T4T це починається з SRK, а потім продовжується з K. Але SR коштує 3 очки для кожного гравця.
Пітер Тейлор

5

Ракета проти T42T

#!/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: немає проблем. Я зроблю це. Потрібно будь-коли додати рядок doc.
Джош Касвелл

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

Я спробував зменшити вагу історії, але недостатньо оптимізував її.


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

Павлов - Виграй, залишайся, програй перемикач

На першому ж етапі він співпрацює, а потім співпрацює, якщо і лише тоді, коли обидва гравці обрали один і той же вибір у попередньому кроці.

#!/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'

Чи не слід це використовувати 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 - не більше .... у новому коді зарахування @ casey-коду casey Ліспер знову на вершині, а за ним - акула.
arrdem

3

"Імовірнісний"

Починається з співпраці, а потім вибирає той варіант, який надає їй найбільшу очікувану цінність. Простий.

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

Раніше починався з співпраці, але зараз здається, що дефекти насправді працюють краще. EDIT: О, чекайте, насправді це не так.


1
Ще один статистик! Подивимося, як це грає проти своїх колег- калькуляторів !
Джош Касвелл

До речі, якщо ви перейдете for (char c = *str;на char c; for (c = *str;тоді, gcc буде компілювати це, не поскаржившись, що його потрібно перевести в режим C99.
Пітер Тейлор

3

Гіперраціональна ос

Реалізовано в Java, тому що я не був впевнений, наскільки складні структури даних будуть в кінцевому підсумку. Якщо це проблема для когось, то я думаю, що я можу перенести її на баш без зайвих проблем, оскільки врешті-решт він використовує лише прості асоціативні масиви.

Примітка . Я видалив це з пакета відповідно до останньої версії мого патча до бомбардира для обробки 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, хороший момент: так, технічно це складено. Причиною того, що я мав вихідний файл у каталозі воїнів, є те, що файли python також є - і вони компілюються. Якщо ви хочете, я можу перевірити, які зміни потрібні для компіляції з ./src до ./warriors - але для цього знадобиться кілька аргументів компілятора, оскільки Java за замовчуванням передбачає, що структура каталогу відображає пакет (простір імен).
Пітер Тейлор

@peter, мені було просто цікаво ... воїни знаходяться в ./warriors в силу того, що вони * nix 777, або виконуються іншим чином. Сценарії Python та Lisp НОМІНАЛЬНО складені для продуктивності, але виконуються у природному (вихідному) стані. МОЮ ЗНАННЯ ЯК ОСОБА НЕ ЯВА, файли .java не мають цих дозволів, і тому вони не відображатимуться. Ось для чого існує хак c, оскільки компіляція - це окремий крок. Так що так. Я дуже вдячний, якби ви хотіли змінити цю зміну. РЕПО ЛІНК
arrdem

Використовуючи свій код і chmod 777'd wasp, 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.
Пітер Тейлор

Петро: Ек, вибач; фіксований.
Joey

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
Петро: Ну, я рідко тестую стратегії безпосередньо один проти одного, оскільки загальне поле має певний вплив на ефективність стратегії. В даний час він в основному бореться з поступово і друїд за перше місце в моїх тестах.
Joey

Поступово і друїд оба оцінюють близько 200 проти Wasp; Випадкова присоска набере приблизно 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, ви його видалили? Це виглядало зацікавленим.
Кейсі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.