가장 작은 고유 번호 KoTH


27

가장 작은 고유 번호를 선택하기 위해 봇을 만듭니다.

(수년 전에 들었던 심리학 실험을 바탕으로 다시 추적 할 수 없었습니다.)

규칙

  • 각 게임은 무작위로 선택된 10 개의 봇으로 구성되며 1000 라운드를합니다.
  • 각 라운드마다 모든 봇은 1에서 10까지의 정수를 선택합니다 (포함). 동일한 값을 선택하는 모든 봇은 제외되며 가장 작은 값을 가진 나머지 봇은 포인트를받습니다.
  • 봇이 고유 한 값을 선택하지 않으면 점수가 부여되지 않습니다.
  • 1000 라운드가 끝날 때 가장 많은 점수를 얻은 봇 (또는 가장 많은 점수로 묶인 모든 봇)이 게임에서 승리합니다.
  • 토너먼트는 200 * (플레이어 수) 게임 동안 지속됩니다.
  • 승리 율이 가장 높은 봇이 토너먼트에서 승리합니다.

명세서

봇은 파이썬 3 개 클래스이어야하며, 두 가지 방법을 구현해야 select하고 update.
봇은 색인으로 구성됩니다.
select인수가 전달되지 않고 현재 라운드에 대한 봇의 선택을 반환합니다.
update이전 라운드에서 각 봇이 한 선택 목록이 전달됩니다.

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

제어 장치

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

추가 정보

  • 봇은 자신을 상대로 게임을하지 않습니다.
  • 봇이 100 개 미만의 게임에 포함되는 경우는 드물지만 토너먼트가 재실행됩니다.
  • 봇은 라운드 사이에 상태를 저장할 수 있지만 게임 사이에는 상태를 저장할 수 없습니다.
  • 컨트롤러 또는 다른 봇에 액세스 할 수 없습니다.
  • 결과가 너무 가변적 인 경우 게임 수와 게임당 라운드 수가 증가 할 수 있습니다.
  • 오류가 발생하거나 유효하지 않은 응답 (int가 아닌 값, [1, 10] 외부의 값 등)을 제공하는 모든 봇은 실격 처리되며 토너먼트는 토너먼트없이 재실행됩니다.
  • 라운드 시간 제한은 없지만 봇이 생각하는 데 시간이 너무 오래 걸리면 라운드를 구현할 수 있습니다.
  • 사용자 당 제출 횟수에는 제한이 없습니다.
  • 제출 마감일은 9 월 28 일 금요일 23:59:59 UTC입니다 . 이제 토너먼트가 마감됩니다.

결과

                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 어떤 뉴스?
user1502040

4
@Herohtar 나는 출근하기 전에 달리기를 설정했습니다. 운이 좋으면 집에 돌아갈 때해야합니다.

1
@Mnemonic 아직 끝났습니까?
user1502040

2
@Justin 지금 실행 중이며 충돌하지 않는 것 같지만이 실행이 실패하면 도움이되지 않습니다.

1
@MihailMalostanidis bots.py모든 봇을 포함하는 동일한 디렉토리에 호출 된 파일을 작성하십시오 . 마지막에 생성자 목록을 작성하십시오.allBotConstructors = [Lowball, BayesBot, ...]

답변:


10

베이 즈봇

간단한 통계 모델을 사용하여 최적의 선택을 시도합니다.

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

지속적인 봇 피하기

어떤 봇이 항상 같은 값을 반환했는지 추적하고 해당 값을 건너 뜁니다. 나머지 값 중에서 무작위로 선택하지만 더 낮은 값으로 크게 편향됩니다.

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

잠깐만

가장 경쟁이 치열한 봇 은 아니고 확실히 GTO 도 아니고, 같은 시나리오에서 WaitWhatBot도 그러한 봇이됩니다.

시간 가중치 (가장 최근-> 더 큰 가중치)와 선택 값 (낮은 포인트-> 더 큰 가중치) 모두에 가중치가 적용되는 진화하는 확률을 사용합니다.

약간의 낄낄 거리기 위해 다소 난독 화 된 코드를 사용합니다.

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
WaitWhatBot이 무게를 사면 WaitWhatBot이 살 무게는 얼마입니까?
Roman Odaisky

set ([… for… in…]) ≡ {… for… in…}, 그런데
Roman Odaisky

@RomanOdaisky 나는 실제로 다른 사람에게 골프를 조언했습니다!
Jonathan Allan

5

스토커

게임 시작시이 봇은 무작위로 특정 인덱스를 대상으로 선택합니다. 그런 다음 전체 게임을 대상으로 스토킹하여 이전 라운드에서 선택한 숫자를 복사합니다.

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

멍청한 욕심 하나

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

이 봇은 다른 봇이 묶고 싶지 않다고 가정합니다.

나는 이것이 제공된 예제와 동일하다는 것을 알고 있지만, 그 책을 읽기 전에 생각했습니다. 이것이 KoTH 챌린지 실행 방식과 일치하지 않는 경우 알려주십시오.


일반적으로 중복 봇을 선호하지 않지만 떠나는 것은 괜찮습니다.

1
@Mnemonic은 기술적으로 초기화되지 않기 때문에 속이 아닙니다 self.index.
hidefromkgb

@Mnemonic 문제 없습니다! 솔직히, 이것은 첫 번째 KoTH 이자 파이썬의 첫 번째 것이므로 첫 두 포스터를 따랐으며 의심해야 할 내용에도 불구하고 변경하지 않았습니다. 또한 테스트에 Lowball을 포함시킬 것인지 확실하지 않거나 실제로 게시물의 예일뿐입니다.
엔지니어 토스트

걱정 마. KoTH의 멋진 세계에 오신 것을 환영합니다!

2
당신은 "에이스 수류탄": puzzling.stackexchange.com/questions/45299/…
kaine

4

역사 봇

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

user2390246의 의견 구현 :

그럼 이건 어때? 1로 시작하십시오. 첫 번째 라운드 후에 승리 값을 추적하고 발생 횟수와 동일한 확률로 무작위로 선택하십시오. 예를 들어 처음 3 라운드에서 승리 한 값이 [2, 3, 2] 인 경우 4 라운드에서는 p = 2/3 인 [2]와 p = 1/3 인 [3]을 선택하십시오.


4

원 어퍼

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

다른 사람의 봇은 1을 목표로하거나 무작위로 목표를 정합니다. 2를 목표로하지 않겠습니까?


4

물 같은 흐름

각 숫자를 두 배로 늘리고 점유되지 않은 경우 더 낮은 값으로 천천히 전진하여 기본 상수 봇 감지 알고리즘을 피합니다.

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

궁금합니다. 봇이 어떻게 든 분수 와 관련이 있습니까? 둘 다 "물 지향적"입니다.
RedClover

솔직히, 나의 초기 계획은 특정 숫자를 두 배로 추측하는 고정 추측 로봇을 만드는 것이 봇의 의사 결정 과정에 대한 동기였습니다. 그것을 시각화 할 때 느리게 움직이는 스트림을 생각하고 있었으며 그 이름에 영감을주었습니다. 그래도 물 테마를 외치십시오 :)
TCFP

그래서 이것은 내가 실행하는 모든 테스트에서 3 또는 4 (보통 3)를 얻고 있습니다. 그런 간단한 전략에는 정말 놀랍습니다.
Robert Fraser

4

완전히 잃어버린

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

마지막 카운트 다운

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

온라인으로 사용해보십시오!

처음 100 라운드에 대해서는 10을, 다음 100 라운드에 대해서는 9를 반환합니다.


4

기회 봇

이 봇은 매 라운드마다 다른 봇이 선택하지 않은 가장 낮은 숫자 (가장 낮은 숫자 또는 기회)를 추적하고 가장 자주 그 숫자였던 숫자를 재생합니다.

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

후두개

봇 제출에서 반복되는 섹션을 찾고 숫자를 예측하고 피하려고 시도합니다.

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

삼각형

n을 선택할 확률은 (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

시간 가중

봇이 숫자를 선택할 확률은에 비례합니다 (10-n)*Δt. 첫 번째 라운드는 삼각형과 동일합니다.

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

가장 빈번한

가장 빈번하게 발생하는 숫자를 제출합니다 (동일한 경우).

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

긴 시간

빈번한 경우와 동일하지만 제출 간격이 가장 깁니다.

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

파괴자

마지막으로 제출 된 가장 낮은 번호를 제출합니다.

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

두 번째

마지막으로 제출 된 두 번째로 낮은 번호를 제출합니다

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

이윤

마지막으로 제출하지 않은 가장 낮은 번호를 제출합니다.

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)

죄송합니다. 이전 봇을 구현하면서 새로운 봇에 대한 아이디어를 얻었습니다. 나는 어느 것이 최고인지 확신하지 못했고 각각의 성능에 대해 궁금합니다. https://repl.it/@Fejfo/Lowest-Unique-Number에서 모두 찾을 수 있습니다.


좋은. 의도하지 않은 경우 자신의 마지막 선택을 무시하도록 Saboteur를 수정하는 것을 고려할 수 있습니다. 또한 특별한 경우를 처리해야 할 수도 있습니다. 모든 봇이 어떤 라운드에서 동일한 값을 선택하면 SecondSaboteur는 어떻게해야합니까? 모든 봇이 다른 값을 선택하면 Profiteur는 어떻게해야합니까? 이후 Profiteur에서 끝 괄호가 필요할 수 있습니다 set(range(10).
Reinstate Monica

PatternMatcher에는 일종의 무한 루프 또는 고정 위치가있는 것으로 보입니다.
Robert Fraser

3

상위 50 % RNG 봇

import random

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

나는 임의의 봇을 게시하려고했지만 hidefromkgb가 나보다 먼저 게시되었다. 이것은 rng 봇을 이길 것으로 기대되는 첫 번째 KOTH 답변입니다.


3

사이 클러

이 봇은 단순히 턴마다 각 숫자를 순환합니다. 재미를 위해서, 인덱스로 카운터를 초기화합니다.

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

이 봇은 무작위로 숫자를 골라 50 라운드 동안 붙인 다음 다른 것을 골라 반복합니다.

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

럭키 세븐

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

나는 오늘 운이 좋은 느낌이야! 나는 7에 모든 것을 버리고있다!


3

내 생각은 전략이 실제 전략 평가보다 봇 수에 더 의존한다는 것입니다.

많은 수의 봇으로 옵션은 다음과 같습니다.

  • "1 ~ 3 개 숫자의 10 개 봇이"영리한 "것을 목표로하고"1 ~ 3 개 숫자의 숫자를 얻는 것을 목표로하는 "Greedy"로봇은 그 봇이 그들 사이에 간섭하도록하는 것이 가장 좋습니다.

  • "4"가 항상 인식되면 "스마트"로봇은 다른 곳으로 갈 것입니다.

  • "임의"및 "일정한"로봇. 여기서 할 일이별로 없습니다.

그래서 # 4에 베팅했습니다.

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

2

필수 RNG 봇

import secrets

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

2

암살자

그림자에 머무르고 현재 가장 낮은 추측을 목표로합니다. 운영.

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

팔로우 봇

마지막 라운드에서 우승자를 복사하거나 우승자가없는 경우 최소한 가장 잘 묶은 선택을하십시오.

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

Psychadelic

핵전쟁에서 승리하는 유일한 방법은 자신을 미치게 만드는 것입니다. 토너먼트의 모든 예측 로봇을 미치게 만들 것입니다.

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

마지막 라운드를 선택하고 선택되지 않은 가장 낮은 숫자를 선택합니다 (물론 UnchosenBot의 선택은 무시).


2

후프 디 스 coop 디 똥

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

똥디 특종

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

나는 파이썬을 보거나 만 본 적이 없다.


1
<!-- language: lang-python -->구문 강조 표시를 활성화하려면 코드 블록 앞에 줄을 추가하십시오
Herman L

@HermanL 나는 python질문에 태그를 환각하고 그것이 자동적이라고 생각했지만 나쁜 것을 썼다.
Mihail Malostanidis

1
이 pythonicer 말 간주 될 수를 제외하고 pythonicity에 관해서는, 코드는 꽤 좋은 others = [c for i, c in enumerate(choices) if i != self.index]이후 만, 회원 테스트를 위해 그 변수를 사용하기 때문에, 또는 { }보다는 [ ]구성체 것 set(A)보다 다소을 list.
Roman Odaisky

if (self.guess)또한 매우 비현실적입니다.
Jonathan Frech

나는 그 주변의 파들이 어떻게 들어 왔는지 전혀 모른다 self.guess! 포맷터 중 하나 여야합니다.
Mihail Malostanidis

2

분수

간단한 봇은 가장 낮은 숫자를 먼저 선택하고 다른 봇도 선택하면 카운터가 증가하여 바닥이 채워지고 물이 흐릅니다. 11에 도달하면 1로 다시 시작됩니다. 물이 다시 위로 펌핑됩니다.

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

현재 봇에서 다른 봇이 1에서 8까지의 모든 숫자를 선택한 경우 봇이 while 루프에 멈출 것입니다. target10 으로 설정 하시겠습니까?
Emil

@Emil True, 원래는 이렇게 변경되었습니다
RedClover

2

포아송 봇

낮은 값으로 바이어스되는 포아송 분포에서 숫자를 선택하십시오. 우리가 동점 일 경우 분포의 평균 모수를 조정하고 아래에 추측이있을 경우 조정합니다. 게임이 진행됨에 따라 스텝 크기가 크게 줄어 듭니다.

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

이기는 값과 최소의 선택되지 않은 값의 실행 횟수를 유지합니다 (여기서 선택되지 않은 최소값은이기는 값보다 작은 경우에만 고려 됨). 이 승리 및 최소값 중에서 무작위로 선택합니다.

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

플레이어를 순환합니다. 현재 플레이어 (자기 일 수 있음)의 선택이 이제이 봇의 선택입니다. 왜 안되서 인쇄 8을 시작합니다. 파이썬을 할 수 없어서 미안합니다, 이것은 아마도 나쁜 코드 일 것입니다.

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

편집 : itertools로 코드를 개선 한 Triggernometry 덕분에


코드는 잘 작동하지만 intertools.cycle ()을 추가하여 자동으로 0-9 사이를 순환하고 증분이나 검사를 수행 할 필요가 없습니다 . 온라인으로 시도하십시오!
Triggernometry

2

너구리

이번에 다시 선택할 수있는 이전 선택을 제외하고 이전 라운드에서 선택하지 않은 가장 낮은 숫자를 선택하십시오. 1 라운드에서 1을 선택하십시오.

나는 이것을 독립적으로 생각해 냈지만 이제는 본질적으로 동일한 적어도 2 개의 이전 봇을 보게됩니다.

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

너구리 삼각형

너구리와 삼각형 결합 : 선택되지 않은 값에서 역삼 각 확률을 기준으로 하나를 선택하십시오.

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)

오류 :AttributeError: 'RaccoonTriangle' object has no attribute 'boundaries'
Renzeee

1
네 죄송합니다. 나는 그것을 고쳤다 고 생각한다. 나는 시험을 그만두었을 때 작문 중이었습니다.
양자 역학

1

장군

일반은 항상 마지막 전쟁 싸움 (들) .

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

무 반복 랜덤

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

봇은 무작위로 선택하지만 이전 라운드와 같은 숫자를 선택하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.