KoTH Birokrasi Surgawi


14

Di Imperial China, peringkat dalam masyarakat tidak ditentukan oleh kelahiran atau kekayaan, tetapi oleh kemampuan seseorang untuk unggul dalam Pemeriksaan Imperial. Kaisar Giok, penguasa ilahi Surga, telah menyerukan agar semua rakyatnya diperiksa untuk menentukan nilainya, dan siapa yang selanjutnya memberikan Mandat Ilahi untuk memerintah Tiongkok.

Aturan Birokrasi:

  • Birokrasi Ilahi terdiri dari peringkat bilangan bulat non-negatif, dimulai dengan 0. Setiap anggota (bot) birokrasi termasuk dalam satu peringkat. Setiap peringkat dapat menampung banyak anggota secara sewenang-wenang, tetapi tidak dapat kosong kecuali semua peringkat di atas kosong
  • Di awal permainan, semua anggota memiliki peringkat 0
  • Setiap belokan, setiap anggota birokrasi harus menjawab ujian. Ujian terdiri dari menebak dengan benar nilai boolean dari daftar. Panjang daftar adalah jumlah pangkat di atas anggota.
  • Pertanyaan ujian disiapkan oleh anggota acak dari peringkat di atas. Anggota dari peringkat tertinggi mendapatkan pertanyaan mereka langsung dari JadeEmperor(lihat di bawah)
  • Seorang anggota yang mencetak setidaknya 50% pada ujian mereka memenuhi syarat untuk Promosi. Anggota yang mendapat skor kurang dari 50% pada ujian mereka memenuhi syarat untuk Demosi.
  • Anggota yang memenuhi syarat untuk Demosi, peringkatnya akan berkurang satu hanya jika ada anggota yang memenuhi syarat untuk Promosi pada peringkat di bawah ini untuk menggantikannya.
  • Semua anggota yang memenuhi syarat untuk Promosi memiliki peringkat mereka naik satu selama ini tidak meninggalkan peringkat kosong.
  • Jika tidak semua anggota yang memenuhi syarat dapat Dipilih atau Dipromosikan, preferensi diberikan kepada yang terendah (untuk Demosi) resp. skor tertinggi (untuk Promosi). Ikatan rusak secara acak.
  • Peringkat anggota hanya dapat berubah paling banyak 1 setiap giliran.

Aturan main:

  • Setiap bot akan diberi ID secara acak pada awal permainan, yang tidak akan berubah seiring perjalanannya. ItuJadeEmperor memiliki ID -1, semua orang lain memiliki ID non-negatif berturut-turut, dimulai dengan 0.
  • Semua bot bersaing pada saat bersamaan
  • Permainan berjalan untuk 100 putaran, skor bot adalah peringkat rata-rata yang dimilikinya selama waktu itu.
  • Skor total diperoleh dengan menjalankan 1000 game dan rata-rata hasilnya.
  • Setiap Bot adalah kelas Python 3 yang mengimplementasikan empat fungsi berikut:
    • ask(self,n,ID), yang membuat ujian dengan mengembalikan a listdari Boolean dengan panjang n. ID adalah ID bot yang harus menebak daftar itu. ask()dapat dipanggil berkali-kali selama satu putaran untuk bot apa pun, tetapi juga tidak sama sekali.
    • answer(self,n,ID), yang merupakan upaya untuk menjawab ujian dengan mengembalikan a listdari Boolean dengan panjang n. ID adalah ID bot yang ask()menghasilkan ujian. answer()disebut tepat sekali per putaran untuk setiap bot.
    • update(self,rankList,ownExam,otherExams)dipanggil setelah Kontroler melakukan semua Pro dan Demosi. Argumennya adalah: Daftar bilangan bulat, daftar semua peringkat dengan ID semua bot; sebuah tuple, yang terdiri dari dua daftar, pertama pertanyaan ujian, lalu jawaban yang diberikan bot (jika lupa); kemudian daftar tupel, yang juga terdiri dari pasangan jawaban-ujian, kali ini untuk semua ujian yang dibagikan bot.
    • __init__(self, ID, n) melewati bot IDnya sendiri dan jumlah bot yang bersaing.
  • Kelas diizinkan untuk mengimplementasikan fungsi lain untuk penggunaan pribadi
  • Menentukan variabel lebih lanjut dan menggunakannya untuk menyimpan data tentang ujian sebelumnya diizinkan secara eksplisit.
  • Pemrograman meta-efek dilarang, artinya setiap upaya untuk secara langsung mengakses kode bot lain, kode Pengendali, menyebabkan Pengecualian atau serupa. Ini adalah kontes strategi untuk ujian, bukan peretasan kode.
  • Bot yang mencoba saling membantu diizinkan secara eksplisit, selama mereka tidak melakukannya melalui meta-efek, tetapi murni oleh informasi yang diteruskan update()
  • Bahasa lain hanya diizinkan jika bahasa itu dapat dengan mudah dikonversi ke Python 3.
  • Perpustakaan numpy akan diimpor sebagai np. Versi 1.6.5, artinya menggunakan pustaka acak lama. Jika Anda memiliki numpy 1.7, fungsi-fungsi lama tersedia numpy.random.mtranduntuk pengujian. Harap ingat untuk menghapus mtrand untuk pengiriman.
  • Jika bot menyebabkan Pengecualian selama runtime, itu didiskualifikasi. Setiap bot yang kodenya begitu dikaburkan sehingga tidak mungkin untuk mengetahui apakah ia menghasilkan daftar panjang n ketika ask()atau answer()dipanggil juga akan didiskualifikasi terlebih dahulu. Bot yang memaksa saya untuk menyalin dalam-dalam mendapat skor -1.
  • Nama kelas harus unik
  • Beberapa bot per orang diperbolehkan, tetapi hanya versi terbaru yang akan diambil dari bot yang diperbarui secara berulang.
  • Karena tampaknya ada beberapa kebingungan tentang kesamaan bot:
    • Anda tidak diperbolehkan memposting salinan bot lain. Ini adalah satu-satunya Celah Standar yang benar-benar berlaku dalam tantangan ini.
    • Anda diizinkan berbagi kode dengan bot lain, termasuk bot orang lain.
    • Anda tidak diperbolehkan mengirimkan bot yang berbeda dari yang lain hanya dengan perubahan sepele pada strategi (seperti perubahan pada seed untuk generasi pertanyaan) kecuali Anda dapat membuktikan bahwa jumlah bot salinan karbon tersebut adalah minimum yang diperlukan untuk berhasil berlakunya strategi mereka (Itu biasanya akan menjadi dua bot untuk kerjasama).

Contoh Bot:

Itu JadeEmperorselalu menjadi bagian dari permainan, tetapi tidak bersaing; dia berfungsi sebagai generator untuk ujian bot peringkat tertinggi. Ujiannya acak, tetapi tidak seragam, untuk memungkinkan bot pintar cara untuk maju.

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]

The pemabuk menghasilkan ujian dan jawaban benar-benar acak. Dia akan menjadi bagian dari permainan.

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

The plagiator hanya salinan ujian sebelumnya. Dia juga akan menjadi bagian dari permainan.

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]

Kode pengontrol tersedia di sini . Untuk pengujian, Anda bisa memasukkan kelas Anda sendiri ke file Contestants.py di folder yang sama, dan mereka akan diimpor.

Ruang obrolan dapat ditemukan di sini .

Ujian dimulai!

Skor saat ini, dalam presisi lebih tinggi (10000 berjalan) untuk Oct20:

PesertaPenulisSkorAlfaSleafar9,669691GammaSleafar9.301362BetaSleafar9.164597WiQeLuUngu P7.870821StudiousBotDignissimus - Spammy7.538537SantayanaSara J7.095528Plagiator6.522047CountOracularIFcoltransG5.881175ThomasAlien @ System5.880041KebalikanDraco18s5.529652Marxsugarfi5.433808Pemabuk5.328178Yin YangUngu P5.102519EqualizerMnemonik4.820996TitForTatAnonim3.35801

Kontes akan dijalankan dengan setiap entri baru untuk masa yang akan datang.


1
Salinan bot adalah Lubang Standar, jadi tidak. Jika Anda mencoba menyalahgunakan beberapa bot per aturan penulis dengan mengirimkan hampir-tetapi-tidak-cukup-salinan, saya akan menghapusnya.
AlienAtSystem

1
@AlienAtSystem Mengapa Anda membiarkan bot saling membantu? Sepertinya lebih banyak kekacauan dan keacakan untuk dihadapi.
Don Thousand

2
Mengapa argumen konstruktor ID, ntetapi argumen metode lain n, ID?
Purple P

1
@DonThousand karena saya percaya bahwa di bawah batasan yang diberikan, itu adalah suatu prestasi untuk membuat dua bot yang A) berhasil berjabat tangan (perhatikan bahwa Plagiarizer mungkin secara tidak sengaja bermain pria di tengah) dan B) kemudian menerapkan strategi yang andal membantu bot itu tetapi tidak ada yang lain untuk bangkit.
AlienAtSystem

1
Peringkat seseorang @ dihitung. Anda mulai dari 0 dan bekerja dengan cara Anda ke nomor yang lebih tinggi
AlienAtSystem

Jawaban:


4

Santayana

Mereka yang tidak dapat mengingat masa lalu dikutuk untuk mengulanginya. Jadi kami membuat keputusan berdasarkan pada tindakan orang lain di masa lalu, menjawab berdasarkan jawaban yang biasanya diharapkan oleh penanya dari kami pada indeks yang diberikan, dan meminta jawaban yang paling jarang mereka berikan pada indeks yang diberikan. .

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

Bot Belajar

Bot ini mempelajari tes! Mencoba untuk menemukan pola dalam tes yang diberikan oleh berbagai bot dan bertindak sesuai.

Sejauh ini, sejauh ini, bot ini mengungguli semua bot lain yang bisa saya kerjakan di komputer saya kecuali dari Alpha, Beta dan Gamma (yang telah diprogram untuk bekerja bersama). Bot tidak memanfaatkan fakta bahwa kerjasama tim diperbolehkan karena saya merasa itu agak seperti curang dan sedikit kotor. Melihat lebih dari itu, bekerja sama tampaknya cukup efektif.

Bot mencoba mengenali kapan jawaban untuk tes acak dan dalam tanggapan cocok dengan yang diharapkan rata-rata 50% pada tes.

Bot juga mencoba mengenali ketika bot hanya membalikkan jawaban untuk membuang bot lain yang ingin memprediksi perilaku mereka, namun saya belum memprogramnya untuk secara khusus bertindak atas hal ini.

Saya telah mencatat kode dengan beberapa komentar untuk membuatnya lebih mudah dibaca

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]

Menilai dari kinerja kami, Anda memiliki algoritma terbaik untuk menjawab dan Wi Qe Lu memiliki algoritma terbaik untuk bertanya. Saya mengusulkan agar kami menggabungkan bot kami menjadi satu bot, yang disebut Xuézhě (bahasa Mandarin untuk "sarjana"), yang kebetulan terdengar seperti "switcher".
Purple P

Saya meretasnya dan menjalankan pemeriksaan di mesin saya. Anehnya, itu mengungguli Studious Bot, tetapi tidak Wi Qe Lu.
Purple P

@PurpleP Haha! Kedengarannya sangat menarik, saya pikir tidak ada cukup waktu bagi saya untuk meningkatkan bot saya tetapi Anda dapat mempostingnya sebagai kiriman di sini
Dignissimus - Spammy

3

Hitung Oracle

Bot ini menggunakan algoritma yang rata-rata ujian dari semua bot kerja lainnya, (mengingat angka bulat dan beberapa heuristik mengerikan) untuk memutuskan apa yang akan ditetapkan masing-masing bot lain sebagai ujian.
Count meminta ujian menggunakan hash MD5. Karena itu baik pertanyaan maupun jawabannya adalah deterministik. Itu mengabaikan sebagian besar input, menanyakan dan menjawab urutan boolean, hujan atau cerah yang sama persis, termasuk terhadap 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

Ide yang bagus dalam teori, tetapi dalam kontes pertamanya Count Oracular berkinerja lebih buruk daripada YinYang, meskipun ada upaya untuk mensimulasikan YinYang.
Purple P

1
@ Ungu Ya, itu tidak terlalu bagus. Alasannya adalah bahwa ia mencoba untuk memilih strategi 'umumnya optimal' dengan meratakan semua strategi spesifik bersama-sama. Misalnya tidak menggunakan strategi yang dirancang untuk mengalahkan YinYang ketika bertemu YinYang. Bahkan tidak menggunakan strategi khusus pada Jade Emporer: itu hanya menambahkan strategi Jade Emporer ke rata-rata. Ini akan lebih baik daripada acak, tetapi tidak banyak.
IFcoltransG

Marx telah diperbaiki. Anda harus memperbarui Count Oracular untuk memperkirakannya.
Purple P

@PurpleP Marx harus didukung sekarang. Ini seperti tahun 1917 lagi.
IFcoltransG

2

Yin Yang

Menjawab semua Trueatau semua False, kecuali satu indeks yang dipilih secara acak sebagai kebalikannya. Tanyakan kebalikan dari apa yang dijawabnya. Bertukar secara acak untuk membuang lawan.

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)

Menjawab dan bertanya secara acak di babak pertama. Setelah itu, ia menggunakan jawaban dari ujian sebelumnya, dan mengubah pertanyaan jika jumlah rata-rata pesaing di atas benar.

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
Menurut Google Translate "wi qe lu" secara kasar diterjemahkan sebagai "Saya penguin jalan."
Purple P

2

Satu bot milik saya:

Thomas

Seorang musafir dari negeri yang jauh, memiliki beberapa ide berbahaya tentang hasil masa lalu yang mengindikasikan kinerja masa depan. Dia menggunakan itu untuk menjaga bot lain turun, kecuali jika itu menghambat kemajuannya sendiri.

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

Apakah Anda lupa membuat indentasi kode Anda setelah pernyataan kelas?
pppery

Itu hanya format SE yang membuat saya tidak sadar. Saya akan memperbaikinya bersama dengan apa pun yang menyebabkan kesalahan dalam pengujian seseorang saat menggunakan bot ini
AlienAtSystem

2

Alfa

Baca obrolan sebelum downvoting. Bot ini tidak melanggar aturan apa pun. OP bahkan mendorong bot yang bekerja sama.

Alpha membentuk tim bersama Beta. Keduanya menggunakan satu set ujian yang telah ditentukan untuk membantu satu sama lain naik peringkat. Keduanya juga memanfaatkan bot menggunakan ujian yang sama berulang-ulang.

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]

Saya percaya ketiga bot ini melanggar aturan OP seperti yang tercantum dalam prompt dan komentar.
Don Thousand

@DonThousand Jika Anda membaca diskusi di obrolan, Anda akan melihat mereka tidak melanggar aturan. chat.stackexchange.com/rooms/98905/imperial-exams-office
Sleafar

Cukup adil. Salahku.
Don Thousand

@ DonThousand Jadi apa gunanya menurunkan mereka semua?
Sleafar

Saya hanya menurunkan Alpha. Tapi saya tidak bisa undownvote. Buat pengeditan berlebihan dan saya akan memperbaikinya.
Don Thousand

1

Equalizer

Setiap orang harus setara (dengan tidak ada omong kosong kaisar konyol ini), jadi sediakan mobilitas sosial sebanyak mungkin. Buat pertanyaan itu sangat mudah (jawabannya selalu Benar) sehingga orang bisa sukses.

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

Baca obrolan sebelum downvoting. Bot ini tidak melanggar aturan apa pun. OP bahkan mendorong bot yang bekerja sama.

Beta membentuk tim bersama dengan Alpha. Keduanya menggunakan satu set ujian yang telah ditentukan untuk membantu satu sama lain naik peringkat. Keduanya juga memanfaatkan bot menggunakan ujian yang sama berulang-ulang.

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

Gamma

Baca obrolan sebelum downvoting. Bot ini tidak melanggar aturan apa pun. OP bahkan mendorong bot yang bekerja sama.

Gamma telah menemukan rencana Alpha dan Beta dan mencoba untuk mengambil keuntungan dari keduanya dengan menyamar sebagai salah satu dari mereka.

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

Mengajukan pertanyaan mudah jika Anda mengajukan pertanyaan mudah di masa lalu. Jika Anda belum pernah memberikan ujian, ujian ini default untuk pertanyaan mudah.

Selain itu, tidak mempercayai siapa pun yang mengajukan pertanyaan sulit, dan akan memberi mereka jawaban yang tidak terduga.

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

Bot ini berfungsi dengan baik jika bot lain bekerja sama dengannya. Saat ini hanya Equalizer yang bekerja sama, tetapi semoga ini cukup.


Saat ini, bot tidak dapat bersaing karena tidak mengikuti spesifikasi. Pastikan bahwa ia mengembalikan listobjek setiap saat. Selain itu, di bawah aturan lama dan yang diperbarui, salinan bot yang sempurna bukan kiriman yang valid, sehingga jumlah mesin bot yang diizinkan yang diizinkan adalah 1.
AlienAtSystem

Saya mengeditnya untuk mengembalikan daftar. Adapun hal salinan sempurna, tidak ada bot saat ini yang bekerja sama dengan benar, sehingga jumlah bot salinan karbon - minimum yang diperlukan untuk keberhasilan penerapan strategi - adalah setidaknya 1 (bot ini dan 1 salinannya diperlukan) ).
Anonim

Anda berpendapat bahwa Anda memenuhi syarat untuk pengecualian dalam klausa 3 saat mencoba mengirim sesuatu yang termasuk dalam klausa 1: Salinan bot yang sempurna tidak pernah valid, tidak ada pengecualian. Dan untuk memenuhi syarat untuk pengecualian ayat 3, Anda harus membuktikan bahwa strategi Anda secara ketat mengharuskan semua mitra ini bereaksi terhadapnya, seperti misalnya sinyal jabat tangan, yang memang tidak berguna tanpa seseorang mendengarkan. Milikmu tidak. Equalizer akan memberi Anda ujian untuk memicu klausa "ramah", sehingga membuktikan bahwa salinan bot Anda diperlukan.
AlienAtSystem

Baiklah kalau begitu. Saya akan membuat beberapa penyesuaian akhir.
Anonim

0

Kebalikan

Kaisar Giok selalu benar, sehingga ia mengimplementasikan fungsi permintaan Kaisar Giok sebagai fungsi jawabannya sendiri ketika ia membutuhkan lebih dari 2 jawaban. Hanya 1 yang menjawabnya true(kemungkinan yang tepat untuk benar) dan untuk 2 menjawabnyatrue,false ( ini melewati "setidaknya setengah" dari pertanyaan tiga dari empat kemungkinan kuis, lebih baik daripada memilih secara acak).

Menggunakan logika yang sama dalam Pembaruannya sehubungan dengan bagaimana ia mengubah pola permintaannya, tetapi logika permintaannya serupa dengan Kaisar Giok, hanya dengan bobot yang berbeda. Berfluktuasi antara nilai yang lebih tinggi truedengan nilai yang lebih tinggi falseketika terlalu banyak kandidat mendapat skor yang cukup tinggi untuk lulus.

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
Tidak true, falsegagal jika ujiannya false, true?
pppery

Beberapa baris pertama answermemiliki kesalahan sintaksis dan nama - truedan falseseharusnya Truedan False, dan ifs hilang :pada akhirnya
Sara J

Terima kasih kalian berdua; Saya tidak memasang Python di komputer saya karena saya tidak sering menggunakannya, jadi saya mengacaukan sintaks secara teratur.
Draco18s tidak lagi mempercayai SE

newExam diatur tetapi tidak pernah dibaca update. passadalah perintah NOP, Anda dapat menghapusnya. (Komentar di baliknya hanyalah pelesetan untuk Drunkard yang Anda salin.) Juga, Anda secara implisit menggunakan mathdan randommodul tetapi tidak menyatakan Anda mengimpornya. Saya telah menulis ulang dalam file kontes saya np.copysigndan np.random.uniformitu harus melakukan hal yang sama.
AlienAtSystem

@AlienAtSystem Harus diperbaiki sekarang.
Draco18s tidak lagi mempercayai SE

0

Marx

Ini adalah bot Marx. Dia percaya bahwa, alih-alih birokrasi, kita harus memiliki sistem komunis. Untuk membantu mencapai tujuan ini, itu memberikan kuis yang lebih sulit ke bot peringkat yang lebih tinggi. Ini juga memberikan jawaban yang lebih acak untuk kuis dari bot yang lebih tinggi, karena mereka mungkin lebih pintar, karena mereka lebih tinggi.

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 saat ini terlalu banyak menjawab byte, jadi dia tidak bisa bersaing sekarang
AlienAtSystem

Apa maksudmu? Apakah ujiannya terlalu lama?
sugarfi

Jawabannya adalah satu entri terlalu lama
AlienAtSystem

OK, saya memperbaikinya. Seharusnya sekarang baik-baik saja.
sugarfi

Maaf, saya memberi Anda umpan balik yang salah: Sekarang, jawabannya terlalu pendek. Masalah sebenarnya adalah Anda mengembangkan diri. Ketika itu terlalu pendek (meskipun tidak cukup sekarang), tetapi jangan memotongnya ketika Marx diturunkan.
AlienAtSystem
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.