천상의 관료제 KoTH


14

중국 제국에서는 사회의 계급이 출생이나 부로 결정되는 것이 아니라 제국 시험에서 뛰어나게하는 사람의 능력에 의해 결정되었습니다. 하늘의 신성한 통치자 인 제이드 황제는 자신의 모든 과목을 검토하여 자신의 가치를 결정하고 다음에 중국의 통치권을 부여 할 신권 명령을 요구했습니다.

관료주의의 규칙 :

  • 신성한 관료주의는 0부터 시작하여 음이 아닌 정수 값 순위로 구성됩니다. 관료주의의 각 구성원 (봇)은 하나의 순위에 속합니다. 각 순위는 임의의 많은 멤버를 보유 할 수 있지만 위의 모든 순위가 비어 있지 않으면 비워 둘 수 없습니다.
  • 게임 시작시 모든 멤버의 순위는 0입니다
  • 매번 관료주의의 각 구성원은 시험에 답해야합니다. 시험은 목록의 부울 값을 올바르게 추측하는 것으로 구성됩니다. 목록의 길이는 멤버 위의 순위 수입니다.
  • 시험 문제는 위의 등급 중 임의의 구성원이 작성합니다. 최고 등급의 회원은 JadeEmperor(아래 참조) 에서 직접 질문을받습니다.
  • 시험에서 최소 50 %의 점수를 얻은 회원은 프로모션 자격이 있습니다. 시험에서 50 % 미만의 점수를받은 회원은 탈퇴 자격이 있습니다.
  • Demotion 자격이있는 회원은 아래 등급에 프로모션 자격이있는 회원이있는 경우에만 등급이 1 씩 감소합니다.
  • 프로모션 자격이되는 모든 회원은 등급이 비워지지 않는 한 등급이 1 씩 증가합니다.
  • 모든 적격 회원이 강등되거나 승격 될 수있는 것은 아니라면, 선호도는 (최하) 수준으로 떨어집니다. 최고 (프로모션) 점수. 동점은 무작위로 끊어집니다.
  • 멤버의 순위는 매 턴마다 최대 1까지만 변경할 수 있습니다.

게임의 규칙:

  • 게임 시작시 각 봇에 무작위로 ID가 할당되며, 코스마다 변경되지 않습니다. 그만큼JadeEmperor ID는 -1이고 다른 모든 ID는 0부터 시작하여 음이 아닌 연속 ID를 갖습니다.
  • 모든 봇은 동시에 경쟁합니다
  • 게임은 100 턴 동안 진행되며, 봇의 점수는 그 시간 동안 보유한 평균 순위입니다.
  • 총 점수는 1000 게임을 실행하고 결과를 평균화하여 얻습니다.
  • 각 Bot은 다음 4 가지 기능을 구현 하는 Python 3 클래스입니다.
    • ask(self,n,ID)list길이 n의 부울을 반환하여 시험합니다 . ID는 해당 목록을 추측해야하는 봇의 ID입니다. ask()모든 봇에 대해 한 라운드 동안 여러 번 호출 할 수 있지만 전혀 없습니다.
    • answer(self,n,ID)list길이 n의 부울을 반환하여 시험에 응답하려는 시도 입니다. ID는 ask()시험을 생성 한 봇의 ID입니다 . answer()각 봇에 대해 라운드 당 정확히 한 번 호출됩니다.
    • update(self,rankList,ownExam,otherExams)컨트롤러가 모든 프로 모션 및 디 모션을 수행하면 호출됩니다. 인수는 다음과 같습니다. 모든 봇의 ID별로 모든 순위를 나열하는 정수 목록. 두 개의 목록으로 구성된 튜플, 먼저 시험 문제, 봇이 제공 한 답변 (잊어 버린 경우); 봇이 나눠준 모든 시험에 대해 이번에는 시험-응답 쌍으로 구성된 튜플 목록입니다.
    • __init__(self, ID, n) 봇에 고유 ID와 경쟁 봇 수를 전달합니다.
  • 수업은 개인 용도로 다른 기능을 구현할 수 있습니다
  • 추가 변수를 정의하고이를 사용하여 과거 시험에 대한 데이터를 저장하는 것은 명시 적으로 허용됩니다.
  • 프로그래밍 메타 효과는 금지되어 있습니다. 즉, 다른 봇 코드, 컨트롤러 코드에 직접 액세스하려는 시도는 예외 등을 발생시킵니다. 이것은 코드 해킹이 아닌 시험 전략에 대한 경쟁입니다.
  • 서로를 돕기 위해 노력하는 봇은 메타 효과를 통해하지 않는 한 순수하게 전달되는 정보에 의해 명시 적으로 허용됩니다. update()
  • 다른 언어는 파이썬 3으로 쉽게 변환 될 수있는 경우에만 허용됩니다.
  • 라이브러리 numpy는로 가져옵니다 np. 버전은 1.6.5이며 이전 임의 라이브러리를 사용합니다. 1.7이 numpy 인 경우 numpy.random.mtrand테스트 를 위해 이전 기능을 사용할 수 있습니다 . 제출을 위해 mtrand를 제거하십시오.
  • 봇이 런타임 중에 예외를 발생 시키면 실격 처리됩니다. 코드가 난독 처리되어 ask()또는 answer()호출 될 때 길이 n의 목록을 생성하는지 여부를 알 수없는 봇은 선제 적으로 실격됩니다. 딥 카피 출력을 요구하는 봇은 점수에서 -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.870821StudiousBot디그 니시 무스-스팸7.538537산타 야나사라 J7.095528표절 자6.522047백작IFcoltransG5.881175도마외국인 @ 시스템5.880041반대로Draco18s5.529652마르크스설탕5.433808술고래5.328178음양퍼플 P5.102519평형 장치니모닉4.820996TitForTat익명3.35801

당분간은 새로운 각 출품작으로 대회가 진행됩니다.


1
봇 사본은 표준 허점이므로 아닙니다. 거의 그러나 거의 필요하지 않은 사본을 제출하여 작성자 당 여러 봇을 남용하려고하면 제거합니다.
AlienAtSystem

1
@AlienAtSystem 봇이 서로 돕는 것을 허용하는 이유는 무엇입니까? 그것은 더 많은 혼란과 무작위 처리처럼 보입니다.
Don Thousand

2
왜 생성자 인수가 ID, n아닌 다른 메소드 인수 n, ID입니까?
Purple P

1
@DonThousand 나는 주어진 제약 조건에서 A)가 성공적으로 핸드 셰이크 (Plagiarizer가 실수로 중간에 사람을 연주 할 수 있음)와 B)를 봇 두 개로 만드는 것은 매우 위업이라고 믿습니다. 그러나 다른 사람은 일어나지 않습니다.
AlienAtSystem

1
@ 누군가는 위를 차지합니다. 0에서 시작하여 더 높은 숫자로가는 길
AlienAtSystem

답변:


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

스튜디오 러스 봇

이 봇은 테스트를 위해 공부합니다! 다양한 봇이 제공 한 테스트에서 패턴을 찾으려고 시도합니다.

결국,이 봇은 알파, 베타, 감마 (함께 작동하도록 프로그래밍 된)를 제외하고 컴퓨터에서 작업 할 수있는 다른 모든 봇보다 성능이 뛰어납니다. 봇은 팀 구성이 허용된다는 사실을 사용하지 않습니다. 팀이 부정 행위와 약간 더럽다는 느낌이 들었 기 때문입니다. 그럼에도 불구하고 팀 구성은 상당히 효과적 인 것 같습니다.

봇은 테스트에 대한 답변이 임의적이며 응답에 따라 테스트에서 평균 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ě (중국어는 "학교")라고하는 단일 봇으로 결합하여 우연히 "스위처"처럼 들립니다.
Purple P

나는 그것을 해킹하고 내 컴퓨터에서 시험을 실행했다. 흥미롭게도 Studious Bot보다 점수가 높았지만 Wi Qe Lu는 아닙니다.
Purple P

트윗 담아 가기 매우 흥미롭게 들리지만 봇을 개선 할 시간이 충분하지 않다고 생각하지만 여기에 제출물로 게시 할 수 있습니다.
Dignissimus-Spammy

3

Oracular 백작

이 봇은 다른 봇이 시험으로 설정할 내용을 결정하기 위해 다른 모든 작업 봇 (라운드 수와 일부 끔찍한 휴리스틱을 부여 함)의 평균을 구하는 알고리즘을 사용합니다.
카운트는 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

이론적으로는 좋은 아이디어이지만 첫 번째 콘테스트에서 Oracular Count는 YinYang을 시뮬레이션하려는 노력에도 불구하고 YinYang보다 더 나빴습니다.
Purple P

1
@PurpleP 네, 좋지 않습니다. 그 이유는 특정 전략을 모두 평균화하여 '일반적으로 최적의'전략을 선택하려고하기 때문입니다. 예를 들어 YinYang을 만나면 YinYang을 이길 수있는 전략을 사용하지 않습니다. Jade Emporer에 특정 전략을 사용하지 않고 평균에 Jade Emporer 전략을 추가합니다. 무작위보다 낫지 만 많이는 아닙니다.
IFcoltransG

마르크스가 수정되었습니다. Count Oracular를 업데이트하여 예측해야합니다.
Purple P

@PurpleP Marx가 지원됩니다. 다시 1917 년과 같습니다.
IFcoltransG

2

음양

하나의 색인이 무작위로 반대로 선택되는 것을 제외하고 는 모두 True또는 모두에 응답합니다 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 (스위 터루)

첫 번째 라운드에서 무작위로 응답하고 묻습니다. 그 후, 그는 이전 시험의 답변을 사용하고 평균 이상의 수의 경쟁 업체가 올바른 경우 질문을 변경합니다.

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
구글 번역에 따르면 "wi qe lu"는 "I am penguin road"로 번역됩니다.
Purple 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

알파

downvoting 전에 채팅을 읽으십시오. 이 봇은 규칙을 위반하지 않습니다. 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]

나는이 세 가지 봇이 프롬프트와 의견에 명시된 바와 같이 OP 규칙을 위반한다고 생각합니다.
Don Thousand

@DonThousand 채팅에서 토론을 읽으면 규칙을 위반하지 않는 것을 볼 수 있습니다. chat.stackexchange.com/rooms/98905/imperial-exams-office
Sleafar

그럴 수 있지. 내 잘못이야.
Don Thousand

@DonThousand 그래서 그들 모두를 downvoting의 요점은 무엇입니까?
Sleafar

나는 알파 만 공감했다. 그래도 취소 할 수는 없습니다. 불필요한 편집을하고 수정하겠습니다.
Don Thousand

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

베타

downvoting 전에 채팅을 읽으십시오. 이 봇은 규칙을 위반하지 않습니다. 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

감마

downvoting 전에 채팅을 읽으십시오. 이 봇은 규칙을 위반하지 않습니다. 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입니다.
AlienAtSystem

목록을 반환하도록 편집했습니다. 완벽한 사본에 관해서는, 올바르게 협력하는 현재 봇이 없으므로 전략을 성공적으로 제정하는 데 필요한 최소의 탄소 복사 봇 수는 1 이상입니다 (이 봇과 1 복사본이 필요합니다) ).
Anonymous

1 항에 해당하는 것을 제출하는 동안 3 항에 따라 예외를받을 자격이 있다고 주장합니다. 봇의 완벽한 사본은 결코 유효하며 예외는 없습니다. 그리고 조항 3의 예외를 받으려면, 당신의 전략은 이러한 파트너들 모두가 이에 반응 할 것을 엄밀히 요구해야한다는 것을 증명해야합니다. 당신은하지 않습니다. 이퀄라이저는 "친절한"조항을 실행하기 위해 시험을 진행하므로 봇 사본이 필요하다는 것을 반증합니다.
AlienAtSystem

그럼 마지막으로 몇 가지를 조정하겠습니다.
Anonymous

0

반대로

Jade Emperor는 항상 옳으므로, 2 개 이상의 답변이 필요할 때 Jade Emperor의 요청 기능을 자체 응답 기능으로 구현합니다. 답이 1 명인 경우 만 true(정확한 확률), 2 명은 답변합니다.true,false ( 은 4 가지 퀴즈 중 3 가지 질문 중 "최소 절반"을 통과하여 무작위로 선택하는 것보다 낫습니다).

업데이트 패턴에서 요청 패턴을 변경하는 방법과 관련하여 유사한 로직을 사용하지만 요청 로직은 가중치가 다른 Jade Emperor와 유사합니다. 너무 많은 후보자가 합격하기에 충분히 높은 점수 truefalse받을 때 더 높은 값을 갖는 더 높은 값 사이에서 변동 합니다.

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구문 이름 오류가 - true하고 false있어야 True하고 False, 상기 ifS는 누락 :끝에들
라 J

두분 감사합니다. 자주 사용하지 않기 때문에 컴퓨터에 Python을 설정하지 않았으므로 구문을 정기적으로 엉망으로 만듭니다.
Draco18s는 더 이상 SE

newExam이 설정되었지만 읽지 마십시오 update. passNOP 명령이므로 삭제할 수 있습니다. (뒤에 주석은 복사 한 Drunkard의 말장난입니다.) 또한 모듈을 암시 적으로 사용 math하고 random있지만 가져 오기를 선언하지 않았습니다. 나는 한 내 대회 파일을 다시 작성 np.copysign하고 np.random.uniform그 같은 일을해야한다.
AlienAtSystem

@AlienAtSystem 지금 수정해야합니다.
Draco18s는 더 이상 SE

0

마르크스

이것은 마르크스 봇입니다. 그는 관료주의 대신에 공산주의 체제가 있어야한다고 믿는다. 이 목표를 달성하기 위해 상위 봇에게 더 어려운 퀴즈를 제공합니다. 또한 높은 봇의 퀴즈에는 더 무작위로 답변 할 수 있습니다.

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]

마르크스는 현재 너무 많은 바이트에 응답하기 때문에 현재 경쟁 할 수 없습니다
AlienAtSystem

무슨 소리 야? 그의 시험 / 응답이 너무 깁니까?
sugarfi

그의 대답은 너무 오래 걸린 것입니다
AlienAtSystem

좋아, 나는 고쳤다. 지금은 괜찮을거야.
sugarfi

죄송합니다. 피드백이 잘못되었습니다. 답변이 너무 짧습니다. 실제 문제는 너무 짧을 때 (현재는 충분하지 않지만) self.e를 확장하지만, Marx가 강등 될 때 자르지 않는다는 것입니다.
AlienAtSystem 5
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.