Beyaz Fil Değişimi


11

Temmuz ayında Noel, bu yüzden kutlamak için sanal bir beyaz fil hediye değişiminden daha iyi bir yol var!

Bu King of the Hill mücadelesi için, bir Beyaz Fil değişim simülasyonunda oynayan ve mümkün olan en değerli hediyeyi almaya çalışan bir bot yaratmalısınız .

Oyun kuralları

  • Oyun, her biri değişken sayıda dönüşten oluşan birçok turda oynanacaktır.
  • Yuvarlak Kurulum : Oyunda, her biri [0 ... 1) aralığında rastgele olarak eşit olarak değer verilen oyuncular olduğu kadar çok hediye olacaktır ve bu değer, şimdiki değer açılana kadar bilinmemektedir. Oyuncular sıraya rastgele sıraya konacak. İlk oyuncu sıranın önünden fırlatılır.
  • Bir oyuncunun sırası geldiğinde, ya bir hediye açabilir ya da başka bir oyuncunun hediyesini çalarak, hediyeleri çalınan oyuncuya geçer.
    • Her bir hediye 3 defaya kadar çalınabilir.
    • Sizden çalmış olan oyuncudan çalamazsınız.
    • Her oyuncu aynı anda sadece bir tane hediye alabilir.
  • Bir hediye açıldıktan sonra, oyun kuyruğun ön tarafından açılan bir sonraki oyuncuya ilerler. Bu, henüz bir dönüşü olmayan bir sonraki oyuncu olacak.
  • Tur Sonu : Tüm hediyeler açıldığında, tur biter ve her oyuncu tarafından tutulan hediyenin değeri o oyuncunun skoruna eklenir. Yeni bir raunt başlar, her oyuncunun elinde hediye yoktur ve oyuncu sırası karıştırılır.
  • Maç Sonu : En az bir oyuncu 100 500 puan aldığında oyun sona erer ve toplamda en yüksek hediye değerine sahip oyuncuya zafer verilir.

Kodlama

Tüm başvurular Python 3.7 ile uyumlu olmalıdır. Doğrudan miras alan bir sınıf yazmalısınız WhiteElephantBot. Örneğin:

class FooBot(WhiteElephantBot):
    # Your implementation here

Bot sınıfınızda çağırmanız gereken bir __init__yöntem (bir argüman alır) sağlayabilirsiniz . Sınıfınızda , bu sırada aşağıdaki bağımsız değişkenleri bekleyen bir yöntem bulunmalıdır :namesuper().__init__(name)take_turn

  • players: Henüz hediyeleri olmayan tüm oyuncuların oyuncu isimlerinin listesi.
  • presents: Oyuncu adlarını, o oyuncunun sahip olduğu mevcut değeri ve mevcut kaç kez çalındığını içeren 2 tuple eşleyen sözlük. Bu sadece şu anda hediye sahibi olan diğer oyuncuları içerecektir.
  • just_stole: Eğer son alınan eylem çalmaksa, bu sadece çalmış olan oyuncunun adı olacaktır. Değilse, olacak None.

Her argüman değişmez ya da yeni bir nesne olacak, böylece bunların herhangi birisini mutasyona uğratmanın oyun üzerinde bir etkisi olmayacaktır. İsterseniz argümanlardan herhangi birinin bir kopyasını saklayabilirsiniz.

Örnek bir değer presents:

{
    'Alice':   (0.35, 0),
    'Bob':     (0.81, 2),
    'Charlie': (0.57, 1)
}

Kişisel take_turnyöntem çalmaya veya istediğiniz oyuncunun adını dönmelidir Nonehediye açın. Bir istisna oluşturursa, strya da dışında bir şey döndürür veya Noneçalamayacağınız bir oyuncunun adı döndürürse , varsayılan olarak bir hediye açarsınız.

Her turun başlangıcında kurucunuz çağrılır, böylece durumu turdan turuna hatırlayamazsınız.

Buradan devralınarak , hediye diksiyonunu alacak ve çalabileceğiniz oyuncuların isimlerini içeren WhiteElephantBotbir steal_targetsyönteme erişebileceksiniz just_stole.

Komut dosyanızın ihtiyaç duyduğu tüm modüller girişinizin en üstüne aktarılmalıdır.

Test Sürücüsü

Test sürücüsü burada bulunabilir . from white_elephant import WhiteElephantBotGönderi cevabınızı eklemenize gerek yoktur , ancak yerel bir modülün bunu yapması gerekecektir.

Temel Rakipler

  • Rastgele : Çalma hedefi rastgele seçilmiş olarak yeni bir hediye açmayı veya çalmayı rastgele seçer.
  • Açgözlü : çalınabilecek en değerli hediyeyi çal. Hiçbir hediye çalınamazsa, bir hediye açın.
  • Güzel : Her zaman yeni bir hediye açar. Asla çalmaz.

Ek Kurallar

  • Tüm istisnaları yakalamak sizin sorumluluğunuzdadır. Sınıfınız bir istisna yakalayamazsa diskalifiye edilecektir. Ayrıca, lütfen KeyboardInterrupts'ı yakalamayın.
  • Oyunlar arasında durumun kaydedilememesini atlamak için dosya veya başka yöntemler kullanmayın. Örneğin, sinir ağı durumunu çalışma ortasında bir dosyaya kaydedemezsiniz.
  • Botunuz sınıf kodu ve ilgili sabitler içinde bağımsız olmalıdır.
  • Yalnızca standart kitaplık içe aktarmalarını kullanabilirsiniz.
  • Kesin bir performans gereksinimi yoktur. Makul ve ihtiyatlı olun. Performans bir sorun haline gelirse, zaman sınırları ekleme hakkımı saklı tutarım.
  • Kişi başına bir giriş. Birden fazla giriş gönderirseniz, botlarınız birlikte çalışmayabilir. Şimdilik kişi başına birden fazla girişe izin vereceğim, ancak bir sorun haline gelirse daha sonra reban edebilirim.
  • Bu kesin bir bitiş tarihi olmayan açık bir yarışmadır. Önemli değişiklikler olduğunda her zaman tekrar çalışacağım.

DÜZENLEME1: Kazanma puanı 100'den 500'e değiştirildi, böylece sıralama daha tutarlı. Test sürücüsünün yeni bir hatası var ve kazanma puanı değişikliklerini de yansıtıyor.

EDIT2: Gerekli ithalatlar hakkında açıklayıcı not.


Büyük Afiş (8 Ağu 2018 itibariyle)

  1. Örnek Bot (500.093)
  2. LastMinuteBot (486.163)
  3. RobinHood (463.160)
  4. OddTodd (448.825)
  5. Açgözlü Bot (438.520)
  6. SecondPlaceBot (430.598)
  7. Eşik Botu (390.480)
  8. Kumarbaz (313.362)
  9. NiceBot (275.536)
  10. RandomBot (256.172)
  11. GoodSamaritan (136.298)

Arka arkaya çalma sayısı olabilir mi? Oynadığımda, genellikle üst üste 2 çalma sınırı vardır ve üçüncü kişi bir tane açmak zorunda kalır. Bu, aynı hediyenin tur başına bir kereden fazla çalınmasını önler.
mbomb007

@ mbomb007 Evet. Zincir çalma, belirli hediyeleri çalmaya bağışıklık kazandıran diğer kurallar dışında sınırsızdır: her hediye sadece 3 kez çalınabilir ve sizden sadece çalmış olan oyuncudan çalamazsınız.
Beefster

Bir hediye çalabilir ve daha sonra sahip olduğunuz orijinali tekrar çalabilir misiniz?
Outgolfer Erik

@EriktheOutgolfer: evet, aralarında başka bir dönüş olduğu sürece. Hediyeniz çalındıktan hemen sonra tekrar çalamazsınız.
Beefster

1
Yankee takas !? Sırada ne var, paylaşılan bir doğum günü partisi mi?
ngm

Yanıtlar:


3

LastMinuteBot

(Python'u neredeyse bilmediğim için kodun iskeleti için @Mnemonic'e çok teşekkürler.)

class LastMinuteBot(WhiteElephantBot):
    def take_turn(self, players, presents, just_stole):
        targets = self.steal_targets(presents, just_stole)
        if len(targets) <= 1:
            return None

        target = None

        # If most of the presents are already distributed, try to steal an 
        #  un-restealable gift of high value
        if len(presents) > (len(players) + len(presents)) * 0.75:
            at_threshold = [t for t in targets if presents[t][1]==2 and presents[t][0]>=0.8]
            if at_threshold:
                target = max(at_threshold, key=lambda x: presents[x][0])

        # Otherwise, take the best available
        if not target:
            target = max(targets, key=lambda x: presents[x][0])

        return target if presents[target][0] > 0.5 else None

Hediyelerin üç defadan fazla çalınamamasından yararlanın, yüksek değerli bir hediye bulursanız ve çoğu hediye açıldıysa üçüncüyü kendiniz çalın.


Basit, ama güzel
r_j

2

Garip Todd

class OddTodd(WhiteElephantBot):
    def take_turn(self, players, presents, just_stole):

        targets = self.steal_targets(presents, just_stole)

        # if none to steal, pick present
        if len(targets) <= 1:
            return None

        # steals the best gift that he can, as long as he's the 1st/3rd steal
        targets = [t for t in targets if presents[t][1] % 2 == 0]
        if targets:
            return max(targets, key=lambda x:presents[x][0])

        else:
            return None

Yapabileceği en iyi armağanı çalar, ancak armağan çalan ikinci kişi olmak istemez, çünkü ondan çalınırsa geri alamaz.


Hat 11. sözdizimi hatası Bir ihtiyaç ==yerine ait =listenizi anlama.
Beefster

düzeltildi, teşekkürler! Python'u fazla kullanmayın.
brian_t

1

SecondPlaceBot

class SecondPlaceBot(WhiteElephantBot):
    def take_turn(self, players, presents, just_stole):
        targets = self.steal_targets(presents, just_stole)
        if len(targets) <= 1:
            return None

        # If most of the presents are already distributed, take the second best.
        if len(presents) > (len(players) + len(presents)) * 0.8:
            target = sorted(targets, key=lambda x: presents[x][0])[-2]
        # Otherwise, take the best and hope someone steals it later.
        else:
            target = max(targets, key=lambda x: presents[x][0])

        return target if presents[target][0] > 0.5 else None

Herkes en değerli armağan için savaşacak. Bir sonraki en iyi hediye neredeyse iyidir, ancak çalınması daha az olasıdır.


1

ThresholdBot

import random

class ThresholdBot(WhiteElephantBot):
    def __init__(self, name):
        self.name = name
        # Choose a minimum value to be happy.
        self.goal = 1 - random.random() ** 2

    def take_turn(self, players, presents, just_stole):
        # Find who has a gift that's sufficiently valuable.
        targets = self.steal_targets(presents, just_stole)
        targets = [x for x in targets if presents[x][0] >= self.goal]
        targets = sorted(targets, key=lambda x: presents[x][0])

        if not targets:
            return None

        # Choose a target (biased toward the best gifts).
        weighted = []
        for i, target in enumerate(targets, 1):
            weighted += [target] * i ** 2
        return random.choice(weighted)

En iyi hediyeyi almayı umursamıyoruz , sadece yeterince iyi bir şey . Çalmaya değer bir şey olduğu sürece bunu yapacağız.


1

SampleBot

import random

class SampleBot(WhiteElephantBot):
    def rollout(self, values, counts, just_stole, next_move):
        targets = set()
        move_chosen = False
        for i, (v, n) in enumerate(zip(values, counts)):
            if v and n < 3 and i != just_stole and i != 0:
                targets.add(i)
        for i in range(len(values)):
            if values[i]:
                break
            while True:
                if not targets:
                    break
                if move_chosen:
                    j = max(targets, key=lambda i: values[i])
                    if values[j] < 0.5:
                        break
                else:
                    move_chosen = True
                    if next_move is None:
                        break
                    j = next_move
                values[i] = values[j]
                counts[i] = counts[j] + 1
                values[j] = 0
                counts[j] = 0
                if just_stole is not None and counts[just_stole] < 3:
                    targets.add(just_stole)
                if j in targets:
                    targets.remove(j)
                just_stole = i
                i = j
            values[i] = random.random()
            for player in (just_stole, i):
                if player is not None and values[player] and counts[player] < 3:
                    targets.add(player)
        return values[0]
    def take_turn(self, players, presents, just_stole, n_rollouts=2000):
        names = [self.name] + players + list(presents.keys())
        values = [presents[name][0] if name in presents else None for name in names]
        counts = [presents[name][1] if name in presents else 0 for name in names]
        if just_stole is not None:
            just_stole = names.index(just_stole)
        targets = [None]
        for i, (v, n) in enumerate(zip(values, counts)):
            if v and n < 3 and i != just_stole and i != 0:
                targets.append(i)
        if len(targets) == 1:
            return targets[0]
        scores = [0. for _ in targets]
        n = n_rollouts // len(targets)
        for i, target in enumerate(targets):
            for _ in range(n):
                scores[i] += self.rollout(list(values), list(counts), just_stole, target) / float(n)
        target_index = targets[scores.index(max(scores))]
        if target_index is None:
            return None
        return names[target_index]

Her oyuncu hırsla hareket ederek 2000 simülasyonu çalıştırır ve en iyi aksiyonu seçer.


Bu bot tam olarak ne yapıyor?
Beefster

@Beefster Her oyuncunun açgözlülükle oynadığı 2000 rastgele oyun oynar ve en yüksek ortalama final skoruyla hamleyi seçer.
user1502040

İsim hatası. Rastgele içe aktarmanız gerekir.
Beefster

1

RobinHood

class RobinHood(WhiteElephantBot):       
    def take_turn(self, players, presents, just_stole):
        #get the possible steal targets
        targets = self.steal_targets(presents, just_stole)
        #who stole his gift?
        targets = [x for x in targets if presents[x][1] > 0]
        #sort by value
        targets = sorted(targets, key=lambda x: presents[x][0])        
        #only steal back if it's worth it        
        targets = [x for x in targets if presents[x][0] > 0.5]

        if len(targets)>0:
           return targets.pop()

Hediyelerini kazanamayan zenginlerden çal


Girinti hatası var.
Beefster

0

GoodSamaritan

class GoodSamaritan(WhiteElephantBot):     
    def take_turn(self, players, presents, just_stole):  
        targets = self.steal_targets(presents, just_stole)

         #if only one player has a gift, don't steal it!
        if len(presents)<=1 or len(targets)==0:
             return None
        else:       
             #Steal the worst present  
             return min(targets, key=lambda x: presents[x][0])

Şanssız insanlara şans açısından bir şans daha verin


0

Kumarbaz

class Gambler(WhiteElephantBot):
    def take_turn(self, players, presents, just_stole):        
        #get the possible steal targets
        targets = self.steal_targets(presents, just_stole)        

        #last player 
        if len(players)==0:
            #lets gamble! Try and get the highest score
            return None

        #If you are not last, steal the best gift that can be restolen so maybe you can become the last player
        targets = [t for t in targets if presents[t][1]<2 ]
        if targets:
            return max(targets, key=lambda x: presents[x][0])   

Kumarbaz bağımlısı, son oyuncu olmaya çalışıyor, sonra diğer tüm oyuncuları yenmek için yeni bir hediye üzerinde kumar oynuyor.


0

Top3Bot

class Top3Bot(WhiteElephantBot):
    def __init__(self, name):
        super().__init__(name)
        self.firstturn = True

    def take_turn(self, players, presents, just_stole):
        if self.firstturn:
            num_presents = len(players) + len(presents) + 1
            self.value_limit = (num_presents - 3) / num_presents
            self.firstturn = False

        targets = self.steal_targets(presents, just_stole)

        if players:
            targets += None

        return max(
            targets,
            key=lambda name: self.steal_ranking(name, presents, len(players))
        )


    def steal_ranking(self, name, presents, presents_remaining):
        if name is None:
            return (0, 0)

        present_value = presents[name][0]
        num_steals = presents[name][1]
        if present_value >= self.value_limit:
            if num_steals == 2:
                return (5, present_value)
            elif  num_steals == 0:
                return (4, -presemt_value)
            elif num_steals == 1 and presents_remaining == 0:
                return (3, -present_value)
            else:
                return (-1, present_value)
        else:
            if num_steals < 2:
                return (2, present_value)
            else:
                return (-2, present_value)

Bu bot mümkün olan en iyi hediyeyi almaya çalışmaz, ancak> = (n-3) / n değerinde bir hediye almaya çalışır, burada n, hediye sayısıdır. Çoğu durumda, bu kadar değerli hediyeler olacak ve Top3Bot bunlardan birini ele almaya çalışacak, ancak hangilerinden aldığını gerçekten umursamıyor.


senin __init__onun eksik selfargüman
Beefster
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.