Harabelerde Maceracılar


27

Test SürücüsüMücadele TartışmaGöndermek Adventurer

Hazine odası ( Resim Kaynağı )

Birkaç rakip maceracı, hazine için yıkıntıları yıkıyor, ancak bir seferde çok fazla taşıyabiliyorlar ve dayanıklılık sınırlarına sahipler. En değerli hazineyi almak ve devam edemeyecek kadar yorulmadan çıkmak istiyorlar. Yağma şenansanlarından olabildiğince zengin olmaya çalışıyorlar.

Oynanış

Her maceracı, zindanın ilk odasında, 1000 dayanıklılık puanı ve sırt çantasında 50kg alan ile başlar.

Oyun, sıra tabanlı bir şekilde çalışır ve tüm oyuncular sıralarını aynı anda çözer. Her seferinde aşağıdaki işlemlerden birini yapabilirsiniz:

  • Bir sonraki odaya geçin.
  • Önceki odaya geçin.
  • Bir hazine almak için teklif dayanıklılık.
  • Bir hazine bırak.

Odalar arasında geçiş yapmak için şu anda sırt çantanızda bulunan her 5 kg için 10 adet dayanıklılık artı 1 adet gerekir. Örneğin, 3 kg hazine taşıyan bir maceracının taşınması için 11 dayanıklılık ve bir 47kg taşıyan bir maceranın taşınması için 20 dayanıklılık gerekir.

Bırakılan hazine, bırakılan hazineden bağımsız olarak 1 dayanıklılık gerektirir.

Kalıntılardan çıktıktan sonra oyuncu tarafından daha fazla dönüş yapılmayacaktır.

Eğer bir oyuncu bu hareketlerden herhangi birini gerçekleştiremezse (dayanıklılık yetersizliği veya hazinelerin bulunmaması nedeniyle), maceracıları tükenmişlikten ölmekte ve hazinelerini o anda işgal edilen odaya dökmektedir. Benzer şekilde, bir oyuncu geçersiz bir işlem yapmaya çalışırsa, maceracıları bunun yerine bir tuzak tarafından öldürülecek ve aynı hazine dökülmesine neden olacaktır.

teklif verme

Bir hazine için asgari teklif, hazinenin ağırlığında olduğu 1 kg başına 1 dayanıklılıktır. Hazineyi edinme ihtimalinin daha yüksek olması için ek dayanıklılık puanları da teklif edebilirsiniz. Sonucu ne olursa olsun teklif edilen dayanıklılık tüketilir.

Birden fazla oyuncunun aynı hazineyi alma teklifi vermesi durumunda, en yüksek teklifi veren oyuncu hazineyi alır. Eğer birden fazla oyuncu en yüksek teklifi verdiyse, hiçbiri hazineyi alamaz.

Koşulu Kazan

Toplam en büyük hazineye sahip oyuncu kazanır. Olası bir bağlanma durumunda, bağlar en küçük toplam ağırlığa, daha sonra en az hazineye, ardından en değerli hazinenin değerine, ikinci en değerli, üçüncü ... bağlar kopana kadar gider. Bu noktada hala bir bağın olmadığı neredeyse imkansız durumda, test sürücüsü "vidala" diyor ve kazananı keyfi belirliyor.

Turnuva kapsamında, oyuncular ilk sırayı 10 puan, ikinci sırayı 9 puan, üçüncü sırayı 8 puan, vb ..., ölü oyuncularla ve maceracılarla 0 puan alan birincilikle sıralayacaktır.

Kalıntılar hakkında

  • Her oda, başlangıçta arasında ihtiva r3+3ver2+5hazineler. (Oda numarasır)
  • Keyfi olarak birçok oda var, sadece maceracıların dayanıklılığı ve keşif isteği ile sınırlı.
  • Her hazine parasal bir değere (bütün olarak $) ve bir ağırlığa (bütün kg olarak) sahip olacaktır.
    • Hazineler daha da derinleştikçe hazineler daha değerli ve bol olma eğilimindedir.
  • Hazineleri oluşturmak için spesifik formüller aşağıdaki gibidir: ( zar rulolarında xdy gösterimi kullanılarak )
    • Ağırlık önce formül 2d6-2 (en az 1) kullanılarak üretilir.
    • Hazine değeri daha sonra 1d[10*w]+2d[5*r+10] aracılığıyla üretilir (burada r , oda sayısıdır ve w , ağırlıktır)

Oyunculara Görünen Bilgiler

Her aşamada, oyuncular aşağıdaki bilgileri alır:

  • Şu an içinde bulundukları oda sayısı. Bu 1 indeksli, yani kavramsal olarak çıkış "oda 0" da.
  • Odadaki hazinelerin listesi
  • Şu anda odada bulunan diğer oyuncuların listesi.
  • Şu anki hazine envanteriniz
  • Mevcut dayanıklılık seviyeniz

Kodlama

Test sürücüsü burada bulunabilir .

Bu Adventurersınıfın bir alt sınıfını uygulamalısınız :

class Adventurer:
    def __init__(self, name, random):
        self.name = name
        self.random = random

    def get_action(self, state):
        raise NotImplementedError()

    def enter_ruins(self):
        pass

Sadece get_actionyöntemi geçersiz kılmanız gerekir . enter_ruinsBir oyun başlamadan önce çalıştırılır ve oyuna hazırlanmak istediğiniz şeyi hazırlama şansınız olur. Geçersiz kılmanıza gerek yok __init__ve gerçekten yapmamalısınız . Eğer __init__çökerse, diskalifiye edilirsiniz.

get_actionnamedtupleaşağıdaki alanları içeren tek bir argüman alır (bu sıralamayı imha etmeyi tercih ediyorsanız):

  • room: o anda bulunduğunuz odanın sayısı
  • treasures: Odadaki hazinelerin listesi
  • players: Odadaki diğer oyuncuların listesi. Sadece oyuncu adını bu şekilde elde edersiniz, böylece hangi botun onları veya envanter / dayanıklılığını kontrol ettiğini bilmiyorsunuzdur.
  • inventory: sırt çantanızdaki hazinelerin listesi
  • stamina: Mevcut dayanıklılık seviyeniz

Bu nesne ayrıca iki yardımcı özellik sağlar:

  • carry_weight: Taşıdığınız tüm hazinelerin toplam ağırlığı
  • total_value: Taşıdığınız tüm hazinelerin toplam değeri

treasuresVe inventorylisteleri ihtiva namedtuplebu özelliklere sahip s:

  • name: hazinenin adı (kozmetik amaçlar için)
  • value: Hazinenin parasal değeri $.
  • weight: hazinenin kg cinsinden ağırlığı

get_action aşağıdaki değerlerden / kalıplardan birini döndürmelidir:

  • 'next'veya 'previous'önceki / sonraki odalara geçmek için
  • 'take', <treasure index>, <bid>(evet, bir demet olarak, herhangi bir sıra teknik olarak da çalışacaktır), odanın hazine listesinde verilen endekste hazineye teklif vermek. Her iki argüman tamsayı olmalıdır. Şamandıralar yuvarlanır.
  • 'drop', <inventory index>Verilen endekste bulunan taşınan hazineyi düşürmek. Endeks (doğal olarak) bir tamsayı olmalıdır.

Diğer Kısıtlamalar

  • Sözde rasgelelık için sadece başlatma sırasında size verilen rastgele örneği kullanabilirsiniz.
    • Davranışsal nondeterminizmi ortaya çıkarabilecek hiçbir şeye izin verilmez. Burada amaç, yeni botların test edilmesine yardımcı olmak için aynı tohum verildiğinde (ve test sürücüsündeki potansiyel böcekler) botların aynı şekilde davranmasını sağlamaktır. Sadece kozmik radyasyon herhangi bir sapma / nondeterminizme neden olabilir.
    • Hash kodlarının Python 3'te rasgele olduğunu, bu nedenle hashherhangi bir karar verme için kullanmanın yasak olduğunu unutmayın. dictPython 3.6'dan bu yana tutarlı bir şekilde garanti edildiğinden kararlar için yineleme emrini kullanırken bile gayet iyi.
  • Test sürücüsünü ctypeshack veyainspect stack voodoo (veya başka bir yöntem) atlatamazsınız. Bu modüller ile yapabileceğiniz etkileyici bazı korkutucu şeyler var. Lütfen yapma
    • Her bot savunma kopyaları ve doğal değişkenliği sayesinde oldukça iyi korunuyor namedtuple s'nin şekilde korunuyor, ancak bazı çizilemeyen boşluklar / istismarlar var.
    • Denetleyicinin işlevselliğini atlatmak için kullanılmadığı sürece, diğer işlevler inspectve ctypesbunlar da kullanılabilir.
    • Mevcut oyunda diğer botların kapma örneklerine hiçbir şekilde izin verilmemektedir.
  • Botlar solo çalışmalı ve herhangi bir amaç için hiçbir şekilde başka botlarla koordine olmamalıdır. Bu, biri diğerinin başarısı için kendini feda edecek şekilde farklı hedeflere sahip iki bot yaratmayı içerir. 10'dan fazla rakip olduktan sonra, aynı oyunda iki botun olması garanti edilmez ve maceracı isimlerinin bot sınıfına dair herhangi bir belirti vermez, bu yüzden bu tür stratejiler zaten sınırlıdır.
  • Halen yürütme süresinde herhangi bir kısıtlama yoktur, ancak turnuvalar çok uzun sürmeye başlarsa ileride kısıtlama hakkını saklı tutarım. Makul olun ve dönüş işleminizi 100ms altında tutmaya çalışın bu işlemi eşiğin altında sınırlamak zorunda öngörmediğim için . (Tüm botlar tur başına yaklaşık 100ms alırsa turnuvalar yaklaşık 2 saat sonra oynanır.)
  • Bot sınıfınız tüm gönderiler arasında benzersiz olarak adlandırılmalıdır.
  • Oyunlar arasında hiçbir şey hatırlamayabilirsin. (Ancak, olabilir arasındaki şeyleri hatırlamak dönüşler )
    • Sys.modules dosyasını düzenleme. Dışarıdaki herhangi bir örnek değişken, sabit olarak değerlendirilmelidir.
  • Kendiniz de dahil olmak üzere hiçbir botun kodunu programlı olarak değiştiremezsiniz.
    • Bu, kodunuzun silinmesini ve geri yüklenmesini içerir. Bu hata ayıklama ve turnuvaları daha düzenli hale getirmektir.
  • Denetleyicinin çökmesine neden olan herhangi bir kod derhal diskalifiye edilir. İstisnaların çoğu yakalanırken, bazıları kayabilir ve segfaults yakalanamaz. (Evet, sayesinde Python'da segfault yapabilirsiniz ctypes)

gönderimler

Cevabın kazınmasına yardım etmek için, cevabın en üstünde botunuzun adını a #Header1ile belirtin ve cevabınızın en az bir kod bloğu içerdiğinden emin olun (cevabınızdaki ilk cevap kullanılacaktır). Sıyırıcı tarafından otomatik olarak ekleneceği için herhangi bir ithalat veya belge eklemeniz gerekmez.

Daha detaylı ve anlaşılır açıklamalarla cevapları yükseltmeye daha meyilli olacağım. Diğerlerinin de aynı şekilde davranması muhtemeldir.

Kabaca konuşursak, cevabınız şu şekilde biçimlendirilmelidir:

# Name of Bot
Optional blurb

    #imports go here

    class BotName(Adventurer):
        #implementation

Explanation of bot algorithm, credits, etc...

(olarak işlendi)

Botun Adı

İsteğe bağlı bulanıklaştırma

#imports go here

class BotName(Adventurer):
    #implementation

Bot algoritması, kredi vb. Açıklama

Test Sürücüsünü Yerel Olarak Çalıştırma

Python 3.7+ sürümüne ihtiyacınız olacak ve tabulatepip ile yüklemenizi de tavsiye ederim . Gönderiler için bu sayfayı kazıma ek olarak lxmlve gerektirir requests. En iyi sonuç için ANSI renk çıkışları destekli bir terminal de kullanmalısınız. Bunu Windows 10'da nasıl ayarlayacağınızla ilgili bilgiler burada bulunabilir .

Botunuzu ruins.py( ruins_botsvarsayılan olarak) aynı dizinde bulunan bir alt dizindeki bir dosyaya ekleyin from __main__ import Adventurerve modülün üstüne eklediğinizden emin olun . Bu, sıyırıcı gönderiminizi indirdiğinde modüllere eklenir ve kesinlikle hack olurken, botunuzun uygun şekilde erişebilmesini sağlamanın en kolay yoludur Adventurer.

Bu dizindeki tüm botlar çalışma zamanında dinamik olarak yüklenir, bu nedenle başka bir değişiklik yapmak gerekmez.

Turnuva

Nihai victor, her oyunda 10 taneye kadar bot içeren bir dizi oyunda belirlenecek. Toplamda 10'dan fazla başvuru varsa, ilk 10 bot, her bot (tam olarak) 20 oyun oynayana kadar sistematik olarak 10'lu gruplara ayırarak belirlenir. Sıfırlama puanları olan ilk 10 bot bu gruptan seçilecek ve ilk yerdeki bot ikinci sıradaki bottan 50 puan kazanana veya 500 oyun oynanana kadar oyun oynayacak.

En az 10 başvuru yapılıncaya kadar, boş alanlar kalıntılar arasında rasgele dolaşan ve dayanma süreleri tükenene ve çıkışa doğru gitmeleri gerekene kadar rasgele hazineleri alan (ve bazen de bırakan) rasgele hazineleri alan "Drunkards" ile doldurulur.

Yeni başvurular varsa, turnuvalar haftada bir tekrarlanacaktır. Bu, belirlenmiş bitiş tarihi olmayan açık bir KOTH mücadelesidir.

Liderler Sıralaması

4 Mayıs 2019, 04:25 PM MDT: (2019-05-04 4:25 - 6: 00 saatleri arasında)

Seed: K48XMESC
 Bot Class    |   Score |   Mean Score
--------------+---------+--------------
 BountyHunter |     898 |        7.301
 Scoundrel    |     847 |        6.886
 Accountant   |     773 |        6.285
 Ponderer     |     730 |        5.935
 Artyventurer |     707 |        5.748
 PlanAhead    |     698 |        5.675
 Sprinter     |     683 |        5.553
 Accomodator  |     661 |        5.374
 Memorizer    |     459 |        3.732
 Backwards    |     296 |        2.407

Güncelleme - 15 Nis: birkaç kural güncellemesi / açıklama

Güncelleme - Nis 17: Diğer botların kodlarını değiştirmek gibi birkaç istisnai dava vakasını yasakladı.

Güncelleme - 4 Mayıs: Bounty, Backea'yı kesinlikle yok ettiği için Sleafar'a verildi. Tebrikler!


1
O sonunda burada! Sanırım şimdi botumu yapmaya başlayacağım.
Belhenix

12
Neden bir botun sınırı? Birkaç özel ayrıcalıklı fikrim var ve her yeni bir fikir ortaya attığımda mükemmel bir bot atmamayı tercih ederim.

@ Anımsatıcı, çoğunlukla birden fazla aynı özdeş bot kullanarak yeni gönderilerin yer değiştirmesini engellemek için kullanılır. Diğer bir sebep de botların birlikte çalışmasını engellemekti, ancak yine de açıkça yasaklandı. İzin vermeyi düşüneceğim. Birden fazla gönderiye izin vermek isteyenler, Mnemonic'in yukarıdaki yorumuna oy vermedi.
Beefster

1
@ Draco18s Eğer pipkurulu ve açıksa PATH(ki bunlar yeni AFAIK kurulumları için varsayılandır) o zaman pencerelerden pip install modulenamekomut isteminde çalıştırabilirsiniz . Diğer durumlar için (bilmediğim) pip için, gerekli modülü ara ve bir seçenek seç.
Artemis,

1
Bunun 'hayır' olacağını tahmin ediyorum, ancak turnuva aracılığıyla bilgi kaydetmemize izin var mı? (örneğin, bir teklif çalıştığında)
Artemis

Yanıtlar:


5

Muhasebeci

import math

class Accountant (Adventurer):
    def enter_ruins(self):
        self.goal = 5000
        self.diving = True

    def expected_rooms_left(self, state):
        if not self.diving:
            return state.room

        else:
            return (state.stamina - (50 - state.carry_weight)) / 14

    def ratio(self, state, treasure):
        stamina_cost = treasure.weight * (1 + 1/5 * self.expected_rooms_left(state)) + bool(state.players)
        ratio = (treasure.value / (self.goal - state.total_value)) / (stamina_cost / state.stamina)

        return ratio

    def get_action(self, state):
        room, treasures, players, inventory, stamina = state

        if stamina < room * (math.ceil(state.carry_weight / 5) + 10) + 40:
            self.diving = False
            return 'previous'

        worthwhile = []
        for i, treasure in enumerate(treasures):
            ratio = self.ratio(state, treasure)
            if ratio >= 1 and state.carry_weight + treasure.weight <= 50:
                worthwhile.append((ratio, i))

        if worthwhile:
            ratio, index = sorted(worthwhile, reverse=True)[0]
            treasure = treasures[index]
            return 'take', index, treasures[index].weight + bool(players)

        return 'next'

Muhasebeci çok riskli bir kişidir. Verdiği durumun gerçekten en iyi seçenek olduğundan emin olmaktan hoşlanıyor. Bu yüzden kendine bir hedef belirler ve hesaplamaları bunun kendisini bu hedefe doğru yolda tuttuğunu gösterirse hazineyi alır. Bununla birlikte, çok bürokratik ve istediği karar vermiş olduğu eşyaları bırakmaktan hoşlanmıyor; Ona bunu yapmayı öğretme girişimleri, şimdiye kadar Muhasebecinin bir maddeyi düşürmesi ve daha sonra derhal tekrar toplamasıyla sonuçlandı.

Muhtemelen devam edilecek.


1
Güzel iş değerinde hazine belirleme. Kesinlikle biraz daha iyi yazmak için aklımdaydı "buna değer mi" kodu, ancak henüz oraya gelmedi. Her ne kadar bu aldatmaca muhasebecinin en sonunda ...
Draco18,

“Ona bunu yapmayı öğretme girişimleri, şimdiye kadar Muhasebecinin bir maddeyi bırakması ve daha sonra derhal tekrar toplamasıyla sonuçlandı.”. Bir takım düşmüş hazine isimleri tutarak bu sorunu çözebilirsin. Hazine isimlerinin işe yarayacağına dair bir his vardı (şu anda sadece numaralandırılmış olsalar bile)
Beefster

Teşekkürler, ama neden olduğunu anladım bile. Derhal düzeltip düzeltmeyeceğimi bilmiyorum, çünkü test ederken nadiren kullanıyor.
ArBo

2

Accomodator

Diğer LightWeight botuma gevşek bir şekilde dayanıyor. LightWeight bot basitti durumlarda, bu bot çok daha karmaşık amacıyla olduğunu karşılamak diğer botlar ile etkileşimleri: benign ve deliberatly distruptive hem.

Bu bot ilk önce rastgele atanan bir odaya koşar ve daha sonra en iyi değer / ağırlık oranı hazinesi için teklif vermeye çalışır, eğer odada başka bir oyuncu varsa, o zaman bunun yerine ikinci en iyi hazine için teklif vereceğini varsayar. Bu teklif başarısız olursa bir sonraki en iyi hazine için bir sonraki dönüş teklifinde.

Bir teklif başarılı olduktan sonra, odada daha fazla hazine bulunmayana kadar en iyinin / saniyenin en iyisini teklif edin, ardından harabeye daha derine inin

Her oda harabeye girdiğinde, odada daha fazla hazine bulunmayana kadar en iyi / saniye en iyisi için tekrar teklifini verin, sonra harabeye daha derine inin ya da daha derine gidemeyeceğimizi tespit edersek 'Çıkma' durumuna geçip en kötüsünü bırakmaya başlarsak harabeden canlı çıkabileceğimizi garanti edene kadar hazine.

Çıkış halindeyken 1kg hazine ekleyip ekleyemeyeceğimizi kontrol edip hala hayatta tutacağız, eğer öyleyse 1kg hazine için teklif vermeye çalışacağız, yoksa o zaman önceki odaya geçeceğiz.

Performansı oldukça değişkendir ... ancak normalde ilk üç bottan biri olacaktır.

import math

class Accomodator(Adventurer):
    def enter_ruins(self):
        self.bidValue = -1
        self.bidWeight = -1
        self.exiting = False
        self.sprintToRoom = self.random.randrange(25,27)
        pass

    def get_action(self, state):
        move_cost = 10 + int(math.ceil(state.carry_weight / 5))
        move_cost_extra_kg = 10 + int(math.ceil((state.carry_weight+1) / 5))

        worstMyTreasure = None
        worstMyTreasureId = -1

        # find our worst treasure
        i=0
        for treasure in state.inventory:
            if (worstMyTreasure is None or treasure.value/treasure.weight < worstMyTreasure.value/worstMyTreasure.weight):
                worstMyTreasure = treasure
                worstMyTreasureId=i
            i+=1

        # are we travelling back to the exit?
        if (self.exiting == True):
          # are we overweight to get back alive?
          if (state.stamina / move_cost < state.room):
            # drop most worthless treasure
            self.bidValue = -1
            self.bidWeight = -1
            return 'drop',worstMyTreasureId

          # would adding one kg cause exhaustion?
          if (state.stamina / move_cost_extra_kg <= state.room ):
            # head back to the exit
            self.bidValue = -1
            self.bidWeight = -1
            return 'previous'

        # sprint if not yet at desired sprintToRoom
        elif (state.room < self.sprintToRoom):
            return 'next'

        # are we now at the limit of stamina to still get back alive?
        if (state.stamina / move_cost <= state.room ):
              self.exiting = True
              # head back to the exit
              self.bidValue = -1
              self.bidWeight = -1
              return 'previous'

        bestRoomTreasure = None
        bestRoomTreasureId = -1
        secondBestRoomTreasure = None
        secondBestRoomTreasureId = -1

        # find the best room treasure
        i=0
        for treasure in state.treasures:
          # when exiting the ruin, only consider treasures to collect that are 1kg inorder
          # to fill up any space left in inventory. Normally consider all treasures
          if (self.exiting == False or treasure.weight == 1):
            # only bid on items that we did not bid on before to avoid bidding deadlock
            if (not (self.bidValue == treasure.value and self.bidWeight == treasure.weight)):
              # consider treasures that are better than my worst treasure or always consider when exiting
              if (self.exiting == True or (worstMyTreasure is None or treasure.value/treasure.weight > worstMyTreasure.value/worstMyTreasure.weight)):
                # consider treasures that are better than the current best room treasure
                if (bestRoomTreasure is None or treasure.value/treasure.weight > bestRoomTreasure.value/bestRoomTreasure.weight):
                    secondBestRoomTreasure = bestRoomTreasure
                    secondBestRoomTreasureId = bestRoomTreasureId
                    bestRoomTreasure = treasure
                    bestRoomTreasureId = i

                    # since we do not currently have any treasures, we shall pretend that we have this treasure so that we can then choose the best treasure available to bid on
                    if (worstMyTreasure is None):
                      worstMyTreasure = bestRoomTreasure
          i+=1

        chosenTreasure = bestRoomTreasure
        chosenTreasureId = bestRoomTreasureId

        # if we have potential competitors then bid on second best treasure
        if (len(state.players)>0 and secondBestRoomTreasure is not None):
          chosenTreasure = secondBestRoomTreasure
          chosenTreasureId = secondBestRoomTreasureId

        # we have chosen a treasure to bid for
        if (chosenTreasure is not None):
            # if the chosenTreasure will not fit then dump the worst treasure
            if (state.carry_weight + chosenTreasure.weight > 50):
              # dump the worst treasure
              self.bidValue = -1
              self.bidWeight = -1
              return 'drop',worstMyTreasureId

            # otherwise lets bid for the treasure!
            self.bidValue = chosenTreasure.value
            self.bidWeight = chosenTreasure.weight
            return 'take',chosenTreasureId,chosenTreasure.weight

        # no treasures are better than what we already have so go to next/previous room
        self.bidValue = -1
        self.bidWeight = -1
        if (self.exiting == False):
          return 'next'
        else:
          return 'previous'

Etkileyici! Bu, yaklaşık 50 turda turnuvaya hükmediyor.
Beefster

2

kısa mesafe koşucusu

Dalgıç'a benzer şekilde, Sprinter derinlere iniyor ve geri dönerken en iyi eşyaları alıyor.

import math


class Sprinter(Adventurer):
    class __OnlyOne:
        __name = None

        def __init__(self, name):
            self.__name = name

        @property
        def name(self):
            return self.__name

        @name.setter
        def name(self, name):
            if self.__name is None:
                self.__name = name
            if self.__name is name:
                self.__name = None

    instance = None

    def set(self, instance):
        if self.instance is not None:
            raise Exception("Already set.")
        self.instance = instance

    def __init__(self, name, random):
        super(Sprinter, self).__init__(name, random)
        if not self.instance:
            self.instance = Sprinter.__OnlyOne(name)

        # else:
        # raise Exception('bye scoundriel')

    def get_action(self, state):
        self.instance.name = self.name
        move_cost = 10 + int(math.ceil(state.carry_weight / 5))
        if state.stamina // move_cost <= state.room + 1:
            return 'previous'
        if state.room < 30 and state.carry_weight < 1:
            return 'next'

        # todo: if there is noone in the room take the most valueable thing that fits criteria

        topVal = 0
        topValIndex = 0
        for t in state.treasures:
            val = t.value / t.weight
            if val > topVal:
                if t.weight + state.carry_weight < 50:
                    topVal = val
                    topValIndex = state.treasures.index(t)

        if len(state.treasures) > topValIndex:
            treasure = state.treasures[topValIndex]
            if treasure.weight + state.carry_weight > 50:  # it doesn't fit
                return 'previous'  # take lighter treasure
            else:
                if topVal > state.room * 2:
                    return 'take', topValIndex, treasure.weight + (self.random.randrange(2, 8) if state.players else 0)

        if state.carry_weight > 0:
            return 'previous'
        else:
            return 'next'

    def enter_ruins(self):
        if self.instance is None or self.name != self.instance.name:
            raise Exception('Hi Scoundrel')

Sprinter derinlere indikten sonra her hazine için bir puan hesaplar ve belirli bir eşiğin üstünde bir şey alır. Bu eşik halihazırda bulunduğu odaya bağlıdır çünkü kalıntıları daha derindeki odalardan eşya almak daha fazla maliyetlidir.

Gelecek günlerde planladığım “hazine için mücadele” ile ilgili 2 optimizasyonum var.

17.04 .: Scoundrel çok akıllı oldu, Sprinter onu tuzağa düşürmeye karar verdi, ilk başta Sprinter'ı çağırmaya çalışan herhangi bir botu öldürmek istedim, ancak test cihazı ne yazık ki init'te olan istisnaları ele almıyordu. Yani Scoundrel için bir sonraki düzeltme oldukça kolay ...


Scoundrel öldürmesi devam eden bir çalışma ...
AKroell

2

Önceden planlamak

import math

class PlanAhead(Adventurer):    
    def get_action(self, state):
        if state.inventory:
            ivals = {}
            for i in range(len(state.inventory)):
                itm = state.inventory[i]
                ivals[i] = itm.value / itm.weight
            worstiind = min(ivals, key=lambda x: ivals[x])
            worsti = (worstiind,
                      state.inventory[worstiind].value,
                      state.inventory[worstiind].weight)
        else:
            worsti = None
        if self.drop_worst:
            self.drop_worst = False
            return 'drop', worsti[0]
        if self.seenItems:
            ivals = {}
            for i in range(len(self.seenItems)):
                itm = self.seenItems[i][0]
                v = itm.value
                if self.seenItems[i][1] >= state.room:
                    v = 0
                if v / itm.weight > 250: #very likely to get picked up already
                    v = 0
                ivals[i] = v / itm.weight
            bestIiind = max(ivals, key=lambda x: ivals[x])
            bestIi = (bestIiind,
                      self.seenItems[bestIiind][0].value,
                      self.seenItems[bestIiind][0].weight)
        else:
            bestIi = None

        stamCarry = state.carry_weight/5
        stamToExit = state.room * (10 + math.ceil(stamCarry))
        if state.room > self.max_room:
            self.max_room = state.room
        if stamToExit > state.stamina and worsti:
            return 'drop', worsti[0]
        if state.treasures:
            tvals = {}
            for i in range(len(state.treasures)):
                itm = state.treasures[i]
                v = itm.value
                tvals[i] = v / itm.weight
                self.seenItems.append((itm,state.room))
            besttind = max(tvals, key=lambda x: tvals[x])
            bestt = (besttind,
                     state.treasures[besttind].value,
                     state.treasures[besttind].weight)
            if len(state.players) > 0 and not self.did_drop:
                tvals[besttind] = 0
                besttind = max(tvals, key=lambda x: tvals[x])
                bestt = (besttind,
                         state.treasures[besttind].value,
                         state.treasures[besttind].weight)
        else:
            bestt = None

        if not self.retreat and stamToExit + (12 + stamCarry)*2 + state.room + (state.room/5*state.room) <= state.stamina:
            return 'next'
        if not self.retreat and stamToExit + 10 > state.stamina:
            self.retreat = True
            return 'previous'
        if bestt:
            if state.carry_weight + state.treasures[besttind].weight > 50 or (not self.did_drop and (worsti and (state.treasures[besttind].value-state.treasures[besttind].weight*20) > worsti[1] and state.treasures[besttind].weight <= worsti[2])):
                if worsti:
                    if len(state.players) > 0:
                        return 'previous'

                    if stamToExit <= state.stamina and math.ceil((state.carry_weight - (worsti[2] - state.treasures[besttind].weight))/5)*state.room >= state.treasures[besttind].weight:
                        return 'previous'
                    self.did_drop = True
                    return 'drop', worsti[0]
                else:
                    self.retreat = True
                    return 'previous'
            bid = state.treasures[besttind].weight
            if bid > 8 and state.room >= self.max_room-5:
                return 'previous'
            if not self.did_drop and state.stamina - bid < state.room * (10 + math.ceil(stamCarry+(bid/5))):
                if worsti:
                    if state.treasures[besttind].weight <= worsti[2]:
                        if state.treasures[besttind].value >= worsti[1]:
                            if state.treasures[besttind].weight == worsti[2]:
                                if state.treasures[besttind].value/state.treasures[besttind].weight >= worsti[1]/worsti[2] * (1+(0.05*worsti[2])):
                                    self.drop_worst = True
                                    return 'take', bestt[0], bid
                if not self.retreat:
                    self.retreat = True
                cost = math.ceil((state.carry_weight+bid)/5) - math.ceil(state.carry_weight/5)
                if state.room <= 10 and state.carry_weight > 0 and (state.stamina - stamToExit) >= bid + cost*state.room and bestt:
                    return 'take', bestt[0], bid
                return 'previous'
            self.did_drop = False

            if bestIi[1]/bestIi[2] * 0.3 > bestt[1]/bestt[2] and state.carry_weight > 0:
                return 'previous'
            self.seenItems = list(filter(lambda x: x[0] != state.treasures[besttind], self.seenItems))
            return 'take', bestt[0], bid
        if stamToExit + (12 + stamCarry + state.room)*2 <= state.stamina:
            return 'next'
        else:
            self.did_drop = False
            self.retreat = True
            return 'previous'
    def enter_ruins(self):
        self.retreat = False
        self.max_room = 0
        self.did_drop = False
        self.seenItems = []
        self.drop_worst = False
        pass

Artemis Fowl'in cevabındaki en iyi / en kötü hesaplama önsezilerini kullandım , ancak seçim mantığı tamamen kendi tasarımımdı ve o zamandan beri önceki odalarda görülen hazineler gibi bir kaç ek faktörü içerecek şekilde değiştirildi. hazine, sadece geri izlemek, düşürmek ve başka bir şey almak için).

Bunu yapmak için makul derecede güvenli olduğunu düşündüğü kadar derin olan bot girişimleri (bu hesaplama etkin bir şekilde belirli bir derinliğe dalma için çalışır, ancak diğer başlangıç ​​dayanma değerlerini kullanma esnekliğine sahiptir), eserler toplar (yüksek maliyet ve düşük ağırlık öncelikli) Daha fazla dayanamayacağına karar verdiğinde geri çekilmeye başlar.

Çıkışta, güvenli bir şekilde çıkışa güvenle taşıyabileceğini belirlediğini gördüğü herhangi bir ek hazineyi alacaktır. Yenisi daha iyi bir anlaşma ise ve bitkinlikle sonuçlanmayacaksa, zaten eserler bile düşecek. Sırt çantasında yer varsa, düşük kaliteyi düşürmeden önce yeni hazineyi alır ve diğer botlarla savaşmayı en aza indirir.


Huh, tarif ettiğin zaman benimkiyle aynı. Numaralarım ile dolaşacağım ... Not: __init__işlev zaten uygulandı, geçersiz kılmanıza gerek yok.
Artemis, Monica


2

Artyventurer

Sarhoşları yaklaşık 1000 $ yener! Yaratıcı bir ad düşünemiyorum, ama buradasınız:

import math, sys, inspect, ntpath, importlib


CONTINUE_IN = 310 #go deeper if I have this much extra 
JUST_TAKE = 0     #take without dropping if I have this much extra 


class Artyventurer(Adventurer): 
    def enter_ruins(self):
        self.drop = False 

    def get_extra(self, state, take=0, drop=0): 
        w = state.carry_weight + take - drop 
        return state.stamina - ((10 + math.ceil(w/5)) * state.room) 

    def get_action(self, state):
        self.fail = 'draco' in ''.join(ntpath.basename(i.filename) for i in inspect.stack())
        if self.fail: 
            return 'previous'
        if state.inventory:
            ivals = {}
            for i in range(len(state.inventory)):
                itm = state.inventory[i]
                ivals[i] = itm.value / (itm.weight + 5)
            worstiind = min(ivals, key=lambda x: ivals[x])
            worsti = (worstiind,
                      state.inventory[worstiind].value,
                      state.inventory[worstiind].weight)
        else:
            worsti = None
        if self.drop and worsti:
            self.drop = False
            return 'drop', worsti[0]
        if state.treasures:
            tvals = {}
            for i in range(len(state.treasures)):
                itm = state.treasures[i]
                if itm.weight > (int(state.room/10) or 2):
                    continue
                tvals[i] = itm.weight#(itm.value * (36-state.room)) / (itm.weight * (state.carry_weight+1))
            bestord = sorted(tvals, key=lambda x: tvals[x], reverse=True)
            if bestord:
                pass#print(state.treasures[bestord[0]], '\n', *state.treasures, sep='\n')
            topt = []
            for i in bestord:
                topt.append((i,
                             state.treasures[i].value,
                             state.treasures[i].weight))
        else:
            topt = None
        extra = self.get_extra(state)
        if extra > CONTINUE_IN: 
            return 'next'
        if extra < 0 and worsti:
            return 'drop', worsti[0]
        if extra < state.room:
            return 'previous'
        if extra > JUST_TAKE and topt:
            choose = topt[:len(state.treasures)//3+1]
            for t in choose:
                bid = int(bool(len(state.players)))*3 + t[2]
                if self.get_extra(state, t[2]) - bid >= 0:
                    if t[2] + state.carry_weight <= 50:
                        return 'take', t[0], bid
        if topt and worsti:
            for t in topt[:len(state.treasures)//3+1]:
                if t[1] > worsti[1] or t[2] < worsti[2]:
                    bid = int(bool(len(state.players)))*3 + t[2]
                    if self.get_extra(state, t[2], worsti[2]) - 1 - bid >= 0:
                        print('a', '+weight:', t[2], '; cweight:', state.carry_weight, '; stamina:', state.stamina)
                        if bid < state.stamina and t[2] + state.carry_weight <= 50:
                            print('o')
                            self.drop = True
                            return 'take', t[0], bid
        return 'previous'

Bazen buradaki kodların çoğu hiçbir zaman bir şey yapmaz (en azından Drunkards'a karşı test ettiğimde), program sadece kendisini koymaya çalıştığı durumların işlenmesi de dahil olmak üzere en iyi hamleyi bulur. Bazıları asla koşamaz, oradadır, böylece hala geliştirilebilecek sayılarla uğraşabiliyorum.

açıklama

  • if state.inventory ... worsti = None
    Envanterdeki 'en kötü' maddeyi, yani en düşük değer / ağırlık oranına sahip maddeyi bulun. worstiDizini içeren değerini, değerini ve tuple olarak ağırlığını depolar ya Noneda envanterde ürün yoksa.

  • if self.drop ... return 'drop', worsti[0]
    Son sırayı bu sırayı bırakmasını söyleseydim (aşağıya bakınız), ve 'en kötü' öğeyi yukarıda hesaplandığı gibi bırakabilir.

  • extra = ... * state.room
    Hesapla o artık ne olacağını görebilirsiniz dayanıklılık eğer ben şimdi düz geri dönmek için anlattı.

  • if extra > CONTINUE_IN:\ return 'next'
    CONTINUE_IN'den fazlaysa, geri dönün 'next'.

  • if extra < 0 and worsti:\ return 'drop', worsti[0]
    Eğer daha küçükse 0, en kötüyü bırakın.

  • if extra < state.room:\ return 'previous'
    Oda numarasından azsa (daha fazla hazine taşıyamaz) geri dönün.

  • if state.treasures: ... bestt = None
    Yukarıdaki envanterdeki en kötü maddeye benzer şekilde alacak en iyi hazineyi hesaplayın. İçinde saklayın bestt.

  • if extra > 0 and bestt: ... return 'take', bestt[0], bid
    Mevcut sayılarla, bu ne zaman elimizde olursa olsun çalıştırılabilir ve hazinemiz var. 'En iyi' hazineyi almak güvenli ise, öyle yapar. Teklif minimum veya en az biri varsa bir oyundur.

  • if bestt and worsti: ... return 'take', bestt[0], bid
    Mevcut sayılarla, bu kod bloğu hiçbir zaman yürütülmez, çünkü önceki kod bloğu daha geniş bir koşula sahiptir. Eğer bu kadar ileriye gidersek, bu işlem yürütülür ve envanterimde ve odamda hem hazine var. Odadaki "en iyi" hazine, envanterimdeki "en kötü" hazineden daha değerliyse ve bunları sonraki iki turda değiştirmek güvenli olacaktı, öyle.

  • return 'previous'
    Bunların hiçbiri olmazsa, sadece geri dönün.

16.04.19 Güncellemesi:

Haşere karşıtı önlemler. Bu bir teklif savaşı olacak :(

Daha Fazla Güncelleme 16/04/19:

Önceden döndürülmüş, bunun yerine en iyisini bulurken rastgele her öğeyi değiştirir, örn. [1, 2, 3, 4, 5, 6] → [2, 1, 3, 4, 6, 5]. Kopyalamak zor olmalı :).

17.04.19 Güncellemesi:

Önceden döndürülmüş, bunun yerine kendi kaynak kodunu siliyor . Bunu __init__her zaman Scoundrel.enter_ruinsöncekinde olacak şekilde yapar ve böylece Scoundrel'in yüklemesini durduracaktır. get_actionİlk çağrıldığında kodunu değiştirir , böylece bir dahaki sefere hazır olur. SABİT, Scoundrel şimdi varışta ölür.

Ek Güncelleme 17.04.29:

Önceden döndürülmüş, bunun yerine sys.modulesgirişini matematik modülüyle değiştirir, böylece Scoundrel onu yüklemeye çalıştığında, yerine matematik modülünü yükler. :)
Ayrıca, sadece hareket dayanıklılığının 10 + ağırlık / 5 olduğunu fark ettim , bu yüzden bunu düzeltmeye çalıştım.

Ek Güncelleme 17.04.29:

Şimdi önceki güncellemelerin her ikisinden de sarımsak var.

18/04/19 Güncellemesi:

Rakam ve hesaplamalarla uğraşmak, şimdi 2000 - 3000 dolar alıyor.

Ek Güncelleme 18/04/19:

Yasaklanmış olduğu gibi silinen dosya silme sarımsak , ilk dönüşte 'draco'geri dönüyorsa, çalışmasından sorumlu olmadığından emin olan yeni bir sarımsak ekledi previous. Sonuçlar, aradığım 1200 - 1800 dolar arasında gizemli bir dalış yaptı.



@ Moogie 8 sarhoş da var olduğunda dalgıç yaklaşık 100 $ kadar yener.
Artemis,

2

The Scoundrel

import math, importlib

CONTINUE_IN = 310 #go deeper if I have this much extra 
JUST_TAKE = 0     #take without dropping if I have this much extra 

class Scoundrel(Adventurer):
    def my_import(self, name):
        components = name.split('.')
        mod = __import__(components[0])
        for comp in components[1:]:
            mod = getattr(mod, comp)
        return mod

    def get_action(self, state):
        if self.following == 0:
            return self.sprinter(state)
        if self.following == 1:
            return self.arty(state)
        if self.following == 2:
            return self.account(state)
        return 'next'

    def enter_ruins(self):
        _weights=[17,0,13]
        self.following = self.random.choices(population=[0,1,2],weights=_weights)[0]
        try:
            self.arty_clone = importlib.import_module('artemis_fowl__artyventurer').Artyventurer(self.name,self.random)
            self.arty_clone.enter_ruins()
        except:
            self.arty_clone = None
        self.sprinter_clone = self.my_import('akroell__sprinter').Sprinter(self.name,self.random)
        self.sprinter_clone.enter_ruins()
        self.account_clone = self.my_import('arbo__accountant').Accountant(self.name,self.random)
        self.account_clone.enter_ruins()
        self.drop = False
        pass

    def sprinter(self, state):
        raw_action = self.sprinter_clone.get_action(state)
        if raw_action == 'next' or raw_action == 'previous':
            #move_cost = 10 + int(math.ceil(state.carry_weight / 5))
            #if state.stamina // move_cost < state.room:
            #    print('wont make it!')
            return raw_action
        else:
            atype, *args = raw_action
            if atype == 'take':
                return self.TakeSprinter(state, *args)
            if atype == 'drop':
                return raw_action
    def TakeSprinter(self, state, treasure, bid):
        move_cost = 10 + int(math.ceil((state.carry_weight+state.treasures[treasure].weight) / 5))
        maxbid = state.stamina - move_cost*(state.room)
        bid = state.treasures[treasure].weight + (7 if state.players else 0)
        if maxbid < state.treasures[treasure].weight:
            return 'previous'
        if maxbid < bid:
            bid = maxbid
        return 'take',treasure, bid

    def arty(self, state):
        if self.arty_clone == None:
            try:
                self.arty_clone = importlib.import_module('artemis_fowl__artyventurer').Artyventurer(self.name,self.random)
                self.arty_clone.enter_ruins()
            except:
                self.arty_clone = None
        if self.arty_clone == None:
            raw_action = self.backup_arty(state)
        else:
            raw_action = self.arty_clone.get_action(state)
        if raw_action == 'previous' and state.carry_weight < 1:
            self.arty_clone.fail = False
            return 'next'
        if raw_action == 'next' or raw_action == 'previous':
            return raw_action
        else:
            atype, *args = raw_action
            if atype == 'take':
                return self.TakeArty(*args)
            if atype == 'drop':
                return raw_action
    def TakeArty(self, treasure, bid):
        return 'take', treasure, bid + self.random.randrange(0, 2)

    def account(self, state):
        raw_action = self.account_clone.get_action(state)
        if raw_action == 'next' or raw_action == 'previous':
            return raw_action
        else:
            atype, *args = raw_action
            if atype == 'take':
                return self.TakeAcc(*args)
            if atype == 'drop':
                return raw_action
    def TakeAcc(self, treasure, bid):
        return 'take',treasure,bid + self.random.randrange(0, 2)

    def get_extra(self, state, take=0, drop=0):
        w = state.carry_weight + take - drop
        return state.stamina - ((10 + math.ceil(w/5)) * state.room)
    def backup_arty(self, state):
        if state.inventory:
            ivals = {}
            for i in range(len(state.inventory)):
                itm = state.inventory[i]
                ivals[i] = itm.value / (itm.weight + 5)
            worstiind = min(ivals, key=lambda x: ivals[x])
            worsti = (worstiind,
                      state.inventory[worstiind].value,
                      state.inventory[worstiind].weight)
        else:
            worsti = None
        if self.drop and worsti:
            self.drop = False
            return 'drop', worsti[0]
        if state.treasures:
            tvals = {}
            for i in range(len(state.treasures)):
                itm = state.treasures[i]
                if itm.weight > (int(state.room/12) or 2):
                    continue
                tvals[i] = (itm.value * (25-state.room)) / (itm.weight * (state.carry_weight+1))
            bestord = sorted(tvals, key=lambda x: tvals[x])
            topt = []
            for i in bestord:
                topt.append((i,
                             state.treasures[i].value,
                             state.treasures[i].weight))
        else:
            topt = None
        extra = self.get_extra(state)
        if extra > CONTINUE_IN: 
            return 'next'
        if extra < 0 and worsti:
            return 'drop', worsti[0]
        if extra < state.room:
            return 'previous'
        if extra > JUST_TAKE and topt:
            choose = topt[:len(state.treasures)//3+1]
            for t in choose:
                bid = int(bool(len(state.players)))*3 + t[2]
                if self.get_extra(state, t[2]) - bid >= 0:
                    if t[2] + state.carry_weight <= 50:
                        return 'take', t[0], bid
        if topt and worsti:
            for t in topt[:len(state.treasures)//3+1]:
                if t[1] > worsti[1] or t[2] < worsti[2]:
                    bid = int(bool(len(state.players)))*3 + t[2]
                    if self.get_extra(state, t[2], worsti[2]) - 1 - bid >= 0:
                        if bid < state.stamina and t[2] + state.carry_weight <= 50:
                            self.drop = True
                            return 'take', t[0], bid
        return 'previous'

Scoundrel öncelikle diğer yarışmacılara müdahale etmeye çalışıyor. Şu anda Sprinter, Artyventurer ve Accountant ile etkileşime giriyor (bu liste Scoundrel'in çıkarları dahilinde olması koşuluyla zamanla büyüyecek). Bunu, diğer botları taklit ederek ve sonra da teklif dışı bırakma, azaltma ya da emanetlerle savaşma yoluyla yapar. Bu nedenle, bu girişin lider panosuna hükmetmesi ve bunun yerine bozulma kuvveti olarak çalışması muhtemel değildir. Bu gönderi sırasındaki güncel revizyon, yaklaşık 7 ortalama puanla 2. sırayı alır.

Scoundrel, diğer botun kodunu doğrudan ayırt edilemez bir klon kopyası olarak uygulayarak Scoundrel'e karşı savunmak için kendilerini değiştirme girişiminde bulunur. Kopyalanan katılımcılarla sonuçlanan ithalatla ilgili sorunlar, Yansıma yoluyla klonların yaratılmasıyla çözüldü (Matematiksel saptamanın ince ayrıntılarını içeren savaşları düzenleme, bir Yığın Değişim bakış açısından istenmez, ancak aynı sonuca neden olur). KOTH zorluklarının da buna izin verme geçmişi var.

Scoundrel, Teamster'leri ilginç olma uğruna tutmak için Teamster'lerin yerine geçer. Bu düzenlemeden sonra, Teamsterler artık denetleyici tarafından kazınmamalıdır.

Güncelleme 4/17/2019: Ekstra karşı önlemler.

Teamsters (yasadışı kılındı)

Ancak, 8'den fazla yarışmacının olmadığı yerlerde yerel olarak koşmaktan çekinmeyin!

class TeamsterA(Adventurer):
    def get_action(self, state):
        if state.room < 25 and state.carry_weight == 0:
            return 'next'
        if state.room == 25 and len(state.players) == 0 and len(state.inventory) <= 1:
            if state.treasures and len(state.inventory) == 0:
                tvals = {}
                for i in range(len(state.treasures)):
                    itm = state.treasures[i]
                    if itm.weight == 1:
                        return 'take',i,1
                for i in range(len(state.treasures)):
                    itm = state.treasures[i]
                    if itm.weight == 2:
                        return 'take',i,2
            if state.carry_weight > 0 and len(state.inventory) == 1 and int(state.inventory[0].name.strip('Treasure #')) < 500:
                return 'drop',0
            return 'previous'
        if state.room >= 25:
            if (((state.carry_weight+4) / 5) + 10) * state.room >= state.stamina:
                return 'previous'
            if len(state.inventory) == 1 and int(state.inventory[0].name.strip('Treasure #')) < 500:
                return 'drop',0
            if state.treasures:
                tvals = {}
                for i in range(len(state.treasures)):
                    itm = state.treasures[i]
                    if int(itm.name.strip('Treasure #')) > 500:
                        if (((state.carry_weight+3+itm.weight) / 5) + 10) * state.room >= state.stamina:
                            return 'previous'
                        return 'take',i,itm.weight
                for i in range(len(state.treasures)):
                    itm = state.treasures[i]
                    if itm.weight == 1:
                        return 'take',i,1
                for i in range(len(state.treasures)):
                    itm = state.treasures[i]
                    if itm.weight == 2:
                        return 'take',i,2
                if len(state.inventory) > 0:
                    return 'previous'
                return 'next'
        return 'previous'

class TeamsterB(Adventurer):
    def get_action(self, state):
        if state.treasures:
            tvals = {}
            for i in range(len(state.treasures)):
                itm = state.treasures[i]
                w = itm.weight
                v = itm.value
                if w + state.carry_weight > self.max_total_weight or w > self.max_single_weight:
                    w = 100
                if v / w < state.room * self.min_value_ratio:
                    v = 0
                tvals[i] = v / w
            besttind = max(tvals, key=lambda x: tvals[x])
            bestt = (besttind,
                     state.treasures[besttind].value,
                     state.treasures[besttind].weight)
        else:
            bestt = None
        if state.room < self.max_dive_dist and state.carry_weight == 0:
            return 'next'
        if state.room > 25 and bestt and state.carry_weight + bestt[2] <= self.max_total_weight and bestt[1] > 0 and bestt[2] <= self.max_single_weight and len(state.players) == 0:
            return 'take',bestt[0],bestt[2]
        if state.carry_weight > 0 and state.room > 25 and len(state.players) == 0:
            return 'previous'
        if state.carry_weight > 0:
            return 'drop',0
        if state.carry_weight > 0:
            return 'take',bestt[0],bestt[2]
        return 'previous'
    def enter_ruins(self):
        self.max_single_weight = 3
        self.max_total_weight = 20
        self.min_value_ratio = 2.5
        self.max_dive_dist = 55
        pass

Bu giriş (şimdi açıkça geçersiz olsa da), aslında, iki bottur ve kontrolör mutlu bir şekilde ikisini de kazıyacak ve yarışmacı listesine ekleyecektir (çünkü yaşasın Python?)

Faz 1:

  • TeamsterA seviye 25'e (ish) 1 inmeye başlar ve tekrar tekrar bulabildiği en hafif hazineyi alır ve düşürür. Bu, ikinci aşamaya kadar bir kuyruklu bir dayanıklılığın maliyetini artırıyor.
  • TeamsterB 55. seviyeye doğru ilerler ve etrafındaki tüm değerli eşyaları toplar ve daha sonra seviye 25'e (ish) geri döner. 2 Sonra 2. aşamaya başlar.

1. Eğer zeminde 3'ten daha az bir hazine yoksa, aşağı doğru hareket eder.
2. Yüzeye dönen son maceracı olacağının garantisi olduğundan , tek yapması gereken birini bulmak.

Faz 2:

  • TeamsterB yorgunluktan ölmek için sürünmeden önce ceplerini boşaltır. Yapabileceğini biliyorduk.
  • TeamsterA "parlak biblolar, iyi arkadaş!" ve çıkışa geçmeden önce odadaki diğer çöplüklerden çok daha değerli hazinelere yükler, cepler altınla dolu.

Hazinelerin adı, mantığın kat 25'in üzerinde hurdaya yüklenmemesine ve iki bot arasında iletişim kurmanın bir yolu olmadığı için erken ayrılmasına (ve TeamsterA'nın kendisini daha önce başkasıyla bir odada bulacağına) yardımcı olmak için gerçekten kullanışlı oldu. TeamsterB geri döndü).

Bir sonraki mantıksal sonuç: Bir ordu oluşturma

Teorik olarak, bu, derinlikleri kapatmak ve Oda 98'in derinliklerinden hazineler elde etmek için kullanılabilir, ancak bu, 2 bottan daha fazlasını gerektireceği için, bu botları içeren mantık giderek daha karmaşık hale gelecektir ve bundan emin olduğum gibi Yazılmamış bir kuralı ihlal ettiği için yasadışı bir başvuruda bulundum, bu yüzden rahatsız etmeyeceğim.

Etkili bir şekilde A30'da Bbekler, 50'de bekler ... n98'e dalışı, bir hazine alır, 97'ye gider, düşürür (ve sonra ölür), n-1alır ve 96'ya gider ... Cdüşer (ölür), Balır yukarı ve 30'a hareket eder, düşürür (ölür), Aalır ve çıkışa geri döner.

Bunun 11 bot alacağını tahmin ediyorum.

Bununla birlikte, hareket etme dayanıklılığı maliyetleri ve ortalama hazinelerin değeri arasındaki ölçeklendirme nedeniyle PlanAhead veya Artyventure gibi girişlerle rekabet edebilmek için bu derinlikten yaklaşık 4 hazine kazanamadığınız sürece yapmaya değmez.

Örnek sonuçlar

Nadiren 4000 $ altında puan, bazen 6000 $ tepeler.

[Turn 141] Homer the Great (TeamsterA) exited the ruins with 286 stamina
    and 16 treasures, totaling $4900 in value.
[Game End] The game has ended!
[Game End] Homer the Great (TeamsterA) won the game

[Turn 145] Samwell Jackson DDS (TeamsterA) exited the ruins with 255 stamina
    and 20 treasures, totaling $6050 in value.
[Game End] The game has ended!
[Game End] Samwell Jackson DDS (TeamsterA) won the game

[Turn 133] Rob the Smuggler (TeamsterA) exited the ruins with 255 stamina
    and 12 treasures, totaling $3527 in value.
[Game End] The game has ended!
[Game End] Eliwood the Forgettable (PlanAhead) won the game

1
Bence, kişi başına sadece bir bot olacağı zaman, böyle açık bir kurala ihtiyaç duyulmadığını düşünüyorum. Ancak, tehlikeli sebeplerden dolayı belirli bir botu hedeflemeyle ilgili kural, bir araya gelerek çoklu botları rahatsız etmekle aynı şey değildir. Dolayısıyla OP’den açık bir karar alması gerekiyor.
Moogie

Evet, bu benden bir hayır olacak, ahbap. Bu, birlikte çalışan botlarla aklımda olan türden bir şey.
Beefster

1
@Beefster Ben de öyle düşündüm. Ancak bunu yaparken eğlendim. Bu akşam dahil edilmeyi engellemeye yönelik düzenlemeyi ele alacağım.
Draco18,

Etkinliği yine de tank alacağından, 11'den fazla yarışmacı varken buna izin vermeyi düşüneceğim. Çoğunlukla, autoban gönderimlerine kod oluşturmak istemiyorum.
Beefster

Zaten sadece ilk kod bloğunu sıyırıyorsanız, tek yapmam gereken üst kısımdaki farklı bir botta düzenleme yapmak.
Draco18,

2

Geriye doğru

Çünkü tersten çalışıyor

import math

class Backwards (Adventurer):
    def enter_ruins(self):
        self.goal = 5000
        self.diving = True

    def expected_rooms_left(self, state):
        if not self.diving:
            return state.room
        else:
            return state.stamina / 18

    def ratio(self, state, treasure):
        stamina_cost = treasure.weight * (1 + 1/5 * self.expected_rooms_left(state)) + math.ceil(len(state.players)/2.9)
        ratio = (treasure.value / (self.goal - state.total_value)) / (stamina_cost / state.stamina)
        return ratio

    def get_action(self, state):
        room, treasures, players, inventory, stamina = state
        if stamina < room * (math.ceil(state.carry_weight / 5) + 10) + 40 or stamina < (room+2.976) * (math.ceil(state.carry_weight / 5) + 11):
            self.diving = False
        if stamina < (room+0.992) * (math.ceil(state.carry_weight / 5) + 10.825):
            return 'previous'

        worthwhile = []
        for i, treasure in enumerate(treasures):
            ratio = self.ratio(state, treasure)
            if ratio >= 1 and state.carry_weight + treasure.weight <= 50:
                worthwhile.append((ratio, i))

        if worthwhile:
            ratio, index = sorted(worthwhile, reverse=True)[0]
            treasure = treasures[index]
            bid = treasures[index].weight + math.ceil(len(players)/2.9)
            if (not self.diving or ratio > 2.8) and stamina >= bid + (room) * (math.ceil((state.carry_weight+treasures[index].weight) / 5) + 10):
                return 'take', index, bid
        return 'next' if self.diving else 'previous'

Neden geriye doğru deniyor?

Çünkü Muhasebeciyi aldım ve mantığını derinden dalacak şekilde çalıştırmaya çalıştım, sonra çıkış yolunda tercih ettiği ganimetini topladım (Muhasebecinin geriye doğru).

Nihayetinde hala ödüllerinin çoğunu toplar (geleneksel toplayıcılar aramadan önce onları toplarlar, herkese karşı çalışırlar), ama daha seçicidir yine de, hangileri aldığı konusunda geri giden şeyleri toplar.

Sonuçta, yüksek değerli hazineleri ön planda tutarken dayanma gücü korunmakta, daha sonra derin bir dönüşten ve geri dönüş sırasında kolay toplamadan yararlanılmaktadır. Geriye doğru 41 odaya kadar hazineleri topladığı biliniyordu (ve geliştirme sırasında girecekti, sonra hemen oda 42 kaldı).


2

Kelle avcısı

Basit yöntem en iyisidir. Olabildiğince derinlere inerken değerli ve hafif hazineleri kapın. Geri dönerken daha az değerli hazineleri kapın.

import math

class BountyHunter(Adventurer):
    def move_cost(self, state, additional_weight):
        return 10 + int(math.ceil((state.carry_weight + additional_weight) / 5))

    def get_action(self, state):
        can_go_deeper = state.stamina > (state.room + 2) * self.move_cost(state, 0)
        if state.treasures:
            best_ratio = 0
            best_index = 0
            best_weight = 0
            for i, treasure in enumerate(state.treasures):
                ratio = treasure.value / treasure.weight
                if ratio > best_ratio:
                    best_ratio = ratio
                    best_index = i
                    best_weight = treasure.weight
            limit = 160 if can_go_deeper else 60
            bid = best_weight + 2 if len(state.players) >= 1 else best_weight
            if state.carry_weight + best_weight <= 50 and best_ratio >= limit and state.stamina >= bid + state.room * self.move_cost(state, best_weight):
                return 'take', best_index, bid
        if can_go_deeper:
            return 'next'
        else:
            return 'previous'

Ödül kazanıyor gibisin. Bu sadece Geriye doğru değil, aynı zamanda Geriye doğru tanktan daha iyi performans gösterir. Aferin.
Beefster,

1

Hafif

Hala oldukça iyi performans gösteren basit bir bot.

Kalıntılara girdikten sonra (şu anda 21 oda) odadaki en iyi hazineyi sadece 1kg (bu nedenle botun adı) alacak ve envanterdeki en az değerli hazineden daha değerli olacak. Envanter doluysa, en az değerli hazineyi düşürün. Başka bir işlem seçilmezse, kalıntılara doğru hareket edin. Eğer canlı olarak çıkabilmek için dayanma gücümüzün sınırındaysak, çıkışa yönel.

import math

class LightWeight(Adventurer):

    def get_action(self, state):
        move_cost = 10 + int(math.ceil(state.carry_weight / 5))

        # are we now at the limit of stamina to still get back alive?
        if (state.stamina / move_cost <= state.room + 3):
            # head back to the exit
            return 'previous'

        if (state.room < 21):
            return 'next'

        bestRoomTreasure = None
        bestRoomTreasureId = -1
        worstMyTreasure = None
        worstMyTreasureId = -1

        # find our worst treasure
        i=0
        for treasure in state.inventory:
            if (worstMyTreasure is None or treasure.value < worstMyTreasure.value):
                worstMyTreasure = treasure
                worstMyTreasureId=i
            i+=1

        # we have hit our carrying capacity... we are now going to dump least valuable treasure
        if (state.carry_weight==50):

            # dump the worst treasure
            return 'drop',worstMyTreasureId

        # find the best room treasure
        i=0
        for treasure in state.treasures:
            if (treasure.weight == 1 and (worstMyTreasure is None or treasure.value > worstMyTreasure.value)):
                if (bestRoomTreasure is None or treasure.value > bestRoomTreasure.value):
                    bestRoomTreasure = treasure
                    bestRoomTreasureId = i
            i+=1

        # we have found a treasure better than we already have!
        if (bestRoomTreasure is not None):
            return 'take',bestRoomTreasureId,1

        # no treasures are better than what we already have so go to next room
        return 'next'

Ben koyarak öneriyoruz dumpingiçinde enter_ruinsyöntemle. Bu aslında oyunlar arasında hatırlayacak ve oyun 2 üzerinde çalışmayacak. Teknik olarak izin verilmemiş, ancak kuralı şimdi ekledim (daha önce unuttum ama amacımdı), bu yüzden biraz gevşeyeceğim. : P
Beefster

@Beefster Boşaltma devlet bayrağını kaldırdım, bot şu an sadece bir hazine attığından dolayı gerekli değil. Hazinesinin yarısını terk ederdi. Öyleyse yeni kuralla uyumlu olmalı.
Moogie

1

Memorizer

Botları kendi KotH'ime gönderebilirim, değil mi?

from __main__ import Adventurer
import math
from collections import namedtuple

class TooHeavy(Exception):
    pass

TreasureNote = namedtuple(
    'TreasureNote',
    ['utility', 'cost', 'room', 'name', 'value', 'weight']
)

def find_treasure(treasures, name):
    for i, t in enumerate(treasures):
        if t.name == name:
            return i, t
    raise KeyError(name)

EXPLORE_DEPTH = 30
TRINKET_MINIMUM_VALUE = 60

class Memorizer(Adventurer):
    def enter_ruins(self):
        self.seen = []
        self.plan = []
        self.backups = []
        self.diving = True
        self.dive_grab = False

    def plan_treasure_route(self, state):
        self.plan = []
        self.backups = []
        weight = state.carry_weight
        for treasure in self.seen:
            if weight + treasure.weight <= 50:
                self.plan.append(treasure)
                weight += treasure.weight
            else:
                self.backups.append(treasure)
        room_utility = lambda t: (t.room, t.utility)
        self.plan.sort(key=room_utility, reverse=True)

    def iter_backups(self, state):
        names = {t.name for t in state.treasures}
        owned = {t.name for t in state.inventory}
        for treasure in self.backups:
            if (treasure.room == state.room
                    and treasure.name in names
                    and treasure.name not in owned):
                yield treasure

    def take(self, state, name):
        index, treasure = find_treasure(state.treasures, name)
        if state.carry_weight + treasure.weight > 50:
            raise TooHeavy(name)
        if state.players:
            bid_bonus = self.random.randrange(len(state.players) ** 2 + 1)
        else:
            bid_bonus = 0
        return 'take', index, treasure.weight + bid_bonus

    def get_action(self, state):
        take_chance = 0.9 ** len(state.players)

        if self.diving:
            if self.dive_grab:
                self.dive_grab = False
            else:
                self.seen.extend(
                    TreasureNote(
                        value / weight,
                        weight + math.ceil(weight / 5) * state.room,
                        state.room,
                        name, value, weight
                    )
                    for name, value, weight in state.treasures
                )
            if state.room < EXPLORE_DEPTH:
                if len(state.inventory) < 5:
                    trinkets = [
                        t for t in state.treasures
                        if t.weight == 1
                        and t.value >= TRINKET_MINIMUM_VALUE
                    ]
                    trinkets.sort(key=lambda t: t.value, reverse=True)
                    for candidate in trinkets:
                        if self.random.random() < 0.99 ** (len(state.players) * state.room):
                            try:
                                action = self.take(state, candidate.name)
                            except (KeyError, TooHeavy):
                                pass # WTF!
                            else:
                                self.dive_grab = True
                                return action
                return 'next'
            else:
                self.diving = False
                self.seen.sort(reverse=True)
                self.plan_treasure_route(state)

        carry_weight = state.carry_weight
        if carry_weight == 50:
            return 'previous'

        if self.plan:
            next_index = 0
            next_planned = self.plan[next_index]
            if state.room > next_planned.room:
                return 'previous'

            try:
                while state.room == next_planned.room:
                    if self.random.random() < take_chance:
                        try:
                            return self.take(state, next_planned.name)
                        except (KeyError, TooHeavy):
                            self.plan.pop(next_index)
                            next_planned = self.plan[next_index]
                    else:
                        next_index += 1
                        next_planned = self.plan[next_index]
            except IndexError:
                pass
        else:
            next_planned = TreasureNote(0, 0, 0, 0, 0, 0)

        for candidate in self.iter_backups(state):
            if candidate.utility * 2 > next_planned.utility and self.random.random() < take_chance:
                try:
                    return self.take(state, candidate.name)
                except (KeyError, TooHeavy):
                    pass

        return 'previous'

Bu bot oda 30'a dalar ve gördüğü tüm hazineleri hatırlar. Bu noktada, daha önceki odalarda gördüğünü hatırladığı güzel hazineleri almaya çalışırken, girişine geri dönüyor.

Daha iyi olacağını umuyordum. Muhtemel iyileştirmeler daha iyi planlama ve dalışın hangi odaya girdiği ve yedekleme seçeneklerini keşfetme konusunda daha istekli olmasından daha dinamik olabilir.

Güncelleme: şimdi yolda 60 $ veya daha fazla değer 1kg hazineleri kapmak.


Sanırım tüm bu iyi hazineler, botun oraya geri döndüğü noktadan sonra gitti ... Belki de, sıradan iyi hazineleri alabileceği bir kombo deneyebilirsiniz, vasat hazinenin alabileceği akılda tutulur. geri dönüş yolunda mı?
ArBo

Çok uzaklarda olabilir
Beefster

Bilginize, geri dönmek için yeterli dayanma gücü varsa, bazen yanlış hesaplar gibi görünüyor: [Turn 072] Ryu Ridley (Memorizer) collapsed in the doorway to room #1 and died of exhaustion
Larkeith

1

ponderer

Memorizer'e oldukça benzer olduğunu düşünüyorum, çünkü çıkışa dönerken hangi odaların ve hazinelerin toplanacağını seçmek için ziyaret edilen odaların bilgisini kullanıyor, ancak bağımsız bir şekilde türetilmiş.

Bu bot, yol boyunca bulunan hazinelerin kaydını tutan rastgele bir derin odaya kadar koşar. Bir kez hedef odasında o zaman olacak ponder çıkmak için onun yolu sırtında almaya hazineler İdeal seçimine. Her dönüş düşünecek en iyi hazine seçimini belirlemek için tekrar .

Şu anda, her oda için alınan hazinelerin (ya da bu bot tarafından ziyaret edildiğinde alınmış) sayılan sayıları veren basit bir algoritma (oda numarasının tersi gücü) vardır ve bu nedenle bu hazineler hangi hazinelerin / odaların üzerinde durdukları zaman göz ardı edilir? almak için. Hangi hazinelerin kaldığını modellemek için daha gelişmiş algoritmalar için fikirlerim var. Ancak, faydaya değip değmeyeceğini görmem gerekecek.

import math

class Ponderer(Adventurer):

  class PondererTreasure:
    def __init__(self):
        self.weight = 0
        self.value = 0
        self.id = -1
        pass

  class PondererRoom:
    def __init__(self):
        self.treasures = []
        pass

  def enter_ruins(self):
      self.exiting = False
      self.sprintToRoom = self.random.randrange(30,33)
      self.rooms = {}
      self.roomsToSkip = 0
      pass

  def getBestEstimatedFinalValue(self, roomId, carry_weight, stamina, action, valueCache):
    if (roomId<=0):
      return 0

    roomValueCache = valueCache.get(roomId)

    if (roomValueCache is None):
      roomValueCache = {}
      valueCache[roomId] = roomValueCache

    value = roomValueCache.get(carry_weight)
    if (value is None):
      room = self.rooms.get(roomId)

      bestTreasureValue = 0
      bestTreasure = None
      treasures = []
      treasures.extend(room.treasures)
      skipRoomTreasure = Ponderer.PondererTreasure()
      treasures.append(skipRoomTreasure)

      roomFactor = 0.075*roomId
      estimatedTreasuresTakenAtCurrentRoom =  int(min(0.5 * len(room.treasures), max(1, 0.5 * len(room.treasures)*(1.0/(roomFactor*roomFactor)))))

      j=0
      for treasure in treasures:
        if (j>=estimatedTreasuresTakenAtCurrentRoom):
          staminaAfterBid = stamina - treasure.weight
          carry_weightAfterBid = carry_weight + treasure.weight
          move_costAfterBid = 10 + int(math.ceil(carry_weightAfterBid/5))

          if (carry_weightAfterBid <=50 and (staminaAfterBid/move_costAfterBid > roomId+1)):
            bestAccumulativeValue = self.getBestEstimatedFinalValue(roomId-1, carry_weightAfterBid, staminaAfterBid - move_costAfterBid, None, valueCache)

            if (bestAccumulativeValue >= 0):
              bestAccumulativeValue += treasure.value
              if (bestTreasure is None or bestAccumulativeValue > bestTreasureValue):
                bestTreasureValue = bestAccumulativeValue
                bestTreasure = treasure
        j+=1

      if (bestTreasure == skipRoomTreasure):
        if (action is not None):
          newAction = []
          newAction.append('previous')
          action.append(newAction)
        value = 0

      elif (bestTreasure is not None):
        if (action is not None):
          newAction = []
          newAction.append('take')
          newAction.append(bestTreasure.id)
          newAction.append(bestTreasure.weight)
          action.append(newAction)
        value = bestTreasureValue

      else:
        if (action is not None):
          newAction = []
          newAction.append('previous')
          action.append(newAction)
        value = -1

      roomValueCache[carry_weight] = value
    return value

  def get_action(self, state):
    room = Ponderer.PondererRoom()

    i=0
    for treasure in state.treasures:
      pondererTreasure = Ponderer.PondererTreasure()
      pondererTreasure.weight = treasure.weight
      pondererTreasure.value = treasure.value
      pondererTreasure.id = i

      room.treasures.append(pondererTreasure)
      i+=1

    room.treasures.sort(key=lambda x: x.value/x.weight, reverse=True)

    self.rooms[state.room] = room

    if (self.exiting == False and state.room < self.sprintToRoom):
      return 'next'

    self.exiting = True

    action = []
    valueCache = {}

    self.getBestEstimatedFinalValue(state.room, state.carry_weight, state.stamina, action, valueCache)

    if (action[0][0] == 'take'):
      return 'take', action[0][1], action[0][2]

    return action[0][0]

1

Stokçu

import math

class Hoarder(Adventurer):
  def canGoOn(self, state):
    costToMove = 10 + math.ceil(state.carry_weight / 5)
    return (state.room + 2) * costToMove <= state.stamina

  def canTakeTreasure(self, state, treasure):
    costToMove = 10 + math.ceil(state.carry_weight / 5)
    treasureCost = treasure.weight + 1
    return treasureCost + state.room * costToMove <= state.stamina

  def get_action(self, state):
    if (len(state.treasures) == 0):
      if (self.canGoOn(state)):
        return "next"
      else:
        return "previous"
    else:
      bestTreasure = -1
      for i, treasure in enumerate(state.treasures):
        if self.canTakeTreasure(state, treasure):
          if (bestTreasure == -1):
            bestTreasure = i
          elif state.treasures[bestTreasure].value < state.treasures[i].value:
            bestTreasure = i
      if (bestTreasure == -1):
        return "previous"
      return "take", bestTreasure, state.treasures[bestTreasure].weight+1

İstifçi, odadaki tüm hazineleri alana kadar bir odada kalır (veya devam ettirmek / devam etmek için yeterli dayanıma sahip olmadığını hesaplar). Tüm hazineler gittiğinde, bot güvenli bir şekilde hareket edebiliyorsa, hazinenin tümünü alma sürecine devam edecektir.


Bu, her oyuna sırt çantasını doldurarak ölür.
Beefster

Benim gibi Minecraft'ta (͡ ° ͜ʖ ͡ °) Bu bot yağacak, daha derine inecek ve daha sonra değerli yağma bulacaktır. Böylece daha önce ganimetin iyi olduğunu düşündüğü şeyi bırakacak. Bu yüzden Backwards, Sprinter'nin ve Memorizerstratejisinin çalışması; Çünkü gördükleri her hazinenin nispi değerlerinin ne olduğunu biliyorlar.
V. Courtois

0

Dalgıç

(Şu anda test edemiyorum, bu yüzden eğer kırılırsa bana bildirin.)

class Diver(Adventurer):
    def get_action(self, state):
        # Don't take anything on the way in.
        if state.stamina > 700:
            return 'next'

        # Take the most valuable thing we can take without dying.
        for treasure in sorted(state.treasures, key=lambda x: x.value, reverse=True):
            total = treasure.weight + state.carry_weight
            if total <= 50 and (10 + (total + 4) // 5) * state.room + treasure.weight <= state.stamina:
                return 'take', state.treasures.index(treasure), treasure.weight

        # If there's nothing else we can do, back out.
        return 'previous'

En iyi hazine kalıntıların derinliklerinde daha derin, çok derinlere dalın, sonra dışarı çıkabileceğimizi alın.


Python ile pek tecrübeli değilim ama nerede divingtanımlanıyor?
Cehalet

1
@EmbodimentofIgnorance Oyun çalıştırılmadan ve çağrılmadan önce çağrılan enter_ruins () 'da.

Jacob the Orphan (Diver) was sliced in half by a swinging blade trap.Neyi yanlış yaptığınızdan emin değilsiniz, ancak bu 'geçersiz iade' olan AFAIK.
Artemis,

@ ArtemisFowl hazine için çok düşük bir teklif verdi. Almak için hazine ağırlığına mal olur.
Beefster

@ Beefster Ah evet.
Artemis,
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.