जेल में बंद कैदी त्रिलम्मा


19

चुनौती स्थिति: खुली

टिप्पणी करें, अगर मैं आपकी बॉट को याद कर रहा हूं, तो एक पीआर खोलें, या अन्यथा मुझ पर चिल्लाएं।


कैदी की दुविधा ... तीन विकल्पों के साथ। पागल, हुह?

यहाँ हमारे भुगतान मैट्रिक्स है। खिलाड़ी A बाईं ओर, B शीर्ष पर है

A,B| C | N | D
---|---|---|---
 C |3,3|4,1|0,5
 N |1,4|2,2|3,2
 D |5,0|2,3|1,1

भुगतान मैट्रिक्स को इंजीनियर किया जाता है ताकि यह दोनों खिलाड़ियों के लिए हमेशा सहयोग करने के लिए सबसे अच्छा हो, लेकिन आप (आमतौर पर) तटस्थ या डेफिनेशन चुनकर लाभ उठा सकते हैं।

यहाँ कुछ (प्रतिस्पर्धा) उदाहरण बॉट्स हैं।

# turns out if you don't actually have to implement __init__(). TIL!

class AllC:
    def round(self, _): return "C"
class AllN:
    def round(self, _): return "N"
class AllD:
    def round(self, _): return "D"
class RandomBot:
    def round(self, _): return random.choice(["C", "N", "D"])

# Actually using an identically-behaving "FastGrudger".
class Grudger:
    def __init__(self):
        self.history = []
    def round(self, last):
        if(last):
            self.history.append(last)
            if(self.history.count("D") > 0):
                return "D"
        return "C"

class TitForTat:
    def round(self, last):
        if(last == "D"):
            return "D"
        return "C"

आपका बॉट पायथन 3 क्लास है। हर गेम के लिए एक नया उदाहरण बनाया round()जाता है , और इसे प्रत्येक राउंड कहा जाता है, आखिरी राउंड से आपके प्रतिद्वंद्वी की पसंद के साथ (या यदि यह पहली बार हो तो)

एक महीने में विजेता के लिए 50 प्रतिनिधि इनाम है।

विशिष्ट तथ्य

  • प्रत्येक बॉट हर दूसरे बॉट (1v1) को, जिसमें [REDACTED] राउंड शामिल हैं, बजाता है।
  • मानक खामियों को दूर किया।
  • अपनी कक्षा या अन्य अल्प शालीनियों के बाहर किसी चीज से कोई खिलवाड़ नहीं करना चाहिए।
  • आप पाँच बॉट तक जमा कर सकते हैं।
  • हां, आप हैंडशेक को लागू कर सकते हैं।
  • किसी भी अन्य की तुलना में प्रतिक्रिया C, Nया Dचुपचाप के रूप में ले जाया जाएगा N
  • उनके द्वारा खेले जाने वाले प्रत्येक खेल से प्रत्येक बॉट के बिंदुओं की कुल और तुलना की जाएगी।

नियंत्रक

चेक!

अन्य भाषाएँ

अगर किसी को जरूरत हो तो मैं एक साथ एपीआई फेंक दूंगा।

स्कोर: 2018-11-27

27 bots, 729 games.

name            | avg. score/round
----------------|-------------------
PatternFinder   | 3.152
DirichletDice2  | 3.019
EvaluaterBot    | 2.971
Ensemble        | 2.800
DirichletDice   | 2.763
Shifting        | 2.737
FastGrudger     | 2.632
Nash2           | 2.574
HistoricAverage | 2.552
LastOptimalBot  | 2.532
Number6         | 2.531
HandshakeBot    | 2.458
OldTitForTat    | 2.411
WeightedAverage | 2.403
TitForTat       | 2.328
AllD            | 2.272
Tetragram       | 2.256
Nash            | 2.193
Jade            | 2.186
Useless         | 2.140
RandomBot       | 2.018
CopyCat         | 1.902
TatForTit       | 1.891
NeverCOOP       | 1.710
AllC            | 1.565
AllN            | 1.446
Kevin           | 1.322

1
बॉट को एक दूसरे के खिलाफ कैसे रखा जाता है? मैं ग्रुगर से प्राप्त करता हूं कि हमेशा एक दूसरे के साथ / के खिलाफ दो बॉट होते हैं और दुश्मन की आखिरी पसंद बॉट को दी जाती है। कितने राउंड खेले जाते हैं? और एक खेल के लिए: क्या केवल परिणाम की गिनती होती है (अर्थात कौन जीता) या अंक भी?
काला उल्लू काई

1
यदि आप इस भाषा-अज्ञेय, या कम से कम व्यापक बना देते हैं तो आपको अधिक प्रविष्टियाँ मिलेंगी। आपके पास एक रैपर अजगर वर्ग हो सकता है जो एक प्रक्रिया को पैदा करता है और पाठ प्रतिक्रियाएं प्राप्त करने के लिए इसे पाठ कमांड भेजता है।
17

1
किया हुआ। यह एक महीने के लिए सैंडबॉक्स पर था!
SIGSTACKFAULT

2
आप में से ज्यादातर main.py लपेट तो while len(botlist) > 1:साथ botlist.remove(lowest_scoring_bot)पाश के निचले भाग में, आप रोचक परिणाम के साथ एक उन्मूलन टूर्नामेंट मिलता है।
स्पर्स

1
किसी दिन इस संस्करण का एक और संस्करण केवल अंतिम चाल के बजाय पूरे इंटरैक्शन इतिहास को पारित कर सकता है। यह बहुत नहीं बदलता है, हालांकि यह उपयोगकर्ता कोड को थोड़ा सरल करता है। लेकिन यह एक्सटेंशन के लिए अनुमति देगा, जैसे कि शोर संचार चैनल जो समय के साथ स्पष्ट करते हैं: "वास्तव में, एक पंक्ति में मैंने चार बार सी कहा है, नहीं; नहीं, मैंने डी नहीं कहा; आप मुझे क्या लेते हैं? ओह, क्षमा करें, क्या हम उस दौर को भूल सकते हैं? "
स्कॉट सॉयट

जवाबों:


10

EvaluaterBot

class EvaluaterBot:
    def __init__(self):
        self.c2i = {"C":0, "N":1, "D":2}
        self.i2c = {0:"C", 1:"N", 2:"D"}
        self.history = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
        self.last = [None, None]

    def round(self, last):
        if self.last[0] == None:
            ret = 2
        else:
            # Input the latest enemy action (the reaction to my action 2 rounds ago)
            # into the history
            self.history[self.last[0]][self.c2i[last]] += 1
            # The enemy will react to the last action I did
            prediction,_ = max(enumerate(self.history[self.last[1]]), key=lambda l:l[1])
            ret = (prediction - 1) % 3
        self.last = [self.last[1], ret]
        return self.i2c[ret]

(शायद) यादृच्छिक बॉट को छोड़कर सभी पहले प्रस्तुत किए गए बॉट के खिलाफ जीत (लेकिन इसका एक फायदा हो सकता है, क्योंकि यह एक ड्रा में डी चुनता है और डी को इष्टतम होना चाहिए) और उनके खिलाफ एक निरंतर ड्रॉ खेलता है।


हाँ, सब कुछ धड़कता है।
SIGSTACKFAULT

स्क्रैच कि, PatternFinder इसे एक बिट से धड़कता है।
SIGSTACKFAULT

7

नैश संतुलन

इस बॉट ने कॉलेज में एक गेम थ्योरी क्लास ली है, लेकिन वह आलसी था और उस क्लास में नहीं जाता था जहाँ वे खेल को कवर करते थे। इसलिए वह केवल सिंगल गेम मिक्स्ड नैश संतुलन खेलता है। 1/2 2/5 2/5 का भुगतान करने के लिए मिश्रित NE है।

class NashEquilibrium:
    def round(self, _):
        a = random.random()
        if a <= 0.2:
            return "C"
        elif a <= 0.6:
            return "N"
        else:
            return "D" 

लगातार गाली नैश इक्विलिब्रियम

इस बॉट ने अपने आलसी भाई से एक या दो सबक लिए। उनके आलसी भाई की समस्या यह थी कि उन्होंने तय रणनीतियों का लाभ नहीं उठाया। यह संस्करण जांचता है कि प्रतिद्वंद्वी एक निरंतर खिलाड़ी है या टाइट्राटैट है और तदनुसार खेलता है, अन्यथा यह नियमित नॅश संतुलन खेलता है।

यह केवल नकारात्मक पक्ष यह है कि यह औसतन प्रति अंक 2.2 अंक ही खेलता है।

class NashEquilibrium2:

    def __init__(self):
        self.opphistory = [None, None, None]
        self.titfortatcounter = 0
        self.titfortatflag = 0
        self.mylast = "C"
        self.constantflag = 0
        self.myret = "C"

    def round(self, last):
        self.opphistory.pop(0)
        self.opphistory.append(last)

        # check if its a constant bot, if so exploit
        if self.opphistory.count(self.opphistory[0]) == 3:
            self.constantflag = 1
            if last == "C":
                 self.myret = "D"
            elif last == "N":
                 self.myret = "C"
            elif last == "D":
                 self.myret = "N"

        # check if its a titfortat bot, if so exploit
        # give it 2 chances to see if its titfortat as it might happen randomly
        if self.mylast == "D" and last == "D":
            self.titfortatcounter = self.titfortatcounter + 1

        if self.mylast == "D" and last!= "D":
            self.titfortatcounter = 0

        if self.titfortatcounter >= 3:
            self.titfortatflag = 1

        if self.titfortatflag == 1:
            if last == "C":
                 self.myret = "D"
            elif last == "D":
                 self.myret = "N"    
            elif last == "N":
                # tit for tat doesn't return N, we made a mistake somewhere
                 self.titfortatflag = 0
                 self.titfortatcounter = 0

        # else play the single game nash equilibrium
        if self.constantflag == 0 and self.titfortatflag == 0:
            a = random.random()
            if a <= 0.2:
                self.myret = "C"
            elif a <= 0.6:
                self.myret = "N"
            else:
                self.myret = "D"


        self.mylast = self.myret
        return self.myret

1
NATEquilibrium.round को तर्क का उपयोग करने की आवश्यकता है, भले ही उनका उपयोग न करें, ताकि अपेक्षित फ़ंक्शन प्रोटोटाइप को फिट किया जा सके।
रे

शुक्रिया तय किया
ofya

थोड़ा छोटा:class NashEquilibrium: def round(self, _): a = random.random() for k, v in [(0.2, "C"), (0.6, "N"), (1, "D")]: if a <= k: return v
रॉबर्ट ग्रांट

7

TatForTit

class TatForTit:
    def round(self, last):
        if(last == "C"):
            return "N"
        return "D"

अगर मैं पेआउट मैट्रिक्स को सही तरीके से पढ़ता हूं, तो यह बीटीएनडीएनडीटी को वैकल्पिक रूप से सीडीएफटी को वैकल्पिक रूप से 3 अंक प्रति चक्कर के हिसाब से उठाएगा। मुझे लगता है कि यह TitForTat के खिलाफ इष्टतम हो सकता है। जाहिर है कि गैर-टीएफटी प्रतिद्वंद्वी का पता लगाने और अन्य रणनीतियों को अपनाने के लिए इसमें सुधार किया जा सकता है, लेकिन मैं सिर्फ मूल इनाम के लिए लक्ष्य कर रहा था।


6

PatternFinder

class PatternFinder:
    def __init__(self):
        import collections
        self.size = 10
        self.moves = [None]
        self.other = []
        self.patterns = collections.defaultdict(list)
        self.counter_moves = {"C":"D", "N":"C", "D":"N"}
        self.initial_move = "D"
        self.pattern_length_exponent = 1
        self.pattern_age_exponent = 1
        self.debug = False
    def round(self, last):
        self.other.append(last)
        best_pattern_match = None
        best_pattern_score = None
        best_pattern_response = None
        self.debug and print("match so far:",tuple(zip(self.moves,self.other)))
        for turn in range(max(0,len(self.moves)-self.size),len(self.moves)):
            # record patterns ending with the move that just happened
            pattern_full = tuple(zip(self.moves[turn:],self.other[turn:]))
            if len(pattern_full) > 1:
                pattern_trunc = pattern_full[:-1]
                pattern_trunc_result = pattern_full[-1][1]
                self.patterns[pattern_trunc].append([pattern_trunc_result,len(self.moves)-1])
            if pattern_full in self.patterns:
                # we've seen this pattern at least once before
                self.debug and print("I've seen",pattern_full,"before:",self.patterns[pattern_full])
                for [response,turn_num] in self.patterns[pattern_full]:
                    score = len(pattern_full) ** self.pattern_length_exponent / (len(self.moves) - turn_num) ** self.pattern_age_exponent
                    if best_pattern_score == None or score > best_pattern_score:
                        best_pattern_match = pattern_full
                        best_pattern_score = score
                        best_pattern_response = response
                    # this could be much smarter about aggregating previous responses
        if best_pattern_response:
            move = self.counter_moves[best_pattern_response]
        else:
            # fall back to playing nice
            move = "C"
        self.moves.append(move)
        self.debug and print("I choose",move)
        return move

यह बॉट हाल के खेल राज्य की पिछली घटनाओं की तलाश करता है, यह देखने के लिए कि प्रतिद्वंद्वी ने उन घटनाओं का जवाब कैसे दिया, लंबे पैटर्न के मैचों और अधिक हाल के मैचों के लिए वरीयता के साथ, फिर वह चाल खेलता है जो प्रतिद्वंद्वी की अनुमानित चाल को "हरा" करेगा। इसके लिए बहुत से कमरे हैं जो उन सभी डेटा के साथ होशियार हो सकते हैं, जिन पर वह नज़र रखता है, लेकिन मैं इस पर काम करने के लिए समय से बाहर भाग गया।


जब आप समय मिलता है, मन उसे एक अनुकूलन पास दे? यह आसानी से सबसे बड़ा समय-सिंक है।
SIGSTACKFAULT

2
@Blacksilver मैं सिर्फ 10 100 से अधिक से अधिक पैटर्न लंबाई कम अब यह लगभग तुरंत चलाना चाहिए अगर आप <200 राउंड चला रहे हैं
Sparr

1
शायद एक उच्च समग्र संख्या (यानी, 12) का उपयोग करने से बेहतर स्कोर होगा?
SIGSTACKFAULT

5

जेड

class Jade:
    def __init__(self):
        self.dRate = 0.001
        self.nRate = 0.003

    def round(self, last):
        if last == 'D':
            self.dRate *= 1.1
            self.nRate *= 1.2
        elif last == 'N':
            self.dRate *= 1.03
            self.nRate *= 1.05
        self.dRate = min(self.dRate, 1)
        self.nRate = min(self.nRate, 1)

        x = random.random()
        if x > (1 - self.dRate):
            return 'D'
        elif x > (1 - self.nRate):
            return 'N'
        else:
            return 'C'

आशावादी शुरू करता है, लेकिन उत्तरोत्तर अधिक कड़वा हो जाता है क्योंकि प्रतिद्वंद्वी सहयोग करने से इनकार करता है। जादू स्थिरांक के बहुत सारे है कि शायद tweaked किया जा सकता है, लेकिन यह शायद समय का औचित्य साबित करने के लिए पर्याप्त नहीं है।


5

कलाकारों की टुकड़ी

यह संबंधित मॉडलों का एक समूह है। अलग-अलग मॉडल इतिहास की विभिन्न मात्राओं पर विचार करते हैं, और या तो हमेशा उस विकल्प को चुनने का विकल्प होता है जो अपेक्षित भुगतान अंतर को अनुकूलित करेगा, या अपेक्षित भुगतान अंतर के अनुपात में किसी चाल का चयन करेगा।

पहनावा का प्रत्येक सदस्य तब अपने पसंदीदा कदम पर वोट देता है। उन्हें प्रतिद्वंद्वी के मुकाबले जितने अधिक वोट मिले हैं, उनके बराबर वोट मिले (जिसका मतलब है कि भयानक मॉडल नकारात्मक वोट प्राप्त करेंगे)। जो भी कदम जीतता है उसके बाद वोट का चयन किया जाता है।

(उन्हें संभवतः प्रत्येक के पक्ष में कदमों के बीच अपने वोटों को विभाजित करना चाहिए, लेकिन मैं अभी ऐसा करने के लिए पर्याप्त परवाह नहीं करता हूं।)

यह EvaluaterBot और PatternFinder को छोड़कर अब तक पोस्ट की गई हर चीज़ को धड़कता है। (एक-पर-एक, यह इवैल्यूटरबॉट को हरा देता है और पैटर्नफाइंडर को खो देता है)।

from collections import defaultdict
import random
class Number6:
    class Choices:
        def __init__(self, C = 0, N = 0, D = 0):
            self.C = C
            self.N = N
            self.D = D

    def __init__(self, strategy = "maxExpected", markov_order = 3):
        self.MARKOV_ORDER = markov_order;
        self.my_choices = "" 
        self.opponent = defaultdict(lambda: self.Choices())
        self.choice = None # previous choice
        self.payoff = {
            "C": { "C": 3-3, "N": 4-1, "D": 0-5 },
            "N": { "C": 1-4, "N": 2-2, "D": 3-2 },
            "D": { "C": 5-0, "N": 2-3, "D": 1-1 },
        }
        self.total_payoff = 0

        # if random, will choose in proportion to payoff.
        # otherwise, will always choose argmax
        self.strategy = strategy
        # maxExpected: maximize expected relative payoff
        # random: like maxExpected, but it chooses in proportion to E[payoff]
        # argmax: always choose the option that is optimal for expected opponent choice

    def update_opponent_model(self, last):
        for i in range(0, self.MARKOV_ORDER):
            hist = self.my_choices[i:]
            self.opponent[hist].C += ("C" == last)
            self.opponent[hist].N += ("N" == last)
            self.opponent[hist].D += ("D" == last)

    def normalize(self, counts):
        sum = float(counts.C + counts.N + counts.D)
        if 0 == sum:
            return self.Choices(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)
        return self.Choices(
            counts.C / sum, counts.N / sum, counts.D / sum)

    def get_distribution(self):
        for i in range(0, self.MARKOV_ORDER):
            hist = self.my_choices[i:]
            #print "check hist = " + hist
            if hist in self.opponent:
                return self.normalize(self.opponent[hist])

        return self.Choices(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)

    def choose(self, dist):
        payoff = self.Choices()
        # We're interested in *beating the opponent*, not
        # maximizing our score, so we optimize the difference
        payoff.C = (3-3) * dist.C + (4-1) * dist.N + (0-5) * dist.D
        payoff.N = (1-4) * dist.C + (2-2) * dist.N + (3-2) * dist.D
        payoff.D = (5-0) * dist.C + (2-3) * dist.N + (1-1) * dist.D

        # D has slightly better payoff on uniform opponent,
        # so we select it on ties
        if self.strategy == "maxExpected":
            if payoff.C > payoff.N:
                return "C" if payoff.C > payoff.D else "D"
            return "N" if payoff.N > payoff.D else "D"
        elif self.strategy == "randomize":
            payoff = self.normalize(payoff)
            r = random.uniform(0.0, 1.0)
            if (r < payoff.C): return "C"
            return "N" if (r < payoff.N) else "D"
        elif self.strategy == "argMax":
            if dist.C > dist.N:
                return "D" if dist.C > dist.D else "N"
            return "C" if dist.N > dist.D else "N"

        assert(0) #, "I am not a number! I am a free man!")

    def update_history(self):
        self.my_choices += self.choice
        if len(self.my_choices) > self.MARKOV_ORDER:
            assert(len(self.my_choices) == self.MARKOV_ORDER + 1)
            self.my_choices = self.my_choices[1:]

    def round(self, last):
        if last: self.update_opponent_model(last)

        dist = self.get_distribution()
        self.choice = self.choose(dist)
        self.update_history()
        return self.choice

class Ensemble:
    def __init__(self):
        self.models = []
        self.votes = []
        self.prev_choice = []
        for order in range(0, 6):
            self.models.append(Number6("maxExpected", order))
            self.models.append(Number6("randomize", order))
            #self.models.append(Number6("argMax", order))
        for i in range(0, len(self.models)):
            self.votes.append(0)
            self.prev_choice.append("D")

        self.payoff = {
            "C": { "C": 3-3, "N": 4-1, "D": 0-5 },
            "N": { "C": 1-4, "N": 2-2, "D": 3-2 },
            "D": { "C": 5-0, "N": 2-3, "D": 1-1 },
        }

    def round(self, last):
        if last:
            for i in range(0, len(self.models)):
                self.votes[i] += self.payoff[self.prev_choice[i]][last]

        # vote. Sufficiently terrible models get negative votes
        C = 0
        N = 0
        D = 0
        for i in range(0, len(self.models)):
            choice = self.models[i].round(last)
            if "C" == choice: C += self.votes[i]
            if "N" == choice: N += self.votes[i]
            if "D" == choice: D += self.votes[i]
            self.prev_choice[i] = choice

        if C > D and C > N: return "C"
        elif N > D: return "N"
        else: return "D"

टेस्ट फ्रेमवर्क

यदि कोई और इसे उपयोगी पाता है, तो व्यक्तिगत मिलानों को देखने के लिए यहां एक परीक्षण रूपरेखा है। को Python2। बस उन सभी विरोधियों को रखें, जिनकी आपको विरोधियों में दिलचस्पी है, और संदर्भों को अपने स्वयं के लिए बदलें।

import sys, inspect
import opponents
from ensemble import Ensemble

def count_payoff(label, them):
    if None == them: return
    me = choices[label]
    payoff = {
        "C": { "C": 3-3, "N": 4-1, "D": 0-5 },
        "N": { "C": 1-4, "N": 2-2, "D": 3-2 },
        "D": { "C": 5-0, "N": 2-3, "D": 1-1 },
    }
    if label not in total_payoff: total_payoff[label] = 0
    total_payoff[label] += payoff[me][them]

def update_hist(label, choice):
    choices[label] = choice

opponents = [ x[1] for x 
    in inspect.getmembers(sys.modules['opponents'], inspect.isclass)]

for k in opponents:
    total_payoff = {}

    for j in range(0, 100):
        A = Ensemble()
        B = k()
        choices = {}

        aChoice = None
        bChoice = None
        for i in range(0, 100):
            count_payoff(A.__class__.__name__, bChoice)
            a = A.round(bChoice)
            update_hist(A.__class__.__name__, a)

            count_payoff(B.__class__.__name__, aChoice)
            b = B.round(aChoice)
            update_hist(B.__class__.__name__, b)

            aChoice = a
            bChoice = b
    print total_payoff

नियंत्रक तैयार है, आपको वह सब नहीं करना है ...
3:13 बजे SIGSTACKFAULT

1
@Blacksilver मुझे एहसास हुआ कि जैसे मैं जमा करने वाला था। लेकिन यह 3.6 से पहले के संस्करणों में काम करता है, और व्यक्तिगत मिलान के बारे में जानकारी देता है जो कमजोर स्पॉट की पहचान करने में मदद कर सकता है, इसलिए यह समय की पूरी बर्बादी नहीं थी।
रे

काफी उचित; अब चल रहा है। मैं शायद इसी तरह की चीजों को करने के लिए अपने नियंत्रक में विकल्प जोड़ूंगा।
SIGSTACKFAULT

"यह अब तक का पहनावा और पैटर्नफाइंडर को छोड़कर सब कुछ पोस्ट करता है" मुझे सम्मानित किया जाता है :)
स्पर्स

@ सपर ऊप्स। यह कहना था कि EvaluaterBot और PatternFinder। लेकिन जब पूरे क्षेत्र के खिलाफ कुल स्कोर की तुलना करते हैं। पैटर्नफाइंडर केवल एक ही रहता है जो इसे सीधे मैच में हरा देता है।
रे

4

OldTitForTat

पुराने स्कूल खिलाड़ी नए नियमों के लिए अपडेट करने के लिए बहुत आलसी है।

class OldTitForTat:
    def round(self, last):
        if(last == None)
            return "C"
        if(last == "C"):
            return "C"
        return "D"

3

NeverCOOP

class NeverCOOP:
    def round(self, last):
        try:
            if last in "ND":
                return "D"
            else:
                return "N"
        except:
            return "N"

यदि विरोधी बॉट दोष या तटस्थ है, तो दोष चुनें। अन्यथा यदि यह पहली बारी है या विरोधी बॉट सहयोग करता है, तो तटस्थ चुनें। मुझे यकीन नहीं है कि यह कितना अच्छा काम करेगा ...


इसके अलावा क्या प्रयास / है?
SIGSTACKFAULT

1
@Blacksilver मुझे लगता है कि यह if(last):आपके Grudger bot में उसी उद्देश्य को पूरा करता है, जिसमें यह पता लगाया जाता है कि क्या कोई पिछला दौर था।
ETHproductions

हाँ! मैंने देखा। None in "ND"त्रुटियों।
SIGSTACKFAULT

क्योंकि if last and last in "ND":बहुत जटिल था?
user253751

3

LastOptimalBot

class LastOptimalBot:
    def round(self, last):
        return "N" if last == "D" else ("D" if last == "C" else "C")

मान लेता है कि विरोधी बॉट हमेशा एक ही चाल को फिर से चलाएगा, और वह चुनता है जिसके पास सबसे अच्छा भुगतान है।

औसत:

Me   Opp
2.6  2    vs TitForTat
5    0    vs AllC
4    1    vs AllN
3    2    vs AllD
3.5  3.5  vs Random
3    2    vs Grudger
2    2    vs LastOptimalBot
1    3.5  vs TatForTit
4    1    vs NeverCOOP
1    4    vs EvaluaterBot
2.28 2.24 vs NashEquilibrium

2.91 average overall

दौलत। शायद T4T के रूप में बेहतर होगा return last
SIGSTACKFAULT

मैं वह पसंद करूँगा! अगर TitForTat return lastहोता, तो LOB 5 राउंड में 13-10 के बजाय 18-9 पर जाता, जो कि वर्तमान में मिल रहे 5 राउंड से अधिक था। मुझे लगता है कि यह ठीक है - उदाहरण बॉट्स के अनुकूलन के बारे में चिंता न करें।
स्पिटमास्टर

return lastइस चुनौती के लिए एक बेहतर T4T होगा, मुझे लगता है
better

अभी-अभी कोशिश की है - if(last): return last; else: return "C"बदतर है।
SIGSTACKFAULT

सही है, लेकिन जैसा @Sparr कह रहा था, यह अधिक उपयुक्त हो सकता है। आपके ऊपर, मुझे लगता है।
स्पिटमास्टर

3

CopyCat

class CopyCat:
    def round(self, last):
        if last:
            return last
        return "C"

प्रतिद्वंद्वी के आखिरी कदम की नकल करता है।
मैं इसके अच्छे प्रदर्शन की उम्मीद नहीं करता, लेकिन किसी ने भी इस क्लासिक को लागू नहीं किया है।


2

बेहतर डिरिचलेट पासा

import random

class DirichletDice2:
    def __init__(self):

        self.alpha = dict(
                C = {'C' : 1, 'N' : 1, 'D' : 1},
                N = {'C' : 1, 'N' : 1, 'D' : 1},
                D = {'C' : 1, 'N' : 1, 'D' : 1}
        )
        self.myLast = [None, None]
        self.payoff = dict(
                C = { "C": 0, "N": 3, "D": -5 },
                N = { "C": -3, "N": 0, "D": 1 },
                D = { "C": 5, "N": -1, "D": 0 }
        )

    def DirichletDraw(self, key):
        alpha = self.alpha[key].values()
        mu = [random.gammavariate(a,1) for a in alpha]
        mu = [m / sum(mu) for m in mu]
        return mu

    def ExpectedPayoff(self, probs):
        expectedPayoff = {}
        for val in ['C','N','D']:
            payoff = sum([p * v for p,v in zip(probs, self.payoff[val].values())])
            expectedPayoff[val] = payoff
        return expectedPayoff

    def round(self, last):
        if last is None:
            self.myLast[0] = 'D'
            return 'D'

        #update dice corresponding to opponent's last response to my
        #outcome two turns ago
        if self.myLast[1] is not None:
            self.alpha[self.myLast[1]][last] += 1

        #draw probs for my opponent's roll from Dirichlet distribution and then return the optimal response
        mu = self.DirichletDraw(self.myLast[0])
        expectedPayoff = self.ExpectedPayoff(mu)
        res = max(expectedPayoff, key=expectedPayoff.get)

        #update myLast
        self.myLast[1] = self.myLast[0]
        self.myLast[0] = res

        return res    

यह Dirichlet Dice का एक उन्नत संस्करण है। ड्यूरिचलेट वितरण से अपेक्षित बहुराष्ट्रीय वितरण लेने के बजाय, यह ड्यूरिचलेट वितरण से बेतरतीब ढंग से एक बहुराष्ट्रीय वितरण खींचता है। फिर, मल्टीनोमियल से ड्राइंग करने और उस पर इष्टतम प्रतिक्रिया देने के बजाय, यह बिंदुओं का उपयोग करके दिए गए मल्टीमोनियल को इष्टतम अपेक्षित प्रतिक्रिया देता है। इसलिए रैंडमनेस को अनिवार्य रूप से मल्टीमिनियल ड्रॉ से डिरिचलेट ड्रॉ में स्थानांतरित कर दिया गया है। इसके अलावा, खोज को प्रोत्साहित करने के लिए, अब पुजारी अधिक फ्लैट हैं।

यह "बेहतर" है, क्योंकि यह अब संभावनाओं के खिलाफ सबसे अच्छा अपेक्षित मूल्य देकर अंक प्रणाली के लिए जिम्मेदार है, जबकि स्वयं संभावनाओं को चित्रित करके अपनी यादृच्छिकता बनाए रखता है। इससे पहले, मैंने बस उम्मीद की संभावनाओं से सबसे अच्छा अपेक्षित भुगतान करने की कोशिश की, लेकिन यह बुरी तरह से किया क्योंकि यह बस अटक गया, और अपने पासा को अपडेट करने के लिए पर्याप्त तलाश नहीं किया। इसके अलावा यह अधिक पूर्वानुमान और शोषक था।


मूल प्रस्तुत:

डिरिचलेट पासा

import random

class DirichletDice:
    def __init__(self):

        self.alpha = dict(
                C = {'C' : 2, 'N' : 3, 'D' : 1},
                N = {'C' : 1, 'N' : 2, 'D' : 3},
                D = {'C' : 3, 'N' : 1, 'D' : 2}
        )

        self.Response = {'C' : 'D', 'N' : 'C', 'D' : 'N'}
        self.myLast = [None, None]

    #expected value of the dirichlet distribution given by Alpha
    def MultinomialDraw(self, key):
        alpha = list(self.alpha[key].values())
        probs = [x / sum(alpha) for x in alpha]
        outcome = random.choices(['C','N','D'], weights=probs)[0]
        return outcome

    def round(self, last):
        if last is None:
            self.myLast[0] = 'D'
            return 'D'

        #update dice corresponding to opponent's last response to my
        #outcome two turns ago
        if self.myLast[1] is not None:
            self.alpha[self.myLast[1]][last] += 1

        #predict opponent's move based on my last move
        predict = self.MultinomialDraw(self.myLast[0])
        res = self.Response[predict]

        #update myLast
        self.myLast[1] = self.myLast[0]
        self.myLast[0] = res

        return res

मूल रूप से मैं मान रहा हूं कि मेरे पिछले आउटपुट के प्रति प्रतिद्वंद्वी की प्रतिक्रिया एक बहुराष्ट्रीय चर (भारित पासा) है, जो मेरे प्रत्येक आउटपुट के लिए है, इसलिए "सी" के लिए एक पासा है, "एन" के लिए, और "डी" के लिए एक है। । इसलिए यदि मेरा अंतिम रोल था, उदाहरण के लिए, एक "एन" तो मैं "एन-पासा" को यह अनुमान लगाने के लिए रोल करता हूं कि मेरी "एन" पर उनकी प्रतिक्रिया क्या होगी। मैं एक डिरिचलेट से पहले शुरू करता हूं जो मानता है कि मेरा प्रतिद्वंद्वी कुछ हद तक "स्मार्ट" है (मेरे अंतिम रोल के खिलाफ सबसे अच्छा भुगतान के साथ खेलने की संभावना है, कम से कम सबसे खराब भुगतान के साथ खेलने की संभावना है)। मैं पहले उपयुक्त डिरिचलेट से "अपेक्षित" बहुराष्ट्रीय वितरण उत्पन्न करता हूं (यह उनके पासा भार पर संभाव्यता वितरण का अपेक्षित मूल्य है)। मैं अपने पिछले आउटपुट के वेटेड डाइस को रोल करता हूं,

तीसरे दौर में शुरू करते हुए, मैं अपने प्रतिद्वंद्वी के अंतिम प्रतिक्रिया से पहले बायर्सियन अपडेट करता हूं, जिस चीज को मैंने दो राउंड पहले खेला था। मैं पुन: प्रयास कर रहा हूँ कि उनके पासा भार सीखें।

मैं भी केवल पासा उत्पन्न करने के बजाय सबसे अच्छा "अपेक्षित" परिणाम के साथ प्रतिक्रिया उठा सकता था, बजाय केवल पासा रोल कर रहा था और परिणाम का जवाब दे रहा था। हालांकि, मैं यादृच्छिकता को अंदर रखना चाहता था, ताकि मेरी बॉट उन लोगों के लिए कम असुरक्षित हो जो एक पैटर्न की भविष्यवाणी करने की कोशिश करते हैं।


2

केविन

class Kevin:
    def round(self, last):      
        return {"C":"N","N":"D","D":"C",None:"N"} [last]

सबसे खराब विकल्प चुनता है। सबसे खराब बॉट बनाया।

निकम्मा

import random

class Useless:
    def __init__(self):
        self.lastLast = None

    def round(self, last):
        tempLastLast = self.lastLast
        self.lastLast = last

        if(last == "D" and tempLastLast == "N"):
            return "C"
        if(last == "D" and tempLastLast == "C"):
            return "N"

        if(last == "N" and tempLastLast == "D"):
            return "C"
        if(last == "N" and tempLastLast == "C"):
            return "D"

        if(last == "C" and tempLastLast == "D"):
            return "N"
        if(last == "C" and tempLastLast == "N"):
            return "D"

        return random.choice("CND")

यह प्रतिद्वंद्वी द्वारा किए गए अंतिम दो चालों को देखता है और सबसे अधिक नहीं किए गए किसी और चीज को यादृच्छिक रूप से चुनता है। ऐसा करने का एक बेहतर तरीका शायद है।


2

ऐतिहासिक औसत

class HistoricAverage:
    PAYOFFS = {
        "C":{"C":3,"N":1,"D":5},
        "N":{"C":4,"N":2,"D":2},
        "D":{"C":0,"N":3,"D":1}}
    def __init__(self):
        self.payoffsum = {"C":0, "N":0, "D":0}
    def round(this, last):
        if(last != None):
            for x in this.payoffsum:
               this.payoffsum[x] += HistoricAverage.PAYOFFS[last][x]
        return max(this.payoffsum, key=this.payoffsum.get)

इतिहास को देखता है और वह क्रिया पाता है जो औसतन सबसे अच्छा होता। सहकारी शुरू करता है।


यह तेजी से चल सकता है अगर यह हर दौर में औसत की फिर से गणना न करे।
स्पर्म

@ सच है। मैंने इसे संपादित किया इसलिए यह अब ऐसा करता है।
मेगाटॉम

1

भारित औसत

class WeightedAverageBot:
  def __init__(self):
    self.C_bias = 1/4
    self.N = self.C_bias
    self.D = self.C_bias
    self.prev_weight = 1/2
  def round(self, last):
    if last:
      if last == "C" or last == "N":
        self.D *= self.prev_weight
      if last == "C" or last == "D":
        self.N *= self.prev_weight
      if last == "N":
        self.N = 1 - ((1 - self.N) * self.prev_weight)
      if last == "D":
        self.D = 1 - ((1 - self.D) * self.prev_weight)
    if self.N <= self.C_bias and self.D <= self.C_bias:
      return "D"
    if self.N > self.D:
      return "C"
    return "N"

प्रतिद्वंद्वी के व्यवहार को सीएनडी के लिए क्रमशः 0,0 0,1 1,0 के कोनों के साथ एक सही त्रिकोण के रूप में तैयार किया गया है। प्रत्येक प्रतिद्वंद्वी उस कोने की ओर उस त्रिकोण के भीतर बिंदु को स्थानांतरित करता है, और हम बिंदु द्वारा इंगित चाल को हराते हैं (सी के साथ त्रिकोण का एक छोटा सा टुकड़ा दिया जाता है)। सिद्धांत रूप में, मैं यह चाहता था कि पिछली चालों के लिए अधिक वजन के साथ एक लंबी स्मृति हो, लेकिन व्यवहार में वर्तमान मेटा फेवर बॉट्स है जो जल्दी से बदल जाता है, इसलिए यह सबसे दुश्मनों के खिलाफ लास्ट ओपटिमबोट के एक अनुमान में विचलित होता है। पोस्टिंग के लिए पोस्टिंग; शायद कोई प्रेरित होगा।


1

Tetragram

import itertools

class Tetragram:
    def __init__(self):
        self.history = {x: ['C'] for x in itertools.product('CND', repeat=4)}
        self.theirs = []
        self.previous = None

    def round(self, last):
        if self.previous is not None and len(self.previous) == 4:
            self.history[self.previous].append(last)
        if last is not None:
            self.theirs = (self.theirs + [last])[-3:]

        if self.previous is not None and len(self.previous) == 4:
            expected = random.choice(self.history[self.previous])
            if expected == 'C':
                choice = 'C'
            elif expected == 'N':
                choice = 'C'
            else:
                choice = 'N'
        else:
            choice = 'C'

        self.previous = tuple(self.theirs + [choice])
        return choice

प्रतिद्वंद्वी की चाल में एक पैटर्न खोजने की कोशिश करें, यह मानते हुए कि वे हमारी आखिरी चाल भी देख रहे हैं।


1

हाथ मिलाना

class HandshakeBot:
  def __init__(self):
    self.handshake_length = 4
    self.handshake = ["N","N","C","D"]
    while len(self.handshake) < self.handshake_length:
      self.handshake *= 2
    self.handshake = self.handshake[:self.handshake_length]
    self.opp_hand = []
    self.friendly = None
  def round(self, last):
    if last:
      if self.friendly == None:
        # still trying to handshake
        self.opp_hand.append(last)
        if self.opp_hand[-1] != self.handshake[len(self.opp_hand)-1]:
          self.friendly = False
          return "D"
        if len(self.opp_hand) == len(self.handshake):
          self.friendly = True
          return "C"
        return self.handshake[len(self.opp_hand)]
      elif self.friendly == True:
        # successful handshake and continued cooperation
        if last == "C":
          return "C"
        self.friendly = False
        return "D"
      else:
        # failed handshake or abandoned cooperation
        return "N" if last == "D" else ("D" if last == "C" else "C")
    return self.handshake[0]

पहचानता है जब वह खुद के खिलाफ खेल रहा है, तो सहयोग करता है। अन्यथा LastOptimalBot की नकल करता है जो कि एकतरफा रणनीति की तरह लगता है। राउंड की संख्या के व्युत्क्रमानुपाती रूप से एक राशि द्वारा, लास्ट ओप्टिमल बॉट से भी बदतर प्रदर्शन करता है। स्पष्ट रूप से बेहतर होगा यदि क्षेत्र में इसकी अधिक प्रतियां थीं * खांसी ** पलक *।


बस कुछ क्लोन प्रस्तुत करें जिनमें अलग-अलग गैर-हैंडशेक व्यवहार हो।
22

जो शोषण-वाई लगता है। मैं यहां प्रस्तुत प्रत्येक सरल व्यवहार के लिए एक ऐसा क्लोन प्रस्तुत कर सकता हूं।
०१:१२ पर स्पर्स

मैंने एक अतिरिक्त खंड जोड़ा है जिसमें कहा गया है कि आप केवल अधिकतम पाँच बॉट प्रस्तुत कर सकते हैं।
SIGSTACKFAULT

1

ShiftingOptimalBot

class ShiftingOptimalBot:
    def __init__(self):
        # wins, draws, losses
        self.history = [0,0,0]
        self.lastMove = None
        self.state = 0
    def round(self, last):
        if last == None:
            self.lastMove = "C"
            return self.lastMove
        if last == self.lastMove:
            self.history[1] += 1
        elif (last == "C" and self.lastMove == "D") or (last == "D" and self.lastMove == "N") or (last == "N" and self.lastMove == "C"):
            self.history[0] += 1
        else:
            self.history[2] += 1

        if self.history[0] + 1 < self.history[2] or self.history[2] > 5:
            self.state = (self.state + 1) % 3
            self.history = [0,0,0]
        if self.history[1] > self.history[0] + self.history[2] + 2:
            self.state = (self.state + 2) % 3
            self.history = [0,0,0]

        if self.state == 0:
            self.lastMove = "N" if last == "D" else ("D" if last == "C" else "C")
        elif self.state == 1:
            self.lastMove = last
        else:
            self.lastMove = "C" if last == "D" else ("N" if last == "C" else "D")
        return self.lastMove

जब तक यह जीत रहा है तब तक यह बॉट LastOptimalBot के एल्गोरिथ्म का उपयोग करता है। यदि दूसरा बॉट इसकी भविष्यवाणी करना शुरू कर देता है, हालांकि, यह अपने प्रतिद्वंद्वी को अंतिम रूप से खेले जाने वाले कदम को खेलना शुरू कर देगा (जो कि चाल है जो बीटओप्टिमल बीट को हरा देगा)। यह उन एल्गोरिदम के सरल संक्रमणों के माध्यम से चक्र करता है जब तक कि यह खोना जारी रहता है (या जब यह बहुत ड्राइंग करके ऊब जाता है)।

ईमानदारी से, मुझे आश्चर्य है कि LastOptimalBot 5 वीं में बैठा है क्योंकि मैं यह पोस्ट करता हूं। मुझे पूरा यकीन है कि यह बेहतर होगा, यह मानते हुए कि मैंने इस अजगर को सही ढंग से लिखा है।


0

HandshakePatternMatch

from .patternfinder import PatternFinder
import collections

class HandshakePatternMatch:
    def __init__(self):
        self.moves = [None]
        self.other = []
        self.handshake = [None,"N","C","C","D","N"]
        self.friendly = None
        self.pattern = PatternFinder()
    def round(self, last):
        self.other.append(last)
        if last:
            if len(self.other) < len(self.handshake):
                # still trying to handshake
                if self.friendly == False or self.other[-1] != self.handshake[-1]:
                    self.friendly = False
                else:
                    self.friendly = True
                move = self.handshake[len(self.other)]
                self.pattern.round(last)
            elif self.friendly == True:
                # successful handshake and continued cooperation
                move = self.pattern.round(last)
                if last == "C":
                    move = "C"
                elif last == self.handshake[-1] and self.moves[-1] == self.handshake[-1]:
                    move = "C"
                else:
                    self.friendly = False
            else:
                # failed handshake or abandoned cooperation
                move = self.pattern.round(last)
        else:
            move = self.handshake[1]
            self.pattern.round(last)
        self.moves.append(move)
        return move

क्यों पैटर्न खुद से मेल खाते हैं? हाथ मिलाना और सहयोग करना।


import PatternFinderमेरी किताबों में धोखा है।
अप्रैल को SIGSTACKFAULT

@Blacksilver यह KOTH में हर समय किया जाता है। यह मौजूदा उत्तर में कोड की प्रतिलिपि बनाने और उसका उपयोग करने से अलग नहीं है। रोबोट रूले: उच्च दांव वाले रोबोट जुए में सभी जगह ऐसा हो रहा था कि बॉट्स यह पता लगा लेंगे कि क्या उनके कोड को प्रतिद्वंद्वी द्वारा बुलाया जा रहा है और वापसी को तोड़फोड़ कर रहा है।
ड्रेको

तो ठीक है। टीआईएल।
SIGSTACKFAULT

मैं कल क्रंचिंग करूंगा।
SIGSTACKFAULT

यहां अन्य बॉट्स कोड का उपयोग करने का एक आदर्श उदाहरण है। आमतौर पर यह नीचे आता है "उस आदमी ने कुछ मुश्किल गणित का काम किया, मुझे इन परिस्थितियों में उसके परिणाम चाहिए।" (मेरी खुद की प्रविष्टि ने बहुत अच्छा प्रभाव डाला; UpYours इसके दृष्टिकोण में अधिक बिखरे हुए-शॉट थे)।
ड्रेको 18s

0

हार्ड कोडित

class Hardcoded:
    sequence = "DNCNNDDCNDDDCCDNNNNDDCNNDDCDCNNNDNDDCNNDDNDDCDNCCNNDNNDDCNNDDCDCNNNDNCDNDNDDNCNDDCDNNDCNNDDCDCNNDNNDDCDNDDCCNNNDNNDDCNNDDNDCDNCNDDCDNNDDCCNDNNDDCNNNDCDNDDCNNNNDNDDCDNCDCNNDNNDDCDNDDCCNNNDNDDCNNNDNDCDCDNNDCNNDNDDCDNCNNDDCNDNNDDCDNNDCDNDNCDDCNNNDNDNCNDDCDNDDCCNNNNDNDDCNNDDCNNDDCDCNNDNNDDCDNDDCCNDNNDDCNNNDCDNNDNDDCCNNNDNDDNCDCDNNDCNNDNDDCNNDDCDNCNNDDCDNNDCDNDNCDDCNDNNDDCNNNDDCDNCNNDNNDDCNNDDNNDCDNCNDDCNNDCDNNDDCNNDDNCDCNNDNDNDDCDNCDCNNNDNDDCDCNNDNNDDCDNDDCCNNNDNNDDCNDNDNCDDCDCNNNNDNDDCDNCNDDCDNNDDCNNNDNDDCDNCNNDCNNDNDDNCDCDNNNDDCNNDDCNNDDNNDCDNCNDDCNNDDNDCDNNDNDDCCNCDNNDCNNDDNDDCNCDNNDCDNNNDDCNNDDCDCDNNDDCNDNCNNDNNDNDNDDCDNCDCNNNDNDDCDNCNNDDCDNNDCNNDDCNNDDCDCDNNDDCNDNCNNNDDCDNNDCDNDNCNNDNDDNNDNDCDDCCNNNDDCNDNDNCDDCDCNNNDNNDDCNDCDNDDCNNNNDNDDCCNDNNDDCDCNNNDNDDNDDCDNCCNNDNNDDCNNDDCDCNNDNNDDCNNDDNCNDDNNDCDNCNDDCNNDDNDCDNNDNDDCCNCDNNDCNNDNDDCNNDDNCDCDNNDCNNDNDDCDCDNNNNDDCNNDDNDCCNNDDNDDCNCDNNDCNNDDNDDCDNCNDDCNNNNDCDNNDDCNDNDDCDNCNNDCDNNDCNNDNDDNCDCNNDNDDCDNDDCCNNNNDNDDCNNDDCDCNNDNNDDCDCDNNDDC"
    def __init__(self):
        self.round_num = -1
    def round(self,_):
        self.round_num += 1
        return Hardcoded.sequence[self.round_num % 1000]

बस शीर्ष नियतात्मक बॉट में से कुछ को हरा करने के लिए अनुकूलित चाल के एक हार्डकोड अनुक्रम निभाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.