1P5:囚徒困境


35

此任务是“第一次定期Premier Programming难题推送”的一部分,旨在演示新挑战之提案

任务是编写一个程序,比其他参赛者更好地发挥被囚徒的困境。

看,温妮。我们认识您的室友-他叫什么名字?是的,Nippo-Irish-Ukranian黑帮老大McWongski忙得不可开交,您知道这是什么。

Vinnie,我们在这里努力要好。给你一个机会。

如果您告诉我们他的计划,我们将为您分配好工作。

如果你不...

游戏规则

  • 比赛由一次完整的循环赛(所有配对)组成,两名选手同时参加(包括自我比赛)。
  • 每对之间进行100轮比赛
  • 在每个回合中,要求每个玩家在与对方玩家合作或背叛他们之间进行选择,而无需知道对方的意图,要记住与对手对战的结果。
  • 基于组合选择,每一轮都将获得积分。如果双方都合作,他们将分别获得2分。相互背叛产生1分。在混合情况下,背叛者获得4分,而合作者则受到1分的惩罚。
  • 我将在发帖后的10天内进行一次“正式”比赛,我将开始处理所有提交的作品,并用于选择“接受的”获胜者。我有一个Mac OS 10.5盒子,所以POSIX解决方案应该可以工作,但是有Linuxisms不能。同样,我不支持win32 API。我愿意尽一切努力安装东西,但是有一个限制。我的系统的限制绝不代表可接受的响应的限制,只是代表那些将包含在“正式”匹配中的响应。

程序员界面

  • 条目应采用可以从命令行运行的程序的形式。决定必须在标准输出上显示程序的(唯一!)输出。与该对手进行的前几轮比赛的历史将作为命令行参数显示。
  • 输出可以是“C”(对于蛤向上)或“t”(对于告诉所有)。
  • 历史记录是单个字符串,代表以前的回合,而最早的回合则最早出现在字符串中。字符是
    • “ K”(表示保持信念,意味着相互合作)
    • “ R”(因为老鼠b @ st @ rd把我卖了!
    • “ S”(傻瓜!意味着您从背叛中受益)
    • “ E”(因为每个人都在寻找相互背叛的第一名

支架

作者将提供四名选手

  • 天使-永远合作
  • 魔鬼-总是会说话
  • TitForTat-在第一轮进行合作,然后总是像在上一轮那样
  • 随机-50/50

我将在其中添加所有可以运行的条目。

总分将是所有对手的总分(包括一次自我比赛,并使用平均分)。

参赛者

(截至2011年5月2日7:00)

秘密握手 | 反T42T导弹 | 不信任(变数) | 防握手 | 小莉珀 | 融合 | 鲨鱼 | 概率 | 巴甫洛夫-获胜,输掉开关 | 盗贼荣誉 | 帮助吸血鬼 | 德鲁伊 | 小计划者 | 过去 | 山雀两刘以达 | Simpleton |

得分手

#! /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
  • 关于我的可怕python的投诉是值得欢迎的,因为我敢肯定这不仅仅一种方法
  • 错误修复

记分员变更日志:

  • 打印排序的球员和比分,并宣布获胜者(凯西,4/29)
  • (可选)运行多个锦标赛(./score warriors/ num_tournaments))default = 1,检测并编译python源代码(4/29,Casey)
  • 修复尤其愚蠢的错误,在该错误中第二位玩家被传递了错误的历史记录。(4/30,dmckee;感谢Josh)

最初的战士

举例来说,这样可以验证结果

天使

#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
如果我的室友是Nippo-Irish-Ukrainian,为什么他的名字看起来像Hiberno-Sino-Russian?
彼得·泰勒

2
@Peter:哈哈。真相?好吧,(1)家谱尚不清楚,但我可能是通过苏格兰爱尔兰语的方式来模仿我的;(2)在写了“ Nippo”之后,我从冉冉升起的太阳的土地上尝试了很多朋友的名字,并且不喜欢他们扫描的方式,所以我继续使用听起来像中文的姓氏(3)如果他们轮流用轮胎熨斗殴打我,我不会知道有什么区别。在这种情况下似乎很有可能。
dmckee 2011年

1
@Josh:更改return (s1, L1+h1), (s2, L2+h1)return (s1, L1+h1), (s2, L2+h2)[Note L2+h2而不是L2+h1结尾]是否简单?// Cut-n-paste错误或同样愚蠢的错误。嘘!
dmckee'5

2
我已经在测试脚本上花了一些时间,很高兴在这里宣布更新。此更新为测试脚本添加了一个简单的外壳,该外壳允许用户手动运行该机器人与该机器人的比较,并使用受限字段和一些其他有趣的东西运行锦标赛。随时提出建议!哦。我欠@josh的bot-vs-bot创意。实际上,这只是他的“培训师”脚本的一种更好的实现。
2011年

2
有趣:有23名选手,所以每人参加22轮比赛。如果每个人都玩过“天使”游戏,那么每个分数将是4400,但是即使是最高分4167,也无法达到这个水平。如果我们生活在一个完美的世界中……:)
Briguy11 2011年

Answers:


11

渐进的

该策略基于Beaufils,Delahaye和Mathieu的论文。我的C确实不是最好的C,所以如果有人对提高/加快代码有任何建议,请告诉我!

[编辑]值得注意的是,Gradual的设计策略优于Tat for Tat。它具有相似的特性,因为它愿意合作并对有缺陷的对手进行报复。与Tat 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;
}

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因此转到代码而非字节码文件)。我认为这是我所有实例所没有的唯一信息,因此这似乎是避免寄生虫的唯一选择。


但是,您的doppelganger如何知道自己会变成魔鬼?
arrdem 2011年

1
(我感觉就像只鹦鹉,一直都在说“ Tat for Tat”……)请注意,T4T将在以下方面与您的策略相提并论:T4T(较早合作)和Devil(较少Rat结果),并将与您并列战略。当然,最后才是总数,而不是配对总数。如您所说,人口很重要。
乔什·卡斯维尔

1
哦,不,您会从Tat for Tat中得到一个额外的S。真好 我不知道TAG是在倒退。但是,您不应该TAGMATCH是“ KEEEKEEEKE”吗?"".join({('c', 'c'):'K', ('t', 't'): 'E'}[moves] for moves in zip(TAG, TAG))
乔什·卡斯维尔

@John Good point-我最初有一个不同的TAG,当我更改它以最小化合作时,我忘了更新TAGMATCH。@Arrdem的想法是,如果我在和自己比赛,那么最好的办法就是让双方一直合作以最大化他们的总分。
亚伦·迪富

1
噢,该死。因此,现在我必须在所有.py文件中搜索您的代码并提取TAG。我不会在C语言中那样做
Joey

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
    )
)

恶魔

考虑以下格式(播放器1,播放器2)

  • (C,T) - P2收益FOUR POINTS他的背叛,而P1 丢了一条
  • (T,T)-P2和P1增益1

假设P2是魔鬼,那么魔鬼就不可能失去任何分数,事实上,他所能做的最糟糕的事情就是只获得1分。因此,面对纯粹随机的对手,恶魔的最差得分将恰好是(5/2)* n,其中n是打的“游戏”数。他的绝对最坏情况是针对自己,他的得分将为n,而他的最佳情况是针对天使,则为4 * n

断言:optimum_strat =魔鬼

这是比赛。与合作伙伴背刺刺伤是比合作更好的策略,因为它可以帮助我提高得分(+4)。奖励-他被猛击(-1)!如果我为他伸出脖子,我将获得(+2)和放松(-1)。因此,统计上反刺是有奖励的。

但这是最优的吗?

没有理由(在该评分系统下)进行合作。

  • 如果您选择了错误的时间来适应,那么您就会松懈。
  • 如果您老鼠,至少您不会放松任何东西。
  • 如果您吃鼠,而他又傻,那么您获得的收益比您长得还不错。

在KOTH系统中,最大化回报至关重要。即使您有两个完全同步和合作的机器人,他们的个人得分也仅会因其体育精神而提高200分。另一方面,魔鬼将至少获得100点,平均情况下为200点,最多为400点,并且使对手每人最多损失100点!因此,实际上,恶魔平均得分为300,最高达到500。

底线-时间会证明一切

在我看来,应该重新考虑得分问题,以免魔鬼花了一天的时间。将合作分数提高到3都可以做到。但是,有可能检测到恶魔并阻止其得分,如pavlov和spite所示。我能证明任何一个人都能为他们的合作拿到足够的积分来证明自己的信念吗?没有。所有这些都取决于竞争者的最终领域。

GL,HF!

并请尽你所能来做这篇文章。一切都说完了之后,我想写我的高级论文。

版本历史

  1. 添加了一个余量变量,该变量随机更改Lisper对duchebaggery的容忍度。
  2. 在前两轮中将lisper更新为蛤,与合作对手一起右脚下车
  3. 使用遗传算法根据随机阈值生成器针对一组标准对手的最大累积得分,为其找到最可靠的值。发布更新,包括它们。

官方版本

开发者版本


得分因游戏的不同而异。我确实在增加合作激励措施,并同意它将对所选策略产生影响。好消息:可以抓住得分手,设定自己的规则并尝试。原则上,您甚至可以提供赏金。
dmckee 2011年

fink install clisp ::反复轻敲手指::
dmckee 2011年

1
@josh-感谢您的链接。我阅读了有关此困境的其他维基百科页面,但我错过了该部分。我刚刚注意到的一个规则错误,没有针对使用文件系统的条目的规则。这创造了沿着握手路线进行更有效合作的潜力。
arrdem 2011年

3
There is no reason to EVER (under this scoring system) co-operate仅正确一半。如果您知道您的对手没有考虑历史(天使,魔鬼,随机的),那么您应该始终背叛。如果您的对手确实考虑了历史,并且您可以同步,那么您可以做得更好。我有两个想法,围绕着判断对手是理性的还是超理性的。
彼得·泰勒

1
使用最新版本时,您不是三分之二的时间都被零除错误吗?每当(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 2011年

啊,是的。但是,我不确定如何检测到第一轮是否是空的第一个参数(历史记录)还是没有。
乔伊

我不确定。这就是python对Popen(p+" "+h,stdout=subprocess.PIPE,shell=True)when 所做的一切h = ''。我在猜argc=1
dmckee 2011年

1
最初的顺序是一个好主意,直​​接针对Tat来弥补Tat的弱点。您会在其中获得微小的领先优势,然后再发挥自己的作用。
乔什·卡斯韦尔

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:主啊,我对这个问题的热情使我犯了很多愚蠢的错误!谢谢,但是为什么要消除爆炸?
乔什·卡斯威尔

嗯,那是个意外。我将其添加回去。
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;
}

我尝试过轻描淡写历史的权重,但没有对其进行适当的优化。


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'

在基本花名册上做得很好。


...抓住蛤?
2011年

:)抓住傻瓜。
乔什·卡斯韦尔

+1用于在当前字段中保持一致的第二名。
2011年

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]始终是本回合的第一步)吗?
乔什·卡斯威尔

噢,你是对的。我假设输入字符串在字符串的末尾而不是开头具有最近的回合。固定。
Casey

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点。
2011年

在目前的比赛中似乎是最强的。
彼得·泰勒

实际上,不,德鲁伊现在可以解决得分手中的错误。
彼得·泰勒

@ rmckenzie,@ Peter:真是的?我只是为了个性。
乔什·卡斯韦尔

@josh-不再。...在新的评分代码上@casey的评分代码Lisper再次居高不下,随后是鲨鱼。
2011年

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

以前从合作开始,但现在看来叛逃实际上更好。编辑:哦,等等,它实际上没有。


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通过.c文件所用的下标放在./warriors文件夹中,或者是java解释的,因此.java和.class在一起吗?在任何情况下,对得分手的好改动……都将使它们进入回购状态。
2011年

@rmckenzie,要点:是的,从技术上讲,它已编译。我在warriors目录中拥有源文件的原因是python文件也在那里-并且它们已经被编译。如果您愿意,我可以检查从./src到./warriors进行哪些更改,但这需要一些编译器参数,因为Java默认情况下假定目录结构反映了包(名称空间)。
彼得·泰勒

@peter,我只是想知道...战士可以通过* nix 777或其他可执行文件在./warriors中找到。Python和Lisp脚本通常是为提高性能而编译的,但可以在其自然(源)状态下执行。以非Java人士的知识,.java文件没有这些权限,因此不会显示。这就是c hack的用途……因为编译是一个单独的步骤。是的。如果您愿意进行更改,我将不胜感激。REPO LINK
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)
2011年

@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
彼得:好吧,我很少互相直接测试战略,因为整个领域对战略绩效都有相当大的影响。目前,在我的测试中,它主要与渐进和德鲁伊战斗。
乔伊,

渐进和德鲁伊对黄蜂的得分均为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'

与基准集相比效果较差,但与目标相比效果却很好。显然,不是用Scheme编写的。


为什么我感觉到挑战?
2011年

击败了这个虫子。...在Lisper中随机化了阈值。
2011年

@rmckenzie:但是这对您在其他领域的比赛有何影响?如果有足够的合作者互相配合,偏执或嫉妒的策略将开始变得更糟。您仍然还有一个固定的上限,可以加以利用。
乔什·卡斯韦尔

如果您通读当前的lisper,则它比令人羡慕的要更具防御性。它试图发现正在追求统计上如此危险的策略的对手,然后才发动射击。它的CC开头旨在与盗贼一起右脚下车,并具有说服大多数合作组织一起前进的额外好处。
2011年

@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]
Casey

您可能省略了该len(history)<2子句,因为最后一个看起来像该else部分。
dmckee 2011年

@Casey @dmckee感谢您的错误修复。“ Du”对我return特别!
乔什·卡斯韦尔

@dmckee:这是作为更复杂的事情的一部分开始的,然后我意识到我已经重新编写了《 Tit for Two Tats》并决定输入。复制粘贴用户错误。
乔什·卡斯威尔

@Josh:我短暂地看到了您的Bygones条目,您将其删除了吗?它看起来很感兴趣。
Casey
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.