天体官僚制KoTH


14

中国帝国では、社会のランクは出生や富ではなく、帝国試験で優れている人の能力によって決定されました。神の天の支配者である玉皇帝は、彼のすべての主題を調べて彼らの価値を決定し、次に中国を統治するために神の使命を誰に与えるかを求めました。

官僚制のルール:

  • 神官官僚制は、0から始まる負ではない整数値のランクで構成されます。官僚制の各メンバー(ボット)は1つのランクに属します。各ランクは任意の数のメンバーを保持できますが、上記のすべてのランクが空でない限り空にすることはできません
  • ゲームの開始時に、すべてのメンバーのランクは0です
  • 毎ターン、官僚の各メンバーは試験に答えなければなりません。試験は、リストのブール値を正しく推測することで構成されています。リストの長さは、メンバーの上のランクの数です。
  • 試験問題は、上記のランクのランダムなメンバーによって準備されます。最高ランクのメンバーは質問を直接受け取りますJadeEmperor(以下を参照)
  • 試験で少なくとも50%を獲得したメンバーは、プロモーションの対象となります。試験の得点が50%未満の会員は降格の資格があります。
  • 降格の資格があるメンバーのランクは、下のランクに昇格する資格のあるメンバーがいる場合にのみ1減少します。
  • 昇格の資格があるすべてのメンバーは、ランクが空にならない限り、ランクが1ずつ上がります。
  • すべての資格のあるメンバーを降格または昇格できるわけではない場合、優先順位は(降格の)最も低いメンバーになります。最高の(プロモーション用)スコア。ネクタイはランダムに壊れます。
  • メンバーのランクは、各ターンで最大1つまでしか変更できません。

ゲームのルール:

  • 各ボットには、ゲームの開始時にIDがランダムに割り当てられますが、そのIDはコース中に変更されることはありません。のJadeEmperorIDは-1で、他のすべては0から始まる連続した非負のIDです。
  • すべてのボットが同時に競合する
  • ゲームは100ターン実行され、ボットのスコアはその期間中に所有した平均ランクです。
  • 合計スコアは、1000ゲームを実行し、結果を平均することにより取得されます。
  • 各ボットは、次の4つの機能を実装するPython 3クラスです。
    • ask(self,n,ID)list長さnのブール値を返すことにより試験を行います。IDは、そのリストを推測する必要があるボットのIDです。ask()任意のボットの単一ラウンド中に何度も呼び出すことができますが、まったく呼び出せません。
    • answer(self,n,ID)、これはlist長さnのブール値のa を返すことにより試験に答える試みです。IDは、ask()試験を生成したボットのIDです。answer()各ボットのラウンドごとに1回だけ呼び出されます。
    • update(self,rankList,ownExam,otherExams)コントローラーがすべての昇格と降格を実行すると呼び出されます。その引数は次のとおりです。すべてのボットのIDですべてのランクをリストする整数のリスト。2つのリストで構成されるタプル。最初は試験の質問、次にボットが出した回答(忘れた場合に備えて)。次に、同様に試験回答ペアで構成されるタプルのリスト。今回はボットが配布したすべての試験について。
    • __init__(self, ID, n) ボットに独自のIDと競合するボットの数を渡します。
  • クラスは私的使用のために他の機能を実装することができます
  • さらに変数を定義し、それらを使用して過去の試験に関するデータを保存することは明示的に許可されています。
  • メタ効果のプログラミングは禁止されています。つまり、他のボットのコード、コントローラーのコードに直接アクセスしようとすると、例外などが発生します。これは試験の戦略のコンテストであり、コードハッキングのコンテストではありません。
  • お互いを助けようとするボットは、メタ効果を介してそれを行わない限り、明示的に許可されますが、純粋に通過する情報によって update()
  • 他の言語は、Python 3に簡単に変換できる場合にのみ許可されます。
  • ライブラリnumpyはとしてインポートされnpます。バージョンは1.6.5です。つまり、古いランダムライブラリを使用します。numpy 1.7をお持ちの場合numpy.random.mtrand、テスト用に古い関数を使用できます。mtrandを削除することを忘れないでください。
  • 実行時にボットが例外を発生させた場合、失格となります。コードが非常に難読化されているため、ask()またはanswer()が呼び出されたときに長さnのリストを生成するかどうかを判断できないボットも、プリエンプティブに失格になります。ディープコピーの出力を強制するボットは、スコアで-1を取得します。
  • クラス名は一意である必要があります
  • 1人につき複数のボットが許可されますが、繰り返し更新されるボットの最新バージョンのみが取得されます。
  • ボットの類似性について混乱があるようです。
    • 別のボットのコピーを投稿することはできません。これは、この課題に実際に適用される唯一の 標準的な抜け穴です。
    • あなたがされている許可され、他の人のボットを含む他のボット、とのコードを共有しているために。
    • そのようなカーボンコピーボットの数が成功するために最低限必要であることを証明できる場合除き、戦略に対する些細な変更(質問生成のシードの変更など)のみが異なるボットを送信することはできません。彼らの戦略の制定(通常、協力のために2つのボットになります)。

ボットの例:

JadeEmperor常にゲームの一部ですが、競合しません。彼は最高ランクのボットの試験のジェネレーターとして機能します。彼の試験はランダムですが、均一ではなく、スマートボットが前進する方法を可能にします。

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]

酔っぱらいは完全にランダム試験と回答を生成します。彼はゲームに参加します。

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

盗作だけコピー前の試験。彼もゲームに参加します。

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]

コントローラコードはこちらから入手できます。テストのために、同じフォルダー内のContestants.pyファイルに独自のクラスを置くと、それらがインポートされます。

チャットルームはこちらにあります

試験が始まります!

Oct20の現在のスコア、より高い精度(10000回実行):

応募者著者スコアアルファスリーファー9.669691ガンマスリーファー9.301362ベータスリーファー9.164597WiQeLuパープルP7.870821StudiousBotDignissimus-スパム7.538537サンタヤナサラ・J7.095528盗作者6.522047カウントIFcoltransG5.881175トーマスエイリアン@システム5.880041逆にドラコ5.529652マルクスシュガーフィ5.433808酔っぱらい5.328178陰陽パープルP5.102519イコライザニモニック4.820996TitForTat匿名3.35801

予見可能な将来の新しいエントリーごとにコンテストが実施されます。


1
ボットのコピーは標準の抜け穴ですので、ありません。ほぼすべてではなくほぼ完全なコピーを送信することにより、作成者ルールごとに複数のボットを悪用しようとする場合は、削除します。
AlienAtSystem

1
@AlienAtSystemなぜボットが互いに助け合うことを許可しているのですか?対処するためのより多くの混乱とランダム性のようです。
ドンサウザンド

2
なぜコンストラクター引数ID, nが他のメソッド引数なのn, IDですか?
パープルP

1
@DonThousand与えられた制約の下で、A)首尾よくハンドシェイク(Plagiarizerが誤って中央の人を演じる可能性があることに注意)およびB)そのボットを確実に支援する戦略を制定する2つのボットを作成することは非常に偉業であると信じているためしかし、他に上昇するものはありません。
AlienAtSystem

1
@someoneランクは上向きにカウントされます。あなたは0から始めて、より高い数字に
向かって進み

回答:


4

サンタヤナ

過去を思い出せない人は、過去を繰り返すと非難されます。そのため、他の人が過去にどのように行動したかに基づいて意思決定を行い、特定のインデックスで質問者が通常どのような回答を期待しているかに基づいて回答し、特定のインデックスで最も頻繁に与えられなかった回答を求めます。

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

勤勉なボット

このボットはテストのために勉強します!さまざまなボットによって与えられたテストでパターンを見つけようとし、それに応じて動作します。

これまでのところ、このボットは、Alpha、Beta、Gamma(一緒に動作するようにプログラムされている)を除き、コンピューターで作業できる他のすべてのボットよりも優れています。ボットはチーム化が許可されているという事実を利用しません。それは、不正行為に少し似ており、少し汚いのだと感じたからです。しかし、それを見渡せば、チーム化は非常に効果的であるようです。

ボットは、テストへの回答がランダムであり、応答でテストの平均50%に一致することと一致することを認識しようとします。

また、ボットは、その行動を予測するために結びついている他のボットを追い払うために、ボットが単にその答えをひっくり返したことを認識しようとしますが、私はまだこれに具体的に行動するようにプログラムしていません。

読みやすくするために、いくつかのコメントを付けてコードに注釈を付けました

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]

私たちのパフォーマンスから判断すると、答えるのに最適なアルゴリズムがあり、Wi Qe Luに尋ねるのに最適なアルゴリズムがあります。ボットをXuézhě(「学者」の中国語)と呼ばれる単一のボットに結合することを提案します。これは偶然「スイッチャー」のように聞こえます。
パープルP

私はそれをハックして、マシンで試験を実行しました。奇妙なことに、Studious Botを上回っていましたが、Wi Qe Luは上回っていません。
パープルP

@PurplePハハ!音は非常に興味深いことを、私は私が私のボットを改善するための十分な時間がないと思うが、あなたはここに提出としてそれを投稿することができます
スパム行為- Dignissimusを

3

オラキュラー伯爵

このボットは、他のすべてのボットが試験として設定するものを決定するために、他のすべての動作中のボットの試験を平均するアルゴリズムを使用します(ラウンド数といくつかのひどいヒューリスティックを与えられます)。
Countは、md5ハッシュを使用して試験を依頼します。したがって、その質問とその答えは両方とも決定論的です。ほとんどの入力を無視し、Jade Emporerに対するものを含め、まったく同じブール値のシーケンス(雨または輝き)を尋ね、答えます。

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

理論上は素晴らしいアイデアですが、最初のコンテストでは、オラキュラー伯爵は陰陽をシミュレートする努力にもかかわらず陰陽よりも悪いパフォーマンスを示しました。
パープルP

1
@PurplePはい、あまり良くありません。その理由は、特定の戦略をすべて平均化することにより、「一般的に最適な」戦略を選択しようとするためです。たとえば、YinYangに遭遇したときにYinYangを倒すように調整された戦略は使用しません。Jade Emporerで特定の戦略を使用することさえしません。JadeEmporer戦略を平均に追加するだけです。ランダムではありませんが、それほどではありません。
IFcoltransG

マルクスが修正されました。予測するには、Count Oracularを更新する必要があります。
パープルP

@PurpleP Marxがサポートされるようになりました。再び1917年のようです。
IFcoltransG

2

陰陽

反対になるようにランダムに選択された1つのインデックスを除き、all Trueまたはallのいずれかに回答しますFalse。答えの反対を尋ねます。ランダムにスワップして、相手を追い払います。

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)

最初のラウンドでランダムに回答および質問します。その後、彼は前の試験の回答を使用し、平均以上の数の競合他社が正解した場合は質問を変更します。

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翻訳によると、「wi qe lu」は「私はペンギンの道です」と大まかに翻訳されています。
パープルP

2

私自身のボット:

トーマス

遠い土地からの旅行者は、過去の結果が将来のパフォーマンスを示すという危険な考えを持っています。彼は他のボットを抑えるためにそれらを使用しますが、それが彼自身の進歩を抑制しない限り。

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]})
```

クラス文の後にコードをインデントするのを忘れましたか?
pppery

それは私が気づかないようになっている単なるSEフォーマットです。このボットを使用するときに誰かのテストでエラーを引き起こしたものと一緒に修正します
AlienAtSystem

2

アルファ

投票する前にチャットを読んでください。これらのボットはルールに違反しません。OPは、協力するボットを奨励しています。

アルファはベータとチームを組んでいます。どちらも事前に定義された一連の試験を使用して、互いにランクを上げるのを助けています。また、両方が同じ試験を繰り返し使用するボットを利用しています。

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]

これら3つのボットは、プロンプトとコメントの両方に記載されているOPルールに違反していると思います。
ドンサウザンド

@DonThousandチャットでディスカッションを読むと、ルールに違反していないことがわかります。chat.stackexchange.com/rooms/98905/imperial-exams-office
Sleafar

けっこうだ。私の悪い。
ドンサウザンド

@DonThousandそれでは、それらすべてをダウン投票することのポイントは何でしたか?
Sleafar

私はアルファのみをダウン投票しました。しかし、私はダウン票を送ることはできません。余分な編集を行い、修正します。
ドンサウザンド

1

イコライザ

誰もが平等でなければなりません(この愚かな皇帝のナンセンスはありません)、可能な限り多くの社会的流動性を提供してください。人々が成功できるように、質問を本当に簡単にします(答えは常に真です)。

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

ベータ

投票する前にチャットを読んでください。これらのボットはルールに違反しません。OPは、協力するボットを奨励しています。

ベータ版はアルファ版とチームを組んでいます。どちらも事前に定義された一連の試験を使用して、互いにランクを上げるのを助けています。また、両方が同じ試験を繰り返し使用するボットを利用しています。

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

ガンマ

投票する前にチャットを読んでください。これらのボットはルールに違反しません。OPは、協力するボットを奨励しています。

ガンマはアルファとベータの計画を発見し、アルファとベータのいずれかを装って両方を活用しようとしています。

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

過去に簡単な質問をした場合、簡単な質問をします。試験を受けたことがない場合は、簡単な質問にデフォルト設定されます。

さらに、難しい質問をする人を信頼せず、予測できない答えを与えます。

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

このボットは、他のボットが協力する場合にうまく機能します。現在、イコライザーのみが協力していますが、これで十分です。


現時点では、ボットは仕様に従っていないため競争できません。list常にオブジェクトを返すようにしてください。また、古いルールと更新されたルールの両方で、ボットの完全なコピーは有効な
送信で

リストを返すように編集しました。完全なコピーについては、適切に連携する現在のボットは存在しないため、カーボンコピーボットの数-戦略を成功させるために最低限必要なもの-は少なくとも1つです(このボットとそのコピーが1つ必要です) )。
匿名

ボットの完璧なコピーがありません:あなたは、条項1に該当何か提出しようとしているときは、第3項の下での例外に適格と主張していない、何の例外が有効に。そして、条項3の例外の資格を得るには、たとえばハンドシェイク信号のように、戦略がそれらに反応するすべてのパートナーを厳密に必要とすることを証明する必要があります。あなたのものはありません。イコライザーは、「フレンドリー」条項をトリガーする試験を提供し、ボットのコピーが必要であることを証明します。
AlienAtSystem

じゃ、はい。最終調整をいくつか行います。
匿名

0

逆に

ade皇帝は常に正しいので、2回以上の回答が必要な場合、J皇帝の質問機能を独自の回答機能として実装します。答えは1つだけtrue(正解のオッズ)で、2つは答えですtrue,false(この応答は、ランダムに選択するよりも4つのクイズのうち3つ以上の質問の「少なくとも半分」に合格します)。

Updateで要求パターンを変更する方法に関して同様のロジックを使用しますが、その要求ロジックは、Jade Emperorのものと類似しており、重みが異なります。あまりにも多くの候補者が合格するのに十分に高いスコアを獲得した場合のtrue高い値と高い値の間で変動します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, false試験が失敗しても失敗しませんかfalse, true
pppery

最初の数行は、answer構文と名前のエラーを持っている- truefalseする必要がありますTrueし、Falseし、ifsが不足している:最後にSを
サラ・J

ありがとうございます。Pythonはあまり使用しないので、マシンにPythonをセットアップしていませんでした。そのため、定期的に構文を台無しにします。
Draco18sは

newExamは設定されていますが、読み込まれませんupdatepassNOPコマンドです。削除できます。(その背後にあるコメントは、コピーしたDrunkerdの単なるしゃれです。)また、暗黙的にmathand randomモジュールを使用していますが、それらをインポートしたと宣言していません。コンテストファイルでnp.copysignを書き直しましたnp.random.uniformが、同じことを行う必要があります。
AlienAtSystem

@AlienAtSystem今すぐ修正する必要があります。
Draco18sは、

0

マルクス

これは、Marxボットです。彼は、官僚制度の代わりに、共産主義体制が必要だと考えています。この目標を達成するために、ランクの高いボットにより難しいクイズを提供します。また、より高いボットからのクイズにランダムな回答を与えます。なぜなら、彼らはおそらくより賢いからです。

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]

マルクスは現在、1バイトにあまりにも多くの回答をしているので、彼は今競争することができません
-AlienAtSystem

どういう意味ですか?彼の試験/解答が長すぎますか?
sugarfi

彼の答えは1つのエントリが長すぎます
-AlienAtSystem

OK、それを修正しました。今は大丈夫です。
sugarfi

申し訳ありませんが、間違ったフィードバックをお送りしました。今、回答は短すぎます。本当の問題は、self.eが短すぎる場合(現時点では十分ではありませんが)self.eを拡張することですが、Marxが降格された場合はトリミングしないでください。
AlienAtSystem
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.