หมายเลขที่ไม่ซ้ำกันที่เล็กที่สุด KoTH


27

สร้างบอทเพื่อเลือกหมายเลขเฉพาะที่เล็กที่สุด

(จากการทดลองทางจิตวิทยาฉันได้ยินมาหลายปีแล้ว แต่ไม่สามารถติดตามได้อีก)

กฎระเบียบ

  • แต่ละเกมจะประกอบไปด้วยบอทที่สุ่มเลือก 10 ตัวซึ่งเล่นได้ 1,000 รอบ
  • แต่ละรอบบอตทั้งหมดจะเลือกจำนวนเต็มตั้งแต่ 1 ถึง 10 (รวม) บอตใด ๆ ที่เลือกค่าเดียวกันจะถูกแยกออกและบอทที่เหลือซึ่งมีค่าน้อยที่สุดจะได้รับแต้ม
  • ในกรณีที่ไม่มีบอทเลือกค่าที่ไม่ซ้ำกันจะไม่มีการให้คะแนน
  • ในตอนท้ายของรอบ 1,000, บอทที่มีคะแนนมากที่สุด (หรือบอททั้งหมดที่ผูกด้วยคะแนนมากที่สุด) ชนะเกม
  • ทัวร์นาเมนต์จะมีอายุ 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 เกมการแข่งขันจะมีการรันใหม่
  • บอตอาจเก็บสถานะระหว่างรอบ แต่ไม่ใช่ระหว่างเกม
  • ไม่อนุญาตให้เข้าถึงตัวควบคุมหรือบ็อตอื่น ๆ
  • จำนวนเกมและจำนวนรอบต่อเกมอาจมีการเพิ่มขึ้นหากผลลัพธ์มีความหลากหลายมากเกินไป
  • บอทใด ๆ ที่ทำให้เกิดข้อผิดพลาดหรือให้การตอบสนองที่ไม่ถูกต้อง (ไม่ใช่ ints, ค่านอก [1, 10], ฯลฯ ) จะถูกตัดสิทธิ์และการแข่งขันจะดำเนินการซ้ำโดยที่ไม่มีพวกเขา
  • ไม่มีการ จำกัด เวลาสำหรับรอบ แต่ฉันอาจนำไปใช้ถ้าบอตใช้เวลานานเกินไปที่จะคิด
  • ไม่ จำกัด จำนวนการส่งต่อผู้ใช้
  • กำหนดส่งผลงานคือ 23:59:59 UTC วันศุกร์ที่ 28 กันยายนการแข่งขันสิ้นสุดลงแล้วสำหรับการส่งผลงาน

ผล

                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
@ จัสตินมันทำงานอยู่ในขณะนี้และดูเหมือนจะไม่ล้มเหลว แต่ฉันก็ไม่รังเกียจที่จะรับความช่วยเหลือหากการวิ่งครั้งนี้ล้มเหลว

1
@MihailMalostanidis สร้างไฟล์ที่เรียกว่าbots.pyในไดเรกทอรีเดียวกันที่มีบอตทั้งหมด ในตอนท้ายสร้างรายการของตัวสร้าง:allBotConstructors = [Lowball, BayesBot, ...]

คำตอบ:


10

BayesBot

พยายามเลือกตัวเลือกที่ดีที่สุดโดยใช้แบบจำลองทางสถิติอย่างง่าย

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

WaitWhatBot

ไม่ใช่บอทที่มีการแข่งขันมากที่สุดและไม่ใช่GTOแต่จะขัดขวางคะแนนของคู่ต่อสู้ "เสมอ 1" หรือ "เกือบเสมอ 1" ในเกมเดียวกันกับในสถานการณ์เช่นนี้ 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 …]) ≡ {…สำหรับ…ใน…} โดยทาง
Roman Odaisky

@ RomanOdaisky จริง ๆ แล้วฉันก็แนะนำใครบางคนว่าแค่วันก่อน ๆ สำหรับการเล่นกอล์ฟ!
Jonathan Allan

5

Stalker

ในตอนเริ่มเกมบอทนี้สุ่มเลือกดัชนีเฉพาะเป็นเป้าหมาย จากนั้นจะสะกดรอยตามเป้าหมายทั้งเกมคัดลอกหมายเลขที่เลือกในรอบก่อนหน้า

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

Stupid Greedy One

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

บอทนี้จะสมมติว่าบ็อตอื่นไม่ต้องการผูก

ฉันรู้ว่านี่เป็นแบบเดียวกับตัวอย่างที่ให้ แต่ฉันมีความคิดก่อนที่ฉันจะอ่านที่ไกล หากสิ่งนี้ไม่สอดคล้องกับความท้าทายของ KoTH ให้แจ้งให้เราทราบ


โดยทั่วไปฉันไม่ต้องการมีบอทที่ซ้ำกัน แต่ฉันไม่ต้องการออกจากบอท

1
@Mnemonic ดีในทางเทคนิคมัน `s ไม่ล่อเป็นมัน doesn`t self.indexการเริ่มต้น
hidefromkgb

@ ความจำไม่มีปัญหา! สุจริตนี่เป็น KoTH แรกของฉันและสิ่งแรกของฉันใน Python ดังนั้นฉันเพียงแค่ติดตามสองโปสเตอร์แรกและไม่เปลี่ยนแปลงแม้ว่าฉันจะสงสัยว่าฉันควรจะมี ฉันยังไม่แน่ใจว่าคุณจะรวม Lowball ไว้ในการทดสอบหรือไม่หรือเป็นเพียงตัวอย่างสำหรับโพสต์
Engineer Toast

ไม่ต้องห่วง. ยินดีต้อนรับสู่โลกมหัศจรรย์ของ KoTH!

2
คุณเป็น "ace grenade": 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))

การดำเนินการตามความคิดเห็นของผู้ใช้ 2390246:

แล้วเรื่องนี้ล่ะ เริ่มต้นด้วย 1. หลังจากรอบแรกติดตามค่าที่ชนะและเลือกสุ่มจากพวกเขาด้วยความน่าจะเป็นเท่ากับจำนวนครั้งที่เกิดขึ้น เช่นหากค่าที่ชนะในสามรอบแรกคือ [2, 3, 2] จากนั้นในรอบสี่ให้เลือก [2] ด้วย p = 2/3 และ [3] ด้วย 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

บอทของคนอื่น ๆ มีจุดมุ่งหมายเพื่อ 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

ฉันอยากรู้อยากเห็นบอของคุณเกี่ยวข้องกับน้ำพุของฉันหรือไม่ ทั้งคู่เป็นแบบ "water-oriented" ฮ่าฮ่า
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

ลองออนไลน์!

ส่งคืน 10 สำหรับ 100 รอบแรก 9 สำหรับอีก 100 รอบต่อไป


4

Opportunitybot

บอทนี้ติดตามจำนวนต่ำสุดที่ไม่ได้เลือกโดยบ็อตอื่น ๆ ในแต่ละรอบ (หมายเลขต่ำสุดหรือโอกาสที่มี) และเล่นหมายเลขที่เป็นตัวเลขนั้นบ่อยที่สุด

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

ค้นหาส่วนที่ทำซ้ำในการส่งบอทพยายามทำนายและหลีกเลี่ยงตัวเลขที่มี

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

TimeWeighted

(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

LeastFrequent

ส่งจำนวนที่เกิดขึ้นน้อยที่สุดหากมีค่าเท่ากันให้ใช้ค่าต่ำสุด

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

LongestTime

เช่นเดียวกับที่พบบ่อย แต่มีระยะเวลายาวนานที่สุดระหว่างการส่งผลงาน

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

SecondSaboteur

ส่งจำนวนต่ำสุดที่สองซึ่งถูกส่งครั้งสุดท้าย

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

ส่งจำนวนต่ำสุดที่ไม่ได้ส่งครั้งสุดท้าย

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

บอท RNG 50% อันดับต้น ๆ

import random

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

ฉันกำลังจะโพสต์บอทแบบสุ่ม แต่ hidefromkgb โพสต์ต่อหน้าฉัน (โดยการโพสต์พวกเขาทำให้ตัวเองเป็นเป้าหมายที่ง่ายสำหรับ KGB ไม่ใช่วิธีที่ดีในการซ่อน) นี่เป็นคำตอบ KOTH แรกของฉันเพียงหวังว่าจะชนะบอท rng


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

Lucky Seven

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 ที่ต่ำกว่าสิ่งที่ดีที่สุดคือการปล่อยให้บ็อตเหล่านั้นเข้าไปยุ่งระหว่างพวกเขา

  • หุ่นยนต์ "ฉลาด" ที่เมื่อพวกเขาตระหนักว่า 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

FollowBot

คัดลอกผู้ชนะจากรอบที่ผ่านมาหรืออย่างน้อยที่สุดก็เลือกน้อยที่สุดที่เชื่อมโยงกันหากไม่มีผู้ชนะ

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

โห่-di-ตัก-di-เซ่อ

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

เซ่อ-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

ฉันไม่เคยเห็นหรือสัมผัส Python นี่คือเสียงไพเราะหรือ


1
เพิ่มบรรทัด<!-- language: lang-python -->ก่อนหน้าบล็อกรหัสเพื่อเปิดใช้งานการเน้นไวยากรณ์
Herman L

@ HermanL ฉันเห็นภาพpythonแท็กคำถามและคิดว่ามันจะเป็นไปโดยอัตโนมัติ แต่ฉันเขียนอะไรบางอย่างที่ไม่ดี
Mihail Malostanidis

1
สำหรับ pythonicity รหัสค่อนข้างดี แต่มันอาจจะได้รับการพิจารณา pythonicer ที่จะพูดothers = [c for i, c in enumerate(choices) if i != self.index]หรือเพราะต่อมาคุณจะใช้ตัวแปรที่สำหรับการทดสอบการเป็นสมาชิก{ }มากกว่า[ ]จะสร้างมากกว่าset 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 คุณหมายถึงตั้งไว้targetที่ 10 หรือไม่?
Emil

@Emil True มันเป็นแบบนี้ แต่เดิมเปลี่ยนแล้ว
RedClover

2

PoissonsBot

เลือกตัวเลขจากการแจกแจงปัวซงซึ่งมีอคติกับค่าที่ต่ำกว่า ปรับพารามิเตอร์ค่าเฉลี่ยของการแจกแจงขึ้นถ้าเราอยู่ในเสมอและลงหากมีการเดาด้านล่างเรา ขนาดของขั้นตอนจะเล็กลงอย่างเป็นระบบเมื่อเกมดำเนิน

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

วนรอบผ่านผู้เล่น ผู้เล่นปัจจุบัน (อาจเป็นตัวเลือก) เป็นตัวเลือกของ bot นี้ เริ่มต้นการพิมพ์ 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)]

แก้ไข: ขอบคุณ Triggernometry สำหรับการปรับปรุงโค้ดด้วย itertools


รหัสของคุณใช้งานได้ดี แต่คุณสามารถเพิ่ม intertools.cycle () เพื่อให้วงจรหมุนไปที่ 0-9 โดยอัตโนมัติและคุณไม่จำเป็นต้องเพิ่มหรือตรวจสอบ - ลองใช้ออนไลน์!
Triggernometry

2

สัตว์คล้ายหมีเล็ก

เลือกหมายเลขต่ำสุดที่ไม่ได้เลือกในรอบก่อนหน้ายกเว้นตัวเลือกก่อนหน้าของเราซึ่งสามารถเลือกได้อีกครั้งในเวลานี้ ในรอบแรกเลือก 1 (เมื่อมีฝ่ายตรงข้าม 9 คนและ 10 ตัวเลือกมีการรับประกันว่าจะมีค่าหนึ่งค่า)

ฉันมากับสิ่งนี้ได้อย่างอิสระ แต่ตอนนี้ดูบอทก่อนหน้านี้อย่างน้อย 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
ใช่ขอโทษ. ฉันคิดว่าฉันแก้ไขมัน ฉันอยู่ในช่วงกลางของการทดสอบการเขียนเมื่อฉันออกไป
Quantum Mechanic

1

ทั่วไป

ทั่วไปมักจะต่อสู้สงครามครั้งสุดท้าย(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

ไม่มีการสุ่มซ้ำ

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.