Utwórz bota, aby wybrać najmniejszy unikalny numer.
(Na podstawie eksperymentu psychologicznego, o którym słyszałem wiele lat temu, ale nie byłem w stanie go ponownie wyśledzić.)
Zasady
- Każda gra będzie się składać z 10 losowo wybranych botów grających w 1000 rund.
- W każdej rundzie wszystkie boty wybierają liczbę całkowitą od 1 do 10 (włącznie). Wszelkie boty, które wybiorą tę samą wartość, zostaną wykluczone, a pozostały bot o najmniejszej wartości otrzyma punkt.
- W przypadku, gdy żaden bot nie wybierze unikalnej wartości, nie zostaną przyznane żadne punkty.
- Pod koniec 1000 rund wygrywa bot z największą liczbą punktów (lub wszystkie boty związane z największą liczbą punktów).
- Turniej potrwa 200 * (liczba graczy) gier.
- Bot z najwyższym procentem wygranych wygrywa turniej.
Dane techniczne
Boty muszą być klasami Python 3 i muszą implementować dwie metody: select
i update
.
Boty będą budowane z indeksem.
select
nie przekazano żadnych argumentów i zwraca wybór bota dla bieżącej rundy.
update
przekazywana jest lista wyborów dokonanych przez każdego bota w poprzedniej rundzie.
Przykład
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
Kontroler
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]))
Dodatkowe informacje
- Żaden bot nie będzie grał przeciwko sobie.
- W mało prawdopodobnym przypadku włączenia bota w mniej niż 100 gier turniej zostanie wznowiony.
- Boty mogą przechowywać stan między rundami, ale nie między grami.
- Dostęp do kontrolera lub innych botów jest niedozwolony.
- Liczba gier i liczba rund na grę mogą ulec zwiększeniu, jeśli wyniki będą zbyt zmienne.
- Wszelkie boty, które zgłaszają błędy lub udzielają nieprawidłowych odpowiedzi (nie-int, wartości spoza [1, 10] itd.) Zostaną zdyskwalifikowane, a turniej zostanie ponownie uruchomiony bez nich.
- Nie ma limitu czasowego na rundy, ale mogę go wprowadzić, jeśli boty zajmują zbyt dużo czasu na myślenie.
- Nie ma ograniczenia liczby zgłoszeń na użytkownika.
Termin przesyłania zgłoszeń upływa o 23:59:59 UTC w piątek, 28 września. Turniej jest teraz zamknięty dla zgłoszeń.
Wyniki
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)
bots.py
w tym samym katalogu, zawierający wszystkie boty. Na koniec utwórz listę konstruktorów:allBotConstructors = [Lowball, BayesBot, ...]
Odpowiedzi:
BayesBot
Próbuje dokonać optymalnego wyboru za pomocą prostego modelu statystycznego.
źródło
Unikaj stałych botów
Śledź, które boty zawsze zwracały tę samą wartość, i pomiń te wartości. Z pozostałych wartości wybierz je losowo, ale znacznie spychasz w stronę niższych wartości.
źródło
WaitWhatBot
Nie najbardziej konkurencyjny bot i zdecydowanie nie GTO , ale zdusi wynik każdego „zawsze 1” lub „prawie zawsze 1” przeciwnika w tej samej grze, jak w takim scenariuszu, WaitWhatBot również staje się takim botem.
Wykorzystuje zmieniające się prawdopodobieństwa z ważonymi wagami zarówno w czasie (nowsze -> większa waga), jak i wartości wyboru (niższy punkt -> większa waga).
Używa nieco zaciemnionego kodu dla odrobiny chichotu.
źródło
Prześladowca
Na początku gry bot ten losowo wybiera określony indeks jako cel. Następnie śledzi, które są ukierunkowane na całą grę, kopiując liczbę wybraną w poprzedniej rundzie.
źródło
Głupi chciwy
Ten bot zakłada, że inne boty nie chcą wiązać.
Zdaję sobie sprawę, że jest to to samo co podany przykład, ale pomyślałem o tym, zanim przeczytałem tak daleko. Jeśli jest to niezgodne ze sposobem uruchamiania wyzwań KoTH, daj mi znać.
źródło
self.index
.HistoryBot
Realizacja komentarza użytkownika 2390246:
źródło
OneUpper
Boty wszystkich innych celują w 1 lub losowo, więc dlaczego nie po prostu dążyć do 2?
źródło
Płyń jak woda
Unika podstawowych algorytmów ciągłego wykrywania botów, podwajając każdą liczbę, powoli przechodząc do niższych wartości, jeśli nie są zajęte.
źródło
Całkiem zagubiona
źródło
Ostateczne odliczanie
Wypróbuj online!
Zwraca 10 za pierwsze 100 rund, 9 za następne 100 i tak dalej.
źródło
Opportunitybot
Ten bot śledzi najniższą liczbę niewybraną przez inne boty w każdej rundzie (najniższa dostępna liczba lub okazja) i odtwarza liczbę, która była tą liczbą najczęściej.
źródło
PatterMatcher
Szuka powtarzających się sekcji w zgłoszeniach botów, próbuje przewidzieć i unikać liczb.
Trójkąt
Szansa na wybranie n to
(10-n)/45
Ważony czasowo
Prawdopodobieństwo, że bot wybierze liczbę, jest proporcjonalne
(10-n)*Δt
. Pierwsza runda jest identyczna z trójkątem.Najmniej często
Podaje najmniej występującą liczbę, jeśli są równe, weź najniższą.
Najdłuższy czas
Tak samo jak w przypadku częstości, ale najdłużej między zgłoszeniami.
Sabotażysta
Podaje najniższą liczbę, która została przesłana ostatnim razem.
SecondSaboteur
Przesyła drugą najniższą liczbę, która została przesłana ostatnim razem
Profiteur
Przesyła najniższą liczbę, która nie została przesłana ostatnim razem
Przepraszam, że trochę mnie poniosło, gdy wpadłem na pomysł nowych botów podczas implementacji poprzedniego. Nie byłem pewien, który z nich byłby najlepszy i jestem ciekawy występu każdego z nich. Możesz je znaleźć tutaj: https://repl.it/@Fejfo/Lowest-Unique-Number
źródło
set(range(10)
.Najlepszy 50% bot RNG
Właśnie miałem opublikować losowego bota, ale hidefromkgb wysłał przede mną (przez wysłanie robią się łatwym celem dla KGB, a nie dobrym sposobem na ukrycie). To jest moja pierwsza odpowiedź KOTH, mając nadzieję na pokonanie bota rng.
źródło
Cykler
Ten bot po prostu cyklicznie przechodzi przez każdą z kolejnych liczb. Dla zabawy inicjuje licznik z jego indeksem.
źródło
OneTrackMind
Ten bot losowo wybiera liczbę i trzyma ją przez 50 rund, a następnie wybiera kolejną i powtarza.
źródło
Szczęśliwa siódemka
Mam dziś szczęście! Wyrzucam wszystko na 7!
źródło
Mój pomysł jest taki, że strategia jest bardziej zależna od liczby botów niż od faktycznej oceny strategii.
Przy znacznej liczbie botów dostępne są następujące opcje:
„Chciwe” roboty celujące w niższe 1-3 numery 10 botów są „sprytne” i dążą do uzyskania niższych 1-3 liczb, najlepsze jest po prostu pozwolenie tym botom interweniować między nimi.
„Inteligentne” roboty, które po uświadomieniu sobie, że 4 są zawsze odbierane, pójdą gdzie indziej.
„Losowe” i „stałe” roboty. Nie ma tu wiele do zrobienia.
Więc stawiam na # 4.
źródło
Niezbędny bot RNG
źródło
Morderca
Pozostaje w cieniu, a następnie dąży do bieżącej najniższej wartości. Biegać.
źródło
FollowBot
Skopiuj zwycięzcę z ostatniej rundy lub przynajmniej najlepszy wybór z minimalną liczbą remisów, jeśli nie było zwycięzcy.
źródło
Psychadelic
Jedynym sposobem na zwycięstwo w wojnie nuklearnej jest oszalenie. Więc sprawię, że każdy bot predykcyjny w turnieju będzie szalony.
źródło
UnchosenBot
Podejmuje decyzje z ostatniej rundy i wybiera najniższą niezbraną liczbę (oczywiście ignorując wybór UnchosenBot).
źródło
Whoop-di-scoop-di-kupa
Poop-di-scoopty
Nigdy nie widziałem ani nie dotykałem Pythona, czy to nie jest mityczne?
źródło
<!-- language: lang-python -->
przed blokiem kodu, aby włączyć wyróżnianie składnipython
tag w pytaniu i myślałem, że to będzie automatyczne, ale napisałem coś złego.others = [c for i, c in enumerate(choices) if i != self.index]
, że można go uznać za pythononic , lub, ponieważ później używasz tej zmiennej tylko do testów członkostwa,{ }
zamiast[ ]
budowaćset
raczej niż alist
.if (self.guess)
jest również bardzo mało mityczny.self.guess
się tam dostały te pareny ! Musiał być jednym z formaterów.Fontanna
Prosty bot najpierw wybiera najniższą liczbę, a jeśli inny też go wybierze, zwiększy licznik - podłoga się wypełni i woda spłynie. Kiedy osiągnie 11, restartuje się do 1 - woda jest pompowana z powrotem na szczyt.
źródło
target
10?PoissonsBot
Wybierz liczby z rozkładu Poissona, który jest tendencyjny do niższych wartości. Dostosuj średni parametr rozkładu w górę, jeśli jesteśmy w remisie, i w dół, jeśli są domysły pod nami. Rozmiar kroku stopniowo maleje wraz z postępem gry.
źródło
MinWin
Prowadzi bieżącą liczbę zwycięskich wartości i minimalne niezaznaczone wartości (gdzie minimalna niezaznaczona wartość jest brana pod uwagę tylko wtedy, gdy jest mniejsza niż wartość wygrywająca). Losowo wybiera spośród wygranych i wartości minimalnych.
źródło
PlayerCycle
Przechodzi między graczami. Wybór bieżącego gracza (może być własnym) jest teraz wyborem tego bota. Zaczyna drukować 8, bo dlaczego nie. Przepraszam, że nie mogę pytona, to prawdopodobnie zły kod.
Edycja: Dzięki Triggernometry za ulepszenie mojego kodu za pomocą itertools
źródło
szop pracz
Wybierz najniższą liczbę, która nie została wybrana w poprzedniej rundzie, z wyjątkiem naszego własnego poprzedniego wyboru, który tym razem może zostać ponownie wybrany. W pierwszej rundzie wybierz 1. (Biorąc pod uwagę 9 przeciwników i 10 wyborów, na pewno jest jedna dostępna wartość).
Wymyśliłem to niezależnie, ale teraz widzę co najmniej 2 poprzednie boty, które są zasadniczo takie same.
Trójkąt szopa pracza
Łączy szop pracz i trójkąt: spośród niezaznaczonych wartości wybierz jedną na podstawie prawdopodobieństwa odwrotnego trójkąta.
źródło
AttributeError: 'RaccoonTriangle' object has no attribute 'boundaries'
Generał
Generał zawsze walczy do ostatniej wojny (y) .
źródło
Bez powtarzania losowo
Bot wybiera losowo, ale unika wybierania tego samego numeru co poprzednia runda.
źródło