นักผจญภัยในซากปรักหักพัง


27

คนขับทดสอบอภิปรายการท้าทายส่งนักผจญภัย

ห้องสมบัติ ( แหล่งรูปภาพ )

นักผจญภัยคู่ต่อสู้หลายคนกำลังบุกหาซากปรักหักพังเพื่อหาสมบัติ แต่พวกเขาสามารถบรรทุกได้ครั้งละมากและมีข้อ จำกัด ด้านความอดทน พวกเขาต้องการได้รับสมบัติที่มีค่าที่สุดและออกไปก่อนที่พวกเขาจะเหนื่อยเกินไปที่จะดำเนินการต่อ พวกเขาพยายามที่จะเป็นคนรวยที่สุดเท่าที่จะทำได้จากการขโมยของ shenanigans

เพลย์

นักผจญภัยแต่ละคนจะเริ่มในห้องแรกของดันเจี้ยนที่มี 1,000 คะแนนความแข็งแกร่งและพื้นที่ 50 กก. ในกระเป๋าเป้สะพายหลังของพวกเขา

เกมดังกล่าวทำงานในแบบเทิร์นเบสโดยผู้เล่นทุกคนสามารถแก้ไขผลัดกันได้ในเวลาเดียวกัน ในแต่ละเทิร์นคุณสามารถทำสิ่งใดสิ่งหนึ่งต่อไปนี้:

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

การย้ายระหว่างห้องต้องใช้ความแข็งแกร่ง 10 อย่างบวก 1 สำหรับทุกๆ 5 กิโลกรัมในกระเป๋าเป้ของคุณ ตัวอย่างเช่นนักผจญภัยที่มีสมบัติ 3 กิโลกรัมต้องใช้ความแข็งแกร่ง 11 ระดับในการเคลื่อนย้ายและน้ำหนัก 47 กิโลกรัมหนึ่งตัวต้องใช้ความแข็งแกร่ง 20 ชิ้นในการเคลื่อนย้าย

การทิ้งสมบัติต้องใช้ 1 ความแข็งแกร่งโดยไม่คำนึงถึงสมบัติที่ลดลง

เมื่อออกจากซากปรักหักพังผู้เล่นจะไม่ถูกเลี้ยวอีกต่อไป

หากผู้เล่นไม่สามารถดำเนินการใด ๆ เหล่านี้ได้ (เนื่องจากการขาดความแข็งแกร่งหรือขาดสมบัติ) นักผจญภัยของพวกเขาจะเสียชีวิตจากความเหนื่อยล้าทะลักสมบัติที่ถือไว้ในห้องที่ถูกครอบครองในปัจจุบัน ในทำนองเดียวกันหากผู้เล่นพยายามกระทำที่ไม่ถูกต้องนักผจญภัยของพวกเขาจะถูกฆ่าโดยกับดักแทนทำให้เกิดการรั่วไหลของสมบัติเดียวกัน

คำสั่ง

การเสนอราคาขั้นต่ำสำหรับขุมทรัพย์คือ 1 เรี่ยวแรงต่อ 1 กิโลกรัมที่สมบัติมีน้ำหนัก คุณอาจเสนอราคาคะแนนความแข็งแกร่งเพิ่มเติมเพื่อให้ได้รับสมบัติ ความแข็งแกร่งที่ถูกเสนอราคาถูกใช้ไปไม่ว่าผลลัพธ์จะออกมาเป็นอะไร

ในกรณีที่ผู้เล่นหลายคนมีการเสนอราคาเพื่อใช้สมบัติเดียวกันผู้เล่นที่เสนอราคาสูงสุดจะได้รับสมบัติ หากผู้เล่นมากกว่าหนึ่งคนทำการเสนอราคาสูงสุดจะไม่มีใครได้รับสมบัติ

เงื่อนไขการชนะ

ผู้เล่นที่มีมูลค่ารวมมากที่สุดคือผู้ชนะ ในกรณีที่ไม่เสมอกันเสมอไปที่น้ำหนักรวมที่น้อยที่สุดจากนั้นจำนวนของสมบัติที่น้อยที่สุดจากนั้นให้มูลค่าของสมบัติที่มีค่าที่สุดที่มีค่ามากที่สุดที่สองที่มีค่าที่สามที่สาม ... จนกว่าเน็คไทจะเสีย ในเหตุการณ์ที่ใกล้เป็นไปไม่ได้ที่ยังมีการผูกกัน ณ จุดนี้ผู้ขับทดสอบบอกว่า "ขันมัน" และผู้ชนะจะถูกตัดสินโดยพลการ

ในบริบทของทัวร์นาเมนต์ผู้เล่นจะได้รับอันดับที่ 1 ซึ่งได้รับ 10 คะแนนอันดับที่สองที่มี 9 คะแนนอันดับที่สามกับ 8 คะแนนและอื่น ๆ ... โดยผู้เล่นที่ตายแล้วและนักผจญภัยที่ไม่มีขุมทรัพย์ให้คะแนน 0 คะแนน

เกี่ยวกับซากปรักหักพัง

  • ห้องพักแต่ละห้องแรกมีระหว่างR3+3และR2+5สมบัติ (โดยที่Rคือหมายเลขห้อง)
  • มีหลายห้องโดยพลการ จำกัด โดยความแข็งแกร่งของนักผจญภัยและความเต็มใจที่จะสำรวจ
  • แต่ละขุมทรัพย์จะมีมูลค่าเป็นเงิน (เป็นเงินทั้งหมด) และน้ำหนัก (เป็นกิโลกรัมทั้งหมด)
    • สมบัติมีค่ามากกว่าและมีอยู่มากมายเมื่อคุณเข้าไปในซากปรักหักพัง
  • สูตรเฉพาะสำหรับการสร้างสมบัติมีดังนี้ (ใช้xdYสัญกรณ์สำหรับลูกเต๋าม้วน)
    • น้ำหนักถูกสร้างขึ้นครั้งแรกโดยใช้สูตร2d6-2 (ขั้นต่ำ 1)
    • ค่าสมบัติจะถูกสร้างผ่าน1d[10* * * *W]+2d[5* * * *R+10] (โดยที่Rคือหมายเลขห้องและWคือน้ำหนัก)

ข้อมูลที่ปรากฏแก่ผู้เล่น

ในแต่ละเทิร์นผู้เล่นจะได้รับข้อมูลต่อไปนี้:

  • จำนวนห้องที่พวกเขาอยู่ในปัจจุบันนี่คือ 1 ดัชนีดังนั้นแนวคิดทางออกอยู่ที่ "ห้อง 0"
  • รายการสมบัติที่อยู่ในห้องในขณะนี้
  • รายชื่อผู้เล่นคนอื่น ๆ ที่อยู่ในห้องด้วย
  • คลังสมบัติปัจจุบันของคุณ
  • ระดับความแข็งแกร่งของคุณในปัจจุบัน

การเข้ารหัส

ขับทดสอบที่สามารถพบได้ที่นี่

คุณควรใช้คลาสย่อยของคลาสนี้Adventurer:

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

คุณจะต้องแทนที่get_actionวิธีการ enter_ruinsทำงานก่อนที่เกมจะเริ่มต้นขึ้นและเป็นโอกาสของคุณในการเตรียมสิ่งที่คุณต้องการให้พร้อมสำหรับเกม คุณไม่จำเป็นต้องแทนที่__init__และคุณไม่ควร หาก__init__เกิดปัญหาของคุณคุณจะถูกตัดสิทธิ์

get_actionรับอาร์กิวเมนต์เดี่ยวซึ่งเป็นnamedtupleฟิลด์ต่อไปนี้ (ตามลำดับนี้หากคุณต้องการทำลาย):

  • room: จำนวนห้องที่คุณอยู่ในปัจจุบัน
  • treasures: รายการสมบัติในห้อง
  • players: รายชื่อผู้เล่นอื่นในห้อง คุณได้รับชื่อผู้เล่นด้วยวิธีนี้เท่านั้นดังนั้นคุณจึงไม่ทราบว่าบอทควบคุมอะไรหรือคลัง / ความแข็งแกร่งของพวกเขา
  • inventory: รายการสมบัติในกระเป๋าเป้ของคุณ
  • stamina: ระดับความแข็งแกร่งในปัจจุบันของคุณ

วัตถุนี้ยังให้คุณสมบัติของอรรถประโยชน์สองอย่างเพิ่มเติม:

  • carry_weight: น้ำหนักรวมของขุมทรัพย์ทั้งหมดที่คุณกำลังบรรทุก
  • total_value: มูลค่ารวมของสมบัติทั้งหมดที่คุณกำลังถือ

treasuresและinventoryรายการประกอบด้วยnamedtuples ด้วยคุณสมบัติเหล่านี้:

  • name: ชื่อสมบัติ (เพื่อความสวยงาม)
  • value: มูลค่าทางการเงินของสมบัติเป็น $
  • weight: น้ำหนักของสมบัติเป็นกิโลกรัม

get_action ควรคืนหนึ่งในค่า / รูปแบบต่อไปนี้:

  • 'next'หรือ'previous'เพื่อย้ายไปยังห้องถัดไป / ก่อนหน้า
  • 'take', <treasure index>, <bid>(ใช่เป็นทูเปิลถึงแม้ว่าลำดับใด ๆ ในทางเทคนิคจะทำงานได้ดีเช่นกัน) เพื่อเสนอราคาสมบัติที่ดัชนีที่กำหนดในรายการสมบัติของห้อง อาร์กิวเมนต์ทั้งสองควรเป็นจำนวนเต็ม ลอยจะถูกปัดเศษลง
  • 'drop', <inventory index>เพื่อทิ้งสมบัติที่หาได้ที่ดัชนีที่กำหนด ดัชนีควร (ตามธรรมชาติ) เป็นจำนวนเต็ม

ข้อ จำกัด อื่น ๆ

  • คุณสามารถใช้อินสแตนซ์แบบสุ่มที่ให้ไว้กับคุณในระหว่างการเริ่มต้นสำหรับการสุ่มหลอกเท่านั้น
    • ไม่อนุญาตให้มีสิ่งอื่นใดที่อาจนำไปสู่ ความตั้งใจที่นี่คือการทำให้บอททำงานเหมือนกันเมื่อได้รับเมล็ดเดียวกันเพื่อช่วยในการทดสอบบอตใหม่ (และอาจเป็นข้อบกพร่องในโปรแกรมควบคุมการทดสอบ) เฉพาะรังสีคอสมิกควรทำให้เกิดการเบี่ยงเบน / nondeterminism ใด ๆ
    • โปรดทราบว่ารหัสแฮชจะถูกสุ่มใน Python 3 ดังนั้นจึงhashไม่อนุญาตให้ใช้สำหรับการตัดสินใจใด ๆ dicts ใช้ได้แม้เมื่อใช้คำสั่งวนซ้ำเพื่อการตัดสินใจเนื่องจากรับประกันการสั่งซื้ออย่างสม่ำเสมอตั้งแต่ Python 3.6
  • คุณไม่สามารถหลีกเลี่ยงการใช้ไดรเวอร์ทดสอบโดยใช้ctypesแฮ็กหรือinspectสแต็ควูดู (หรือวิธีอื่นใด) มีบางสิ่งที่น่ากลัวอย่างน่าประทับใจที่คุณสามารถทำได้กับโมดูลเหล่านั้น โปรดอย่า
    • บอทแต่ละบ็อกซ์นั้นมีเหตุผลที่ดีในการป้องกันการคัดลอกและความไม่เปลี่ยนแปลงตามธรรมชาติของnamedtuples แต่ก็มีช่องโหว่ / ช่องโหว่ที่ไม่สามารถจับคู่ได้
    • ฟังก์ชั่นอื่น ๆ จากinspectและctypesอาจใช้งานได้ตราบใดที่ไม่ใช้เพื่อหลีกเลี่ยงการทำงานของคอนโทรลเลอร์
    • ไม่อนุญาตให้ใช้วิธีการจับอินสแตนซ์ของบ็อตอื่นในเกมปัจจุบันของคุณ
  • บอตควรดำเนินงานเดี่ยวและไม่สามารถประสานงานกับบ็อตอื่น ๆ ไม่ว่าด้วยวิธีใด ๆ ซึ่งรวมถึงการสร้างสองบอทโดยมีเป้าหมายที่แตกต่างกันเช่นที่หนึ่งเสียสละตัวเองเพื่อความสำเร็จ เมื่อมีคู่แข่งมากกว่า 10 รายคุณจะไม่ได้รับการรับรองว่ามีบอทสองตัวในเกมเดียวกันและชื่อนักผจญภัยไม่ได้บ่งบอกคลาสบ็อตดังนั้นกลยุทธ์ประเภทนี้จึง จำกัด
  • ขณะนี้ไม่มีการ จำกัด เวลาในการดำเนินการอย่างหนัก แต่ฉันขอสงวนสิทธิ์ในการ จำกัด การใช้ในอนาคตหากการแข่งขันเริ่มต้นใช้เวลานานเกินไป มีเหตุผลและพยายามที่จะประมวลผลเทิร์นต่ำกว่า 100msเนื่องจากฉันไม่คิดว่าจะต้อง จำกัด ไว้ต่ำกว่าเกณฑ์นั้น (ทัวร์นาเมนต์จะใช้เวลาประมาณ 2 ชั่วโมงหากบอตทั้งหมดใช้เวลาประมาณ 100ms ต่อเทิร์น)
  • คลาสบอตของคุณจะต้องมีชื่อไม่ซ้ำกันในทุกการส่ง
  • คุณไม่สามารถจำอะไรได้ระหว่างเกม (อย่างไรก็ตามคุณสามารถจดจำสิ่งต่าง ๆ ระหว่างรอบได้ )
    • อย่าแก้ไข sys.modules ตัวแปรอินสแตนซ์ที่อยู่นอกสิ่งใดควรถูกถือว่าเป็นค่าคงที่
  • คุณไม่สามารถแก้ไขโค้ดของบ็อตใด ๆ โดยทางโปรแกรมรวมถึงของคุณเอง
    • ซึ่งรวมถึงการลบและกู้คืนรหัสของคุณ นี่คือการทำให้การดีบักและการแข่งขันมีความคล่องตัวยิ่งขึ้น
  • รหัสใด ๆ ที่ทำให้ตัวควบคุมล้มเหลวจะถูกตัดสิทธิ์ทันที ในขณะที่ข้อยกเว้นส่วนใหญ่จะถูกจับบางคนอาจผ่านไปและ segfaults ไม่สามารถจับได้ (ใช่คุณสามารถใช้ segfault ใน Python ได้ด้วยctypes)

การส่ง

เพื่อช่วยในการคัดคำตอบให้ระบุชื่อของบอทของคุณที่ด้านบนของคำตอบด้วย#Header1และตรวจสอบให้แน่ใจว่าคำตอบของคุณมีรหัสบล็อกอย่างน้อยหนึ่งบล็อก คุณไม่จำเป็นต้องรวมการนำเข้าหรือเอกสารใด ๆ เนื่องจากมีดโกนจะถูกเพิ่มโดยอัตโนมัติ

ฉันจะมีแนวโน้มที่จะถอนคำตอบมากขึ้นด้วยคำอธิบายที่ละเอียดและเข้าใจง่าย คนอื่น ๆ มีแนวโน้มที่จะประพฤติตัวเหมือนกัน

คำตอบของคุณควรมีรูปแบบดังนี้:

# Name of Bot
Optional blurb

    #imports go here

    class BotName(Adventurer):
        #implementation

Explanation of bot algorithm, credits, etc...

(แสดงผลเป็น)

ชื่อ ธ ปท

ประกาศแจ้งทางเลือก

#imports go here

class BotName(Adventurer):
    #implementation

คำอธิบายของอัลกอริทึม bot เครดิต ฯลฯ ...

เรียกใช้การทดสอบไดรเวอร์ในเครื่อง

คุณจะต้องใช้ Python 3.7+ และฉันแนะนำให้คุณติดตั้งtabulateผ่าน pip ขูดหน้านี้สำหรับการส่งนอกจากนี้ยังต้องและlxml requestsคุณควรใช้เทอร์มินัลพร้อมรองรับ ANSI color escapes เพื่อผลลัพธ์ที่ดีที่สุด ข้อมูลเกี่ยวกับวิธีการตั้งค่านี้ใน Windows 10 สามารถพบได้ที่นี่

เพิ่มบ็อตของคุณไปยังไฟล์ในไดเรกทอรีย่อยภายในไดเรกทอรีเดียวกันกับruins.py( ruins_botsโดยค่าเริ่มต้น) และอย่าลืมเพิ่มfrom __main__ import Adventurerไปที่ด้านบนของโมดูล นี้จะถูกเพิ่มโมดูลเมื่อมีดโกนดาวน์โหลดส่งของคุณและในขณะที่มันเป็น hacky แน่นอนนี้เป็นวิธีที่ตรงไปตรงมามากที่สุดของการทำให้แน่ใจว่า ธ Adventurerปทคุณอย่างถูกต้องมีการเข้าถึง

บอตทั้งหมดในไดเรกทอรีนั้นจะถูกโหลดแบบไดนามิกเมื่อรันไทม์ดังนั้นไม่จำเป็นต้องทำการเปลี่ยนแปลงเพิ่มเติม

การแข่งขัน

ผู้ชนะเลิศจะได้รับการพิจารณาในชุดของเกมที่มีมากถึง 10 บอทในแต่ละเกม หากมีการส่งมากกว่า 10 รายการบอท 10 อันดับแรกจะถูกกำหนดโดยแบ่งพาร์ติชันเป็น 10 กลุ่มอย่างเป็นระบบจนกว่าบอททุกเกมจะเล่น (ตรง) 20 เกม บอท 10 อันดับแรกจะถูกเลือกจากกลุ่มนี้ด้วยคะแนนรีเซ็ตและจะเล่นเกมจนกว่าบอทแรกจะได้รับแต้ม 50 แต้มเหนือบอทที่สองหรือจนถึง 500 เกมที่เล่น

จนกว่าจะมีการส่งอย่างน้อย 10 ครั้งช่องว่างจะเต็มไปด้วย "Drunkards" ซึ่งเดินสุ่มผ่านซากปรักหักพังและนำสมบัติสุ่ม (และบางครั้งทิ้ง) จนกว่าพวกเขาจะวิ่งออกจากความแข็งแกร่งและต้องตรงไปที่ทางออก

การแข่งขันจะเริ่มใหม่ทุกสัปดาห์หากมีการส่งใหม่ นี่เป็นความท้าทาย KOTH แบบเปิดโดยไม่มีวันที่สิ้นสุด

ลีดเดอร์บอร์ด

ตั้งแต่วันที่ 4 พฤษภาคม 2019 เวลา 16:25 นพ MDT: (2019-05-04 4:25 -6: 00)

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

อัปเดต - 15 เมษายน: การอัปเดต / การชี้แจงกฎสองข้อ

อัปเดต - 17 เม.ย. : ห้ามไม่ให้มีคดีขอบสองสามคดีที่น่ารังเกียจเช่นการแก้ไขโค้ดของบอทอื่น ๆ

อัพเดท - 4 พฤษภาคม: มอบรางวัลให้กับ Sleafar สำหรับทำลายย้อนหลังอย่างแน่นอน ขอแสดงความยินดี!


1
ในที่สุดมันก็มาถึงที่นี่! เดาฉันจะต้องเริ่มต้นสร้างบอทของฉันตอนนี้
Belhenix

12
ทำไมถึงขีด จำกัด หนึ่งบอท ฉันมีความคิดพิเศษร่วมกันหลายประการและฉันก็ไม่จำเป็นต้องโยนบอทที่ดีเลิศออกมาในแต่ละครั้งที่ฉันคิดใหม่

@Monemonic ส่วนใหญ่เป็นการป้องกันการแทนที่การส่งใหม่โดยใช้บอทใกล้เคียงหลาย ๆ ชุด อีกเหตุผลหนึ่งก็คือเพื่อป้องกันไม่ให้บอททำงานร่วมกัน แต่ถูกห้ามอย่างชัดเจน ฉันจะพิจารณาอนุญาต ผู้ที่อนุญาตให้มีการส่งหลายรายการขึ้นความคิดเห็นของ Mnemonic ด้านบน
Beefster

1
@ Draco18s หากคุณได้pipติดตั้งและเปิดPATH(ซึ่งเป็นค่าเริ่มต้นสำหรับการติดตั้งใหม่ AFAIK) จากนั้นคุณสามารถเรียกใช้pip install modulenameในพรอมต์คำสั่ง สำหรับสถานการณ์อื่น ๆ (ซึ่งฉันไม่รู้) ไปที่pipค้นหาโมดูลที่ต้องการและเลือกตัวเลือก
อาร์ทิมิสรองรับโมนิก้า

1
ฉันเดาว่านี่จะเป็น 'ไม่' แต่เราได้รับอนุญาตให้บันทึกข้อมูลผ่านการแข่งขันหรือไม่? (เช่นเมื่อการประมูลทำงาน)
อาร์ทิมิสสนับสนุนโมนิก้า

คำตอบ:


5

นักบัญชี

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'

นักบัญชีเป็นคนที่ไม่ชอบความเสี่ยงมาก เขาชอบที่จะทำให้แน่ใจว่าสิ่งที่เขาทำคือตัวเลือกที่ดีที่สุดในสถานการณ์ที่กำหนด ดังนั้นเขาจึงตั้งเป้าหมายและรับค่าสมบัติหากการคำนวณของเขาแสดงให้เห็นว่าสิ่งนี้ทำให้เขาไปสู่เป้าหมายที่ถูกต้อง อย่างไรก็ตามเขามีระบบราชการมากและไม่ชอบวางสิ่งของที่เขาตัดสินใจแล้วว่าเขาต้องการ; ความพยายามใด ๆ ในการสอนให้เขาทำเช่นนั้นได้ส่งผลให้นักบัญชีทิ้งรายการแล้วหยิบขึ้นมาอีกครั้งในภายหลัง

อาจเป็นไปได้ที่จะดำเนินการต่อ


1
งานที่ดีกำหนดมูลค่าสมบัติ ฉันมีความคิดที่จะเขียนรหัสที่ดีกว่า "มันคุ้มค่า" หรือไม่ แต่ยังไม่ได้ไปถึง วายร้ายกำลังจะมาถึงจุดต่ำสุดของนักบัญชีแม้ว่า ...
Draco18s

"ความพยายามใด ๆ ในการสอนให้เขาทำเช่นนั้นจนถึงตอนนี้ส่งผลให้นักบัญชีทิ้งรายการแล้วหยิบขึ้นมาอีกครั้งในภายหลัง". คุณสามารถทำสิ่งนี้ได้โดยเก็บชื่อของสมบัติที่หล่นไว้ ฉันมีความรู้สึกว่าชื่อสมบัติจะมีประโยชน์ (แม้ว่าตอนนี้พวกเขาจะถูกนับหมายเลข)
Beefster

ขอบคุณ แต่ฉันคิดแล้วว่าทำไมมันถึงเกิดขึ้น ไม่ทราบว่าฉันจะแก้ไขได้ทันทีแม้ว่าเขาจะไม่ค่อยได้ใช้เมื่อฉันทดสอบวางไว้
ArBo

2

Accomodator

อิงตามบ็อต LightWeight อื่น ๆ ของฉันอย่างหลวม ๆ ที่ซึ่ง LightWeight bot นั้นเรียบง่ายบอทนี้มีความซับซ้อนกว่ามากในการรองรับการโต้ตอบกับบอทอื่น ๆ : ทั้งอ่อนโยนและผิดเพี้ยนโดยเจตนา

บอทนี้จะวิ่งไปที่ห้องสุ่มที่ได้รับมอบหมายก่อนจากนั้นจะพยายามประมูลสมบัติอัตราส่วน / น้ำหนักที่ดีที่สุดหากมีผู้เล่นคนอื่นในห้องสันนิษฐานว่าพวกเขาจะเสนอราคาแทนสมบัติที่ดีที่สุดอันดับสอง หากการเสนอราคานั้นล้มเหลวให้เปิดการประมูลครั้งถัดไปเพื่อหาสมบัติที่ดีที่สุดต่อไป

เมื่อการเสนอราคาสำเร็จให้ทำซ้ำการเสนอราคาที่ดีที่สุด / ที่สองที่ดีที่สุดจนกว่าจะไม่มีสมบัติอยู่ในห้องจากนั้นย้ายเข้าไปในซาก

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

เมื่ออยู่ในสถานะออกเราจะตรวจสอบเพื่อดูว่าเราสามารถเพิ่มสมบัติ 1 กิโลกรัมและยังทำให้มันมีชีวิตอยู่ได้ถ้าเป็นเช่นนั้นเราจะพยายามเสนอราคาสมบัติ 1 กิโลกรัมถ้าไม่เราจะมุ่งหน้าไปยังห้องก่อนหน้า

ประสิทธิภาพของมันค่อนข้างแปรผัน ... แต่โดยปกติจะเป็นหนึ่งในสามบอทอันดับต้น ๆ

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'

ที่น่าประทับใจ! คนนี้มีอำนาจเหนือการแข่งขันในรอบ 50
Beefster

2

ผู้วิ่งแข่ง

คล้ายกับนักประดาน้ำ Sprinter เข้าไปลึกและหยิบไอเท็มที่ดีที่สุดระหว่างทาง

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

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

ฉันยังคงมีข้อดี 2 ข้อเกี่ยวกับ "การต่อสู้เพื่อสมบัติ" ที่วางแผนไว้สำหรับวันต่อไป

17.04: คนใจร้ายฉลาดเกินไป Sprinter ตัดสินใจผลักเขาเข้ากับดักในตอนแรกฉันต้องการฆ่าบอทที่พยายามเรียกสปรินท์ แต่ผู้ทดสอบไม่ได้จัดการกับข้อยกเว้นที่เกิดขึ้น ดังนั้นการแก้ไขต่อไปสำหรับ Scoundrel ค่อนข้างง่าย ...


การฆ่าวายร้ายกำลังทำงานอยู่ ...
AKroell

2

วางแผนล่วงหน้า

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

ธ ปท. ผจญภัยลึกเท่าที่คิดว่าปลอดภัยพอสมควร (การคำนวณนี้ทำได้อย่างมีประสิทธิภาพในการดำน้ำลึกที่เฉพาะเจาะจง แต่มีความยืดหยุ่นในการจัดการค่าความแข็งแกร่งเริ่มต้นอื่น ๆ ) รวบรวมวัตถุ (จัดลำดับความสำคัญสูงและน้ำหนักต่ำ) เริ่มถอยเมื่อกำหนดว่ามันไม่สามารถดำเนินการได้อีกต่อไป

ระหว่างทางออกมันจะไปรับสมบัติเพิ่มเติมใด ๆ ที่เห็นว่าเป็นตัวกำหนดว่ามันยังสามารถพาไปยังทางออกได้อย่างปลอดภัย มันจะวางสิ่งประดิษฐ์ที่มีอยู่แล้วถ้าสิ่งใหม่เป็นข้อตกลงที่ดีกว่าและจะไม่ส่งผลให้หมดแรง หากมีที่ว่างในกระเป๋าเป้สะพายหลังมันจะเลือกสมบัติใหม่ขึ้นมาก่อนที่จะทิ้งที่มีคุณภาพต่ำลงลดการต่อสู้กับบอทอื่น ๆ


หืมเมื่อคุณอธิบายมันเป็นเช่นเดียวกับฉัน ฉันจะเล่นกับตัวเลขของฉัน ... หมายเหตุ: __init__ฟังก์ชั่นนี้ได้รับการติดตั้งใช้งานแล้วคุณไม่จำเป็นต้องแทนที่มัน
อาร์ทิมิสสนับสนุนโมนิก้า

ขอให้เรายังคงอภิปรายนี้ในการแชท
Draco18s

2

Artyventurer

เอาชนะพวกขี้เมาประมาณ $ 1,000! ไม่สามารถนึกชื่อสร้างสรรค์ได้ แต่ที่นี่คือ:

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'

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

คำอธิบาย

  • if state.inventory ... worsti = None
    ค้นหารายการ 'ที่เลวร้ายที่สุด' ในพื้นที่โฆษณานั่นคือรายการที่มีอัตราส่วนต่ำที่สุดต่อน้ำหนัก มันเก็บworstiซึ่งมีดัชนีของมันเป็นค่าและน้ำหนักเป็น tuple หรือNoneหากไม่มีรายการในสินค้าคงคลัง

  • if self.drop ... return 'drop', worsti[0]
    ถ้าผมบอกว่ามันจะลดลงเทิร์นนี้เปิดที่ผ่านมา (ดูด้านล่าง) และมันสามารถวางรายการ 'เลวร้ายที่สุดตามที่คำนวณข้างต้น

  • extra = ... * state.room
    คำนวณความแข็งแกร่งที่เหลืออยู่ถ้าฉันบอกให้ย้อนกลับไปตอนนี้

  • if extra > CONTINUE_IN:\ return 'next'
    ถ้ามันมากกว่า CONTINUE_IN 'next'กลับ

  • if extra < 0 and worsti:\ return 'drop', worsti[0]
    หากน้อยกว่า0ให้ดรอปไอเท็มที่แย่ที่สุด

  • if extra < state.room:\ return 'previous'
    ถ้ามันน้อยกว่าหมายเลขห้อง (ไม่สามารถพกพาสมบัติได้อีก) ให้ย้อนกลับไป

  • if state.treasures: ... bestt = None
    หาสมบัติที่ดีที่สุดที่จะนำไปใช้ซึ่งคล้ายกับรายการที่แย่ที่สุดในคลังด้านบน besttเก็บไว้ใน

  • if extra > 0 and bestt: ... return 'take', bestt[0], bid
    ด้วยตัวเลขปัจจุบันนี้จะดำเนินการเมื่อใดก็ตามที่เรามีมาไกลขนาดนี้และมีสมบัติที่เป็นประโยชน์ หากปลอดภัยที่จะรับสมบัติที่ดีที่สุดก็จะทำได้ มันคือการเสนอราคาขั้นต่ำหรือมากกว่านั้นถ้ามีใครอยู่

  • if bestt and worsti: ... return 'take', bestt[0], bid
    ด้วยหมายเลขปัจจุบันบล็อกโค้ดนี้จะไม่ทำงานเนื่องจากบล็อคโค้ดก่อนหน้ามีเงื่อนไขที่กว้างกว่า สิ่งนี้จะดำเนินการถ้าเราได้มาไกลขนาดนี้และมีทั้งสมบัติ / s ในสินค้าคงคลังและห้องของฉัน หากสมบัติ 'ที่ดีที่สุด' ในห้องนั้นมีค่ามากกว่าสมบัติ 'ที่เลวร้ายที่สุด' ในสินค้าคงคลังของฉันและมันจะปลอดภัยที่จะแลกเปลี่ยนพวกเขาในอีกสองรอบถัดไปมันจะทำเช่นนั้น

  • return 'previous'
    หากไม่มีสิ่งเหล่านี้เกิดขึ้นเพียงย้อนกลับไป

อัปเดต 16/04/19:

มาตรการต่อต้านการหลอกลวง นี่จะกลายเป็นสงครามการเสนอราคา :(

อัพเดทเพิ่มเติม 16/04/19:

เปลี่ยนกลับก่อนหน้านี้ แต่จะสุ่มสลับองค์ประกอบอื่น ๆ ทุกครั้งเมื่อค้นหาสิ่งที่ดีที่สุดเช่น [1, 2, 3, 4, 5, 6] → [2, 1, 3, 4, 6, 5]. ควรคัดลอกยากกว่า :)

อัปเดต 17/04/19:

ย้อนกลับก่อนหน้า แต่จะลบล้างซอร์สโค้ดของตัวเองแทน มันทำเช่นนี้__init__ซึ่งจะเป็นมาก่อนเสมอScoundrel.enter_ruinsและจะหยุด Scoundrel ไม่ให้ทำการโหลด มันจะแทนที่รหัสเมื่อget_actionถูกเรียกครั้งแรกเพื่อที่จะพร้อมในครั้งต่อไป แก้ไขแล้ววายร้ายในขณะนี้เสียชีวิตเมื่อเดินทางมาถึง

อัพเดทเพิ่มเติม 17/04/19:

เปลี่ยนกลับก่อนหน้านี้ แต่จะแทนที่sys.modulesรายการด้วยโมดูลคณิตศาสตร์ดังนั้นเมื่อ Scoundrel พยายามโหลดมันจะโหลดโมดูลคณิตศาสตร์แทน :)
นอกจากนี้ฉันเพิ่งรู้ว่าความแข็งแกร่งในการเคลื่อนไหวคือ 10 + น้ำหนัก/ 5ดังนั้นพยายามแก้ไขมัน

อัพเดทเพิ่มเติม 17/04/19:

ตอนนี้มีกระเทียมจากทั้งการอัพเดทก่อนหน้า

อัปเดต 18/04/19:

เล่นกับตัวเลขและการคำนวณตอนนี้ได้รับ $ 2,000 - $ 3,000

อัพเดทเพิ่มเติม 18/04/19:

นำกระเทียมเช็ดไฟล์ออกเมื่อถูกแบนเพิ่มกระเทียมใหม่ซึ่งทำให้แน่ใจว่า'draco'จะไม่รับผิดชอบต่อการทำงานหากเป็นเพียงแค่ส่งคืนpreviousในเทิร์นแรก ผลลัพธ์มีการดำน้ำลึกลับถึง $ 1,200 - $ 1800 ซึ่งฉันกำลังมองหา


ดูเหมือนจะมีประสิทธิภาพมากกับคนขี้เมาฉันอยากจะดูว่ามันเป็นยังไงเมื่อบอทคนอื่น ๆ เข้าร่วมการจู่โจม :)
Moogie

@Mogogie Beats Diver ประมาณ $ 100 เมื่อมี 8 Drunkards อยู่ด้วย
อาร์ทิมิสสนับสนุนโมนิก้า

2

ตัววายร้าย

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 ส่วนใหญ่ทำงานเพื่อแทรกแซงผู้เข้าแข่งขันคนอื่น ๆ ขณะนี้มันรบกวน Sprinter, Artyventurer และนักบัญชี (รายการนี้จะเพิ่มขึ้นเมื่อเวลาผ่านไปหากอยู่ในความสนใจที่ดีที่สุดของ Scoundrel) มันทำได้โดยการเลียนแบบบ็อตอื่นและจากนั้นออกประมูล, ตัดต่ำ, หรือต่อสู้กับพระธาตุ ดังนั้นจึงไม่น่าเป็นไปได้ที่รายการนี้จะครองกระดานผู้นำและดำเนินการแทนกองกำลังที่เสียหาย การแก้ไขปัจจุบัน ณ เวลาที่ทำการโพสต์นี้อยู่ในอันดับที่ 2 โดยมีคะแนนเฉลี่ยประมาณ 7

Scoundrel ขัดขวางความพยายามของบอทคนอื่นในการแก้ไขตัวเองเพื่อป้องกัน Scoundrel โดยรันโค้ดของผู้เข้าแข่งขันคนอื่นโดยตรงเพื่อคัดลอกโคลนนิ่งที่แยกไม่ออก ปัญหาเกี่ยวกับการนำเข้าที่ทำให้ผู้เข้าแข่งขันซ้ำได้รับการแก้ไขผ่านการสร้างโคลนผ่านการสะท้อน (แก้ไขสงครามที่เกี่ยวข้องกับรายละเอียดทางคณิตศาสตร์อย่างละเอียดไม่เป็นที่ต้องการจากมุมมองการแลกเปลี่ยนแบบสแต็ก แต่จะส่งผลเหมือนกัน) ความท้าทายของ KOTH นั้นมีประวัติการอนุญาตเช่นนี้เช่นกัน

Scoundrel แทนที่ Teamsters เพื่อให้ Teamsters นั้นมีความน่าสนใจ หลังจากแก้ไขนี้คนขับรถบรรทุกไม่ควรถูกคัดลอกโดยผู้ควบคุมอีกต่อไป

อัปเดต 4/17/2019: มาตรการตอบโต้เคาน์เตอร์เพิ่มเติม

The Teamsters (แสดงผิดกฎหมาย)

แต่อย่าลังเลที่จะวิ่งในพื้นที่ที่มีผู้เข้าแข่งขันไม่เกิน 8 คน!

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

รายการนี้ (ในขณะนี้ไม่ถูกต้องชัดเจน) ในความเป็นจริงสองบอทและตัวควบคุมจะขูดทั้งสองอย่างมีความสุขและเพิ่มลงในรายการผู้เข้าประกวด (เพราะไชโยหลาม?)

ขั้นตอนที่ 1:

  • TeamsterA มุ่งหน้าสู่ระดับ 25 (ish) 1แล้วหยิบขึ้นมาซ้ำ ๆ และทิ้งสมบัติที่เบาที่สุดที่เขาสามารถหาได้ ค่าใช้จ่ายมหันต์ 1 ความแข็งแกร่งจนในระยะที่สอง
  • TeamsterB มุ่งหน้าสู่ระดับ 55 และรับสิ่งของมีค่าทั้งหมดที่วางอยู่รอบ ๆ จากนั้นมุ่งหน้ากลับไปยังระดับ 25 (ish) 2จากนั้นเริ่มเฟส 2

1. หากไม่มีสมบัติที่มีน้ำหนักน้อยกว่า 3 ตัวบนพื้นเขาจะเลื่อนลง
2. เนื่องจากเขารับประกันได้ว่าจะเป็นสุดท้ายนักผจญภัยกลับมาสู่ผิวน้ำสิ่งที่เขาต้องทำคือค้นหาใครสักคน

เฟส 2:

  • TeamsterB ล้างกระเป๋าของเขาก่อนที่จะคลานไปตายจากความเหนื่อย เรารู้ว่าคุณสามารถทำได้
  • TeamsterA คิดว่า "มันเป็นเครื่องประดับเล็ก ๆ น้อย ๆ มันเป็นเพื่อนที่ดีนะ!" และโหลดของมีค่าที่มีค่ามากกว่าขยะอื่น ๆ ในห้องก่อนที่จะไปยังทางออกให้เต็มไปด้วยทองคำ

ชื่อของสมบัตินั้นมีประโยชน์จริง ๆ เพื่อช่วยให้ตรรกะไม่โหลดขึ้นบนชั้น 25 ขยะและออกไปก่อนเพราะไม่มีทางสื่อสารระหว่างทั้งสองบอท (และ TeamsterA มักจะพบตัวเองอยู่ในห้องกับคนอื่นก่อน TeamsterB ส่งคืนแล้ว)

ข้อสรุปเชิงตรรกะต่อไป: การสร้างกองทัพ

ในทางทฤษฎีสิ่งนี้สามารถใช้ในการลดความลึกและรับสมบัติจากที่ลึกที่สุดเท่าที่ห้อง 98 อย่างไรก็ตามเนื่องจากต้องใช้มากกว่า 2 บอทตรรกะที่ประกอบด้วยบอตเหล่านั้นจะซับซ้อนมากขึ้นและในขณะที่ฉันมั่นใจว่า การส่งที่ผิดกฎหมายสำหรับการละเมิดกฎที่ไม่ได้เขียนไว้ดังนั้นฉันจะไม่รบกวน

Aรออย่างมีประสิทธิภาพที่ 30 Bรอที่ 50 ... nดำน้ำถึง 98 เก็บสมบัติย้ายไปที่ 97 หยอดมัน (แล้วตาย) n-1หยิบมันขึ้นมาและย้ายไปที่ 96 ... Cลดลง (ตาย) Bหยิบมันขึ้นมา ขึ้นและย้ายไปที่ 30 ลดลง (ตาย) Aหยิบมันขึ้นมาและกลับไปที่ทางออก

ฉันคาดว่ามันจะใช้เวลา 11 บอท

อย่างไรก็ตามมันไม่คุ้มค่าหากคุณสามารถกู้คืนสมบัติได้ประมาณ 4 ชิ้นจากความลึกนั้นเพื่อแข่งขันกับรายการอย่าง PlanAhead หรือ Artyventure เนื่องจากการปรับขนาดระหว่างค่าใช้จ่ายในการเคลื่อนย้ายและค่าเฉลี่ยของสมบัติ

ตัวอย่างผลลัพธ์

คะแนนน้อยกว่า $ 4,000 บางครั้งยอด $ 6,000

[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
ฉันคิดว่าเมื่อมีเพียงบอตเดียวต่อคนก็ไม่จำเป็นต้องมีกฎที่ชัดเจน แต่กฎเกี่ยวกับการกำหนดเป้าหมายบอทโดยเฉพาะด้วยเหตุผลทางประสาทนั้นไม่เหมือนกับการไม่อนุญาตให้บอทหลายตัวทำงานร่วมกัน ดังนั้นจึงจำเป็นต้องมีการพิจารณาคดีอย่างชัดเจนจาก OP
Moogie

ใช่นี่จะไม่เป็นของฉันเลยอ่ะ นี่คือสิ่งที่ฉันมีอยู่ในใจด้วยบอทที่ทำงานร่วมกัน
Beefster

1
@Beefster นั่นคือสิ่งที่ฉันคิด ฉันสนุกที่จะทำมัน ฉันจะจัดการกับการแก้ไขเพื่อป้องกันการรวมในเย็นวันนี้
Draco18s

ฉันจะพิจารณาอนุญาตเมื่อมีคู่แข่งมากกว่า 11 รายเพราะประสิทธิภาพจะดีขึ้น ส่วนใหญ่เป็นเพราะฉันไม่ต้องการสร้างรหัสสำหรับการส่งอัตโนมัติ
Beefster

หากคุณเพียงแค่คัดลอกบล็อกโค้ดแรกสิ่งที่ฉันต้องทำคือแก้ไขในบอตอื่นที่ด้านบน
Draco18s

2

ย้อนกลับ

เพราะมันทำงานในสิ่งที่ตรงกันข้าม

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'

ทำไมถึงเรียกว่าย้อนกลับ

เพราะฉันเอานักบัญชีและพยายามทำให้มันใช้ตรรกะของมันเพื่อที่จะดำน้ำลึกจากนั้นหยิบของที่ต้องการจากทาง (ด้านหลังของนักบัญชี)

ในท้ายที่สุดมันยังรวบรวมรางวัลมากมายในวิธีการ (ตักพวกเขาขึ้นมาก่อนที่ผู้แสวงหาที่เก็บรวบรวมแบบดั้งเดิมจะดำเนินการย้อนกลับไปหาคนอื่น) แต่ก็มีการเลือกมากกว่าที่มันจะใช้ หยิบสิ่งต่าง ๆ ออกมา

ผลลัพธ์ที่ได้คือความแข็งแกร่งได้รับการอนุรักษ์ในขณะที่ยังคงจัดลำดับความสำคัญของสมบัติที่มีมูลค่าสูงจากนั้นใช้ประโยชน์จากการหมุนรอบลึกและการเลือกที่ง่ายในการสำรอง ย้อนกลับเป็นที่รู้จักกันในการเก็บสมบัติจากที่ไกลที่สุดเท่าที่ห้อง 41 (และในระหว่างการพัฒนาจะเข้าสู่จากนั้นออกทันทีห้อง 42)


2

นักล่าเงินรางวัล

วิธีการง่าย ๆ ที่ดีที่สุด คว้าสมบัติที่มีค่าและแสงในขณะที่ไปให้ลึกที่สุด คว้าสมบัติที่มีค่าน้อยลงระหว่างทางกลับ

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'

ดูเหมือนว่าคุณได้รับรางวัล สิ่งนี้ไม่เพียงทำงานได้ดีกว่าถอยหลัง แต่มันยังทำให้ย้อนกลับไปที่รถถัง ทำได้ดี.
Beefster

1

มีน้ำหนักเบา

บอทธรรมดาที่ยังทำงานได้ค่อนข้างดี

หลังจากเข้าไปในซากปรักหักพัง (ปัจจุบันมี 21 ห้อง) มันจะคว้าสมบัติที่ดีที่สุดในห้องที่มีน้ำหนักเพียง 1 กิโลกรัม (ดังนั้นชื่อของบอท) และมีค่ามากกว่าสมบัติที่มีค่าน้อยที่สุดในคลัง หากสินค้าคงคลังเต็มให้ทิ้งสมบัติที่มีค่าน้อยที่สุด ถ้าไม่มีการกระทำอื่นถูกเลือกย้ายเข้าไปในซากปรักหักพัง หากเราอยู่ในขีด จำกัด ของความแข็งแกร่งของเราที่จะสามารถออกจากชีวิตแล้วไปที่ทางออก

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'

ฉันขอแนะนำให้ใส่dumpingในenter_ruinsวิธีการ นี่จะจำได้จริงระหว่างเกมและจะไม่ทำงานในเกมที่ 2 ไม่ได้รับอนุญาตทางเทคนิค แต่ตอนนี้ฉันเพิ่มกฎ (ฉันลืมไปก่อนหน้านี้ แต่มันเป็นเจตนาของฉัน) ดังนั้นฉันจะลดความหย่อน : P
Beefster

@Beefster ฉันได้ลบสถานะการทุ่มตลาดแล้วมันไม่จำเป็นเพราะบอททิ้งสมบัติเพียงหนึ่งชิ้นเท่านั้นในตอนนี้ มันเคยทิ้งสมบัติครึ่งหนึ่ง ดังนั้นควรเข้ากันได้กับกฎใหม่
Moogie

1

Memorizer

ฉันสามารถส่งบอทไปยัง KotH ของฉันเองได้ไหม

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'

บอทนี้พุ่งไปที่ห้อง 30 และจดจำสมบัติทั้งหมดที่ได้เห็น ณ จุดนั้นมันเริ่มต้นช่วงระยะการเดินทางกลับไปที่ทางเข้าพยายามที่จะใช้สมบัติที่ดีที่จำได้ว่าเห็นในห้องก่อนหน้านี้

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

อัปเดต: ตอนนี้คว้าสมบัติ 1 กิโลกรัมมูลค่า $ 60 ขึ้นไประหว่างทาง


ฉันจินตนาการว่าสมบัติที่ดีทั้งหมดจะหายไปโดยจุดที่บอทกลับมาที่นั่น ... บางทีคุณอาจลองคอมโบที่ซึ่งมันจะนำสิ่งที่ดีจริงๆไปให้ได้ กำลังเดินทางกลับ
ArBo

มันอาจจะไปไกลเกินไป
Beefster

FYI ดูเหมือนว่าบางครั้งผิดพลาดหากมีความแข็งแกร่งพอที่จะได้รับกลับ: [Turn 072] Ryu Ridley (Memorizer) collapsed in the doorway to room #1 and died of exhaustion
Larkeith

1

Ponderer

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

บอทนี้จะวิ่งไปเรื่อย ๆ จนกระทั่งห้องลึกสุ่มเก็บบันทึกสมบัติที่พบตลอดทาง เมื่อถึงห้องเป้าหมายมันจะไตร่ตรองการเลือกสมบัติที่ดีที่สุดเพื่อกลับไปที่ทางออก มันจะเปิดแต่ละครั้งไตร่ตรองอีกครั้งเพื่อกำหนดสมบัติที่ดีที่สุดในการเลือกใช้

ขณะนี้มีอัลกอริทึมง่าย ๆ (กำลังผกผันของหมายเลขห้องพัก) ที่ให้จำนวนสมบัติที่ได้รับ (หรือจะถูกนำไปเมื่อเยี่ยมชมโดยบอทนี้) สำหรับแต่ละห้องและสมบัติเหล่านี้จะถูกเพิกเฉยเมื่อพิจารณาว่าสมบัติ / ห้องใด ที่จะใช้จาก ฉันมีแนวคิดสำหรับอัลกอริธึมขั้นสูงอื่น ๆ ในการสร้างแบบจำลองสมบัติที่เหลืออยู่ แต่ฉันจะต้องดูว่าผลประโยชน์คุ้มค่าหรือไม่

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

ผู้สะสม

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

ผู้สะสมอยู่ในห้องจนกว่าจะได้รับสมบัติทั้งหมดในห้อง (หรือคำนวณว่ามันไม่มีความแข็งแกร่งพอที่จะถ่ายหรือเคลื่อนไหวต่อไป) เมื่อสมบัติทั้งหมดหายไปถ้าบอทสามารถเดินหน้าต่อไปได้อย่างปลอดภัยมันก็จะดำเนินการตามขั้นตอนเพื่อนำสมบัติทั้งหมดไปใช้


เกมนี้ตายทุกครั้งโดยใส่กระเป๋าเป้สะพายหลังมากเกินไป
Beefster

เหมือนฉันใน Minecraft (͡°͜ʖ͡°) บอทนี้จะยกเค้าลึกเข้าไปแล้วก็เจอของมีค่า ดังนั้นมันจะดรอปสิ่งที่เขาคิดว่าเป็นของขวัญที่ดีก่อนหน้านี้ นั่นเป็นเหตุผลที่Backwards's, Sprinter' และMemorizer's งานกลยุทธ์; เพราะพวกเขารู้ว่าอะไรคือค่านิยมสัมพัทธ์ของสมบัติทุกอย่างที่พวกเขาเห็น
V. Courtois

0

ประดาน้ำ

(ไม่สามารถทดสอบได้ในขณะนี้ดังนั้นแจ้งให้เราทราบหากสิ่งนี้เสีย)

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'

ขุมทรัพย์ที่ดีที่สุดอยู่ลึกเข้าไปในซากปรักหักพังดำน้ำลึกแล้วคว้าสิ่งที่เราสามารถหาได้


ฉันไม่ค่อยมีประสบการณ์เกี่ยวกับงูหลาม แต่มีคำdivingจำกัดความที่ไหน?
ศูนย์รวมแห่งความไม่รู้

1
@EmbodimentofIgnorance ใน enter_ruins () ซึ่งถูกเรียกใช้ก่อนที่เกมจะทำงานและมีการดำเนินการ

Jacob the Orphan (Diver) was sliced in half by a swinging blade trap.ไม่แน่ใจว่าสิ่งที่คุณทำผิด แต่หมายถึง AFAIK
อาร์ทิมิสรองรับโมนิก้า

@ArtemisFowl เขาเสนอราคาต่ำเกินไปสำหรับสมบัติ มันมีค่าใช้จ่ายน้ำหนักของสมบัติที่จะรับมัน
Beefster

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.