KoTH angka unik terkecil


27

Buat bot untuk memilih nomor unik terkecil.

(Berdasarkan percobaan psikologi yang saya dengar bertahun-tahun yang lalu tetapi belum dapat melacak lagi.)

Aturan

  • Setiap permainan akan terdiri dari 10 bot yang dipilih secara acak, bermain 1000 putaran.
  • Setiap putaran, semua bot memilih bilangan bulat dari 1 hingga 10 (termasuk). Setiap bot yang memilih nilai yang sama akan dikeluarkan, dan bot yang tersisa dengan nilai terkecil akan menerima poin.
  • Jika tidak ada bot yang mengambil nilai unik, tidak ada poin yang akan diberikan.
  • Pada akhir 1000 putaran, bot dengan poin terbanyak (atau semua bot yang terikat dengan poin terbanyak) memenangkan permainan.
  • Turnamen ini akan berlangsung 200 * (jumlah pemain) permainan.
  • Bot dengan persentase kemenangan tertinggi memenangkan turnamen.

Spesifikasi

Bot harus kelas Python 3 dan harus menerapkan dua metode: selectdan update.
Bot akan dibangun dengan indeks.
selectdilewatkan tanpa argumen dan mengembalikan pilihan bot untuk putaran saat ini.
updatedisahkan daftar pilihan yang dibuat oleh masing-masing bot di babak sebelumnya.

Contoh

class Lowball(object):
    def __init__(self, index):
        # Initial setup happens here.
        self.index = index
    def select(self):
        # Decision-making happens here.
        return 1
    def update(self, choices):
        # Learning about opponents happens here.
        # Note that choices[self.index] will be this bot's choice.
        pass

Pengendali

import numpy as np

from bots import allBotConstructors
allIndices = range(len(allBotConstructors))
games = {i: 0 for i in allIndices}
wins = {i: 0 for i in allIndices}

for _ in range(200 * len(allBotConstructors)):
    # Choose players.
    playerIndices = np.random.choice(allIndices, 10, replace=False)
    players = [allBotConstructors[j](i) for i, j in enumerate(playerIndices)]

    scores = [0] * 10
    for _ in range(1000):
        # Let everyone choose a value.
        choices = [bot.select() for bot in players]
        for bot in players:
            bot.update(choices[:])

        # Find who picked the best.
        unique = [x for x in choices if choices.count(x) == 1]
        if unique:
            scores[choices.index(min(unique))] += 1

    # Update stats.
    for i in playerIndices:
        games[i] += 1
    bestScore = max(scores)
    for i, s in enumerate(scores):
        if s == bestScore:
            wins[playerIndices[i]] += 1

winRates = {i: wins[i] / games[i] for i in allIndices}
for i in sorted(winRates, key=lambda i: winRates[i], reverse=True):
    print('{:>40}: {:.4f} ({}/{})'.format(allBotConstructors[i], winRates[i], wins[i], games[i]))

Informasi tambahan

  • Bot tidak akan bermain dalam pertandingan melawan dirinya sendiri.
  • Jika bot tidak termasuk dalam kurang dari 100 pertandingan, turnamen akan dijalankan kembali.
  • Bot dapat menyimpan status di antara ronde, tetapi tidak di antara gim.
  • Mengakses pengontrol atau bot lain tidak diperbolehkan.
  • Jumlah game dan jumlah putaran per game dapat meningkat jika hasilnya terlalu bervariasi.
  • Setiap bot yang menimbulkan kesalahan atau memberikan respons yang tidak valid (non-int, nilai di luar [1, 10], dll.) Akan didiskualifikasi, dan turnamen akan dijalankan kembali tanpa mereka.
  • Tidak ada batasan waktu untuk putaran, tapi saya bisa menerapkannya jika bot terlalu lama untuk berpikir.
  • Tidak ada batasan jumlah pengiriman per pengguna.
  • Batas waktu pengiriman adalah 23:59:59 UTC pada hari Jumat, 28 September. Turnamen ini sekarang ditutup untuk pengiriman.

Hasil

                BayesBot: 0.3998 (796/1991)
      WhoopDiScoopDiPoop: 0.3913 (752/1922)
           PoopDiScoopty: 0.3216 (649/2018)
                   Water: 0.3213 (660/2054)
                 Lowball: 0.2743 (564/2056)
                Saboteur: 0.2730 (553/2026)
                OneUpper: 0.2640 (532/2015)
         StupidGreedyOne: 0.2610 (516/1977)
          SecondSaboteur: 0.2492 (492/1974)
                    T42T: 0.2407 (488/2027)
                     T4T: 0.2368 (476/2010)
          OpportunityBot: 0.2322 (454/1955)
              TheGeneral: 0.1932 (374/1936)
             FindRepeats: 0.1433 (280/1954)
                  MinWin: 0.1398 (283/2025)
             LazyStalker: 0.1130 (226/2000)
               FollowBot: 0.1112 (229/2060)
                Assassin: 0.1096 (219/1999)
           MostlyAverage: 0.0958 (194/2024)
             UnchosenBot: 0.0890 (174/1955)
                 Raccoon: 0.0868 (175/2015)
               Equalizer: 0.0831 (166/1997)
       AvoidConstantBots: 0.0798 (158/1980)
WeightedPreviousUnchosen: 0.0599 (122/2038)
               BitterBot: 0.0581 (116/1996)
               Profiteur: 0.0564 (114/2023)
              HistoryBot: 0.0425 (84/1978)
            ThreeFourSix: 0.0328 (65/1984)
                 Stalker: 0.0306 (61/1994)
             Psychadelic: 0.0278 (54/1943)
              Unpopulist: 0.0186 (37/1994)
             PoissonsBot: 0.0177 (35/1978)
         RaccoonTriangle: 0.0168 (33/1964)
              LowHalfRNG: 0.0134 (27/2022)
              VictoryPM1: 0.0109 (22/2016)
            TimeWeighted: 0.0079 (16/2021)
             TotallyLost: 0.0077 (15/1945)
            OneTrackMind: 0.0065 (13/1985)
              LuckySeven: 0.0053 (11/2063)
          FinalCountdown: 0.0045 (9/2000)
                Triangle: 0.0039 (8/2052)
           LeastFrequent: 0.0019 (4/2067)
                Fountain: 0.0015 (3/1951)
             PlayerCycle: 0.0015 (3/1995)
                  Cycler: 0.0010 (2/1986)
               SecureRNG: 0.0010 (2/2032)
             SneakyNiner: 0.0005 (1/2030)
            I_Like_Nines: 0.0000 (0/1973)

2
@Mnemonic Ada berita?
user1502040

4
@Herohtar Saya membuatnya berjalan sebelum saya pergi bekerja. Dengan sedikit keberuntungan, itu harus dilakukan ketika saya pulang.

1
@Mnemonic Sudah selesai?
user1502040

2
@ Justin Ini sedang berjalan sekarang, dan sepertinya tidak akan mogok, tapi saya pasti tidak akan keberatan dengan bantuan jika proses ini gagal.

1
@MihailMalostanidis Membuat file bernama bots.pydi direktori yang sama yang berisi semua bot. Pada akhirnya, buat daftar konstruktor:allBotConstructors = [Lowball, BayesBot, ...]

Jawaban:


10

BayesBot

Berusaha membuat pilihan optimal menggunakan model statistik sederhana.

import random

def dirichlet(counts):
    counts = [random.gammavariate(n, 1) for n in counts]
    k = 1. / sum(counts)
    return [n * k for n in counts]

class BayesBot(object):
    def __init__(self, index):
        self.index = index
        self.counts = [[0.2 * (10 - i) for i in range(10)] for _ in range(10)]
    def select(self):
        player_distributions = []
        for i, counts in enumerate(self.counts):
            if i == self.index:
                continue
            player_distributions.append(dirichlet(counts))
        cumulative_unique = 0.
        scores = [0.] * 10
        for i in range(10):
            p_unpicked = 1.
            for d in player_distributions:
                p_unpicked *= (1. - d[i])
            p_unique = p_unpicked * sum(d[i] / (1. - d[i]) for d in player_distributions)
            scores[i] = p_unpicked * (1. - cumulative_unique)
            cumulative_unique += p_unique * (1. - cumulative_unique)
        return scores.index(max(scores)) + 1
    def update(self, choices):
        for i, n in enumerate(choices):
            self.counts[i][n - 1] += 1

10

Hindari Bot Konstan

Catat bot mana yang selalu mengembalikan nilai yang sama, dan lewati nilai-nilai itu. Dari nilai yang tersisa, pilih secara acak, tetapi bias secara signifikan terhadap nilai yang lebih rendah.

import numpy as np

class AvoidConstantBots(object):
    all_values = range(1, 11)
    def __init__(self, index):
        self.index = index
        self.constant_choices = None

    def select(self):
        available = set(self.all_values)
        if self.constant_choices is not None:
            available -= set(self.constant_choices)
        if len(available) == 0:
            available = set(self.all_values)
        values = np.array(sorted(available))
        weights = 1. / (np.arange(1, len(values) + 1)) ** 1.5
        weights /= sum(weights)
        return np.random.choice(sorted(available), p=weights)

    def update(self, choices):
        if self.constant_choices is None:
            self.constant_choices = choices[:]
            self.constant_choices[self.index] = None
        else:
            for i, choice in enumerate(choices):
                if self.constant_choices[i] != choice:
                    self.constant_choices[i] = None

10

WaitWhatBot

Bukan bot yang paling kompetitif dan jelas bukan GTO , tetapi akan menghambat skor setiap lawan "selalu 1" atau "hampir selalu 1" dalam permainan yang sama seperti dalam skenario seperti itu WaitWhatBot menjadi bot seperti itu juga.

Menggunakan probabilitas yang berkembang dengan bobot tertimbang baik dalam waktu (lebih baru - lebih besar -) dan nilai pilihan (titik lebih rendah -> bobot lebih besar).

Menggunakan kode yang agak dikaburkan untuk sedikit tawa.

from random import choices as weightWeight
class WaitWhatBot(object):
    def __init__(wait,what):
        weight,weightWhat=5,2
        wait.what,wait.weight=what,(weight**(weight/weight/weightWhat)+weightWhat/weightWhat)/weightWhat
        wait.whatWeight,wait.weightWeight=[wait.what==wait.weight]*int(wait.weight**weight),wait.weight
        wait.whatWhat=wait.whatWeight.pop()#wait, when we pop weight off whatWeight what weight will pop?
        wait.waitWait=tuple(zip(*enumerate(wait.whatWeight,wait.weightWeight!=wait.whatWeight)))[weightWeight==wait.weight]
    def select(what):return int(what.weight**what.whatWhat if all(not waitWait for waitWait in what.whatWeight)else weightWeight(what.waitWait,what.whatWeight)[what.weight==what.what])
    def update(waitWhat,whatWait):
        what,wait,weightWhat=set(wait for wait in whatWait[:waitWhat.what]+whatWait[waitWhat.what+1:]if wait in waitWhat.waitWait),-~waitWhat.whatWhat,waitWhat.weightWeight
        while wait not in what:
            waitWhat.whatWeight[wait+~waitWhat.whatWhat]+=weightWhat
            weightWhat/=waitWhat.weight
            wait-=~waitWhat.whatWhat
        if not wait!=(what!=weightWhat):waitWhat.whatWeight[waitWhat.whatWhat]+=weightWhat
        waitWhat.weightWeight*=waitWhat.weight

9
Berapa berat yang akan dibeli WaitWhatBot, jika WaitWhatBot mau membeli berat?
Roman Odaisky

atur ([... untuk ... dalam ...]) ≡ {... untuk ... dalam ...}, omong-omong
Roman Odaisky

@RomanOdaisky Saya benar-benar menyarankan seseorang untuk bermain golf kemarin!
Jonathan Allan

5

Penguntit

Di awal permainan, bot ini secara acak memilih indeks tertentu sebagai targetnya. Itu kemudian menguntit yang menargetkan seluruh permainan, menyalin nomor yang dipilihnya di babak sebelumnya.

import random

class Stalker(object):
  def __init__(self, index):
    # choose a random target to stalk that isn't ourself
    self.targetIndex = random.choice([x for x in range(10) if x != index])
    # get a random number to start with since we haven't seen our target's value yet
    self.targetValue = random.randint(1, 10)
  def select(self):
    return self.targetValue
  def update(self, choices):
    # look at what our target chose last time and do that
    self.targetValue = choices[self.targetIndex]

4

Bodoh Satu Serakah

class StupidGreedyOne(object):
    def __init__(self, index):
        pass
    def select(self):
        return 1
    def update(self, choices):
        pass

Bot ini mengasumsikan bahwa bot lain tidak ingin mengikat.

Saya menyadari ini sama dengan contoh yang diberikan tetapi saya memiliki pemikiran sebelum saya membaca sejauh itu. Jika ini tidak sesuai dengan bagaimana tantangan KoTH dijalankan, beri tahu saya.


Secara umum saya lebih suka tidak memiliki duplikat bot, tapi saya tidak keberatan meninggalkannya.

1
@Mnemonic juga secara teknis itu bukan penipuan, karena tidak menginisialisasi self.index.
hidefromkgb

@Mnemonic Tidak masalah! Jujur, ini adalah KoTH pertama saya dan apa pun yang pertama saya di Python jadi saya hanya mengikuti dua poster pertama dan tidak mengubahnya meskipun ada kecurigaan saya bahwa saya harus melakukannya. Saya juga tidak yakin apakah Anda akan memasukkan Lowball dalam tes Anda atau itu benar-benar hanya contoh untuk posting.
Engineer Toast

Jangan khawatir. Selamat datang di dunia KoTH yang indah!

2
Anda ciri khas sebuah "ace granat": puzzling.stackexchange.com/questions/45299/...
Kaine

4

HistoryBot

import random

class HistoryBot(object):
    def __init__(self, index):
        self.pastWins = []
    def select(self):
        if not self.pastWins:
            return 1
        return random.choice(self.pastWins)
    def update(self, choices):
        unique = [x for x in choices if choices.count(x) == 1]
        if unique:
            self.pastWins.append(min(unique))

Implementasi dari komentar user2390246:

Bagaimana dengan ini? Mulailah dengan 1. Setelah putaran pertama, catat nilai-nilai yang menang dan pilih secara acak dari mereka dengan probabilitas yang sama dengan jumlah kemunculannya. Misalnya, jika nilai yang menang di tiga putaran pertama adalah [2, 3, 2] maka di babak empat, pilih [2] dengan p = 2/3 dan [3] dengan p = 1/3.


4

OneUpper

class OneUpper(object):
    def __init__(self, index):
        self.index = index
    def select(self):
        return 2
    def update(self, choices):
        pass

Bot orang lain bertujuan untuk 1 atau acak, jadi mengapa tidak membidik 2 saja?


4

Mengalir Seperti Air

Menghindari algoritma deteksi bot konstan dasar dengan menggandakan pada setiap nomor, perlahan-lahan maju menuju nilai yang lebih rendah jika tidak dihuni.

class Water(object):
    def __init__(self, index):
        self.index = index
        self.round = 0
        self.play = 4
        self.choices = [0]*10

    def select(self):
        if self.round > 0 and self.round%2 == 0:
            if not max([1, self.play - 1]) in self.choices:
                self.play -= 1
        return self.play

    def update(self, choices):
        self.round += 1
        self.choices = choices

Saya ingin tahu, apakah bot Anda entah bagaimana terkait dengan Air Mancur saya ? Keduanya "berorientasi air", haha.
RedClover

Jujur, rencana awal saya adalah membuat bot tebakan tetap yang bisa menebak angka-angka tertentu, yang menjadi motivasi saya untuk proses pengambilan keputusan bot. Ketika saya memvisualisasikannya, saya memikirkan aliran bergerak lambat, yang mengilhami nama itu. Serukan tema air :)
TCFP

Jadi ini semakin ke-3 atau ke-4 (biasanya ke-3) di setiap tes yang saya jalankan. Itu cukup luar biasa untuk strategi yang sederhana.
Robert Fraser

4

Benar-benar hilang

class TotallyLost(object):
    def __init__(self, index):
        self.index = index
        self.round = 0
        self.numbers = [4,8,1,5,1,6,2,3,4,2]
    def select(self):
        return self.numbers[self.round % len(self.numbers)]
    def update(self, choices):
        self.round = self.round + 1

4

Hasil akhir

class FinalCountdown(object):
    def __init__(self, index):
        self.round = -1
    def select(self):
        self.round += 1
        return (10 - self.round // 100)
    def update(self, choices):
        pass

Cobalah online!

Mengembalikan 10 untuk 100 ronde pertama, 9 untuk 100 ronde berikutnya dan seterusnya.


4

Peluangbot

Bot ini melacak nomor terendah yang tidak dipilih oleh bot lain setiap putaran (jumlah terendah yang tersedia, atau peluang), dan memainkan nomor yang paling sering nomor itu.

class OpportunityBot(object):
    def __init__(self, index):
        self.index = index
        self.winOccasions = [0,0,0,0,0,0,0,0,0,0]

    def select(self):
        return self.winOccasions.index(max(self.winOccasions))+1

    def update(self, choices):
        choices.pop(self.index)
        succeeded = [choices.count(i)==0 for i in range(1,11)]
        self.winOccasions[succeeded.index(True)] += 1

4

PatterMatcher

Mencari bagian berulang dalam pengiriman bot, mencoba untuk memprediksi dan menghindari angka di sana.

class PatternMatcher(object):
    def __init__(self, index):
        self.bots=[[]]*9
        self.index=index
    def select(self):
        minVisible=3    #increase these if this bot is to slow
        minOccurences=2
        predictions=set()
        for bot in self.bots:     
            #match patters of the form A+(B+C)*minOccurences+B and use C[0] as a prediction      
            for lenB in range(minVisible,len(bot)//(minVisible+1)+1):
                subBot=bot[:-lenB]
                patterns=[] 
                for lenBC in range(lenB,len(subBot)//minOccurences+1):
                    BC=subBot[-lenBC:]
                    for i in range(1,minOccurences):
                        if BC!=subBot[-lenBC*i-lenBC:-lenBC*i]:
                            break
                    else:
                        patterns.append(BC)
                predictions|={pattern[lenB%len(pattern)] for pattern in patterns}
        other=set(range(1,11))-predictions
        if other: return min(other)
        else: return 1                

    def update(self, choices):
        j = 0
        for i,choice in enumerate(choices):
            if i == self.index:
                continue
            self.bots[j].append(choice)
            j += 1

Segi tiga

Peluang memilih n adalah (10-n)/45

import random
class Triangle(object):
    def __init__(self, index):pass
    def select(self):return random.choice([x for x in range(1, 11) for _ in range(10 - x)])
    def update(self, choices):pass

Waktu berat

Probabilitas bot memilih nomor sebanding dengan (10-n)*Δt. Babak pertama ini identik dengan segitiga.

import random
class TimeWeighted(object):
    def __init__(self, index):
        self.last=[0]*10
        self.round=1 
    def select(self):
        weights=[(self.round-self.last[i])*(10-i) for i in range(10)]
        return 1+random.choice([x for x in range(10) for _ in range(weights[x])])

    def update(self, choices):
        for c in choices:
            self.last[c-1]=self.round
        self.round+=1

LeastFrequent

Menyerahkan nomor yang paling jarang terjadi, jika mereka sama, ambil yang terendah

class LeastFrequent(object):
    def __init__(self, index):self.frequenties=[0]*10
    def select(self):return 1+self.frequenties.index(min(self.frequenties))
    def update(self, choices):
        for c in choices:
            self.frequenties[c-1]+=1

Waktu terlama

Sama seperti dengan frekuensi tetapi dengan waktu terlama di antara pengiriman.

class LongestTime(object):
    def __init__(self, index):
        self.frequencies=[0]*10
        self.round=1
    def select(self):return 1+self.frequencies.index(min(self.frequencies))
    def update(self, choices):
        for c in choices:
            self.frequencies[c-1]=self.round
        self.round+=1

Penyabot

Menyerahkan angka terendah yang telah dikirimkan terakhir kali.

class Saboteur(object):
    def __init__(self, index):self.last=[1]
    def select(self):return min(self.last)
    def update(self, choices):self.last=choices

SecondSaboteur

Menyerahkan angka terendah kedua yang diajukan terakhir kali

class SecondSaboteur(object):
    def __init__(self, index):self.last=[1,2]
    def select(self):return min({i for i in self.last if i!=min(self.last)})
    def update(self, choices):self.last=choices

Profiteur

Mengirimkan angka terendah yang tidak dikirimkan terakhir kali

class Profiteur(object):
    def __init__(self, index):self.last=set()
    def select(self):return min(set(range(1, 11))-self.last, default=1)
    def update(self, choices):self.last=set(choices)

Maaf saya agak terbawa suasana, mendapatkan ide untuk bot baru sambil menerapkan sebelumnya. Saya tidak yakin mana yang akan menjadi yang terbaik dan saya ingin tahu tentang kinerja masing-masing. Anda dapat menemukannya di sini: https://repl.it/@Fejfo/Lowest-Unique-Number


Bagus. Anda mungkin mempertimbangkan memodifikasi Saboteur untuk mengabaikan pilihan terakhirnya sendiri (kecuali itu disengaja). Juga, saya pikir Anda mungkin perlu menangani beberapa kasus khusus: apa yang harus dilakukan SecondSaboteur jika setiap bot memilih nilai yang sama di beberapa babak, dan apa yang harus dilakukan Profiteur jika setiap bot memilih nilai yang berbeda? Anda mungkin perlu tanda kurung berakhir di Profiteur setelah set(range(10).
Pasang kembali Monica

PatternMatcher tampaknya memiliki semacam infinite loop atau tempat macet.
Robert Fraser

3

50% bot RNG teratas

import random

class LowHalfRNG(object):
    def __init__(self, index):
        pass
    def select(self):
        return random.randint(1, 5)
    def update(self, choices):
        pass

Saya hendak memposting bot acak, tetapi hidefromkgb diposting sebelum saya (dengan memposting mereka menjadikan diri mereka target empuk KGB, bukan cara yang baik untuk menyembunyikan). Ini adalah jawaban KOTH pertamaku, hanya berharap bisa mengalahkan bot rng.


3

Pengendara sepeda

Bot ini cukup menggilir setiap angka pada putarannya. Hanya untuk bersenang-senang, ini menginisialisasi penghitung dengan indeksnya.

class Cycler(object):
  def __init__(self, index):
    self.counter = index # Start the count at our index
  def select(self):
    return self.counter + 1 # Add 1 since we need a number between 1-10
  def update(self, choices):
    self.counter = (self.counter + 1) % 10

3

OneTrackMind

Bot ini secara acak memilih nomor dan tetap menggunakannya selama 50 putaran, lalu memilih yang lain dan mengulanginya.

import random

class OneTrackMind(object):
    def __init__(self, index):
        self.round = 0;
        self.target = random.randint(1,10)
    def select(self):
        return self.target
    def update(self, choices):
        self.round += 1;
        if self.round % 50 == 0:
            self.target = random.randint(1,10)

3

Lucky Seven

class LuckySeven(object):
    def __init__(self, index):
        pass
    def select(self):
        return 7
    def update(self, choices):
        pass

Saya merasa beruntung hari ini! Saya membuang semuanya pada 7!


3

Ide saya adalah bahwa strategi lebih tergantung pada jumlah bot daripada pada evaluasi strategi yang sebenarnya.

Dengan sejumlah besar bot, opsinya adalah:

  • Robot "serakah" yang mengarah ke angka 1-3 yang lebih rendah 10 bot menjadi "pintar" dan bertujuan untuk mendapatkan angka 1-3 yang lebih rendah, yang terbaik adalah membiarkan bot itu mengganggu mereka.

  • Robot "pintar" yang, begitu mereka sadari 4 selalu diangkat, akan pergi ke tempat lain.

  • Robot "Acak" dan "konstan". Tidak banyak yang bisa dilakukan di sini.

Jadi, saya bertaruh di # 4.

class LazyStalker(object):
    def __init__(self, index):
        pass
    def select(self):
        return 4
    def update(self, choices):
        pass

2

Bot RNG esensial

import secrets

class SecureRNG(object):
    def __init__(self, index):
        pass
    def select(self):
        return secrets.randbelow(10) + 1
    def update(self, choices):
        pass

2

Pembunuh

Tetap dalam bayangan, kemudian bertujuan untuk tebakan terendah saat ini. Menjalankan.

class Assassin(object):
    def __init__(self, index):
        self.index = index
        self.round = 0
        self.choices = [0]*10

    def select(self):
        if self.round == 0:
            return 10
        else:
            return min(self.choices)

    def update(self, choices):
        self.round += 1
        self.choices = choices
        self.choices[self.index] = 10

2

FollowBot

Salin pemenang dari babak terakhir, atau setidaknya pilihan terikat minimal terbaik jika tidak ada pemenang.

import collections

class FollowBot(object):
    def __init__(self, index):
        self.lastround = []

    def select(self):
        counter = collections.Counter(self.lastround)
        counts = [(count,value) for (value,count) in counter.items()]
        counts.sort()
        if len(counts) >= 1:
            return counts[0][1]
        else:
            return 1

    def update(self, choices):
        self.lastround = choices

2

Psikadelik

Satu-satunya cara untuk memenangkan perang nuklir adalah membuat diri Anda gila. Jadi saya akan membuat setiap bot prediksi di turnamen menjadi gila.

class Psychadelic(object):
    def __init__(self, index):
        self.index = index
    def select(self):
        return random.randint(1, self.index + 1)
    def update(self, choices):
        pass

2

UnchosenBot

class UnchosenBot(object):
    def __init__(self, index):
        self.index = index
        self.answer = 0
    def select(self):
        if self.answer == 0:
            return 1
        return self.answer
    def update(self, choices):
        self.answer = 0
        del choices[self.index]
        for x in range(1, 11):
            if x not in choices:
                self.answer = x
                return

Mengambil pilihan babak terakhir, dan memilih nomor yang belum dipilih yang terendah (mengabaikan pilihan UnchosenBot, tentu saja).


2

Whoop-di-scoop-di-poop

class WhoopDiScoopDiPoop(object):
    def __init__(self, index):
        self.index = index
        self.guess = 1
        self.tenure = 0
        self.perseverance = 4

    def select(self):
        return self.guess

    def update(self, choices):
        others = {c for i, c in enumerate(choices) if i != self.index}
        for i in range(1, self.guess):
            if i not in others:
                self.guess = i
                self.tenure = 0
                self.perseverance += 1
                return
        if self.guess not in others:
            self.tenure = 0
            return
        self.tenure += 1
        if self.tenure > self.perseverance:
            if self.guess == 10:
                return
            self.guess += 1
            self.tenure = 0

Kotoran-di-scoopty

class PoopDiScoopty(object):
    def __init__(self, index):
        self.index = index
        self.guess = 1
        self.tenure = 0
        self.perseverance = 4

    def select(self):
        return self.guess

    def update(self, choices):
        others = [c for i, c in enumerate(choices) if i != self.index]
        for i in range(1, self.guess):
            if i not in others:
                self.guess = i
                self.tenure = 0
                self.perseverance += 1
                return
        if self.guess not in others:
            self.tenure = 0
            return
        self.tenure += others.count(self.guess) # this is the change
        if self.tenure > self.perseverance:
            if self.guess == 10:
                return
            self.guess += 1
            self.tenure = 0

Saya tidak pernah melihat atau menyentuh Python, apakah ini unpythonic?


1
Tambahkan baris <!-- language: lang-python -->sebelum blok kode untuk mengaktifkan penyorotan sintaks
Herman L

@HermanL Saya berhalusinasi pythontag pada pertanyaan dan berpikir itu akan otomatis tetapi saya menulis sesuatu yang buruk.
Mihail Malostanidis

1
Adapun pythonicity, kode ini cukup baik, kecuali mungkin dianggap pythonicer untuk mengatakan others = [c for i, c in enumerate(choices) if i != self.index], atau, karena selanjutnya Anda hanya menggunakan variabel itu untuk tes keanggotaan, { }daripada [ ]membangun sebuah setdaripada sebuah list.
Roman Odaisky

if (self.guess)juga sangat unpythonic.
Jonathan Frech

Saya tidak tahu bagaimana orang-orang tua itu self.guessmasuk ke sana! Pasti salah satu pembuat format.
Mihail Malostanidis

2

Air mancur

Bot sederhana, mengambil nomor terendah terlebih dahulu dan jika ada bot lain yang memilihnya, bot itu akan menambah penghitung - lantainya diisi dan air mengalir ke bawah. Ketika mencapai 11, itu restart ke 1 - air dipompa kembali ke atas.

class Fountain:

    def __init__(self, index, target=10):

        # Set data
        self.index = index
        self.pick  = 1
        self.target = target+1

    def select(self):

        # Select the number
        return self.pick

    def update(self, choices: list):

        # Remove self from the list
        choices.pop(self.index)  # I hope `choices[:]` is passed, not `choices`.

        # While the selected number is occupied
        while self.pick in choices:

            # Pick next number
            self.pick += 1

            # If target was reached
            if self.pick == self.target:

                # Reset to 1
                self.pick = 1

Dalam bentuk saat ini bot Anda akan macet di loop sementara jika bot lain telah memilih semua angka dari 1 hingga 8. Apakah maksud Anda mengatur targetke 10?
Emil

@Emil Benar, awalnya seperti ini, berubah
RedClover

2

PoissonsBot

Pilih angka dari distribusi Poisson yang bias ke nilai yang lebih rendah. Sesuaikan parameter rata-rata distribusi ke atas jika kita berada dalam ikatan dan turun jika ada tebakan di bawah kita. Ukuran langkah semakin kecil secara progresif saat permainan berlangsung.

from numpy.random import poisson
import math

class PoissonsBot(object):
    def __init__(self, index):
        self.index = index
        self.mean = 2
        self.roundsleft = 1000

    def select(self):
        self.roundsleft = max(self.roundsleft-1, 2)
        return max(min(poisson(self.mean),10),1)

    def update(self, choices):
        myval = choices[self.index]
        nequal = len([c for c in choices if c==myval])
        nless = len([c for c in choices if c<myval])
        step = math.log10(self.roundsleft)
        if nequal > 1:
            self.mean += nequal/step
        self.mean -= nless/step
        self.mean = max(self.mean, 0.3)

2

MinWin

Menyimpan hitungan berjalan dari nilai yang menang dan nilai minimum yang tidak dipilih (di mana nilai minimum yang tidak dipilih hanya dipertimbangkan jika kurang dari nilai yang menang). Ini secara acak memilih di antara nilai-nilai menang dan minimum ini.

import random

class MinWin:

    def __init__(self, index):
        self.index = index
        self.mins = list(range(1, 11))
        self.wins = list(range(1, 11))

    def select(self):
        return min(random.choice(self.mins), random.choice(self.wins))

    def update(self, choices):
        counts = [0] * 10
        for x in choices:
            counts[x - 1] += 1

        if 0 in counts and (1 not in counts or counts.index(0) < counts.index(1)):
            self.mins.append(counts.index(0) + 1)
        if 1 in counts:
            self.wins.append(counts.index(1) + 1)

2

PlayerCycle

Siklus melalui para pemain. Pilihan pemain saat ini (bisa mandiri) sekarang menjadi pilihan bot ini. Mulai mencetak 8, karena mengapa tidak. Maaf saya tidak bisa python, ini mungkin kode yang buruk.

import itertools
class PlayerCycle(object):
    def __init__(self, index):
        self.a = itertools.cycle(range(10))
        self.b = 8
    def select(self):
        return self.b
    def update(self, choices):
        self.b = choices[next(self.a)]

Sunting: Terima kasih kepada Triggernometry untuk meningkatkan kode saya dengan itertools


Kode Anda berfungsi dengan baik, tetapi Anda dapat menambahkan intertools.cycle () untuk kode sehingga secara otomatis menggilir 0-9 dan Anda tidak perlu melakukan peningkatan atau pemeriksaan - Cobalah online!
Triggernometri

2

Rakun

Pilih angka terendah yang tidak dipilih di babak sebelumnya, kecuali pilihan kita sebelumnya, yang bisa dipilih lagi kali ini. Di babak pertama, pilih 1. (Diberikan 9 lawan dan 10 pilihan, dijamin ada satu nilai yang tersedia.)

Saya datang dengan ini secara independen, tetapi sekarang melihat setidaknya 2 bot sebelumnya yang pada dasarnya sama.

class Raccoon(object):
    def __init__(self, index):
        self.index = index
        self.last_round = None
        self.domain = None
    def select(self):
        # Return the lowest number not chosen last time.
        if self.domain is None:
            return 1
        else:
            # This finds the smallest element of domain, not present in last_round
            return min(self.domain-self.last_round)
    def update(self, choices):
        last_round = choices[:]
        last_round[self.index] = 0 # don't include our own choice
        self.last_round = set(last_round)
        if self.domain is None:
            self.domain = set(range(1,len(choices)+1))

Segitiga Rakun

Menggabungkan Raccoon dan Triangle: dari nilai yang tidak dipilih, pilih satu berdasarkan probabilitas segitiga terbalik.

import random
class RaccoonTriangle(object):
    def __init__(self, index):
        self.index = index
        self.unchosen = set([1,])
        self.domain = None
    def select(self):
        # Return the lowest number not chosen last time.
        if self.domain is None:
            return random.randint(1,self.index+1)
        else:
            # Reverse triangle weights for unchosen values
            weighted_choices = [u for i,u in enumerate(sorted(self.unchosen),0) for _ in range(len(self.unchosen)-i)]
            return random.choice(weighted_choices)
    def update(self, choices):
        last_round = choices[:] # make a copy
        last_round[self.index] = 0 # don't include our own choice
        if self.domain is None:
            self.domain = set(range(1,len(choices)+1))
        self.unchosen = self.domain - set(last_round)

Kesalahan:AttributeError: 'RaccoonTriangle' object has no attribute 'boundaries'
Renzeee

1
Ya maaf. Saya pikir saya memperbaikinya. Saya berada di tengah-tengah tes menulis, ketika saya tinggalkan.
Quantum Mechanic

1

Umum

General selalu berjuang perang terakhir (s) .

import numpy
import random

class TheGeneral:
    def __init__(self, index):
        self.round = 0
        self.index = index
        self.would_have_won = [0] * 10

    def select(self):
        if self.round <= 100:
            return random.choice((list(numpy.nonzero(self.would_have_won)[0]) + [0, 1])[:2]) + 1

        return random.choice(numpy.argsort(self.would_have_won)[-2:]) + 1

    def update(self, choices):
        for i, s in enumerate(numpy.bincount([c - 1 for i, c in enumerate(choices)
            if i != self.index], minlength=10)):

            if s == 0:
                self.would_have_won[i] += 1
            elif s == 1:
                break

        self.round += 1

1

Tanpa-Ulangi Acak

import secrets

class NoRepeats(object):
    def __init__(self, index):
        self.lastround = secrets.randbelow(10) + 1

    def select(self):
        i = secrets.randbelow(10) + 1
        while i == self.lastround:
             i = secrets.randbelow(10) + 1
        self.lastround = i
        return self.lastround

    def update(self, choices):
        pass

Bot memilih secara acak, tetapi menghindari memilih nomor yang sama dengan yang dilakukan pada putaran sebelumnya.

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.