Göksel Bürokrasi KoTH


15

İmparatorluk Çin'de, toplumdaki saflara doğum veya servet tarafından değil, bir kişinin İmparatorluk Sınavlarında üstünlük gösterme yeteneği tarafından karar verildi. Göklerin ilahi hükümdarı olan Yeşim İmparator, tüm konularının değerlerini belirlemesi için incelenmesini ve daha sonra Çin'e hükmetmek için İlahi Vekalet vermesini istedi.

Bürokrasi Kuralları:

  • İlahi Bürokrasi, 0 ile başlayan negatif olmayan tamsayı değerli derecelerden oluşur. Bürokrasinin her üyesi (botu) bir rütbeye aittir. Her rütbe keyfi olarak birçok üye tutabilir, ancak yukarıdaki tüm rütbeler boş olmadığı sürece boş olamaz
  • Oyunun başında tüm üyeler 0.
  • Her fırsatta, bürokrasinin her üyesi bir sınava cevap vermek zorundadır. Muayene, bir listenin boole değerlerini doğru tahmin etmekten oluşur. Listenin uzunluğu, üyenin üstündeki rütbenin sayısıdır.
  • Sınav soruları yukarıdaki sıralamanın rastgele bir üyesi tarafından hazırlanır. En yüksek rütbe üyeleri doğrudan kendi soru almak JadeEmperor(aşağıya bakınız)
  • Sınavlarında en az% 50 alan bir üye Promosyon için uygundur. Sınavlarında% 50'den daha az puan alan bir üye Demotion'a hak kazanır.
  • Demotion için uygun bir üye, yalnızca aşağıdaki sıralamada yer almak için Promosyon için uygun bir üye varsa, rütbeleri bir azaldı.
  • Tanıtım için uygun olan tüm üyeler, hiçbir rütbe boş bırakılmadığı sürece rütbeleri bir puan artar.
  • Tüm uygun üyeler indirgenemez veya yükseltilemezse, tercih en düşük (Demotion için) üyelere aittir. en yüksek (Promosyon için) puan. Bağlar rastgele kırılır.
  • Üyenin rütbesi her turda en fazla 1 değişiklik gösterebilir.

Oyunun kuralları:

  • Her bot, oyunun başında rastgele bir kimliği ile atanır ve bu parkurun rotası boyunca değişmez. JadeEmperorID var -1, diğerleri 0 ile başlamak üzere, ardışık, negatif olmayan kimlikleri.
  • Tüm botlar aynı anda yarışıyor
  • Oyun 100 tur koşuyor, botun puanı o zamana ait ortalama rütbesi.
  • Toplam puan 1000 oyun çalıştırarak ve sonuçların ortalaması alınarak elde edilir.
  • Her Bot, aşağıdaki dört işlevi uygulayan bir Python 3 sınıfıdır:
    • ask(self,n,ID), listn uzunluğundaki Boole'ları döndürerek bir sınav yapar . Kimlik, bu listeyi tahmin etmesi gereken botun kimliğidir. ask()herhangi bir bot için tek bir tur sırasında birçok kez çağrılabilir, ama aynı zamanda hiç de değil.
    • answer(self,n,ID)Bu, bir sınava listBooleans n. Kimlik, ask()sınavı oluşturan botun kimliğidir . answer()her bot için tur başına tam olarak bir kez çağrılır.
    • update(self,rankList,ownExam,otherExams)Denetleyici tüm Pro-Democumları gerçekleştirdiğinde çağrılır. Argümanları: Tüm sıraları tüm botların kimliğine göre listeleyen bir tamsayı listesi; iki listeden oluşan bir grup, önce sınav soruları, daha sonra botun verdiği cevaplar (unutması durumunda); daha sonra benzer şekilde sınav cevap çiftlerinden oluşan bir tuples listesi, bu sefer verilen tüm sınavlar için.
    • __init__(self, ID, n) botun kendi kimliğini ve rakip botların sayısını geçer.
  • Sınıfların özel kullanım için diğer işlevleri uygulamalarına izin verilir
  • Diğer değişkenlerin tanımlanması ve geçmiş sınavlarla ilgili verilerin depolanması için kullanılmasına açıkça izin verilir.
  • Programlama meta efektleri yasaktır, yani diğer botların koduna, Denetleyici koduna doğrudan erişme girişimleri İstisnalara veya benzeri bir şeye neden olur. Bu, kod korsanlığı değil, sınavlar için bir strateji yarışmasıdır.
  • Birbirlerine yardım etmeye çalışan botlara, meta efektlerle yapmadıkları sürece, yalnızca iletilen bilgilerle açıkça izin verilir. update()
  • Diğer dillere yalnızca Python 3'e kolayca dönüştürülebilmeleri durumunda izin verilir.
  • Kütüphane numpy olarak alınır np. Sürüm 1.6.5, yani eski rastgele kütüphaneyi kullanıyor. Numpy 1.7 varsa, eski işlevler numpy.random.mtrandtest için kullanılabilir . Lütfen gönderilmesi için mtrand'ı soymayı unutmayın.
  • Bir bot çalışma zamanı sırasında bir İstisnaya neden olursa, diskalifiye edilir. Kodu o kadar gizlenmiş ki , çağrıldığında ask()veya answer()çağrıldığında n uzunluğunda bir liste oluşturup oluşturmadığını söylemek imkansızdır . Beni derin kopya çıktılarına zorlayan bir bot, skorun -1'ini alır.
  • Sınıf adları benzersiz olmalıdır
  • Kişi başına birden fazla bot'a izin verilir, ancak yinelenen güncellenen botların yalnızca en son sürümü alınacaktır.
  • Bot benzerliği hakkında bir karışıklık olduğu için:
    • Sen edilir izin verilmeyen başka bot bir kopyasını göndermek için. Bu, bu mücadelede gerçekten geçerli olan tek Standart Loophole .
    • Sen edilir izin diğer insanların botlara dahil diğer botlara ile paylaşılan kod olması.
    • Sen edilir izin verilmez sadece (soru nesil için tohum bir değişiklik gibi) stratejiye önemsiz bir değişiklikten başka farklı bir bot göndermek için sürece böyle karbon kopyası botlara sayısı başarılı için gerekli olan minimum olduğunu kanıtlayabilir (Bu genellikle bir işbirliği için iki bot olacaktır).

Örnek Botlar:

Her JadeEmperorzaman oyunun bir parçasıdır, ancak rekabet etmez; en üst sıradaki botların sınavlarında jeneratör olarak hizmet vermektedir. Akıllı botların ilerlemesine izin vermek için sınavları rastgele, ancak tekdüze değil.

class JadeEmperor:
    def __init__(self):
        pass

    def ask(self,n,ID):
        num=min(np.random.exponential(scale=np.sqrt(np.power(2,n))),np.power(2,n)-1)
        bi=list(np.binary_repr(int(num),width=n))
        return [x=='0' for x in bi]

Ayyaş tamamen rastgele sınav ve cevapları üretir. Oyunun bir parçası olacak.

class Drunkard:
    def __init__(self,ID,n):
        pass

    def ask(self,n,ID):
        return list(np.random.choice([True,False],size=n,replace=True))

    def answer(self,n,ID):
        return list(np.random.choice([True,False],size=n,replace=True))

    def update(self,rankList,ownExam,otherExams):
        pass #out

Plagiarist sadece kopya önceki sınavları. Ayrıca oyunun bir parçası olacak.

class Plagiarist:
    def __init__(self,ID,n):
        self.exam=[True]

    def ask(self,n,ID):
        return (self.exam*n)[0:n]

    def answer(self,n,ID):
        return (self.exam*n)[0:n]

    def update(self,rankList,ownExam,otherExams):
        self.exam=ownExam[0]

Denetleyici kodu burada mevcuttur . Test için, kendi sınıfınızı aynı klasördeki bir Contestants.py dosyasına koyabilirsiniz ve içe aktarılacaktır.

Sohbet odası burada bulunabilir .

Sınavlar başlıyor!

Ekim20 için daha yüksek hassasiyette (10000 çalışma) mevcut puan:

EntrantAuthorScoreAlphaSleafar9.669691GammaSleafar9.301362BetaSleafar9.164597WiQeLuPurple P7.870821StudiousBotDignissimus - Spammy7.538537SantayanaSara J7.095528Plagiarist6.522047CountOracularIFcoltransG5.881175ThomasAlien@System5.880041ContraryDraco18s5.529652Marxsugarfi5.433808Drunkard5.328178YinYangPurple P5.102519EqualizerMnemonic4.820996TitForTatAnonymous3.35801

Öngörülebilir gelecek için her yeni girişte yarışmalar düzenlenecek.


1
Botların kopyaları bir Standart Loophole'dur, bu yüzden hayır. Neredeyse ancak kopya değil, kopyaları göndererek yazar kuralı başına birden çok botu kötüye kullanmaya çalışırsanız, onu kaldıracağım.
AlienAtSystem

1
@AlienAtSystem Botların neden birbirlerine yardım etmesine izin veriyorsunuz? Başa çıkmak için daha fazla kaos ve rastgelelik gibi görünüyor.
Don Bin

2
Yapıcı bağımsız değişkenleri neden ID, ndiğer yöntem bağımsız değişkenleri n, ID?
Purple P

1
@DonTusand çünkü verilen kısıtlamalar altında, A) başarıyla el sıkışma (İntihal'in yanlışlıkla adamı ortada oynayabileceğini unutmayın) ve B'nin iki botu yapmak oldukça başarılı olduğuna inanıyorum. ama yükselecek kimse yok.
AlienAtSystem

1
@someone sıralaması yukarı doğru. 0'dan başlarsınız ve daha yüksek sayılara
ulaşırsınız

Yanıtlar:


4

Santayana

Geçmişi hatırlayamayanlar, onu tekrarlamaya mahkumdur. Böylece kararlarımızı, diğerlerinin geçmişte nasıl davrandığına, belirli bir endekste erkeğin bizden genellikle ne beklediğine cevap vererek ve belirli bir endekste bize en az sıklıkla verdikleri cevabı sorarak veriyoruz. .

import numpy as np

class Santayana:
    """
    Those who cannot remember the past are condemned to repeat it
    """
    def __init__(self, ID, num_competitors):
        self.ID = ID
        self.exams_taken = {}
        self.exams_issued = {}
        self.last_exam_asker = None
        self.recent_exam_takers = []

        for i in range(num_competitors):
            self.exams_taken[i] = []
            self.exams_issued[i] = []

    def ask(self, length, taker_ID):
        # Remember who asked
        self.recent_exam_takers.append(taker_ID)
        new_exam = []

        # At every index, expect the answer they've given the least often (default to False if equal)
        for i in range(length):
            trues = 0
            falses = 0
            for exam in self.exams_issued[taker_ID]:
                if len(exam) <= i: continue
                if exam[i]:
                    trues += 1
                else:
                    falses += 1
            new_exam.append(trues < falses)
        return new_exam

    def answer(self, num_answers, asker_ID):
        self.last_exam_asker = asker_ID
        if asker_ID == -1:
            # Copy emperor's process to hopefully get a similar exam
            num = min(np.random.exponential(scale=np.sqrt(np.power(2,num_answers))),np.power(2,num_answers)-1)
            as_bin = list(np.binary_repr(int(num),width=num_answers))
            return [x=='0' for x in as_bin]
        else:
            new_answer = []

            # At every index, give the answer that's been correct the greatest number of times (default to True if equal)
            for i in range(num_answers):
                trues = 0;
                falses = 0;
                for exam in self.exams_taken[asker_ID]:
                    if len(exam) <= i: continue
                    if exam[i]:
                        trues += 1
                    else:
                        falses += 1
                new_answer.append(trues >= falses)
            return new_answer

        return [True for i in range(num_answers)]

    def update(self, rank_list, own_exam, other_exams):
        if self.last_exam_asker > -1:
            # Save the exam we took, unless it was from the Emperor - we already know how he operates
            self.exams_taken[self.last_exam_asker].append(own_exam[0])
        for i in range(len(self.recent_exam_takers)):
            # Save the responses we got
            self.exams_issued[i].append(other_exams[i][1])

        self.recent_exam_takers = []

3

Çalışkan Bot

Bu bot testler için çalışıyor! Çeşitli botlar tarafından verilen testlerde desen bulmaya çalışır ve buna göre hareket eder.

Sonunda, bu bot, Alpha, Beta ve Gamma (birlikte çalışmak üzere programlanmış) dışında bilgisayarımda çalışabileceğim diğer tüm botlardan daha iyi performans gösteriyor. Bot takım almasına izin vermiyor çünkü biraz hile ve biraz kirli olduğunu hissettim. Bununla birlikte, takımlaşmanın oldukça etkili olduğu görülüyor.

Bot, testlere verilen cevapların rastgele olduğunu ve yanıtların testlerde ortalama% 50 olmasıyla eşleştiğini anlamaya çalışır.

Bot, bir botun davranışlarını tahmin etmek için bağlayan diğer botları atmak için sadece cevaplarını çevirdiğini anlamaya çalışır, ancak henüz bu konuda özel olarak hareket etmek için programlamamıştım.

Okumayı kolaylaştırmak için kodu birkaç yorumla ekledim

import random
import numpy as np


class StudiousBot:
    GRAM_SIZE = 5
    def __init__(self, identifier, n):
        self.id = identifier
        self.ranks = {i: 0 for i in range(n)} # Stores ranks
        self.study_material = {i: [] for i in range(n)} # Stores previous exam data
        self.distribution = {i: [] for i in range(n)} # Stores the percentage of answers that were `True` on a Bot's tests over time
        self.last_examiner = None

    def ask(self, n, identifier):
        # This bot gives random tests, it doesn't bother making them difficult based on answers to them
        # The reason for this is that I can't personalise the tests for each bot
        return [random.choice([True, False]) for i in range(n)] 

    def answer(self, n, examiner_id):
        self.last_examiner = examiner_id
        if examiner_id == -1:
            return StudiousBot.answer_emperor(n) # Easy win, I know the distribution of answers for the Emperor's tests

        bother_predicting = True # Whether or not the Bot will attempt to predict the answers to the exam
        study_material = self.study_material[examiner_id]
        distribution = self.distribution[examiner_id]
        if len(distribution) > 0: # If there is actually data to analyse
            sd = StudiousBot.calculate_standard_deviation(distribution)
            normalised_sd = StudiousBot.calculate_normalised_standard_deviation(distribution)

            if abs(30 - sd) < 4: # 30 is the expected s.d for a random distribution
                bother_predicting = False # So I won't bother predicting the test 

            if abs(sd - normalised_sd * 2) > 4: # The bot is merely inverting answers to evade being predicted
                pass # However, at this time, I'm not certain how I should deal with this. I'll continue to attempt to predict the test 


        if bother_predicting and len(study_material) >= StudiousBot.GRAM_SIZE:
            return StudiousBot.predict(study_material, n)

        return [random.choice([True, False]) for i in range(n)]

    def predict(study_material, n): # Predicts the answers to tests with `n` questions
        grams = StudiousBot.generate_ngrams(study_material, StudiousBot.GRAM_SIZE) # Generate all n-grams for the study material
        last_few = study_material[-(StudiousBot.GRAM_SIZE - 1):] # Get the last 9 test answers
        prediction = None
        probability = -1
        for answer in [True, False]: # Finds the probabiility of the next answer being True or False, picks the one with the highest probability
            new_prediction = last_few + [answer]
            new_probability = grams.count(new_prediction)         

            if new_probability > probability:
                prediction = answer
                probability = new_probability

        if n == 1:
            return [prediction]

        return [prediction] + StudiousBot.predict(study_material + [prediction], n-1)          


    @staticmethod
    def calculate_standard_deviation(distribution):
        return np.std(distribution)

    def calculate_normalised_standard_deviation(distribution): # If the answers happen to be inverted at some point, this function will return the same value for answers that occured both before and after this point  
        distribution = list(map(lambda x: 50 + abs(50-x), distribution))
        return StudiousBot.calculate_standard_deviation(distribution)   

    @staticmethod
    def generate_ngrams(study_material, n):
        assert len(study_material) >= n
        ngrams = []
        for i in range(len(study_material) - n + 1):
            ngrams.append(study_material[i:i+n])

        return ngrams

    def update(self, ranks, own_exam, other_exams):
        self.ranks = dict(enumerate(ranks))
        if self.last_examiner != -1:
            self.study_material[self.last_examiner] += own_exam[0]
            self.distribution[self.last_examiner].append(own_exam[0].count(True) / len(own_exam[0]) * 100) # Stores the percentage of the answers which were True

    @staticmethod
    def answer_emperor(n): # Algorithm to reproduce Emperor's distribution of test answers  
        exp = np.random.exponential(scale=np.sqrt(np.power(2,n)))
        power = np.power(2,n) - 1        
        num = min(exp, power)
        bi = list(np.binary_repr(int(num), width=n))
        return [x == '0' for x in bi]

Performansımıza bakarak, yanıtlamak için en iyi algoritmaya sahipsiniz ve Wi Qe Lu, sormak için en iyi algoritmaya sahip. Botlarımızı, tesadüfen "değiştirici" gibi görünen Xuézhě (Çince "bilgin" için Çince) adı verilen tek bir botta birleştirmeyi öneriyorum.
Mor P

Onu hackledim ve sınavları makinemde çalıştırdım. Tuhaf bir şekilde, Studious Bot'dan daha iyi sonuç verdi, ancak Wi Qe Lu'dan değil.
Mor P

@MorP Haha! Bu çok ilginç geliyor,
botumu

3

Oracular Sayısı

Bu bot, her botun sınav olarak ne belirleyeceğine karar vermek için diğer tüm çalışma botlarının (yuvarlak sayı ve bazı korkunç buluşsal yöntemler göz önüne alındığında) sınavlarının ortalamasını alan bir algoritma kullanır.
Kont sınavlarını bir md5 karma kullanarak soruyor. Hem soruları hem de cevapları belirleyicidir. Çoğu girdiyi yok sayar, Jade Emporer'a karşı da dahil olmak üzere tam olarak aynı boolean, yağmur veya parlaklık dizilerini sorar ve yanıtlar.

import numpy as np
import hashlib

class CountOracular:
    '''Uses very little external data to make heuristical statistical
    deterministic predictions about the average exam.
    (Assonance not intended.)
    To generate its own exams, uses a deterministic hash.'''
    def __init__(self, id, number_of_bots):
        self.last_round = []
        #functions for calculating what other bots will likely do.
        self.bots_calculators = [
            self._jad, #Jade Emporer
            self._alp, #Alpha
            self._bet, #Beta
            self._gam, #Gamma
            self._wiq, #Wi Qe Lu
            self._stu, #StudiousBot
            self._pla, #Plagiarist
            self._san, #Santayana
            self._tho, #Thomas
            self._dru, #Drunkard
            self._yin, #YinYang
            self._con, #Contrary
            self._tit, #TitForTat
            self._equ, #Equalizer
            self._mar, #Marx
        ]
        self.bot_types = len(self.bots_calculators)
    def ask(self, n, id):
        #if we can, show that hardcoding is no match for the power of heuristics:
        if n == 2:
            return [False, True]
        #otherwise, refer to the wisdom of Mayor Prentiss in order to command The Ask
        #i.e. hashes a quote, and uses that as the exam.
        salt = b"I AM THE CIRCLE AND THE CIRCLE IS ME " * n
        return self._md5_from(salt, n)
    def answer(self, n, id):
        #uses the power of heuristics to predict what the average bot will do
        #ignores all inputs except the length of the output
        #very approximate, and deterministic
        #i.e. every game, Count Oracular will send the same lists of answers, in the same order
        best_guess_totals = [0.5] * n #halfway between T and F
        for bot in self.bots_calculators:
            exam, confidence = bot(n)
            if not exam:
                continue
            while len(exam) < n:
                #ensure exam is long enough
                exam += exam[:1]
            exam = exam[:n] #ensure exam is short enough
            #map T and F to floats [0,1] based on confidence
            weighted_exam = [0.5+confidence*(0.5 if q else -0.5) for q in exam]
            best_guess_totals = [current+new for current,new in zip(best_guess_totals, weighted_exam)]
        best_guess_averages = [total/self.bot_types
            for total
            in best_guess_totals
        ]
        best_guess = [avg > 0.5 for avg in best_guess_averages]
        self.last_round = best_guess
        return best_guess
    def update(self, ranks, own, others):
        pass
    def _md5_from(self, data, n):
        md5 = hashlib.md5(data)
        for i in range(n):
            md5.update(data)
        exam = []
        while len(exam) < n:
            exam += [x == "0"
                for x
                in bin(int(md5.hexdigest(), 16))[2:].zfill(128)
            ]
            md5.update(data)
        return exam[:n]
    def _invert(self, exam):
        return [not val for val in exam]
    def _digits_to_bools(self, iterable):
        return [char=="1" for char in iterable]
    def _plagiarise(self, n):
        copy = (self.last_round * n)[:n]
        return copy

    '''functions to calculate expected exams for each other bot:
       (these values, weighted with corresponding confidence ratings,
       are summed to calculate the most likely exam.)'''
    def _jad(self, n):
        '''Calculate the mean of _jad's distribution, then
        use that as the guess'''
        mean = max(int(np.sqrt(np.power(2,n))), (2<<n)-1)
        string_mean = f"{mean}".zfill(n)
        exam = self._invert(self._digits_to_bools(string_mean))
        return exam, 0.5
    def _alp(self, n):
        '''Alpha uses a predictable hash,
        until it figures out we aren't Beta,
        modelled by the probability of giving or solving
        Alpha's exam'''
        #probability that Alpha thinks we're Beta
        #assuming we fail to pretend to be Beta if we meet Alpha
        chance_beta = ((1 - 1/self.bot_types) ** n) ** 2
        return self._md5_from(b"Beta", n), chance_beta
    def _gam(self, n):
        '''Gamma is like Beta, except after realising,
        switches to 50-50 random choice of inverse
        either Beta or Alpha's hash'''
        #probability that Gamma thinks we're Alpha still
        #(Unlikely that Gamma will think we're Beta;
        #we'd need to fail Alpha but pass Beta,
        #therefore, not accounted for)
        chance_unknown = ((1 - 1/self.bot_types) ** n) ** 2
        #default exam that assumes that Gamma thinks we're Alpha
        exam = self._md5_from(b"Beta", n)
        if chance_unknown > 0.5:#there exists a better heuristic here
            #assume Gamma will consider us Alpha
            confidence = chance_unknown
        else:
            #assume Gamma considers us neither Alpha nor Beta
            alpha = self._invert(self._md5_from(b"Beta", n))
            beta = self._invert(self._md5_from(b"Alpha", n))
            #check for bools where both possible exams match
            and_comp = [a and b for a, b in zip(alpha, beta)]
            nor_comp = [not (a or b) for a, b in zip(alpha, beta)]
            #count up matches vs times when fell back on default
            #to calculate ratio of default
            #to bools where hashes agree
            confidence_vs_default = (sum(and_comp)+sum(nor_comp)) / n
            confidence = confidence_vs_default * chance_unknown + (1 - confidence_vs_default) * (1 - chance_unknown)
            for i in range(n):
                if and_comp[i]:
                    exam[i] = True
                if nor_comp[i]:
                    exam[i] = False
        return exam, confidence
    def _bet(self, n):
        '''Beta is like Alpha, but with a different hash'''
        #probability we haven't matched with Beta yet
        #i.e. probability that Beta still thinks we're Alpha
        chance_alpha = ((1 - 1/self.bot_types) ** n) ** 2
        return self._md5_from(b"Alpha", n), chance_alpha
    def _wiq(self, n):
        '''Wi Qe Lu is hard to model, so we pretend
        that it mimicks Plagiarist for the most part'''
        if n == 1:
            #first round is random
            return [False], 0
        #other rounds are based on exams it met
        #leaning towards same as the previous exam
        return self._plagiarise(n), 0.1
    def _stu(self, n):
        '''StudiousBot is random'''
        return [False] * n, 0
    def _pla(self, n):
        '''Plagiarist copies the exams it received,
        which can be modelled with the standard prediction
        calculated for the previous round, padded with its first
        element.'''
        if n == 1:
            return [True], 1
        return self._plagiarise(n), 0.3
    def _san(self, n):
        '''Santayana is based on answers, which we don't predict.
        Modelled as random.'''
        #mostly random, slight leaning towards default False
        return [False] * n, 0.1
    def _tho(self, n):
        '''Thomas has an unpredictable threshold.'''
        #for all intents, random
        return [False] * n, 0
    def _dru(self, n):
        '''Drunkard is utterly random.'''
        return [False] * n, 0
    def _yin(self, n):
        '''YinYang inverts itself randomly, but not unpredictably.
        We can model it to find the probability. Also notably,
        one index is inverted, which factors into the confidence
        especially for lower n.'''
        if n == 1:
            #one element is inverted, so whole list must be False
            return [False], 1
        if n == 2:
            #split half and half randomly; can't predict
            return [True] * n, 0
        #cumulative chance of mostly ones or mostly zeros
        truthy = 1
        for _ in range(n):
            #simulate repeated flipping
            truthy = truthy * 0.44 + (1-truthy) * 0.56
        falsey = 1 - truthy
        if falsey > truthy:
            return [False] * n, falsey - 1/n
        return [True] * n, truthy - 1/n
    def _con(self, n):
        '''Contrary is like Jade Emporer, but inverts itself
        so much that modelling the probability of inversion
        is not worth the effort.'''
        #there are some clever ways you could do statistics on this,
        #but I'm content to call it uniform for now
        return [False] * n, 0
    def _tit(self, n):
        '''TitForTat is most likely to give us False
        but the confidence drops as the chance of having
        met TitForTat increases.
        The square root of the probability we calculate for
        Alpha, Beta and Gamma, because those also care about what
        we answer, whereas TitForTat only cares about what we ask'''
        #probability that we've not given TitForTat an exam
        chance_friends = (1 - 1/self.bot_types) ** n
        return [False] * n, chance_friends
    def _equ(self, n):
        '''Equalizer always asks True'''
        #certain that Equalizer's exam is all True
        return [True] * n, 1
    def _mar(self, n):
        '''Marx returns mostly True, randomised based on our rank.
        We don't predict our rank.
        There's ~50% chance an answer is random'''
        #75% chance we guess right (= 50% + 50%*50%)
        return [True] * n, 0.75

Teoride harika bir fikir, ancak ilk yarışmasında Kont Oracular, YinYang'ı simüle etme çabalarına rağmen YinYang'dan daha kötü performans gösterdi.
Mor P

1
@MorP Evet, çok iyi değil. Bunun nedeni, tüm spesifik stratejileri birlikte ortalayarak 'genel olarak optimal' bir strateji seçmeye çalışmasıdır. Örneğin, YinYang ile karşılaştığında YinYang'ı yenmek için uyarlanmış bir strateji kullanmaz. Jade Emporer'da belirli bir strateji bile kullanmıyor: Jade Emporer stratejisini ortalamaya ekliyor. Rastgele olmaktan daha iyi olacak, ama çok fazla değil.
IFcoltransG

Marx düzeltildi. Tahmin etmek için Kont Oracular'ı güncellemelisiniz.
Mor P

@PurpleP Marx şimdi desteklenmeli. Yine 1917 gibi.
IFcoltransG

2

Yin Yang

Rastgele zıt olarak seçilen bir dizin hariç, tümünü Trueveya tümünü yanıtlar False. Yanıtının tam tersini sorar. Rakipleri fırlatmak için rastgele değiştirir.

import random

class YinYang:
    def __init__(self, ID, n):
        self.exam = True

    def update(self, rankList, ownExam, otherExams):
        if random.random() < 0.56:
            self.exam = not self.exam

    def answer(self, n, ID):
        a = [not self.exam] * n
        a[random.randint(0, n-1)] = self.exam
        return a

    def ask(self, n, ID):
        e = [self.exam] * n
        e[random.randint(0, n-1)] = not self.exam
        return e

Wi Qe Lu (Switcheroo)

İlk turda rastgele cevaplar ve soruyor. Daha sonra, bir önceki sınavdan gelen cevapları kullanır ve ortalamanın üzerinde sayıda yarışmacı doğru yaparsa bir soruyu değiştirir.

class WiQeLu:
    def __init__(self, ID, n):
        self.rounds = 1
        self.firstexam = True
        self.firstanswer = True
        self.lastexaminer = -1
        self.exam = []
        self.pastanswers = {}

    def update(self, rankList, ownExam, otherExams):
        questions, lastanswers = ownExam
        self.pastanswers[self.lastexaminer] = questions

        if len(otherExams) == 0:
            return
        correctCounts = [0 for i in otherExams[0][0]]
        for ourExam, response in otherExams:
            for i in range(len(response)):
                if ourExam[i] == response[i]:
                    correctCounts[i] += 1

        newExam = otherExams[0][0]
        meanWhoAnsweredCorrectly = sum(correctCounts) / len(correctCounts)
        for i in range(len(correctCounts)):
            if correctCounts[i] > meanWhoAnsweredCorrectly:
                newExam[i] = not newExam[i]
        self.exam = newExam

    def answer(self, n, ID):
        self.lastexaminer = ID
        if ID not in self.pastanswers:
            randomanswer = [random.randint(0, 1) == 1] * n
            self.pastanswers[ID] = randomanswer
            return randomanswer
        return (self.pastanswers[ID] * n)[:n]

    def ask(self, n, ID):
        if self.firstexam:
            self.firstexam = False
            self.exam = [random.randint(0, 1) == 1] * n
        return (self.exam * n)[:n]

5
Google Translate'e göre "wi qe lu" kabaca "Ben penguen yolum" olarak çevrilmiştir.
Mor P

2

Kendi botum:

Thomas

Uzak bir ülkeden gelen bir gezgin, geçmişteki sonuçların gelecekteki performansın göstergesi olduğu konusunda bazı tehlikeli fikirlere sahiptir. Kendi ilerlemesini engellemedikçe, diğer botları aşağıda tutmak için bunları kullanır.

class Thomas:
    def __init__(self,ID,n):
        N=10
        self.ID=ID
        self.myrank=n
        self.lowerank=0
        #The highest number of questions is equal to the number of participants, so we can do this:
        self.probs=[{i:1.0/N for i in np.linspace(0,1,num=N)} for i in np.arange(n)]
        self.output=[0.5]*n

    def ask(self,n,ID):
        if self.myrank==1 and self.lowerrank > 1: #I can't advance without promoting somebody first
            return [self.output[i]>np.random.rand() for i in np.arange(n)]
        #Otherwise, try to step on their fingers by going against the expected probability
        return [self.output[i]<np.random.rand() for i in np.arange(n)]


    def answer(self,n,ID):
        return [self.output[i]>np.random.rand() for i in np.arange(n)]

    def update(self,rankList,ownExam,otherExams):
        #Update our ranks
        self.myrank=len([i for i in rankList if i==rankList[self.ID]])
        self.lowerrank=len([i for i in rankList if i==rankList[self.ID]-1])
        #Update our expectations for each input we've been given
        self.bayesianupdate(ownExam[0])
        for ex in otherExams:
            self.bayesianupdate(ex[1])
        #Compress into output variable
        self.output=[np.sum([l[entry]*entry for entry in l]) for l in self.probs]

    def bayesianupdate(self,data):
        for i in np.arange(len(data)):
            if data[i]: #Got a True
                self.probs[i].update({entry:self.probs[i][entry]*entry for entry in self.probs[i]})
            else: #Got a False
                self.probs[i].update({entry:self.probs[i][entry]*(1-entry) for entry in self.probs[i]})
            s=np.sum([self.probs[i][entry] for entry in self.probs[i]]) #Renormalize
            self.probs[i].update({entry:self.probs[i][entry]/s for entry in self.probs[i]})
```

Sınıf ifadesinden sonra kodunuzu girintili hale getirmeyi unuttunuz mu?
pppery

Bu sadece SE biçimlendirmesi beni bilmeden yakalar. Bu botu kullanırken birinin testinde hataya neden olan şeyle birlikte
çözeceğim

2

Alfa

İndirmeden önce sohbeti okuyun. Bu botlar herhangi bir kuralı ihlal etmiyor. OP işbirliği yapan botları bile teşvik ediyor.

Alpha, Beta ile birlikte bir takım kuruyor. Her ikisi de birbirlerinin saflarına yükselmesine yardımcı olmak için önceden tanımlanmış bir sınav seti kullanıyor. Ayrıca her ikisi de aynı sınavları tekrar tekrar kullanan botlardan yararlanıyor.

import numpy as np
import hashlib

class Alpha:
    def __init__(self, ID, n):
        self.alpha = hashlib.md5(b"Alpha")
        self.beta = hashlib.md5(b"Beta")
        self.asker = -1
        self.betas = set(range(n)).difference([ID])
        self.fixed = set(range(n)).difference([ID])
        self.fixedExams = [[]] * n

    def ask(self,n,ID):
        if ID in self.betas:
            return self.md5ToExam(self.alpha, n)
        else:
            return list(np.random.choice([True, False], n))

    def answer(self,n,ID):
        self.asker = ID
        if self.asker == -1:
            return [True] * n
        elif self.asker in self.fixed and len(self.fixedExams[self.asker]) > 0:
            return (self.fixedExams[self.asker] * n)[:n]
        elif self.asker in self.betas:
            return self.md5ToExam(self.beta, n)
        else:
            return list(np.random.choice([True, False], n))

    def update(self,rankList,ownExam,otherExams):
        if self.asker >= 0:
            if self.asker in self.betas and ownExam[0] != self.md5ToExam(self.beta, len(ownExam[0])):
                    self.betas.remove(self.asker)
            if self.asker in self.fixed:
                l = min(len(ownExam[0]), len(self.fixedExams[self.asker]))
                if ownExam[0][:l] != self.fixedExams[self.asker][:l]:
                    self.fixed.remove(self.asker)
                    self.fixedExams[self.asker] = []
                elif len(ownExam[0]) > len(self.fixedExams[self.asker]):
                    self.fixedExams[self.asker] = ownExam[0]
        self.alpha.update(b"Alpha")
        self.beta.update(b"Beta")

    def md5ToExam(self, md5, n):
        return [x == "0" for x in bin(int(md5.hexdigest(), 16))[2:].zfill(128)][:n]

Bu üç botun hem istemlerde hem de yorumlarda belirtildiği gibi OP kurallarını ihlal ettiğini düşünüyorum.
Don Bin

@DonThousand Sohbetteki tartışmayı okursanız, kuralları ihlal etmediklerini göreceksiniz. chat.stackexchange.com/rooms/98905/imperial-exams-office
Sleafar

Yeterince adil. Benim hatam.
Don Bin

@DonThousand Peki hepsini küçümsemenin anlamı neydi?
Sleafar

Sadece Alpha'yı düşürdüm. Yine de oy kullanamıyorum. Gereksiz bir düzenleme yapın ve düzelteceğim.
Don Bin

1

Ekolayzer

Herkes eşit olmalıdır (bu aptal imparator saçmalıklarının hiçbiri olmadan), bu yüzden mümkün olduğunca fazla sosyal hareketlilik sağlayın. İnsanların başarılı olabilmesi için soruları gerçekten kolaylaştırın (cevap her zaman doğrudur).

class Equalizer:
    def __init__(self, ID, n):
        self.previousAnswers = [[0, 0] for _ in range(n)]
        self.previousAsker = -1

    def ask(self, n, ID):
        return [True] * n

    def answer(self, n, ID):
        if ID == -1:
            return [True] * n

        # Assume that questions from the same bot will usually have the same answer.
        t, f = self.previousAnswers[ID]
        return [t >= f] * n

    def update(self, rankList, ownExam, otherExams):
        if self.previousAsker == -1:
            return

        # Keep track of what answer each bot prefers.
        counts = self.previousAnswers[self.previousAsker]
        counts[0] += ownExam[0].count(True)
        counts[1] += ownExam[0].count(False)

1

Beta

İndirmeden önce sohbeti okuyun. Bu botlar herhangi bir kuralı ihlal etmiyor. OP işbirliği yapan botları bile teşvik ediyor.

Beta, Alpha ile birlikte bir ekip kuruyor. Her ikisi de birbirlerinin saflarına yükselmesine yardımcı olmak için önceden tanımlanmış bir sınav seti kullanıyor. Ayrıca her ikisi de aynı sınavları tekrar tekrar kullanan botlardan yararlanıyor.

import numpy as np
import hashlib

class Beta:
    def __init__(self,ID,n):
        self.alpha = hashlib.md5(b"Alpha")
        self.beta = hashlib.md5(b"Beta")
        self.asker = -1
        self.alphas = set(range(n)).difference([ID])
        self.fixed = set(range(n)).difference([ID])
        self.fixedExams = [[]] * n

    def ask(self,n,ID):
        if ID in self.alphas:
            return self.md5ToExam(self.beta, n)
        else:
            return list(np.random.choice([True, False], n))

    def answer(self,n,ID):
        self.asker = ID
        if self.asker == -1:
            return [True] * n
        elif self.asker in self.fixed and len(self.fixedExams[self.asker]) > 0:
            return (self.fixedExams[self.asker] * n)[:n]
        elif self.asker in self.alphas:
            return self.md5ToExam(self.alpha, n)
        else:
            return list(np.random.choice([True, False], n))

    def update(self,rankList,ownExam,otherExams):
        if self.asker >= 0:
            if self.asker in self.alphas and ownExam[0] != self.md5ToExam(self.alpha, len(ownExam[0])):
                    self.alphas.remove(self.asker)
            if self.asker in self.fixed:
                l = min(len(ownExam[0]), len(self.fixedExams[self.asker]))
                if ownExam[0][:l] != self.fixedExams[self.asker][:l]:
                    self.fixed.remove(self.asker)
                    self.fixedExams[self.asker] = []
                elif len(ownExam[0]) > len(self.fixedExams[self.asker]):
                    self.fixedExams[self.asker] = ownExam[0]
        self.alpha.update(b"Alpha")
        self.beta.update(b"Beta")

    def md5ToExam(self, md5, n):
        return [x == "0" for x in bin(int(md5.hexdigest(), 16))[2:].zfill(128)][:n]

1

Gama

İndirmeden önce sohbeti okuyun. Bu botlar herhangi bir kuralı ihlal etmiyor. OP işbirliği yapan botları bile teşvik ediyor.

Gamma, Alfa ve Beta'nın planlarını keşfetti ve bunlardan biri olarak gizleyerek her ikisinden de faydalanmaya çalışıyor.

import numpy as np
import hashlib

class Gamma:
    def __init__(self, ID, n):
        self.alpha = hashlib.md5(b"Alpha")
        self.beta = hashlib.md5(b"Beta")
        self.asker = -1
        self.alphas = set(range(n)).difference([ID])
        self.betas = set(range(n)).difference([ID])
        self.fixed = set(range(n)).difference([ID])
        self.fixedExams = [[]] * n

    def ask(self,n,ID):
        if ID in self.alphas:
            return self.md5ToExam(self.beta, n)
        elif ID in self.betas:
            return self.md5ToExam(self.alpha, n)
        else:
            return self.md5ToWrongExam(np.random.choice([self.alpha, self.beta], 1)[0], n)

    def answer(self,n,ID):
        self.asker = ID
        if self.asker == -1:
            return [True] * n
        elif self.asker in self.fixed and len(self.fixedExams[self.asker]) > 0:
            return (self.fixedExams[self.asker] * n)[:n]
        elif self.asker in self.alphas:
            return self.md5ToExam(self.alpha, n)
        elif self.asker in self.betas:
            return self.md5ToExam(self.beta, n)
        else:
            return list(np.random.choice([True, False], n))

    def update(self,rankList,ownExam,otherExams):
        if self.asker >= 0:
            if self.asker in self.alphas and ownExam[0] != self.md5ToExam(self.alpha, len(ownExam[0])):
                    self.alphas.remove(self.asker)
            if self.asker in self.betas and ownExam[0] != self.md5ToExam(self.beta, len(ownExam[0])):
                    self.betas.remove(self.asker)
            if self.asker in self.fixed:
                l = min(len(ownExam[0]), len(self.fixedExams[self.asker]))
                if ownExam[0][:l] != self.fixedExams[self.asker][:l]:
                    self.fixed.remove(self.asker)
                    self.fixedExams[self.asker] = []
                elif len(ownExam[0]) > len(self.fixedExams[self.asker]):
                    self.fixedExams[self.asker] = ownExam[0]
        self.alpha.update(b"Alpha")
        self.beta.update(b"Beta")

    def md5ToExam(self, md5, n):
        return [x == "0" for x in bin(int(md5.hexdigest(), 16))[2:].zfill(128)][:n]

    def md5ToWrongExam(self, md5, n):
        return [x == "1" for x in bin(int(md5.hexdigest(), 16))[2:].zfill(128)][:n]

1

TitForTat

Geçmişte kolay sorular sorduysanız size kolay sorular sorar. Daha önce hiç sınav vermediyseniz, varsayılan olarak kolay sorulardır.

Ek olarak, zor sorular soran kimseye güvenmez ve onlara öngörülemeyen cevaplar verir.

import numpy as np

class TitForTat:
    def __init__(self, ID, n):
        self.friendly = [True] * n
        self.asker = -1

    def make_answers(self, n, ID):
        if ID == -1 or self.friendly[ID]:
            return [False] * n
        else:
            return list(np.random.choice([True, False], n))

    def ask(self, n, ID):
        return self.make_answers(n, ID)

    def answer(self, n, ID):
        self.asker = ID
        return self.make_answers(n, ID)

    def update(self, rankList, ownExam, otherExams):
        if self.asker != -1:
            # You are friendly if and only if you gave me a simple exam
            self.friendly[self.asker] = all(ownExam[0])

Diğer botlar onunla işbirliği yaparsa bu bot iyi çalışır. Şu anda sadece Ekolayzır işbirliği yapıyor, ancak bu umarım yeterli olacaktır.


Şu anda, bot şartnamelere uymadığı için rekabet edemiyor. listNesneleri her zaman döndürdüğünden emin olun . Ayrıca, hem eski hem de güncellenmiş kurallar altında, bir botun mükemmel kopyaları geçerli gönderimler değildir, bu nedenle bu bot çalışmasına izin verilen örnek sayısı 1'dir.
AlienAtSystem

Listeleri döndürmek için düzenledim. Mükemmel kopyalar gelince, onunla düzgün bir şekilde işbirliği yapan mevcut bir bot yoktur, bu yüzden stratejinin başarılı bir şekilde yürürlüğe girmesi için gereken minimum - karbon kopya botlarının sayısı en az 1'dir (bu bot ve 1 kopyası gereklidir) ).
İsimsiz

1. fıkra kapsamındaki bir şeyi göndermeye çalışırken, 3. fıkra uyarınca bir istisna için hak kazandığınızı iddia ediyorsunuz: Bir botun mükemmel kopyaları hiçbir zaman geçerli değildir, istisna yoktur. Ve 3. madde istisnası için, stratejinizin tüm bu ortakların buna tepki vermesini gerektirdiğini kanıtlamanız gerekir, örneğin bir kişi dinlemeden gerçekten işe yaramayan bir el sıkışma sinyali. Seninki değil. Ekolayzer "dostu" yan tümcesi tetiklemek için sınavlar, böylece bot bir kopyasını gerekli onaylanamayacaktır.
AlienAtSystem

Tamam o zaman. Birkaç son ayar yapacağım.
İsimsiz

0

aksi

Yeşim İmparatoru her zaman haklıdır, bu yüzden Yeşim İmparatoru'nun soran işlevini 2'den fazla cevaba ihtiyaç duyduğunda kendi cevap işlevi olarak uygular. Sadece 1 cevap için true(doğru olma olasılığı true,falseyüksektir ) ve 2 için cevap verir (bu cevap soruların "en az yarısından" dört olası sınavdan üçünü geçer, rastgele seçmekten daha iyidir).

Güncellemesinde, soran düzenini nasıl değiştirdiği konusunda benzer bir mantık kullanır, ancak soran mantığı, sadece farklı bir ağırlıkla Yeşim İmparatorununkine benzer. Çok sayıda adayın geçebilecek kadar yüksek puan aldığı trueyüksek değerler ile dalgalanmalar arasında dalgalanmalar false.

class Contrary:
    def __init__(self,ID,n):
        self.rank = 0
        self.ID = ID
        self.competitors = {}
        self.weight = -2
        pass

    def ask(self,n,ID):
        if self.weight > 0:
            num=min(np.random.exponential(scale=np.sqrt(np.power(self.weight,n))),np.power(2,n)-1)
            bi=list(np.binary_repr(int(num),width=n))
            return [x=='0' for x in bi]
        else:
            num=min(np.random.exponential(scale=np.sqrt(np.power(-self.weight,n))),np.power(2,n)-1)
            bi=list(np.binary_repr(int(num),width=n))
            return [x=='1' for x in bi]

    def answer(self,n,ID):
        if n == 1:
            return [True]
        if n == 2:
            return [True,False]
        num=min(np.random.exponential(scale=np.sqrt(np.power(2,n))),np.power(2,n)-1)
        bi=list(np.binary_repr(int(num),width=n))
        return [x=='0' for x in bi]

    def update(self,rankList,ownExam,otherExams):
        self.rank = rankList[self.ID];
        if len(otherExams) == 0:
            return
        correctCounts = [0 for i in otherExams[0][0]]
        for ourExam, response in otherExams:
            for i in range(len(response)):
                if ourExam[i] == response[i]:
                    correctCounts[i] += 1

        meanWhoAnsweredCorrectly = sum(correctCounts) / len(correctCounts)
        for i in range(len(correctCounts)):
            if correctCounts[i]+1 > meanWhoAnsweredCorrectly:
                self.weight = np.copysign(np.random.uniform(1,3),-self.weight)

1
true, falseSınav yapılırsa başarısız olmaz mı false, true?
pppery

İlk birkaç satır answersözdizimi ve isim hataları - trueve falseolması gerektiği Trueve Falseve ifs eksik :sonunda s
Sara J

İkinize teşekkürler; Makinemde bu kadar sık ​​kullanmadığım için Python kurulmamıştı, bu yüzden sözdizimini düzenli olarak karıştırıyorum.
Draco18s artık SE

newExam ayarlanmış ancak asla okunmamış update. passbir NOP komutudur, silebilirsiniz. (Arkasındaki yorum, kopyaladığınız Drunkard için sadece bir cinstir.) Ayrıca, dolaylı olarak mathve randommodülleri kullanıyorsunuz , ancak bunları içe aktardığınızı beyan etmediniz. Yarışma dosyamda yeniden yazdım np.copysignve np.random.uniformbu da aynı şeyi yapmalı.
AlienAtSystem

@AlienAtSystem Şimdi düzeltilmelidir.
Draco18s artık SE

0

Marx

Bu Marx botu. Bürokrasi yerine komünist bir sistemimizin olması gerektiğine inanıyor. Bu hedefe ulaşmaya yardımcı olmak için, daha üst sıradaki botlara daha sert sınavlar verir. Ayrıca daha yüksek botlardan sınavlara daha rastgele cevaplar verir, çünkü muhtemelen daha zekidirler, çünkü daha yüksektirler.

import numpy as np

class Marx():
    def __init__(self, ID, n):
        self.ID = ID
        self.n = n
        self.ranks = [] # The bot rankings
        self.e = [] # Our quiz
        self.rank = 0 # Our rank
    def ask(self, n, ID):
        test = [True] * n
        # Get the rank of the bot being quizzed
        if self.ranks:
            rank = self.ranks[ID]
        else:
            rank = 0
        for i in range(len(test)):
            item = test[i]
            if np.random.uniform(0, rank / self.n) > 0.5:
                # If the bot is higher ranking, make the quiz harder
                item = np.random.choice([True, False], 1)[0]
            test[i] = item
        # IF the test is not long enough, add Falses to the end
        while len(test) < n - 1:
            test.append(False)
        return test
    def answer(self, n, ID):
        # Get the rank of the asking bot
        if self.ranks:
            rank = self.ranks[ID]
        else:
            rank = 0
        if self.e:
            # Pad our quiz with Falses so it will not throw IndexError
            while len(self.e) < n:
                self.e.append(False)
            for i in range(len(self.e)):
                item = self.e[i]
                if np.random.uniform(0, rank / self.n) > 0.5:
                    # Assume that higher ranking bots are cleverer, so add more random answers
                    item = np.random.choice([True, False], 1)[0]
                self.e[i] = item
            if len(self.e) > self.rank + 1:
                self.e = self.e[:self.rank + 1]
            return self.e
        else:
            # If it is the first round, return all Trues
            return [True] * n
    def update(self, rankList, ownExam, otherExams):
        # Update our list of ranks
        self.ranks = rankList
        # Store the quiz we were given, to give to the next bot
        self.e = ownExam[0]
        # Store our rank
        self.rank = rankList[self.ID]

Marx şu anda bir bayta çok fazla cevap veriyor, bu yüzden şu anda rekabet edemiyor
AlienAtSystem

Ne demek istiyorsun? Sınavları / cevapları çok mu uzun?
sugarfi

Cevabı çok uzun bir giriş
AlienAtSystem

Tamam, düzelttim. Şimdi iyi olmalı.
sugarfi

Üzgünüm, size yanlış geri bildirim verdim: Şimdi cevaplar çok kısa. Asıl sorun, benlik süresini uzatmanızdır. E çok kısa olduğunda (şu anda yeterli olmasa da), ancak Marx düştüğünde onu kesmeyin.
AlienAtSystem
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.