เกมหิว - กินหรือตาย


60

เกมหิว - กินหรือตาย

ถ้าคุณไม่กินคุณก็ตาย ถ้าคุณกินคุณมีชีวิตอยู่ (จนกว่าคุณจะตาย) คุณจะตายดังนั้นพยายามที่จะตายครั้งสุดท้าย

ภาพรวม

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

วิธีการเล่น

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

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

การแข่งขันจะจัดขึ้นในระบบ Linux 64 บิต โปรดระลึกไว้เสมอเมื่อมีคำแนะนำที่จำเป็น

รายละเอียด

  • ตำแหน่งและทิศทางของสิ่งมีชีวิตแต่ละตัวอยู่ในรูปแบบของตัวเลขทศนิยมที่มีความแม่นยำสองเท่า (เช่นdouble) แทนxและyพิกัดตามลำดับ

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

  • เกาะนี้มีสี่เหลี่ยมจัตุรัส 500 ด้าน หากคุณพยายามที่จะเสี่ยงเกินขอบเขตเหล่านั้นคุณจะถูกบีบลงบนขอบ ต้นกำเนิด{0,0}อยู่ที่ด้านซ้ายบนโดยxเพิ่มขึ้นไปทางขวาและyเพิ่มขึ้นลง อีกครั้งแผนที่ไม่ห่อ

  • เกมเริ่มต้นด้วย1,500 + (packCount * 50)สัตว์ล่าเหยื่อ พวกเขาจะรวมตัวกันในใจกลางของเกาะ แต่ตัดสินใจอย่างรวดเร็วว่าจะเริ่มเคลื่อนไหว

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

  • สัตว์ที่เป็นเหยื่อสามารถมองเห็นสัตว์อื่น ๆ ทั้งหมดภายในรัศมี30หน่วย พวกเขาสามารถเคลื่อนที่ได้สูงสุด6.0หน่วยต่อเทิร์น

  • นักล่าสามารถมองเห็นสัตว์อื่น ๆ ทั้งหมดภายในรัศมี50หน่วยพวกเขาสามารถเคลื่อนที่ได้สูงสุด6.1หน่วยต่อเทิร์น ซึ่งหมายความว่าพวกเขาสามารถเห็นเหยื่อก่อนที่จะเห็นและ (แทบ) เอาชนะพวกเขา

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

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

  • ทุกๆ1,000รอบเหยื่อจะวางไข่มากขึ้น จำนวนเหยื่อใหม่จะเป็นจำนวนผู้ล่าที่มีชีวิตลบหนึ่งตัว

  • ผู้ล่าไม่สามารถโจมตีผู้ล่ารายอื่นได้ พวกเขากินเหยื่อเมื่อพวกมันจับได้ แค่นั้นแหละ.

  • คำสั่งซื้อภายในเทิร์นคือ:

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

พิธีสาร (ทั่วไป)

US-ASCIIการสื่อสารทั้งหมดจะทำในรูปแบบสตริง ตัวเลขจะถูกแปลงเป็นสตริงโดยใช้ Java ของหรือDouble.toString() Integer.toString()เอาต์พุตของคุณจะต้องจัดรูปแบบเพื่อให้สามารถอ่านได้โดย Java Double.valueOf(String)(คุณจะไม่ได้รับการส่งออกจำนวนเต็ม) สำหรับรายละเอียดเกี่ยวกับรูปแบบ parseable ดูที่เอกสาร Doubleเขตข้อมูลทั้งหมดบนเส้นจะถูกคั่นด้วยมาตรฐานตัวอักษรและการขึ้นบรรทัดใหม่เป็น\t สตริงทั้งหมดจะถูกยกเลิกจะไบต์\n null\0

ในตัวอย่างด้านล่างฉันใช้<>เพื่อทำเครื่องหมายเขตข้อมูลเพื่อประโยชน์ในการอ่าน สิ่งเหล่านี้ไม่ปรากฏในสตริงที่แท้จริง

โปรโตคอล (อินพุต)

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

  • บรรทัดที่ 0: ข้อมูลพื้นฐานเกี่ยวกับเกม turnคือหมายเลขเทิร์นปัจจุบันและการนับเป็นจำนวนรวมของเหยื่อและผู้ล่าที่เหลือในสนาม เหล่านี้อยู่integerในรูปแบบสตริง

    <turn>\t<preyCount>\t<predatorCount>\n
    
  • บรรทัดที่ 1: รหัสที่ไม่ซ้ำกันและระดับความหิวของสมาชิกแพ็คของคุณ สิ่งเหล่านี้ไม่ได้อยู่ในลำดับเดียวกันสำหรับทุกอินพุต ใช้รหัสที่ไม่ซ้ำกันเพื่อติดตามสมาชิกแต่ละคนไม่ใช่ลำดับที่ปรากฏในอินพุต อีกครั้งสิ่งเหล่านี้integerเป็นสตริง สำหรับแพ็คสองอันนี้จะเป็น:

    <id[0]>\t<hunger[0]>\t<id[1]>\t<hunger[1]>\n
    
  • บรรทัดที่ 2: ตำแหน่งสมาชิกแพ็คของคุณในลำดับเดียวกับที่ได้รับในบรรทัด 1 เหล่านี้doubleเป็นสตริง:

    <x[0]>\t<y[0]>\t<x[1]>\t<y[1]>\n
    

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

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

สำหรับสมาชิกแต่ละคนที่ยังมีชีวิตอยู่:

<prey[0].x>\t<prey[0].y>\t<prey[1].x>\t<prey[1].y>\n
<predator[0].x>\t<predator[0].y>\t<predator[1].x>\t<predator[1].y>\n

ในที่สุดตัวละครสุดท้ายจะอยู่\0ที่จุดเริ่มต้นของบรรทัดถัดไป

ข้อยกเว้น:ถ้าคุณได้รับอินพุตdead\0แพ็คของคุณจะตาย จบโปรแกรมของคุณด้วยความกรุณา ผู้ควบคุมควรปิดกระบวนการที่มีชีวิตทั้งหมดเมื่อปิด แต่ฉันไม่ต้องการให้มีกระบวนการซอมบี้ทั่วสถานที่ คุณอาจรวมถึงการหมดเวลาป้อนข้อมูลด้วย ตัวอย่างเช่นคลาสตัวอย่างของฉันจะสิ้นสุดลงหากไม่ได้รับอินพุตเป็นเวลา 15 วินาที

โปรโตคอล (เอาท์พุท)

ผลผลิตง่าย คุณจะให้ค่าหนึ่งคู่doubleสำหรับสมาชิก live pack แต่ละคน สิ่งเหล่านี้แสดงถึงการเคลื่อนไหวที่คุณต้องการให้พวกเขาทำในเทิร์นนี้ ตัวอย่างเช่นถ้าสิ่งมีชีวิตของคุณในขณะที่{100.0, 100.0}คุณให้พวกเขามีคำสั่งของพวกเขาจะย้ายไป{-1.0, 1.0} {99.0, 101.0}ตัวเลขทั้งหมดจะอยู่ในบรรทัดเดียวคั่นด้วยแท็บ

ตัวอย่างเช่นหากคุณมีสมาชิก 3 คนที่ยังมีชีวิตอยู่นี่จะเป็นการตอบสนองที่ถูกต้อง:

1.0\t-1.0\t2.0\t-2.0\t3.0\t-3.0\0

นี้จะย้ายสิ่งมีชีวิตของคุณโดย{1.0,-1.0}, และ{2.0,-2.0} {3.0,-3.0}คำสั่งซื้อนั้นเหมือนกับที่ได้รับในอินพุต อย่าลืมตอนจบ\0!

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

ทุกทิศทางจะถูกจับยึดไว้ที่ระยะสูงสุด 6.1 หน่วย คุณสามารถเคลื่อนที่ช้ากว่านี้ได้หากต้องการ ตัวอย่างเช่น{1, 0}จะย้ายคุณหนึ่งหน่วย {6,8}(ระยะทาง 10) จะย้ายคุณ 6.1 {3.66, 4.88}หน่วยและจะลดไปประมาณ ทิศทางคงที่

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

โปรแกรมควบคุม / การทดสอบ

แหล่งสำหรับการควบคุมที่สามารถพบได้ที่นี่ที่ bitbucket.org คุณจะต้องรวบรวมมันก่อนที่จะทำงาน คลาสหลักคือGameและคลาสทั้งหมดอยู่ในแพ็คเกจเริ่มต้น หากต้องการเรียกใช้ให้รวมคำสั่งแต่ละชุดเป็นอาร์กิวเมนต์แยกต่างหาก ตัวอย่างเช่นหากคุณต้องการเรียกใช้ Java ChaserPack และ Python LazyPack.py คุณสามารถใช้:

java Game "java ChaserPack" "python LazyPack.py"

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

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

java Game -silent "java ChaserCat" "./someOtherPack"

รวมเป็นชุดโครงกระดูก Java GenericPackชื่อ มันรวมถึงการดำเนินงานอินพุต / เอาท์พุตพื้นฐานที่จำเป็น มันอยู่ที่นั่นเพื่อให้ตัวอย่างที่ชัดเจนของวิธีการแยกและตอบกลับ หากคุณต้องการเพิ่มเทมเพลตในภาษาอื่นให้ฉันรู้

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

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

ภาพหน้าจอ

เกณฑ์การให้คะแนน

ผู้ชนะจะถูกกำหนดโดยทัวร์นาเมนต์รับคะแนนในแต่ละรอบ

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

สถานที่แรกสำหรับแต่ละรอบจะได้รับ 100 คะแนน สำหรับแต่ละสถานที่หลังจากนั้นรางวัลจะลดลง 20% (ปัดเศษลง) สิ่งนี้จะดำเนินต่อไปจนกว่าคะแนนจะถึงศูนย์ (หลังจากที่ 17) สถานที่ 18+ จะไม่ได้รับคะแนนสำหรับรอบ แพ็คที่เสมอกันจะได้รับคะแนนเท่ากัน ตัวอย่างเช่น:

1st : 100
2nd : 80
3rd : 64 (T)
3rd : 64 (T)
4th : 51
...
17th: 1
18th: 0
19th: 0

คะแนนสูงสุดที่เป็นไปได้ตลอดการแข่งขันคือ 1,000 จากสถานที่แรกทั้งสิบครั้ง

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

ฉันจะพยายามเล่นทัวร์นาเมนต์ทุกสัปดาห์โดยประมาณหรือเมื่อมีการส่งใหม่ ๆ

กฎเพิ่มเติม (เล่นอย่างยุติธรรม!)

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

  • อย่ารบกวนกระบวนการ / การส่งอื่น ๆ สิ่งนี้ไม่ได้หมายความว่าอย่าพยายามขโมยเหยื่อของพวกเขาวิ่งเร็วกว่า ฯลฯ หมายความว่าอย่ารบกวนการทำงานของกระบวนการ นี่คือดุลยพินิจของฉัน

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

  • คอมเมนต์อาจไม่ได้มีไว้เพื่อโพสต์รายการอื่น ๆ แต่ละคนควรเล่นเพื่อชนะด้วยตนเอง

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

ผลลัพธ์ - 29 เมษายน 2014

นี่คือผลการแข่งขันสิบรอบล่าสุด:

Clairvoyant         : 1000
EcoCamels           : 752
Netcats             : 688
RubySpiders         : 436
RubyVultures        : 431
CivilizedBeasts     : 382
LazyPack            : 257

แพ็คที่ส่งก่อน 09:00 EDT 2014/04/29 จะรวมอยู่ในการเรียกใช้นี้

คุณสามารถดูรายละเอียดของแต่ละรอบได้ ด้วยเหตุผลบางอย่างฉันตัดสินใจที่จะนับจำนวนรอบย้อนหลังดังนั้นจึงเริ่มต้นด้วย "รอบ 10"

อัพเดท

2014/04/23 : FGreg รายงานข้อผิดพลาดเกี่ยวกับการหมดเวลา (ขอบคุณ!) มีการใช้งานการแก้ไขดังนั้นผู้ทดสอบจะต้องการอัปเดตรหัสโปรแกรมควบคุม


28
ฉันชอบคำถามเหล่านี้
Cruncher

2
@ มนูฉันเขียนบอทตัวอย่างบน Windows 7 และทดสอบทั้ง win และ linux คุณมีปัญหาอะไรกับพวกเขา?
Geobits

2
คำถามกษัตริย์แห่งเขาเหล่านี้ยอดเยี่ยมมากและอันนี้น่าสนใจอย่างแน่นอน ตอนนี้ฉันมีสองชุดที่แตกต่างกัน!
mackthehobbit

2
@ githubphagocyte ฉันไม่ต้องการฆ่าแพ็คในการหมดเวลาครั้งแรกเพียงเพราะฉันเคยเห็นแม้แต่โปรแกรมที่เรียบง่ายหมดเวลาทุกๆ 40k + รอบหรือรอบที่คล้ายกัน ฉันส่งการเปลี่ยนแปลงการตั้งชื่อในคอนโทรลเลอร์ เทิร์นเป็นที่รู้จักในฐานะเทิร์นตลอดทั้งโปรแกรมยกเว้นว่าฉันพลาดไปที่ไหนสักแห่ง
Geobits

2
@Geobits ใช่มั้ยนั่นเป็นเรื่องดีสำหรับฉัน คุณรู้ไหมว่ามันดูเหมือนกับโครงการวิจัยที่อาจารย์ฟิสิกส์คนหนึ่งของฉันกำลังทำอยู่ซึ่งฉันอาจจะช่วยในช่วงฤดูร้อน ฉันจะอธิบายเล็กน้อยเกี่ยวกับเรื่องนั้นในภายหลังถ้าฉันสามารถ
krs013

คำตอบ:


10

ผู้มีญาณทิพย์

อัปเดตรหัสเพื่อเผชิญกับ AbleDogs

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

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

อาจเป็นไปได้ว่าฉันสามารถรวมเคล็ดลับของ CivilizedBeasts เพื่อลดจำนวนของเหยื่ออย่างมีนัยสำคัญในช่วงสองสามพันแรก

ทำเสร็จใน 5.21 นาที
ทิพย์ (1): เลี้ยว 9270: คะแนน 100
EcoCamel.pl (3): Turn 8118: คะแนน 80
Netcats (0): Turn 6111: คะแนน 64
RubyVultures.rb (5): เลี้ยว 4249: คะแนน 51
RubySpiders.rb (4): เลี้ยว 3495: คะแนน 40
CivilizedBeasts (2): Turn 3176: คะแนน 32
ChaserPack (6): Turn 2492: คะแนน 25

จากชื่อชุดของฉันคุณควรรู้ว่าฉันใช้กลยุทธ์ใด = D

แก้ไข :

  • อัปเดตระบบการจัดการแพ็คเพื่อไม่ไล่ล่าเหยื่อคนเดียวกัน (และพยายามหาคู่ที่ดีที่สุด!)
  • ปรับปรุงกระบวนการหลงทางเมื่อจำนวนเหยื่อมีน้อย (นี่เป็นสิ่งสำคัญสำหรับการชนะ!)
  • ปรับปรุงเคสพิเศษเมื่อเวอร์ชันก่อนหน้าติดอยู่ตรงมุม
  • แก้ไขข้อบกพร่องในอัลกอริทึมการตรวจจับผู้ล่า (ตอนนี้มันค่อนข้างแม่นยำ!)
  • รวมถึงflock[ALIGN]ปัจจัยเหยื่อ
  • ให้เหยื่อหนึ่งคนเป็นสัตว์เลี้ยงหากอาหารหายาก
  • สร้างถ้ำที่ฝูงสัตว์จะรวมฝูงของมันไว้
  • ล่อนักล่าที่อยู่ใกล้เคียงให้ไล่ล่าเหยื่อของเราซึ่งพวกมันจะไม่ชนะ

ฉันนับจำนวนเหยื่อที่กินแต่ละแพ็คและนี่คือผลลัพธ์:

ผู้มีญาณทิพย์ (1) บริโภค 916 เหยื่อใน 9270 ตา (0.099 เหยื่อ / รอบ)
EcoCamel.pl (3) บริโภค 73 เหยื่อใน 8118 ครั้ง (0.009 เหยื่อ / รอบ)
Netcats (0) บริโภค 563 คนในรอบ 6111 ครั้ง (0.092 รอบ / รอบ)
RubyVultures.rb (5) บริโภค 77 เหยื่อใน 4249 รอบ (0.018 เหยื่อ / รอบ)
RubySpiders.rb (4) บริโภค 293 เหยื่อใน 3495 รอบ (0.084 เหยื่อ / รอบ)
CivilizedBeasts (2) บริโภค 10 เหยื่อใน 3176 ตา (0.003 เหยื่อ / เทิร์น)
ChaserPack (6) บริโภค 43 preys ใน 2492 ตาร์ (0.017 preys / turn)

ชุดของฉันก้าวร้าวมากและส่วนใหญ่ของ 916 ครั้งที่ฉันคิดว่ามันได้มาจากการขโมยเหยื่อจาก Netcats เหมือนกับ RubySpiders

CivilizedBeasts น่าเสียดายที่สูญเสียไปเนื่องจากอูฐกลางจาก EcoCamel

และ EcoCamel (ที่มีความหิวสำคัญ 500) นั้นค่อนข้างมีประสิทธิภาพมันกินเพียงพอที่จะเอาชีวิตรอดจนจบ

นอกจากนี้เมื่อ Clairvoyant ที่อัพเดทนี้เกมแทบจะไม่ถึง 10,000 รอบ

รหัส:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.TreeSet;

public class Clairvoyant extends GenericPack {
    private static final double MAX_SPEED = 6.1;

    private TreeSet<Animal> foods = new TreeSet<Animal>(new AnimalComparator());
    private TreeSet<Animal> predators = new TreeSet<Animal>(new AnimalComparator());

    private XY abattoirCorner;
    private double abattoirRadius = 100;

    private MyMember[] myMembers = new MyMember[100];

    public class AnimalComparator implements Comparator<Animal>{

        @Override
        public int compare(Animal arg0, Animal arg1) {
            if(arg0.x < arg1.x){
                return -1;
            } else if (arg0.x > arg1.x){
                return 1;
            } else {
                if(arg0.y < arg1.y){
                    return -1;
                } else if(arg0.y > arg1.y){
                    return 1;
                } else {
                    return 0;
                }
            }
        }
    }

    public class MyMember extends Member{
        public XY target;
        public XY herdPos;
        public double herdRadius; 
        public boolean mayEat;
        public XY pos;
        public ArrayList<MyAnimal> closestPreys;
        public boolean outdated;

        public MyMember(int id) {
            super(id);
            this.pos = new XY(x, y);
            closestPreys = new ArrayList<MyAnimal>();
            mayEat = true;
            outdated = true;
        }

        public MyMember(Member member){
            super(member.id);
            this.pos = new XY(x, y);
            closestPreys = new ArrayList<MyAnimal>();
            mayEat = true;
            outdated = true;
        }

        public MyMember(Member member, Animal target){
            super(member.id);
            this.target = new XY(target.x, target.y);
            this.pos = new XY(x, y);
            closestPreys = new ArrayList<MyAnimal>();
            mayEat = true;
            outdated = true;
        }

        public void reset(Member me){
            x = me.x;
            y = me.y;
            pos = new XY(x, y);
            closestPreys.clear();
            mayEat = true;
            outdated = true;
        }
    }

    public class MyAnimal extends Animal{
        public ArrayList<MyMember> chasers;
        public XY pos;
        public boolean resolved;

        public MyAnimal(double x, double y){
            super(x, y);
            pos = new XY(x, y);
            chasers = new ArrayList<MyMember>();
            resolved = false;
        }

        public MyAnimal(Animal ani){
            super(ani.x, ani.y);
            pos = new XY(x, y);
            chasers = new ArrayList<MyMember>();
            resolved = false;
        }
    }

    public static void main(String[] args){
        new Clairvoyant().run();
    }

    public Clairvoyant(){
        for(int i=0; i<100; i++){
            nextIdx[i] = 0;
        }
        int cornerIdx = (int)Math.floor(Math.random()*4);
        switch (cornerIdx){
        case 0: abattoirCorner = new XY(0,0); break;
        case 1: abattoirCorner = new XY(500,0); break;
        case 2: abattoirCorner = new XY(500,500); break;
        case 3: abattoirCorner = new XY(0,500); break;
        }
    }

    @Override
    public void respond(){
        updateData();
        goToTarget();
    }

    private void updateData(){
        for(int i=0; i<100; i++){
            if(myMembers[i]!=null){
                myMembers[i].pos = null;
            }
        }
        foods.clear();
        predators.clear();
        for(Member me: members){
            foods.addAll(me.foods);
            predators.addAll(me.others);
            predators.add(new Animal(me.x, me.y));
            if(myMembers[me.id] != null){
                myMembers[me.id].reset(me);
            } else {
                myMembers[me.id] = new MyMember(me);
            }
        }
        for(int i=0; i<100; i++){
            if(myMembers[i]!=null && myMembers[i].pos == null){
                myMembers[i] = null;
            }
        }

        TreeSet<MyAnimal> closestPreys = new TreeSet<MyAnimal>(new AnimalComparator());
        for(int i=0; i<100; i++){
            if (myMembers[i]==null) continue;
            MyMember me = myMembers[i];
            ArrayList<Animal> animals = findClosest(foods, me.pos, members.size());
            boolean first = true;
            for(Animal ani: animals){
                MyAnimal myAni = new MyAnimal(ani);
                if(closestPreys.contains(ani)){
                    myAni = closestPreys.ceiling(myAni);
                } else {
                    closestPreys.add(myAni);
                }
                if(first){
                    myAni.chasers.add(me);
                    first = false;
                }
                me.closestPreys.add(myAni);
            }
        }
        performMatching();
        for(int i=0; i<100; i++){
            if (myMembers[i] == null) continue;
            MyMember me = myMembers[i];
            if(!me.outdated) continue;
            if(me.closestPreys.size() == 0) continue;
            MyAnimal closestPrey = me.closestPreys.get(0);
            if(closestPrey.resolved) continue;
            if(closestPrey.chasers.size() > 1){
                MyMember hungriest = me;
                MyMember closest = me;
                for(MyMember otherMe: closestPrey.chasers){
                    if(sqDist(closestPrey.pos, otherMe) < sqDist(closestPrey.pos, closest)){
                        closest = otherMe;
                    }
                    if(otherMe.hunger < hungriest.hunger){
                        hungriest = otherMe;
                    }
                }
                if(hungriest.hunger > 200){ // Nobody's critically hungry, the closest takes the prey
                    closest.target = closestPrey.pos;
                    closest.mayEat = true;
                    closest.herdPos = abattoirCorner;
                    closest.herdRadius = abattoirRadius;
                    closest.outdated = false;
                } else {
                    if(hungriest == closest){
                        closest.target = closestPrey.pos;
                        closest.mayEat = true;
                        closest.herdPos = abattoirCorner;
                        closest.herdRadius = abattoirRadius;
                        closest.outdated = false;
                    } else {
                        closest.target = closestPrey.pos;
                        closest.mayEat = false;
                        closest.herdPos = hungriest.pos;
                        closest.herdRadius = 0;
                        closest.outdated = false;
                        hungriest.target = closestPrey.pos;
                        hungriest.mayEat = true;
                        hungriest.herdPos = abattoirCorner;
                        hungriest.herdRadius = 10;
                        hungriest.outdated = false;
                    }
                }
                closestPrey.resolved = true;
            } else {
                me.target = closestPrey.pos;
                me.herdPos = abattoirCorner;
                me.herdRadius = abattoirRadius;
                me.mayEat = true;
                me.outdated = false;
            }
        }
        for(int i=0; i<100; i++){
            if (myMembers[i] == null) continue;
            MyMember me = myMembers[i];
            if(me.outdated){
                me.target = null;
                me.outdated = false;
            }
        }
    }

    private void goToTarget(){
        for(Member me: members){
            MyMember mem = myMembers[me.id];
            if(mem.target == null){
                wander(me, 2*(me.id%2)-1);
                continue;
            } else {
                nextIdx[me.id] = 0;
                XY[] nearestHostile = new XY[100];
                for(Animal other: me.others){
                    XY otherPos = new XY(other.x, other.y);
                    boolean isMember = false;
                    for(Member otherMember: members){
                        if(other.x==otherMember.x && other.y==otherMember.y){
                            isMember = true;
                            break;
                        }
                    }
                    if(!isMember){
                        if(nearestHostile[me.id] == null || XY.sqDistance(mem.pos, otherPos) < XY.sqDistance(mem.pos,  nearestHostile[me.id])){
                            nearestHostile[me.id] = otherPos;
                        }
                    }
                }

                // Go towards the target by predicting its next position
                XY target = predictNextPos(mem.target, me);

                me.dx = (target.x - me.x);
                me.dy = (target.y - me.y); 

                // Try to herd the target to our abattoir if this member is not too hungry
                // and if there is no other hostile predator who is closer to the target than us
                // This will make the other hostile predator to keep targeting this target, while
                // it is certain that we will get the target.
                // This is a win situation for us, since it will make the other predator wasting his turn.
                if((me.hunger <= 200 && XY.sqDistance(mem.target, mem.pos) > 400) || me.hunger <= 50 ||
                        (nearestHostile[me.id] != null && Math.sqrt(XY.sqDistance(mem.target, nearestHostile[me.id])) < Math.sqrt(XY.sqDistance(mem.target, mem.pos)))){
                    continue;
                }

                // Don't eat if not threatened nor hungry
                if(me.hunger > 50 && (nearestHostile[me.id] == null ||
                        Math.sqrt(XY.sqDistance(mem.target, nearestHostile[me.id])) > Math.sqrt(XY.sqDistance(mem.target, mem.pos)) + 6)){
                    mem.mayEat = false;
                }

                // Herd to abattoir corner
                double distFromHerd = Math.sqrt(XY.sqDistance(target, mem.herdPos));
                XY oppositeAbattoirCorner = new XY(500-abattoirCorner.x, 500-abattoirCorner.y);
                double distFromOpposite = Math.sqrt(XY.sqDistance(target, oppositeAbattoirCorner));
                if((me.dx*me.dx+me.dy*me.dy > 64 && distFromHerd > mem.herdRadius && distFromOpposite > abattoirRadius)
                        || (preyCount < 5*predCount)){
                    double herdDistance = 4*(distFromHerd-mem.herdRadius)/(Island.SIZE-mem.herdRadius);
                    if(!mem.mayEat) herdDistance = 4;
                    XY gradient = target.minus(abattoirCorner);
                    me.dx += gradient.x*herdDistance/distFromHerd;
                    me.dy += gradient.y*herdDistance/distFromHerd;
                }
            }
        }
    }

    private void performMatching(){
        for(int i=0; i<100; i++){
            if (myMembers[i] == null) continue;
            MyMember me = myMembers[i];
            if(me.closestPreys.size()==0) continue;
            MyAnimal closestPrey = me.closestPreys.get(0);
            if(closestPrey.chasers.size() > 1){
                resolveConflict(closestPrey);
            }
        }
    }

    private void resolveConflict(MyAnimal prey){
        ArrayList<MyMember> chasers = prey.chasers;
        MyMember winner = null;
        double closestDist = Double.MAX_VALUE;
        for(MyMember me: chasers){
            if(sqDist(prey.pos, me) < closestDist){
                closestDist = sqDist(prey.pos, me);
                winner = me;
            }
        }
        for(int i=chasers.size()-1; i>=0; i--){
            MyMember me = chasers.get(i);
            if(me!=winner){
                me.closestPreys.get(0).chasers.remove(me);
                me.closestPreys.add(me.closestPreys.remove(0));
                me.closestPreys.get(0).chasers.add(me);
            }
        }
    }

    private Animal findClosest(Collection<Animal> preys, XY me){
        Animal target = null;
        double cDist = Double.MAX_VALUE;
        double x, y, sqDist;
        for (Animal food : preys) {
            x = food.x - me.x;
            y = food.y - me.y;
            sqDist = x * x + y * y + Double.MIN_NORMAL;
            if (sqDist < cDist) {
                cDist = sqDist;
                target = food;
            }
        }
        return target;
    }

    private ArrayList<Animal> findClosest(Collection<Animal> preys, XY me, int num){
        ArrayList<Animal> result = new ArrayList<Animal>();
        for(Animal food: preys){
            int addIdx = -1;
            for(int i=0; i<num && i<result.size(); i++){
                Animal regFood = result.get(i);
                if(sqDist(me, food) < sqDist(me, regFood)){
                    addIdx = i;
                    break;
                }
            }
            if(addIdx == -1){
                result.add(food);
            } else {
                result.add(addIdx, food);
            }
            if(result.size() > num){
                result.remove(num);
            }
        }
        return result;
    }

    private Member findClosestToTarget(Collection<Member> members, Animal target){
        Member member = null;
        double cDist = Double.MAX_VALUE;
        double x, y, sqDist;
        for (Member me : members) {
            x = me.x - target.x;
            y = me.y - target.y;
            sqDist = x * x + y * y + Double.MIN_NORMAL;
            if (sqDist < cDist) {
                cDist = sqDist;
                member = me;
            }
        }
        return member;
    }

    private static final XY[] CHECKPOINTS = new XY[]{
        new XY(49.5,49.5),
        new XY(450.5,49.5),
        new XY(450.5,100),
        new XY(49.5,100),
        new XY(49.5,150),
        new XY(450.5,150),
        new XY(450.5,200),
        new XY(49.5,200),
        new XY(49.5,250),
        new XY(450.5,250),
        new XY(450.5,300),
        new XY(49.5,300),
        new XY(49.5,350),
        new XY(450.5,350),
        new XY(450.5,400),
        new XY(49.5,400),
        new XY(49.5,450.5),
        new XY(450.5,450.5)};
    private int[] nextIdx = new int[100];

    private int advanceIdx(int idx, int sign, int amount){
        return sign*(((Math.abs(idx)+CHECKPOINTS.length-1+sign*amount) % CHECKPOINTS.length) + 1);
    }

    private void wander(Member me, int sign) {
        if(preyCount > 20*predCount){
            if (me.dx == 0 && me.dy == 0) {
                me.dx = 250 - me.x;
                me.dy = 250 - me.y;
                return;
            }

            double lx, ly, px, py;
            lx = me.dx / 4;
            ly = me.dy / 4;
            boolean dir = Math.random() < 0.5 ? true : false;
            px = dir ? ly : -ly;
            py = dir ? -lx : lx;

            me.dx += px;
            me.dy += py;
        } else {
            if(nextIdx[me.id]==0){
                XY farthest = new XY(2000,2000);
                int farthestIdx = -1;
                for(int i=0; i<CHECKPOINTS.length; i++){
                    if(sign*sqDist(CHECKPOINTS[i], me) > sign*sqDist(farthest, me)){
                        farthest = CHECKPOINTS[i];
                        farthestIdx = i+1;
                    }
                }
                nextIdx[me.id] = farthestIdx*sign;
                for(Member mem: members){
                    if(mem.id == me.id) continue;
                    if(nextIdx[mem.id]==nextIdx[me.id]){
                        nextIdx[me.id] = advanceIdx(nextIdx[me.id], sign, 5); 
                    }
                }
            }
            if(sqDist(CHECKPOINTS[Math.abs(nextIdx[me.id])-1],me) < 1){
                nextIdx[me.id] = advanceIdx(nextIdx[me.id], sign, 1);
            }
            me.setDirection(CHECKPOINTS[Math.abs(nextIdx[me.id])-1].x-me.x,
                    CHECKPOINTS[Math.abs(nextIdx[me.id])-1].y-me.y);
        }
    }

    private double sqDist(XY me, Animal target){
        double dx = me.x-target.x;
        double dy = me.y-target.y;
        return dx*dx + dy*dy + Double.MIN_NORMAL;
    }

    private double sqDist(XY me, Member target){
        double dx = me.x-target.x;
        double dy = me.y-target.y;
        return dx*dx + dy*dy + Double.MIN_NORMAL;
    }

    private double sqDist(Animal target, Member me){
        double dx = me.x-target.x;
        double dy = me.y-target.y;
        return dx*dx + dy*dy + Double.MIN_NORMAL;
    }

    private List<Animal> getNeighbors(double radius, XY pos, Collection<Animal> candidates) {
        List<Animal> neighbors = new ArrayList<Animal>();
        for(Animal neighbor: candidates){
            if(sqDist(pos, neighbor) < radius * radius){
                neighbors.add(neighbor);
            }
        }
        return neighbors;
    }

    final double[] weights = { 1, 1, 0.96, 2, 4 };
    double weightSum;

    static final int ALIGN = 0;
    static final int SEPARATE = 1;
    static final int COHESION = 2;
    static final int FLEE = 3;
    static final int WALL = 4;
    static final int VISIBLE = 30;
    static final int VISIBLE_PRED = 50;

    private HashMap<Member, List<Animal>> prevPreys = new HashMap<Member, List<Animal>>();

    private XY matchPreys(List<Animal> prevs, List<Animal> curs, XY prey){
        XY result = new XY();
        double sqDist = 0;
        Animal candidate;
        XY otherPos;
        for(Animal otherPrey: curs){
            otherPos = new XY(otherPrey.x, otherPrey.y);
            sqDist = XY.sqDistance(prey, otherPos);
            if(sqDist > VISIBLE * VISIBLE)
                continue;
            candidate = findClosest(getNeighbors(6, otherPos, prevs), prey);
            if(candidate == null){
                return null;
            }
            result.add(otherPos.x-candidate.x, otherPos.y-candidate.y);
        }
        return result;
    }

    private XY predictNextPos(XY prey, Member me) {
        List<Animal> preys = getNeighbors(VISIBLE_PRED, prey, foods);
        List<Animal> preds = getNeighbors(VISIBLE, prey, predators);

        XY flock[] = new XY[weights.length];
        for (int i = 0; i < weights.length; i++)
            flock[i] = new XY();

        double dx, dy, dist, sqDist;
        for (Animal otherPrey : preys) {
            sqDist = XY.sqDistance(prey, new XY(otherPrey.x, otherPrey.y));
            if(sqDist > VISIBLE * VISIBLE)
                continue;
            dx = otherPrey.x - prey.x;
            dy = otherPrey.y - prey.y;
            flock[COHESION].add(dx*sqDist, dy*sqDist);
            flock[SEPARATE].add(-dx*(1d/sqDist), -dy*(1d/sqDist));
            flock[ALIGN].add(new XY(prey.x-me.x,prey.y-me.y));
        }

        if(sqDist(prey, me) < 400){
            if(prevPreys.get(me) == null){
                prevPreys.put(me, preys);
            } else {
                XY flockAlign = matchPreys(prevPreys.get(me), preys, prey);
                if(flockAlign == null){
                    prevPreys.put(me , null);
                } else {
                    flock[ALIGN] = flockAlign;
                    prevPreys.put(me, preys);
                }
            }
        }

        flock[ALIGN].unitize().multiply(5);
        flock[COHESION].unitize().multiply(5);
        flock[SEPARATE].unitize().multiply(5);

        for (Animal predator : preds){
            flock[FLEE].add(prey.x-predator.x, prey.y-predator.y);
        }

        dx = Island.CENTER.x - prey.x;
        dy = Island.CENTER.y - prey.y;
        dist = Math.max(Math.abs(dx), Math.abs(dy));
        if(dist > 240){
            flock[WALL].x = dx * dist;
            flock[WALL].y = dy * dist;
            flock[WALL].unitize().multiply(5);
        }

        XY vec = new XY();
        vec.x = 0;
        vec.y = 0;
        for (int i = 0; i < flock.length; i++) {
            flock[i].multiply(weights[i]);
            vec.add(flock[i]);
        }
        limitSpeed(vec);
        return vec.add(prey);
    }

    private XY limitSpeed(XY move) {
        if (move.x*move.x+move.y*move.y > MAX_SPEED*MAX_SPEED)
            move.unitize().multiply(MAX_SPEED);
        return move;
    }
}

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

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

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

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

15

Netcats

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

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

ตาข่ายเริ่มค่อนข้างเล็ก แต่กว้างขึ้นเมื่อฝูงเล็กลงเพื่อที่จะอวนลากสนามได้อย่างมีประสิทธิภาพยิ่งขึ้น

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

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

รุ่นนี้รอดชีวิตได้ดีกว่า Netcats ไร้เดียงสาที่เห็นในวิดีโอที่เชื่อมโยงกับคำถาม

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class Netcats extends GenericPack {

    boolean seeking;
    Member head = null;
    Set<Animal> foods;

    public static void main(String[] args) {
        new Netcats().run();
    }

    @Override
    public void respond() {
        if (foods == null)
            foods = new HashSet<Animal>();
        else
            foods.clear();
        for (Member member : members)
            foods.addAll(member.foods);

        if (members.size() < 3) {
            soloRun();
        } else {
            head = setHead();
            setHeadVec();
            for (int i = 1; i < members.size(); i++) {
                setMemberVec(i);
            }
        }
    }

    Member setHead() {
        if (!members.contains(head))
            return members.get(0);

        Member hungry = head;
        int idx = 0;
        for (int i = 0; i < members.size(); i++) {
            Member me = members.get(i);
            if (me.hunger < hungry.hunger) {
                hungry = me;
                idx = i;
            }
        }

        if (hungry != head) {
            members.remove(hungry);
            members.remove(head);
            members.add(0, hungry);
            members.add(idx, head);
            return hungry;
        }
        return head;
    }

    void setHeadVec() {
        double x = 0, y = 0;

        Collection<Animal> yummy = getFoods(head);

        seeking = false;
        if (yummy.size() == 0) {
            scoutHead();
            return;
        }

        if (members.size() == 1)
            if (findFood(head))
                return;

        for (Animal food : yummy) {
            x += food.x - head.x;
            y += food.y - head.y;
        }
        x *= 10000000;
        y *= 10000000;

        head.dx = x;
        head.dy = y;
        if (members.size() > 1)
            limitSpeed(head, MAX_SPEED * HEAD_MULT);
    }

    void scoutHead() {
        seeking = true;
        head.dy = 250 - head.y;
        head.dx = round % 80 < 40 ? -head.x : 500 - head.x;
    }

    void setMemberVec(int idx) {
        Member me = members.get(idx);
        Member leader;
        leader = idx < 3 ? members.get(0) : members.get(idx - 2);
        if (findFood(me))
            return;

        double lx, ly, px, py, tx, ty, dist;
        lx = -leader.dx;
        ly = -leader.dy;
        dist = Math.sqrt(lx * lx + ly * ly) + Double.MIN_NORMAL;
        lx /= dist;
        ly /= dist;
        px = idx % 2 == 0 ? ly : -ly;
        py = idx % 2 == 0 ? -lx : lx;

        tx = leader.x + leader.dx;
        ty = leader.y + leader.dy;
        int xtrack = seeking ? COMB : preyCount > 400 ? ASIDE : MID_SIDE;
        tx += lx * BEHIND + px * xtrack;
        ty += ly * BEHIND + py * xtrack;

        me.dx = tx - me.x;
        me.dy = ty - me.y;
        limitSpeed(me, MAX_SPEED * (idx < 3 ? MID_MULT : 1));
    }

    Collection<Animal> getFoods(Member me) {
        return me.foods.size() == 0 ? foods : me.foods;
    }

    boolean findFood(Member me) {
        if (me.hunger > 500)
            return false;

        Collection<Animal> yummy = getFoods(me);
        if (yummy.size() == 0)
            return false;

        double x, y, sqDist, cDist = 10 * 10;
        Animal target = null;
        for (Animal food : me.foods) {
            x = food.x - me.x;
            y = food.y - me.y;
            sqDist = x * x + y * y + Double.MIN_NORMAL;
            if (sqDist < cDist) {
                cDist = sqDist;
                target = food;
            }
        }

        if (target == null)
            return false;

        if (cDist < 5 * 5 || me.hunger < 200) {
            me.dx = (target.x - me.x) * 10000000d;
            me.dy = (target.y - me.y) * 10000000d;
            return true;
        }
        return false;
    }

    void soloRun() {
        double x, y, sqDist, cDist;
        for (Member me : members) {
            Collection<Animal> yummy = getFoods(me);
            if (yummy.size() == 0) {
                wander(me);
                continue;
            }

            Animal target = null;
            cDist = Double.MAX_VALUE;
            for (Animal food : yummy) {
                x = food.x - me.x;
                y = food.y - me.y;
                sqDist = x * x + y * y + Double.MIN_NORMAL;
                if (sqDist < cDist) {
                    cDist = sqDist;
                    target = food;
                }
            }

            me.dx = (target.x - me.x) * 100000d;
            me.dy = (target.y - me.y) * 100000d;
        }
    }

    void wander(Member me) {
        if (me.dx == 0 && me.dy == 0) {
            me.dx = 250 - me.x;
            me.dy = 250 - me.y;
            return;
        }

        double lx, ly, px, py;
        lx = me.dx / 4;
        ly = me.dy / 4;
        boolean dir = Math.random() < 0.5 ? true : false;
        px = dir ? ly : -ly;
        py = dir ? -lx : lx;

        me.dx += px;
        me.dy += py;
    }

    void limitSpeed(Member me, double max) {
        double x = me.dx, y = me.dy;
        double dist = Math.sqrt(x * x + y * y) + Double.MIN_NORMAL;
        if (dist > max) {
            x = (x / dist) * max;
            y = (y / dist) * max;
        }
        me.dx = x;
        me.dy = y;
    }

    final static double MAX_SPEED = 6.1;
    final static double HEAD_MULT = 0.85;
    final static double MID_MULT = 0.92;
    final static int BEHIND = -25;
    final static int ASIDE = 15;
    final static int MID_SIDE = 30;
    final static int COMB = 150;
}

11

ทับทิมแมงมุม

เนื่องจากบางครั้งมีน้อยมากและอาจมีวิธีแก้ปัญหามากมายที่จะพยายามกำจัดเหยื่อต่อไป ...

ฉันคิดว่าชุดของฉันสามารถแยกและรอให้คนอื่นทำงานได้

gets
print "3.0\t3.0\t3.0\t-3.0\t-3.0\t-3.0\t-3.0\t3.0\t0.0\t0.0\0"
STDOUT.flush

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


4
+1 โซลูชั่นปรสิตตัวแรก ผมคิดว่าประเภทของคำตอบนี้จะผลักดันคุณภาพของคำตอบอื่น ๆ โดยช่องโหว่ค่อยๆกำจัด ...
Trichoplax

@githubphagocyte ฉันมีปรสิตที่ฉลาดกว่า แต่มันมีประสิทธิภาพมากขึ้นในแง่ของเวลาสด / บรรทัดของรหัส ฉันหวังว่าฉันจะหาเวลาที่จะใช้มัน
Legat

บางที @Synthetica กำลังเข้ารหัสความคิดของฉันอยู่ หรือถ้าความคิดของเขายังเป็นอีกหนึ่งเราอาจมีปรสิตอีกไม่นานนักล่า;)
Legat

1
@ githubphagocyte เราได้รับอนุญาตให้สร้างสามรายการดังนั้นฉันจะโพสต์อีกชุดเมื่อพร้อม ถึงกระนั้นฉันคิดว่ามันน่าสนใจที่รหัสนี้ถูกเข้ารหัสในระหว่างนี้และอาจพิสูจน์ได้ว่ามีประสิทธิภาพมากขึ้น มันใช้ประโยชน์จาก Netcats ได้ดีจริงๆและมันมีค่ามากกว่ากลุ่มนักล่าคนแรกของฉัน
Legat

3
สิ่งนี้สามารถป้อนได้ตามที่เป็นแม้ว่าฉันจะใช้เวลาสักครู่ในการหาสาเหตุ ดูเหมือนว่าจะทำดีกว่า Netcats ที่คุณเพิ่มเข้าไป (ซึ่งก็สมเหตุสมผล) +1 จากฉันมาดูกันว่านักล่าประเภทไหนที่จะหลีกเลี่ยงมุมต่างๆได้ :)
Geobits

11

CivilizedBeasts

ในที่สุดเวลาที่จะอวดสัตว์ของฉัน!

สายพันธุ์ของฉันคิดว่าการล่าสัตว์นั้นค่อนข้างดั้งเดิมดังนั้นพวกเขาจึงทำงานร่วมกันในทีม 4 คนดังนั้นพวกเขาจึงละทิ้งพันธมิตรคนที่ 5 ของพวกเขาเพราะ: นักล่าน้อยลง = เหยื่อมากขึ้นสำหรับตัวเอง โดยทั่วไปแล้วสิ่งที่พวกเขาทำคือสิ่งที่มนุษย์ทำพวกเขาจับเหยื่อและดูแลปศุสัตว์ของพวกเขาอย่างดี;)

public class CivilizedBeasts extends GenericPack{

    private static int TL = 0, TR = 0, BL = 0, BR = 0; // TopLeft/BotRight
    private static int teamSize = 0, turnsWaiting = 0, turnsToWait = 20;

    private boolean out = true;
    private double maxSpeed = 6.1, mapSize = 500;

    public CivilizedBeasts(){
    }

    @Override
    public void respond(){
        if(teamSize > members.size()){

            Member check = getMemberById(TL);
            totalLoop:
            if(check == null){
                for (Member member : members) {
                    if(member.id != TR && member.id != BL && member.id != BR){
                        TL = member.id;
                        break totalLoop;
                    }
                }

                TL = 0;
            }

            check = getMemberById(TR);
            totalLoop:
            if(check == null){
                for (Member member : members) {
                    if(member.id != TL && member.id != BL && member.id != BR){
                        TR = member.id;
                        break totalLoop;
                    }
                }

                TR = 0;
            }

            check = getMemberById(BL);
            totalLoop:
            if(check == null){
                for (Member member : members) {
                    if(member.id != TL && member.id != TR && member.id != BR){
                        BL = member.id;
                        break totalLoop;
                    }
                }

                BL = 0;
            }

            check = getMemberById(BR);
            totalLoop:
            if(check == null){
                for(Member member : members) {
                    if(member.id != TL && member.id != TR && member.id != BL){
                        BR = member.id;
                        break totalLoop;
                    }
                }

                BR = 0;
            }
        }else if(teamSize < members.size()){
            for(Member member : members) {
                if(member.id != TL && member.id != TR && member.id != BL && member.id != BR){
                    if(TL == 0)
                        TL = member.id;
                    else if(TR == 0)
                        TR = member.id;
                    else if(BL == 0)
                        BL = member.id;
                    else if(BR == 0)
                        BR = member.id;
                }
            }
        }

        teamSize = members.size();

        double border = 1;
        double x, y;
        boolean reached = true;

        double distance = 16.3;

        for (Member member : members) {
            boolean doesNotCount = false;
            x = 0; y = 0;
            if(member.id == TL){
                if(out){
                    x = -(member.x - border);
                    y = -(member.y - border);
                }else{
                    x = ((mapSize/2 - distance) - member.x);
                    y = ((mapSize/2 - distance) - member.y);
                }
            }else if(member.id == TR){
                if(out){
                    x = (mapSize - member.x - border);
                    y = -(member.y - border);
                }else{
                    x = ((mapSize/2 + distance) - member.x);
                    y = ((mapSize/2 - distance) - member.y);
                }
            }else if(member.id == BL){
                if(out){
                    x = -(member.x - border);
                    y = (mapSize - member.y - border);
                }else{
                    x = ((mapSize/2 - distance) - member.x);
                    y = ((mapSize/2 + distance) - member.y);
                }
            }else if(member.id == BR){
                if(out){
                    x = (mapSize - member.x - border);
                    y = (mapSize - member.y - border);
                }else{
                    x = ((mapSize/2 + distance) - member.x);
                    y = ((mapSize/2 + distance) - member.y);
                }
            }else{
                double dist = 50, temp = 0;
                int index = -1;
                for(int i = 0; i < member.foods.size(); i++){
                    temp = (Math.abs(member.foods.get(i).x - member.x)+Math.abs(member.foods.get(i).y - member.y));
                    if(temp < dist){
                        dist = temp;
                        index = i;
                    }
                }
                if(index != -1){
                    x = (member.foods.get(index).x - member.x);
                    y = (member.foods.get(index).y - member.y);
                }
                doesNotCount = true;
            }

            if(!doesNotCount && Math.abs(x)+Math.abs(y) > maxSpeed)
                reached = false;
            member.setDirection(x,y);
        }

        if(reached){
            if(!out){ // in the middle.
                if(teamSize < 4){
                    int temp = TL;
                    TL = BR;
                    BR = temp;
                    temp = TR;
                    TR = BL;
                    BL = temp;
                    out = true;
                }else{
                    turnsWaiting++;
                }
            }else // no need to wait in the corners
                out = false;

            if(turnsWaiting >= turnsToWait){
                turnsToWait = 15;
                out = true;
                turnsWaiting = 0;
            }

        }

    }

    public static void main(String[] args){
        new CivilizedBeasts().run();
    }
}

มันกลายเป็นเรื่องยากสำหรับหน้าอกของฉันที่จะมีชีวิตรอดด้วยเหยื่อน้อยกว่า 200 ตัวเมื่อถึงเทิร์น + -12,000 กับศัตรูเฉพาะ Netcats ในเกม คุณจะมีความสุขกับสายพันธุ์นี้เพราะมันกินเหยื่อจำนวนมากด้วยความเร็วอย่างที่ไม่เคยมีใครทำได้ (ไม่ใช่คนที่ฆ่าเร็วและใหญ่จะได้รับชัยชนะ


3
ถ้าโดย " ดูแลพวกเขาดี " คุณหมายถึง " ฝูงพวกเขาไปที่กลางๆซ้ำ ๆ และฆ่า / กินพวกมัน " ถ้าใช่พวกเขาก็ทำได้ดี +1
Geobits

มันเป็นเรื่องตลกด้วย Evil Camels เวอร์ชั่นดั้งเดิมที่ไม่ได้กลายพันธุ์ยุทธวิธีที่ศิวิไลซ์นั้นไม่มีประสิทธิภาพเลยเพราะ 'อูฐกลาง'
2846289

1
@VadimR Crap ขอบคุณสำหรับการปรับปรุงอูฐของคุณ: PI ไม่สามารถทดสอบได้เนื่องจากไม่ใช่ Java แต่ฉันรู้ว่ากลยุทธ์ของฉันไม่มีประโยชน์กับนักล่าที่อยู่ในอาณาเขตของฉัน: P
Herjan

5
มันคือ Herjan อีกครั้ง! นอกจากนี้ "มันค่อนข้างยากสำหรับเต้านมของฉันที่จะอยู่รอดโดยมีเหยื่อน้อยกว่า 200 ตัว" (เน้นที่การเพิ่ม) ฉันไม่ได้ตระหนักถึงพลังของเต้านมของคุณขึ้นอยู่กับจำนวนของเหยื่อในการจำลองด้วยคอมพิวเตอร์ ....
Justin

5

ทับทิมแร้ง

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

พวกเขายังไม่เสร็จขณะที่ฉันโพสต์สิ่งนี้เพื่อผลักดันจังหวะ :)

ฉันหวังว่าจะ:

  • ทำให้พวกเขาค้นหาผู้ล่านอกเขตการมอง
  • คำนึงถึงเหยื่อ - บ่อยครั้งที่หนึ่งในนั้นอยู่ระหว่างอีกซองหนึ่งกับเหยื่อ!
  • เริ่มหมุนมันเพื่อหลีกเลี่ยงการอดอาหารหนึ่งมื้อ

22 เมษายน 2014:เพิ่มความเบื่อซึ่งทำให้พวกเขาเหนียวน้อยลงและช่วยให้พวกเขาล่าเหยื่อด้วยตัวเองและค้นหาผู้ล่า

class Animal
  attr_accessor :x, :y
end

class Hunter < Animal
  attr_accessor :id, :bored

  def initialize diff
   @diff = diff
   @lastGoal = nil
   @bored = false
  end

  def move goal
    if not goal.nil? 
      if @bored or goal != @lastGoal
        @lastGoal = goal
        return [goal.first - x + @diff.first, goal.last - y + @diff.last]
      end
    end
    [250 - x + 3*@diff.first, 250.0 - y + 3*@diff.last]
  end
end

class Pack
  def initialize
    @file = File.open "pack_log", "w"
    @count = 0
    @pack = []
    @order = []
    @hunters = []
    @closest = nil
    @random_goal = [250.0, 250.0]
    @locations = []
    @timer = 0
    d = 25.0
    diffs = [[d, d], [d, -d], [-d, -d], [-d, d], [0.0, 0.0]]
    5.times do |i|
      @pack << (Hunter.new diffs[i])
    end
    line = 0
    s = gets
    loop do
      s = gets
      if not (s =~ /dead\0/).nil?
        break
      end
      if line == 0
        get_structure s
      elsif line == 1
        get_positions s
      end
      @pack.length.times do |i|
        if line == i*2 + 3
          look_for_hunters s
          if @count <= i+1
            @closest = closest_hunter
            move
          end
        end
      end
      if not (s =~ /\0/).nil?
        line = 0
        @hunters = []
      else
        line += 1
      end
    end
  end

  def member_by_id id
    member = nil
    @pack.each do |v|
      if v.id == id
        member = v
        break
      end
    end
    member
  end

  def member_by_order index
    member_by_id @order[index]
  end

  def distance a, b
    Math.sqrt((a.first - b.first)**2 + (a.last - b.last)**2)
  end

  def bored?
    bored = true
    l1 = @locations.first
    @locations.each do |l2|
      if distance(l1, l2) > 20
        bored = false
      end
    end 
    bored
  end

  def bored_move v
    if @timer <= 0
      @random_goal = [rand(1000).to_f - 250, rand(1000).to_f - 250]
      @pack.each do |m|
        m.bored = true
      end
      @timer = 250 
    else
      @timer -= 1
    end
    v.move @random_goal
  end

  def move
    first_one = true
    answer = ""
    @order.each do |id|
      v = member_by_id id
      x, y = 0, 0
      if bored?
        x, y = (bored_move v)
      elsif @timer > 0
        @location = []
        x, y = (bored_move v)
      else
        @pack.each do |m|
          m.bored = false
        end
        @timer = 0
        x, y = v.move @closest
      end
      if not first_one
        answer << "\t"
      end
      answer << "#{x.to_i}.0\t#{y.to_i}.0"
      first_one = false
    end
    answer << "\0"
    print answer
    STDOUT.flush
  end

  def get_structure line
    @order = []
    if @pack.first.id.nil? 
      @count = 0
      line.split.each_with_index do |v, i|
        if i % 2 == 0
          @order << v.to_i
          @pack[i/2].id = v.to_i
          @count += 1
        end
      end
    else
      @count = 0
      line.split.each_with_index do |v, i|
        if i % 2 == 0
          @order << v.to_i
          @count += 1
        end
      end
    end
  end

  def get_positions line
    if not @order.empty?
      line.split.each_with_index do |v, i|
        if i % 2 == 0
          member_by_order(i/2).x = v.to_f
        else
          member_by_order(i/2).y = v.to_f
        end
      end
    end
  end

  def look_for_hunters line
    line.split.each_with_index do |v, i|
      if i % 2 == 0
        @hunters << [v.to_f]
      else
        @hunters.last << v.to_f
      end
    end
  end

  def closest_hunter
    mass_center
    closest = nil
    bestDist = 500*500
    if not @hunters.nil? and not @hunters == []
      @hunters.each do |h|
        our = false
        @pack.each do |v|
          if h.first == v.x and h.last == v.y
            our = true
          end
        end
        if our
          next
        end
        sqDist = (@mass_center.first - h.first)**2 + (@mass_center.last - h.last)**2
        if sqDist < bestDist
          closest = []
          closest << h.first
          closest << h.last
        end
      end
    end
    closest
  end

  def mass_center
    center_x = 0
    center_y = 0
    @pack.each do |v|
      center_x += v.x
      center_y += v.y
    end
    @mass_center = [center_x.to_f / @count, center_y.to_f / @count]
    if @locations.length > 30
      @locations.shift
      @locations << @mass_center
    else
      @locations << @mass_center
    end
  end
end

Pack.new

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

โอ้ใช่ในสภาพแวดล้อมการทดสอบของฉันฉันมีชุดนักล่าอีกสองชุด หากปราศจากพวกมันแล้วอีแร้งอาจจะไร้เดียงสา โดยเฉพาะอย่างยิ่ง netcats สามารถทำงานมุมได้อย่างรวดเร็วโดยไม่ต้องมองจากตรงกลาง
Legat

ฉันคิดว่าฉันรู้ว่าสิ่งใดที่ทำให้พวกเขากังวลเป็นพิเศษ การเต้นรำสงครามอูฐที่ชั่วร้าย @Geobits วิธีการเกี่ยวกับการต่อสู้บน Youtube? 10 รอบไม่มากเกินกว่าที่จะจับตาดู แน่นอนว่าจะต้องมีกองบัญชาการ ไม่ได้คาดหวังว่าผู้ชมหลายล้านคน แต่มันจะเป็นเรื่องสนุกที่จะเห็นว่าแพ็คของคุณมีประสิทธิภาพอย่างไรและอาจส่งเสียงเชียร์พวกเขาสักหน่อย :)
Legat

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

@Geobits ความเร็วแตกต่างกันมากในรอบ 8 นาทีหรือไม่? ฉันสงสัยว่ามันคุ้มค่าที่จะบันทึกเฟรมต่อรอบเพื่อให้พวกเขาสามารถเล่นในอัตราคงที่แทนที่จะชะลอตัวลงในช่วงที่มีการคำนวณอย่างเข้มข้น สำหรับวัตถุประสงค์ของ YouTube ฉันหมายถึง
trichoplax

5

Evil Eco Camels

แก้ไข: Mutation # 2 โอ้ไม่ฉันใช้สายในการทำนายการเคลื่อนไหวของเหยื่อเป็นคนแรกที่จะเอาชนะ Netcats ตกลงไม่ว่าจะเป็น

การกลายพันธุ์นี้มี$hunger_criticalตัวแปร (คงที่) การเปลี่ยนเป็นค่าที่สูงกว่า 1,000 ทำให้อูฐสามารถตามล่าได้เช่น Clairvoyants แล้ว:

Done in 11.93 minutes
camels1.pl(0)                   : Turn 23112    : Score 100
Netcats(1)                      : Turn 22508    : Score 80

หาก$hunger_criticalตั้งค่าเป็นเช่น 500 (ด้านล่าง) จากนั้นอูฐของฉัน (หลังจากได้เห็นความน่าสะพรึงกลัวของอารยธรรม ) พยายามที่จะประพฤติในลักษณะที่เป็นมิตรกับสิ่งแวดล้อม หากไม่หิวพวกเขาลาดตระเวนพื้นที่สำคัญของเกาะ - ศูนย์กลางและมุมเพื่อป้องกันการสังหารโดยนักล่าคนอื่น ด้วยศูนย์มันทำงานได้ไม่มากก็น้อย แนวคิดของการวนรอบเป็นมุมเพื่อหลบเหยื่อและทำให้ชีวิตยากขึ้นสำหรับแมวและปรสิต มันไม่ทำงาน เหยื่อที่โง่ก็เข้าไปในมุมต่อไป

มันน่าสนใจและflock[ALIGN]องค์ประกอบนั้นสามารถคาดเดาได้โดยนักล่าและการใช้งานของฉันแตกต่างจากของ Justhalf ฉันกลัวว่าจะมีข้อผิดพลาดเล็กน้อยในการนำรหัส Geobits ไปใช้เพื่อดู / เปรียบเทียบการล่าสัตว์ของ Camels กับ Clairvoyants

และโปรแกรมก็ค่อนข้างยาวแล้วขออภัย


แก้ไข: Mutation # 1 เกาะนี้มีกัมมันตภาพรังสีค่อนข้างมาก (ซึ่งอธิบายถึงการขาดพืชพรรณและธรรมชาติที่ไม่สามารถอธิบายได้ของสิ่งมีชีวิต 'เหยื่อ') ดังนั้นนี่คือการกลายพันธุ์ครั้งแรกของอูฐของฉัน ทุกคนสามารถเป็นนักล่าเดี่ยวได้หากหิวหรือไม่มีมุมว่างสำหรับทุกคน ฮันเตอร์พยายามไล่ล่าเหยื่อที่อยู่ใกล้เคียง หากไม่มีมันลาดตระเวนเป็นวงกลมกว้างรอบใจกลางเกาะจากนั้นไล่ล่าสัตว์ที่ใกล้ที่สุดเมื่อพบมัน น่าเสียดายที่ทิศทางของเหยื่อไม่สามารถคาดเดาได้เมื่ออยู่ใกล้ฝูง (คุ้มค่าการตรวจสอบ ... ) ดังนั้นการไล่ล่าเดี่ยวจึงไม่มีประสิทธิภาพมาก แต่ถ้าทำได้สำเร็จอูฐจะไปที่มุมฟรีที่ใกล้ที่สุด (ถ้ามี) เมื่อระดับความหิวอยู่ต่ำกว่าระดับที่แน่นอนอูฐก็ละทิ้งมุมของมัน (อาจจะสาปแช่ง Netcats ('อาหารอยู่ที่ไหน') )) และไปโรมมิ่งฟรีด้วยตัวเอง และอื่น ๆ


เรื่องตลกที่เหมือนกันบอกสองครั้งไม่ตลก แต่ (1) ฉันต้องเริ่มต้นที่ไหนสักแห่งและฉันใหม่กับสิ่งเหล่านี้ (2) ซื่อสัตย์ฉันคิดเกี่ยวกับกลยุทธ์มุม (และผู้ที่ไม่ได้?) ดู Netcats ก่อนทับทิม แมงมุมปรากฎตัวบนเกาะ

ดังนั้นเคยได้ยินเกี่ยวกับอูฐสัตว์กินเนื้อหรือไม่? สัตว์ที่น่าสงสารตื่นขึ้นมาบนเกาะที่ถูกทอดทิ้งในวันนี้เพื่อพบว่าไม่มีหญ้าหรือต้นไม้เลย แต่มีสีเขียวแปลก ๆ มากมายแม้ว่าจะเคลื่อนไหวได้เร็ว (กินได้) น่ารำคาญ ไม่มีนิสัยการล่าสัตว์ (แต่พวกเขาจะกลายพันธุ์ในไม่ช้าฉันหวังว่า) อูฐของฉันพัฒนาแผนการชั่วร้ายมากเพื่อความอยู่รอด: พวกเขาแยกและเข้าไปใน 1 ใน 4 มุมและอันดับที่หนึ่งไปที่ศูนย์ (จะตายที่นั่นก่อน มันเปิดออก) ในสถานที่ของพวกเขาพวกเขาอดทนรอการแสดงอูฐสงคราม - เต้นรำหรือบางทีพวกเขาก็พยายามที่จะไม่เหยียบย่ำสัตว์อื่น ๆ ที่นั่นแมงมุมและอื่น ๆ ...

#!/usr/bin/env perl
use strict;
use warnings;

binmode STDOUT;
binmode STDIN;
$| = 1;
$, = "\t";

my $hunger_critical = 500;
my %pack;
my ($turn, $prey_count, $predators_count);
my $patrol_radius_hunt = 150;
my $patrol_radius_corner = 16;
my $patrol_radius_center = 1;
my @roles = qw/C LL LR UL UR/; # or P (patrol if > 5), H (hunt)
my %places = (
    UL => {x =>   1 + $patrol_radius_corner, y =>   1 + $patrol_radius_corner},
    UR => {x => 499 - $patrol_radius_corner, y =>   1 + $patrol_radius_corner},
    LR => {x => 499 - $patrol_radius_corner, y => 499 - $patrol_radius_corner},
    LL => {x =>   1 + $patrol_radius_corner, y => 499 - $patrol_radius_corner},
    C  => {x => 250, y => 250},
);

sub sq_dist {
    my ($x1, $y1, $x2, $y2) = @_;
    return ($x1 - $x2)**2 + ($y1 - $y2)**2
}

sub distance {
    return sqrt(&sq_dist)
}

sub assign_role {
    my $camel = shift;
    if (@roles) {
        my %choice = (d => 1000, i => 0);
        for my $i (0..$#roles) {
            my $r = $roles[$i];
            if ($r eq 'C') {
                if ($prey_count > 700) {
                    $choice{i} = $i;
                    last
                }
                else {
                    next
                }
            }
            my $d = distance($camel->{x}, $camel->{y}, $places{$r}{x}, $places{$r}{y});
            if ($d < $choice{d}) {
                @choice{qw/d i/} = ($d, $i)
            }
        }
        return splice @roles, $choice{i}, 1
    }
    else {
        return 'P'
    }
}

sub xy_average {
    my $xy = shift;
    my $x = my $y = 0;
    if ($xy && @$xy) {
        for my $item (@$xy) {
            $x += $item ->{x};
            $y += $item->{y}
        }
        $x /= @$xy;
        $y /= @$xy
    }
    return $x, $y
}

sub patrol {
    my ($xc, $yc, $radius, $camel) = @_;
    my ($x, $y) = ($camel->{x} - $xc, $camel->{y} - $yc);
    my $d = distance(0, 0, $x, $y);
    my $a = atan2($y, $x);
    if (abs($d - $radius) < 3) {
        $a += 6 / $radius
    }
    return $radius * cos($a) - $x, $radius * sin($a) - $y
}

while (1) {

    # Get input

    my @in;
    # Line 0 - turn, counts
    $_ = <>;
    die if /dead/;
    ($turn, $prey_count, $predators_count) = /\0?(\S+)\t(\S+)\t(\S+)/;
    # Line 1 - pack's ids and hunger
    $_ = <>;
    while (/(\S+)\t(\S+)/g) {
        push @in, {id => $1, hunger => $2}
    };
    # Line 2 - positions
    $_ = <>;
    for my $animal (@in) {
        /(\S+)\t(\S+)/g;
        ($animal->{x}, $animal->{y}) = ($1, $2);
    }
    # 2 lines per member, visible prey and predators
    for my $animal (@in) {
        $_ = <>;
        my @prey;
        while (/(\S+)\t(\S+)/g) {
            push @prey, {x => $1, y => $2}
        };
        $animal->{prey} = \@prey;
        $_ = <>;
        my @beasts;
        while (/(\S+)\t(\S+)/g) {
            push @beasts, {x => $1, y => $2}
        };
        $animal->{beasts} = \@beasts
    }
    # trailing \0 zero will be prepended to next turn input

    # Update my pack

    for my $n (0..$#in) {
        my $animal = $in[$n];
        my $id = $animal->{id};
        # old average prey position
        my @opp = xy_average($pack{$id}{prey});
        # new average prey position
        my @npp = xy_average($animal->{prey});
        # average prey displacement
        my %apd = (x => $npp[0] - $opp[0], y => $npp[1] - $opp[1]);
        $pack{$id}{apd}    = \%apd;
        $pack{$id}{hunger} = $animal->{hunger};
        $pack{$id}{x}      = $animal->{x};
        $pack{$id}{y}      = $animal->{y};
        $pack{$id}{prey}   = $animal->{prey};
        $pack{$id}{beasts} = $animal->{beasts};
        $pack{$id}{num}    = $n;
        $pack{$id}{dead}   = 0
    }

    # Bury dead animals, retrieve their roles

    while (my ($id, $camel) = each %pack) {
        if ($camel->{dead}) {
            my $role = $camel->{role};
            push @roles, $role if $role ne 'P' and $role ne 'H';
            delete $pack{$id};
        }
        else {
            $camel->{dead} = 1
        }
    }

    # See that everyone has a role and lives accordingly

    my @out;
    for my $camel (values %pack) {
        my $role = $camel->{role} ||= assign_role($camel);
        if ($camel->{hunger} < $hunger_critical and $role ne 'H') {
            push @roles, $role if $role ne 'P';
            $role = $camel->{role} = 'H'
        }
        if ($camel->{hunger} > $hunger_critical and ($role eq 'H' or $role eq 'P') and $prey_count > 400) {
            $role = $camel->{role} = assign_role($camel)
        }
        my @vector = (0, 0);
        if ($role eq 'H') {
            my @prey = @{$camel->{prey}};
            if (@prey) {
                my %nearest = (p => undef, dd => 2500);
                for my $prey (@prey) {
                    my $dd = sq_dist($camel->{x}, $camel->{y}, $prey->{x}, $prey->{y});
                    if ($dd <= $nearest{dd}) {
                        @nearest{qw/p dd/} = ($prey, $dd)
                    }
                }
                my $target = $nearest{p};
                if ($nearest{dd} > 900) {
                    @vector = ($target->{x} - $camel->{x}, $target->{y} - $camel->{y})
                }
                else {
                    my @vect = map{{x => 0, y => 0}}1..5;
                    my $n = 0;
                    for my $prey (@prey) {
                        next if $prey eq $target;
                        my $dd = sq_dist($target->{x}, $target->{y}, $prey->{x}, $prey->{y}) + 1/(~0);
                        next if $dd > 900;
                        $n ++;
                        my $dx = $prey->{x} - $target->{x};
                        my $dy = $prey->{y} - $target->{y};
                        $vect[1]{x} -= $dx / $dd;
                        $vect[1]{y} -= $dy / $dd;
                        $vect[2]{x} += $dx * $dd;
                        $vect[2]{y} += $dy * $dd
                    }
                    $vect[0] = {x => $n * $camel->{apd}{x}, y => $n * $camel->{apd}{y}};
                    my $dx = abs(250 - $target->{x});
                    my $dy = abs(250 - $target->{y});
                    my $d = $dx > $dy ? $dx : $dy;
                    if ($d > 240) {
                        $vect[4]{x} = $dx * $d;
                        $vect[4]{y} = $dy * $d;
                    }
                    for my $v (@vect) {
                        my $d = sqrt($v->{x}**2 + $v->{y}**2) + 1/(~0);
                        $v->{x} /= $d;
                        $v->{y} /= $d;
                    }
                    for my $beast (@{$camel->{beasts}}, $camel) {
                        my $dd = sq_dist($target->{x}, $target->{y}, $beast->{x}, $beast->{y});
                        next if $dd > 900;
                        $vect[3]{x} += $target->{x} - $beast->{x};
                        $vect[3]{y} += $target->{y} - $beast->{y};
                    }
                    $vector[0] = 5 * 1   * $vect[0]{x}
                               + 5 * 1   * $vect[1]{x}
                               + 5 * .96 * $vect[2]{x}
                               + 1 * 2   * $vect[3]{x}
                               + 5 * 4   * $vect[4]{x};
                    $vector[1] = 5 * 1   * $vect[0]{y}
                               + 5 * 1   * $vect[1]{y}
                               + 5 * .96 * $vect[2]{y}
                               + 1 * 2   * $vect[3]{y}
                               + 5 * 4   * $vect[4]{y};
                    my $dd = $vector[0]**2 + $vector[1]**2;
                    if ($dd > 36) {
                        my $d = sqrt($dd);
                        @vector = map {$_ * 6.1 /$d} @vector
                    }
                }
            }
            else {
                @vector = patrol(250, 250, $patrol_radius_hunt, $camel)
            }
        }
        elsif ($role eq 'P') {
            @vector = patrol(250, 250, $patrol_radius_hunt, $camel)
        }
        else {
            my $r = $role eq 'C' 
                ? $patrol_radius_center 
                : $patrol_radius_corner;
            @vector = patrol($places{$role}{x}, $places{$role}{y}, $r, $camel)
        }
        my $id_x = $camel->{num} << 1;
        my $id_y = $id_x + 1;
        @out[$id_x, $id_y] = @vector
    }

    # And let the cruel world know about it

    print @out;
    print "\0"
}

__END__

5
นี่จะต้องเป็นสคริปต์ Perl ที่ชัดเจนที่สุดเท่าที่ฉันเคยเห็นในเว็บไซต์นี้จนถึงปัจจุบัน
Geobits

คุณต้องไปที่มุมเพื่อไล่พวกเขาอย่างมีประสิทธิภาพมิฉะนั้นคุณจะเข้าร่วมการสังหาร Netcats จริงๆฮ่า ๆ ๆ
justhalf

@ justhalf มันเหมือนที่ฉันพูด: แผนไม่ทำงาน ปรสิตที่นั่งอยู่ตรงมุมก็ไม่ได้ยิงเหยื่อออกไป หืมมมอาจเป็นสัตว์ 2 ตัวหรือมากกว่าที่ลาดตระเวนหนึ่งมุมจะช่วยได้
2846289

อูฐของคุณค่อนข้างดีจริง ๆ ! โชคดี (สำหรับฉัน) ฉันได้ปรับปรุง Clairvoyants ของฉันดังนั้นส่วนใหญ่ (ไม่เสมอไป) ฝูงของฉันจะชนะคุณในระหว่างการต่อสู้ครั้งสุดท้าย ที่น่าสนใจ!
justhalf

1
หากคุณอยู่ใกล้กว่า 8 (20-2 * 6) หน่วยจากเหยื่อเราจะเห็นการเคลื่อนไหวของเหยื่ออื่น ๆ ทั้งหมดที่อยู่ภายใน 30 หน่วยของเหยื่อของเราในเทิร์นปัจจุบัน และvecคุณสมบัติเป็นเพียงการกำจัดจากเทิร์นก่อนหน้าถึงเทิร์นปัจจุบัน และอย่างที่ฉันบอกว่าเราทำการจับคู่จากเทิร์นก่อนหน้าเพื่อค้นหาว่าเหยื่อคนไหนไปทางไหนเราไม่สามารถพึ่งพาคำสั่งของเหยื่อได้ สิ่งนี้เป็นไปได้เพราะเหยื่อมัก (ในสถานการณ์ปกติ) รักษาระยะห่างจากกันและกัน (> 12 หน่วย) และเวลาส่วนใหญ่เราสามารถจับคู่เหยื่อในเทิร์นก่อนหน้ากับเทิร์นปัจจุบัน
justhalf

4

AbleDogs - PHP

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

ใส่รหัสลงในAbleDogsไฟล์และเรียกใช้ด้วยphp AbleDogs

<?php
// simulation parameters

define ("ARENA_SIZE", 500);

define ("HUNGER_MAX", 1000);

define ("PREY_SPEED", 6);
define ("PRED_SPEED", 6.1);

define ("PREY_VISION", 30);
define ("PRED_VISION", 50);

define ("WALL_BOUNCE", 10); // distance from a wall from which a prey starts bouncing

// derived constants

define ("PRED_SPEED2" , PRED_SPEED  * PRED_SPEED );
define ("PRED_VISION2", PRED_VISION * PRED_VISION);
define ("PREY_VISION2", PREY_VISION * PREY_VISION);

// grid to speedup preys lookup

define ("GRID_SIZE", ceil (ARENA_SIZE/PRED_VISION));
define ("GRID_STEP", ARENA_SIZE/GRID_SIZE);

// search patterns

define ("SEARCH_OFFSET", WALL_BOUNCE+PRED_VISION/sqrt(2));
define ("SEARCH_WIDTH" , 2*sqrt(PRED_VISION2-PRED_SPEED2/4));
define ("SEARCH_HEIGHT", ARENA_SIZE-2*SEARCH_OFFSET);
define ("SEARCH_SIZE"  , ceil(SEARCH_HEIGHT/SEARCH_WIDTH));
define ("SEARCH_STEP"  , SEARCH_HEIGHT/SEARCH_SIZE);
define ("SEARCH_LEGS"  , 2*SEARCH_SIZE+1);

// tracking

define ("MAX_TRACK_ERROR", 10); // max abs distance for prey tracking correlation
define ("TRACKING_HUNGER_START", HUNGER_MAX*.9); // hunger limit to try and eat the tracked prey (start of game)
define ("TRACKING_HUNGER_END", 4);     // idem, for endgame
define ("TRACKING_DISTANCE", PREY_SPEED*2.5);
define ("TRACKING_DISTANCE2", TRACKING_DISTANCE * TRACKING_DISTANCE);

class Point {
    public $x = 0;
    public $y = 0;

    function __construct ($x=0, $y=0)
    {
        $this->x = (float)$x;
        $this->y = (float)$y;
    }

    function __toString() // for comparisons
    {
        return "$this->x,$this->y";
    }

    function multiply ($scalar)
    {
        return new Point ($this->x * $scalar, $this->y * $scalar);
    }

    function add ($v)
    {
        return new Point ($this->x + $v->x, $this->y + $v->y);
    }

    function dot($v)
    {
        return $this->x * $v->x + $this->y * $v->y;
    }

    function rotate90()
    {
        return new Point (-$this->y, $this->x);
    }

    function vector_to ($goal)
    {
        return new Point ($goal->x - $this->x, $goal->y - $this->y);
    }

    function norm2 ()
    {
        return $this->dot ($this);
    }

    function norm ()
    {
        return sqrt ($this->norm2());
    }

    function normalize ($norm = 1)
    {
        $n = $this->norm();
        if ($n != 0) $n = $norm/$n;
        return $this->multiply ($n);
    }

    function limit ($norm)
    {
        return $this->norm() > $norm
             ? $this->normalize($norm)
             : clone $this;
    }
}

class Search {

    function __construct ($direction)
    {
        switch ($direction % 4)
        {
            case 0: $this->pos = new Point (          0,           0); break;
            case 1: $this->pos = new Point (SEARCH_SIZE,           0); break;
            case 2: $this->pos = new Point (SEARCH_SIZE, SEARCH_SIZE); break;
            case 3: $this->pos = new Point (          0, SEARCH_SIZE); break;
        }
        $this->start();
    }

    private function start ()
    {
        $this->dir = $this->pos->x == $this->pos->y;
        $this->adj = $this->pos->x ? -1 : 1;
        $this->target = new Point ($this->pos->x * SEARCH_STEP + SEARCH_OFFSET,
                                   $this->pos->y * SEARCH_STEP + SEARCH_OFFSET);
        $this->leg = 0;
    }

    function point ($pos)
    {
        if ($pos == $this->target)
        {
            if ($this->leg % 2)
            {
                if ($this->dir) $this->pos->y+= $this->adj;
                else            $this->pos->x+= $this->adj;
            }
            else
            {
                if ($this->dir) $this->pos->x = $this->pos->x ? 0 : SEARCH_SIZE;
                else            $this->pos->y = $this->pos->y ? 0 : SEARCH_SIZE;
            }
            $this->leg++;
            if ($this->leg == SEARCH_LEGS) $this->start();
            $this->target = new Point ($this->pos->x * SEARCH_STEP + SEARCH_OFFSET,
                                       $this->pos->y * SEARCH_STEP + SEARCH_OFFSET);
        }
        return $this->target;
    }
}

class Pack {

    public static $turn;   // turn number
    public static $size;   // number of live members
    public static $member; // array of members

    public static $prev_preys;     // previous coordinates of all preys
    public static $prev_preds;     // previous coordinates of foreign predators

    public static $n_preys; // total number of preys     (including those not currently seen)
    public static $n_preds; // total number of predators (including those not currently seen)

    public static $preys;     // coordinates of all preys
    public static $preds;     // coordinates of all predators
    public static $own_preds; // coordinates of all predators in our pack
    public static $foe_preds; // coordinates of all foreign predators

    public static $arena_center; // arena center

    private static $output_order; // to send output according to input order

    function init ()
    {
        Pack::$member = array();
        Pack::$arena_center = new Point (ARENA_SIZE/2, ARENA_SIZE/2);
    }

    function read_line ($line)
    {
        $values = array();
        if ($line == "") return $values;
        $input = explode ("\t", $line);
        $num = count($input);
        if ($num % 2) panic ("read_line: invalid input $line num $num");
        $num /= 2;
        for ($i = 0 ; $i != $num ; $i++)
        {
            $values[] = new Point ($input[$i*2  ], $input[$i*2+1]);
        }
        return $values;
    }

    function read_input ()
    {
        // read controller input (blocking)
        $input = "";
        while (($in = fread(STDIN, 1)) !== false)
        {
            if ($in == "\0") break;
            $input .= $in;
        }

        // check extinction
        if ($input == "dead") return false;
        $lines = explode ("\n", $input);

        // save previous predators and preys positions
        Pack::$prev_preys = Pack::$preys;
        Pack::$prev_preds = Pack::$foe_preds;

        // line 0: turn, preys, predators
        list (self::$turn, Pack::$n_preys, Pack::$n_preds) = explode ("\t", $lines[0]);

        // line 1: list of ids and hunger levels
        $id = array();
        Pack::$size = 0;
        Pack::$output_order = array();
        foreach (Pack::read_line($lines[1]) as $i=>$v)
        {
            $id[$i] = $v->x;
            Pack::$output_order[] = $id[$i];

            if (!isset (Pack::$member[$id[$i]])) Pack::$member[$id[$i]] = static::new_member();
            Pack::$size++;
            Pack::$member[$id[$i]]->hunger = $v->y;
            Pack::$member[$id[$i]]->ttl = self::$turn;
        }

        // line 2: member positions
        Pack::$own_preds = array();
        foreach (Pack::read_line($lines[2]) as $i=>$pos)
        {
            Pack::$member[$id[$i]]->pos = $pos;
            Pack::$own_preds[] = $pos;
        }

        // lines 3 to 2*#members+3: coordinates of all visible preys and predators
        $preys = array();
        $preds = array();
        $y_seen = array();
        $d_seen = array();
        for ($i = 0 ; $i != Pack::$size ; $i++)
        {
            // visible preys
            foreach (Pack::read_line($lines[2*$i+3]) as $coords)
            {
                if (!in_array ($coords, $preys) || !isset($y_seen[(string)$coords]))
                {
                    $preys[] = $coords;
                }
            }
            foreach ($preys as $p) $y_seen[(string)$p] = true;

            // visible predators
            foreach (Pack::read_line($lines[2*$i+4]) as $coords)
            {
                if (!in_array ($coords, $preds) || !isset($d_seen[(string)$coords]))
                {
                    $preds[] = $coords;
                }
            }
            foreach ($preds as $p) $d_seen[(string)$p] = true;
        }

        // remove dead members
        foreach (Pack::$member as $k => $m)
        {
            if ($m->ttl != self::$turn)
            {
                unset (Pack::$member[$k]);
            }
        }

        // filter out own positions from predators list
        Pack::$foe_preds = array_diff ($preds, Pack::$own_preds);
        Pack::$preds = Pack::$foe_preds;
        foreach (Pack::$own_preds as $p) Pack::$preds[] = $p;
        Pack::$preys = $preys;

        // done
        return true;
    }

    function output_moves ()
    {
        $output = array();
        foreach (Pack::$output_order as $i)
        {
            $output[] = Pack::$member[$i]->move->x;
            $output[] = Pack::$member[$i]->move->y;
        }
        echo implode ("\t", $output) . "\0";
    }

    static function point_closest_to_walls ($pos)
    {
        $delta = $pos->vector_to (Pack::$arena_center);
        if (abs ($delta->x) > abs ($delta->y))
        {
            $y = $pos->y;
            $x = $delta->x > 0 ? -1 : ARENA_SIZE+1;
        }
        else
        {
            $x = $pos->x;
            $y = $delta->y > 0 ? -1 : ARENA_SIZE+1;
        }
        return new Point ($x, $y);
    }

    static function in_arena ($pos)
    {
        $delta = $pos->vector_to (Pack::$arena_center);
        return abs ($delta->x) <= ARENA_SIZE/2 && abs ($delta->y) <= ARENA_SIZE/2;
    }

    static function clamp_to_arena (&$pos)
    {
        // mimics the slightly strange behaviour of the Java engine setInZeroBounds function
        if ($pos->x >= ARENA_SIZE) $pos->x = ARENA_SIZE-1; // should rather be ARENA_SIZE
        if ($pos->x <           0) $pos->x = 0;
        if ($pos->y >= ARENA_SIZE) $pos->y = ARENA_SIZE-1;
        if ($pos->y <           0) $pos->y = 0;
    }

    function get_closest ($pos, $set, $max_dist)
    {
        // check for empty set
        if (count ($set) == 0) return null;

        // construct an array of distances with the same indexes as the points
        $dist = array();
        $max_dist *= $max_dist;
        foreach ($set as $k=>$pt)
        {
            $d = $pos->vector_to($pt)->norm2();
            if ($d <= $max_dist) $dist[$k] = $d;
        }
        if (count($dist) == 0) return false;

        // get the key of the smallest distance and use it to retrieve the closest point
        $keys = array_keys ($dist, min($dist));
        return $set[$keys[0]];
    }

    function get_visible ($pos, $set)
    {
        $res = array();
        $skipped = false;
        $pts = 0;
        foreach ($set as $point)
        {
            $d = $pos->vector_to($point)->norm2();
            if ($d == 0 && !$skipped)
            {
                $skipped = true;
                continue; // skip ourself
            }
            if ($d > PREY_VISION2) continue; // skip far points
            $res[] = $point;
            if ($pts++ > 10) break; // too many points are useless since prediction will go haywire anyway
        }
        return $res;
    }
}
Pack::init();

class PackMember {
    public $pos; // current position
    public $ttl; // last turn reported alive

    function move_to ($goal)
    {
        $this->move = $this->pos->vector_to ($goal);
    }

    function intercept ($target_pos, $target_speed)
    {
        // change reference to position difference
        $delta = $this->pos->vector_to($target_pos);
        $i = $delta->normalize();
        $j = $i->rotate90();

        // match tangential speeds
        $vj = $target_speed->dot ($j);

        // deduce axial speed
        $vi = PRED_SPEED2 - $vj*$vj; // this should always be positive since predators are faster than preys
        $vi = sqrt ($vi);

        // return intercept speed in original reference coordinates
        return $i->multiply($vi)->add($j->multiply($vj));
    }
}

class Target {
    public $pos;      // current position
    public $pos_next; // predicted position
    public $speed;    // estimated speed

    function __construct ($pos)
    {
        $this->pos    = $pos;
        $this->speed  = new Point(0,0);
        $this->predict();
    }

    private function predict()
    {
        // predators contribution
        $preds = Pack::get_visible ($this->pos, Pack::$preds);
        $this->preds = count ($preds);
        $res = new Point();
        foreach ($preds as $predator)
        {
            $res = $res->add ($predator->vector_to ($this->pos));
        }
        $res = $res->multiply (2);

        // preys contribution
        $preys = Pack::get_visible ($this->pos, Pack::$preys);
        $this->preys = count ($preys);

        $f_cohesion  = new Point;
        $f_separate  = new Point();
        foreach ($preys as $prey)
        {
            $delta = $this->pos->vector_to ($prey);
            $d2 = $delta->norm2();
            if ($d2 != 0)
            {
                $f_cohesion  = $f_cohesion ->add ($delta->multiply ($d2));
                $f_separate  = $f_separate ->add ($delta->multiply (-1/$d2));
            }
        }

        $res = $res
        ->add ($this->speed->normalize(5*.96)) // assume all preys have same speed as target
        ->add ($f_cohesion ->normalize(5*1))
        ->add ($f_separate ->normalize(5*1));
        $delta = $this->pos->vector_to(Pack::$arena_center);
        $dist = max (abs($delta->x), abs($delta->y));
        if ($dist > (ARENA_SIZE/2-WALL_BOUNCE))
        {
            $res = $res->add ($delta->normalize(5*4));
        }

        $this->raw_speed = $res;
        $this->speed = $res->limit(PREY_SPEED);
        $this->pos_next = $this->pos->add ($this->speed);
        Pack::clamp_to_arena ($this->pos_next);
    }

    function track ()
    {
        // see if we can find our prey at the start of a new turn
        $min = 1e10;
        foreach (Raptors::$free_preys as $k=>$prey)
        {
            $dist = abs ($this->pos_next->x - $prey->x) + abs ($this->pos_next->y - $prey->y);
            if ($dist < $min)
            {
                $min = $dist;
                $new_pos = $prey;
                $new_k = $k;
                if ($min < .001) break;
            }
        }
        if ($min > MAX_TRACK_ERROR) return false;

        // remove this prey from free preys
        unset(Raptors::$free_preys[$new_k]);

        $delta = $new_pos->vector_to($this->pos_next);

        // update postion and speed
        if ($this->speed->norm2() == 0)
        {
            // this can be either an endgame prey not yet moving
            // OR initial speed for a new target
            $this->speed = $this->pos->vector_to ($new_pos);
        }
        $this->pos = $new_pos;

        // predict speed and position
        $this->predict();
        return true;
    }
}

class Raptor extends PackMember {

    // possible states
    const IDLE     = 1;
    const TRACKING = 2;
    const HUNTING  = 3;
    const RUSHING  = 4;
    public $state;

    public  $target;  // current prey
    public  $patrol;  // patrol governor

    private static $id_gen;

    function __construct ()
    {
        $this->patrol = new Search (++self::$id_gen);
        $this->target  = null;
        $this->state = Raptor::IDLE;
        $this->pos = null;
        $this->hunger = HUNGER_MAX;
    }

    function __destruct ()
    {
        $this->tracking_lost();
    }

    function tracking_lost()
    {
        $this->target  = null;
        $this->state = Raptor::IDLE;
    }

    function track_prey()
    {
        // stop tracking if hunger went back to max
        if ($this->hunger == HUNGER_MAX)
        {
            $this->tracking_lost();
        }

        // try to acquire a new target
        if (!$this->target)
        {
            $victim = Pack::get_closest ($this->pos, Raptors::$free_preys, PRED_VISION);
            if (!$victim) return;
            $this->target = new Target ($victim);
            $this->state = Raptor::TRACKING;
        }

        // track prey
        if (!$this->target->track (Pack::$preys))
        {
            // prey was eaten or move prediction failed
            $this->tracking_lost();
        }
    }

    function beat_competition ()
    {
        if ($this->target === null) return;
        $pm = $this->target->pos_next->vector_to ($this->pos);
        $dm = $pm->norm2();
        foreach (Pack::$foe_preds as $f)
        {
            $pf = $this->target->pos_next->vector_to($f);
            $df = $pf->norm2();
            if ($df > PRED_VISION2) continue;
//          if ($df < ($dm*2))
            {
                $this->state = Raptor::RUSHING;
                return;
            }
        }
        if ($this->state == Raptor::RUSHING) $this->state = Raptor::TRACKING;
        return;
    }
}

class Raptors extends Pack {
    public static $free_preys; // coordinates of all preys that are not targeted

    // allows generic Pack to create a proper pack member instance
    static function new_member()
    {
        return new Raptor();
    }

    // main AI loop
    static function think ()
    {
        $hunger_limit = Pack::$n_preys > 2 * Pack::$n_preds ? TRACKING_HUNGER_START : TRACKING_HUNGER_END;
        self::$free_preys = static::$preys;

        // update targets and members states
        foreach (Pack::$member as $m)
        {
            // track current targets
            $m->track_prey();

            // rush to target if a competitor draws near
            $m->beat_competition();

            // hunt if hungry enough
            if ($m->state == Raptor::TRACKING && $m->hunger < $hunger_limit)
            {
                $m->state = Raptor::HUNTING;
            }
        }

        // move members
        foreach (Pack::$member as $m)
        {
            switch ($m->state)
            {
            case Raptor::IDLE:
                $destination = $m->patrol->point($m->pos);
                break;
            case Raptor::TRACKING:
                $wall_point = Pack::point_closest_to_walls ($m->target->pos_next);
                $destination = $wall_point->vector_to ($m->target->pos_next)->normalize (TRACKING_DISTANCE)->add($m->target->pos_next);
                break;
            case Raptor::HUNTING:
                $wall_point = Pack::point_closest_to_walls ($m->target->pos_next);
                $to_hunter = $m->target->pos_next->vector_to ($m->pos);
                $dist_to_target = $to_hunter->norm();

                if ($dist_to_target > (PREY_VISION-PREY_SPEED)) // intercept the prey
                {
                    // use actual speed (i.e. true position delta, including wall stops)
                    $target_true_speed = $m->target->pos->vector_to ($m->target->pos_next);
                    $intercept_speed = $m->intercept ($m->target->pos, $target_true_speed);
                    $destination = $m->pos->add ($intercept_speed);
                }
                else if ($dist_to_target < PRED_SPEED) // pounce on the prey!
                {
                    $destination = $m->target->pos_next;
                }
                else if ($to_hunter->dot($m->target->speed) > 0)
                {
                    $destination = $m->target->pos_next;
                }
                else // goad the prey
                {
                    $to_wall = $m->target->pos->vector_to ($wall_point);
                    $wall_point = $wall_point;
                    $raw_speed = $m->target->raw_speed->add($m->target->pos->vector_to($m->pos)->multiply(2))->multiply (-0.5);
                    $wpd_t = $m->target->pos->vector_to ($wall_point)->normalize()->rotate90(); // wpd = Wanted Prey Direction
                    $delta = $wpd_t->multiply ($raw_speed->dot ($wpd_t));
                    $destination = $delta->vector_to ($m->target->pos_next);
                    if (!Pack::in_arena ($destination)) $destination = $m->target->pos_next;
                }
                break;
            case Raptor::RUSHING:
                $destination = $m->target->pos_next;
                break;
            }
            $m->move_to ($destination);
        }
    }
}

while (Raptors::read_input())
{
    Raptors::think();
    Raptors::output_moves();
}
?>

ข้อพิจารณาทั่วไป

  • มันเป็นเกมจบที่นับ คุณสามารถมีอัลกอริธึมการล่าสัตว์ที่ฉลาดที่สุดได้หากคุณไม่เห็นและจับเหยื่อเดี่ยวสองสามตัวเร็วกว่าฝ่ายค้านคุณก็แพ้

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

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

ไล่ล่าหาง

วิธีที่ไม่มีประสิทธิภาพที่สุดในการจับเหยื่อคือไล่ล่ามัน สมมติว่านักล่าคนเดียวไล่ล่าเหยื่อคนเดียวและไม่มีอิทธิพลภายนอก (ผนังเหยื่อคนอื่น ๆ ฯลฯ ) การไล่ล่าหางอาจอยู่ได้ตลอดไป ทันทีที่คุณเข้าสู่รัศมีการมองเห็นเหยื่อ 30 หน่วยเหยื่อจะหนีไปที่ความเร็ว 6 สำหรับ 6.1 ของคุณดังนั้นคุณจะได้รับระยะทาง. 1 ต่อการเลี้ยว: ในแนวเส้นตรงคุณจะต้องใช้ประมาณ 300 รอบเพื่อให้ได้

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

เห็นได้ชัดว่ากลยุทธ์การชนะคือการหาหนทางที่จะทำให้เหยื่อช้าลงนั่นคือการมีนักล่าอีกคนหรือมีกำแพง / มุมอยู่ด้านหน้า

ทำนาย

ด้วยความเร็วเหยื่อ 6 เหยื่อสามารถเคลื่อนที่ไปยังพื้นที่ 36 * pi หน่วยกำลังสอง ด้วยรัศมีที่จับได้ของ 1 การคาดเดาที่ตาบอดว่าเหยื่อรายต่อไปจะมีโอกาส 1/36 * pi (ประมาณ 1%) ที่จะประสบความสำเร็จ เห็นได้ชัดว่ามีบางสิ่งที่จะต้องทำเพื่อปรับปรุง!

เมื่อดูที่รหัสเครื่องยนต์จำลองคุณจะเห็นว่าอินพุตมีดังนี้

  • มองเห็นตำแหน่งเหยื่อและนักล่า
  • ความเร็วเหยื่อก่อนหน้า

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

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

เหยื่อบุก

ด้วยความรู้ที่แน่นอนเกี่ยวกับการคำนวณความเร็วของเหยื่อมันเป็นไปได้ที่จะ "คัดท้าย" เหยื่อที่กำหนดไปยังทิศทางที่ต้องการโดยการปรับตำแหน่งของนักล่า

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

ขโมยเหยื่อ

ลักษณะหนึ่งของพฤติกรรมของเหยื่อคืออิทธิพลของนักล่าเพิ่มขึ้นตามสัดส่วนของระยะห่างจากเหยื่อ (หากมันยังคงอยู่ภายในรัศมีการมองเห็นของเหยื่อ) นักล่าที่อยู่ใกล้ที่สุดจะมาหาเหยื่ออย่างน้อยที่สุดเหยื่อก็จะพรากไปจากมัน

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

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

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

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

การเปลี่ยนแปลงที่แนะนำ

เพื่อให้สามารถใช้กลยุทธ์ที่ซับซ้อนยิ่งขึ้นการย้ายนักล่าที่มีความเร็วสูงกว่าเหยื่ออาจมีค่าใช้จ่ายในคะแนนความหิวตามสัดส่วนกับความเร็วที่มากเกินไป พูดเช่นการเลื่อนขึ้นไปที่ความเร็ว 6 เป็นอิสระและทุกจุดที่ความเร็วสูงกว่า 6 ค่าใช้จ่าย 100 คะแนนความหิว (ไปที่ 6.3 ค่าใช้จ่าย 30 คะแนนความหิวต่อเทิร์นการเผาไหม้ 1,000 คะแนนความหิวจะอนุญาตให้ถึงความเร็ว 16 จับเหยื่อทำเช่นนั้น!)

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

สีพิเศษสำหรับชุดแรกค่อนข้างยากที่จะมองเห็น ฉันแนะนำสีฟ้าหรือสีส้มแทนสีน้ำเงิน


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

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

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

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

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

3

Lazy Pack Haskell

import Control.Monad
import Control.Concurrent

main :: IO ()
main=do
    t<-forkIO $ forever $ (putStrLn "Pack is paralyzed with indecision.\0")
    loop
    killThread t
        where
            loop=do
                line <- getLine
                case line of
                    "dead\0" -> return ()
                    _        -> loop

คุณจะต้องใช้แพลตฟอร์ม Haskellเพื่อเรียกใช้งานนี้ จากนั้นคุณใช้runhaskellคำสั่งเพื่อเรียกใช้ ฝูงของฉันรอให้เหยื่อมาหาพวกเขา


+1 สำหรับโซลูชันโครงกระดูกในภาษาใหม่ คุณคงมีความสุขที่ผู้คนจะสร้างกลยุทธ์ใหม่นอกเหนือจากนี้?
trichoplax

แน่นอนว่าทำไมไม่ (แม้ว่ามันจะไม่ทำอะไรเลยนอกจากสร้างผลผลิตคงที่และออกจาก "ตาย \ 0" ดังนั้นฉันไม่แน่ใจว่ามันจะมีประโยชน์มาก)
PyRulez

ฉันยังคงแนะนำให้ทุกคนที่ใช้-silentตัวเลือกนี้ใช้ตัวเลือกแม้ว่า ...
Geobits

3

ไม่ใช่รายการฉันสนใจเพิ่มสีที่กำหนดเองสำหรับแต่ละรายการที่เข้าร่วมใน ;)

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

Game.java

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.JFrame;

public class Game {

    static int preyStartCount = 0; // 0 means 1500 + (packs * 50)
    static int turn;
    static boolean silent = false;
    long startTime;

    JFrame frame;
    BufferedImage img;
    Color[] colors;

    Island map;
    List<Prey> preys;
    List<Predator> predators;
    List<Pack> packs;
    List<Pack> initPacks;

    public static void main(String[] args) throws InterruptedException {

        Game game = new Game();
        game.init(args);
        if (game.packs.size() > 0){
            game.run();
            game.score();
        }
        game.end();
    }

    void end() {
        frame.setVisible(false);
        frame.dispose();
        for (Pack pack : packs)
            pack.handler.end();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        } finally {
            for (Pack pack : packs)
                pack.handler.shutdown();
        }

        System.exit(0);
    }

    void score() {
        Collections.sort(initPacks);
        int score = 100;
        initPacks.get(0).score = score;
        for (int i = 1; i < initPacks.size(); i++) {
            Pack pack = initPacks.get(i);
            if (pack.extinctionTurn < initPacks.get(i - 1).extinctionTurn)
                score = score < 1 ? score : score * 80 / 100;
            pack.score = score;
        }
        print("", true);
        print("Done in " + getElapsedTime(), true);
        for (Pack pack : initPacks)
            print(pack.toString() + "\t: Turn " + pack.extinctionTurn + "\t: Score " + pack.score, true);
    }

    String getElapsedTime(){
        double elapsed = (System.currentTimeMillis() - startTime) / 1000d;
        if(elapsed < 60)
            return String.format("%.2f", elapsed) + " seconds";
        elapsed /= 60;
        if(elapsed < 60)
            return String.format("%.2f", elapsed) + " minutes";
        elapsed /= 60;
        return String.format("%.2f", elapsed) + " hours";       
    }


    public Game() {
        initPacks = new ArrayList<Pack>();
        packs = new ArrayList<Pack>();
        preys = new ArrayList<Prey>();
        predators = new ArrayList<Predator>();
    }

    void run() throws InterruptedException {
        frame.setVisible(true);
        turn = 0;
        Graphics2D g = img.createGraphics();

        printStatus();
        while (true) {
            turn++;

            getAllMoves();
            moveAll();
            spawn();
            removeDead();
            shuffle();

            if (turn % 500 == 0)
                printStatus();
            paint(frame, g);
            Thread.sleep(5);
            if (packs.size() < 1)
                break;
        }
    }

    void getAllMoves(){
        for (Prey prey : preys)
            prey.setNextMove();
        for (Pack pack : packs){    
            pack.talk(preys.size(), predators.size(), turn);
        }
        while(true){
            int doneCount = 0;
            for(Pack pack : packs)
                if(pack.doneTalking)
                    doneCount++;
            if(doneCount >= packs.size())
                break;
            try {Thread.sleep(1);}catch(InterruptedException e){}
        }
    }

    void moveAll(){
        for (Creature prey : preys) 
            prey.move();
        for(Pack pack : packs){
            for (Predator predator : pack.members) {
                predator.move();
                predator.eatOrStarve();
            }
        }
    }

    void paint(JFrame frame, Graphics2D g){
        g.setPaint(Color.BLACK);
        g.fillRect(0, 0, img.getWidth(), img.getHeight());

        for(Prey prey : preys)
            prey.paint(g);
        for(Pack pack : packs)
            for(Predator predator : pack.members)
                predator.paint(g);

        frame.repaint();
    }

    List<Prey> deadPreys;
    List<Predator> deadPredators;
    List<Pack> deadPacks;

    void removeDead(){
        deadPreys.clear();
        for (Prey prey : preys)
            if (!prey.alive)
                deadPreys.add(prey);
        preys.removeAll(deadPreys);

        deadPredators.clear();
        for (Predator predator : predators)
            if (!predator.alive)
                deadPredators.add(predator);
        predators.removeAll(deadPredators);

        deadPacks.clear();
        for (Pack pack : packs)
            if (!pack.alive)
                deadPacks.add(pack);
        packs.removeAll(deadPacks);

        for (Pack pack : packs) {
            pack.members.removeAll(deadPredators);
        }

        map.rebuildLists(preys, predators);
    }

    void shuffle(){
        Collections.shuffle(packs);
        for(Pack pack : packs)
            Collections.shuffle(pack.members);
    }

    void spawn(){
        if(turn % 5000 == 0)
            addPredators(1);
        if(turn % 1000 == 0)
            populatePrey(predators.size()-1, false);
    }

    void addPredators(int count){
        for(Pack pack : packs){
            if(!pack.alive)
                continue;
            if(pack.aliveCount == 0)
                continue;
            Predator parent = null;
            for(Predator predator : pack.members)
                if(predator.alive)
                    parent = predator;
            if(parent != null){
                for(int i=0;i<count;i++){
                    XY pos = new XY(Math.random() * 30, Math.random()   * 30);
                    pos.add(parent.pos);
                    pos.setInZeroBounds(Island.SIZE, Island.SIZE);
                    Predator child = new Predator(pack);
                    child.color = colors[pack.id];
                    child.moveTo(pos, Island.getCellByPosition(pos));
                    predators.add(child);
                    pack.members.add(child);
                    pack.aliveCount++;
                }
            }
        }
    }

    Color[] generateColors(int n){
        Color[] result = new Color[n];
        double maxR = -1000;
        double minR = 1000;
        double maxG = -1000;
        double minG = 1000;
        double maxB = -1000;
        double minB = 1000;
        double[][] colors = new double[n][3];
        for(int i=0; i<n; i++){
            double cos = Math.cos(i * 2 * Math.PI / n);
            double sin = Math.sin(i * 2 * Math.PI / n);
            double bright = 1;
            colors[i][0] = bright + sin/0.88;
            colors[i][1] = bright - 0.38*cos - 0.58*sin;
            colors[i][2] = bright + cos/0.49;
            maxR = Math.max(maxR, colors[i][0]);
            minR = Math.min(minR, colors[i][0]);
            maxG = Math.max(maxG, colors[i][1]);
            minG = Math.min(minG, colors[i][1]);
            maxB = Math.max(maxB, colors[i][2]);
            minB = Math.min(minB, colors[i][2]);
        }
        double scaleR = 255/(maxR-minR);
        double scaleG = 255/(maxG-minG);
        double scaleB = 255/(maxB-minB);
        for(int i=0; i<n; i++){
            int R = (int)Math.round(scaleR*(colors[i][0]-minR));
            int G = (int)Math.round(scaleG*(colors[i][1]-minG));
            int B = (int)Math.round(scaleB*(colors[i][2]-minB));
            result[i] = new Color(R,G,B);
        }
        return result;
    }

    void populatePredators(String[] args) {
        int start = 0;
        if(args[0].equals("-silent")){
            silent = true;
            start = 1;
        }

        colors = generateColors(args.length-start);
        if(colors.length==1){
            colors[0] = Color.BLUE;
        }

        for (int i = start; i < args.length; i++) {
            Pack pack = new Pack(args[i]);
            if (pack.handler.init()) {
                packs.add(pack);
                initPacks.add(pack);
            }
        }
        Collections.shuffle(packs);
        XY[] positions = map.getPackStartLocations(packs.size());
        XY offset = new XY(-15, -15);
        for(int i=0;i<packs.size();i++){
            Pack pack = packs.get(i);
            for (Predator predator : pack.members) {
                predator.color = colors[pack.id];
                XY pos = new XY(Math.random() * 30, Math.random()   * 30);
                pos.add(positions[i]);
                pos.add(offset);
                pos.setInZeroBounds(Island.SIZE, Island.SIZE);
                predator.moveTo(pos, Island.getCellByPosition(pos));
                predators.add(predator);
            }
        }
        deadPredators = new ArrayList<Predator>(predators.size());
        deadPacks = new ArrayList<Pack>(packs.size());
    }

    void populatePrey(int count, boolean center) {
        XY pos = new XY();
        for (int i = 0; i < count; i++) {
            Prey prey = new Prey();
            if(center){
                pos.x = Math.random() * 100 + 200;
                pos.y = Math.random() * 100 + 200;
            } else {
                pos.x = Math.random() * 500;
                pos.y = Math.random() * 500;
            }

            prey.moveTo(pos, Island.getCellByPosition(pos));
            preys.add(prey);
        }
        deadPreys = new ArrayList<Prey>(preys.size());
    }

    static void print(String txt){
        print(txt, false);
    }

    static void print(String txt, boolean override){
        if(!silent || override)
            System.out.println(txt);
    }

    void printStatus(){
        print("Turn " + turn + " : Prey " + preys.size()
                + " : Predators " + predators.size() + " (" + getElapsedTime() + " elapsed)");
    }

    @SuppressWarnings("serial")
    void init(String[] args) {
        startTime = System.currentTimeMillis();
        map = new Island();
        populatePredators(args);
        if (preyStartCount == 0)
            preyStartCount = 1500 + (packs.size() * 50);

        populatePrey(preyStartCount, true);
        map.rebuildLists(preys, predators);
        img = new BufferedImage(Island.SIZE, Island.SIZE, 1);
        frame = new JFrame() {
            @Override
            public void paint(Graphics g) {
                g.drawImage(img, 32, 32, null);
            }
        };
        frame.setSize(Island.SIZE+64, Island.SIZE+64);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                for (Pack pack : packs)
                    pack.handler.end();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                } finally {
                    for (Pack pack : packs)
                        pack.handler.shutdown();
                }
            }
        });
    }
}

Predator.java

import java.awt.Graphics2D;


public class Predator extends Creature {

    static int count = 0;

    int id;
    int hunger;
    Pack pack;

    public Prey eatOrStarve() {
        for (Prey prey : preys) {
            if (prey.alive && pos.isCloserThan(prey.pos, eatDist)) {
                prey.die();
                hunger = MAX_HUNGER;
                return prey;
            }
        }
        if (hunger-- < 1)
            die();
        return null;
    }

    @Override
    public void die() {
        super.die();
        pack.aliveCount--;
        Game.print(pack.toString() + " starved! " + pack.aliveCount + " members remaining.");
    }

    @Override
    void paint(Graphics2D g){
        g.setPaint(color);
        int size = ((hunger + 10) > MAX_HUNGER && Game.turn > 10) ? 3+(int)Math.pow((hunger+10-MAX_HUNGER)/4,3) : 3;
        g.drawOval((int)pos.x - 1, (int)pos.y - 1, size, size);
        g.fillOval((int)pos.x - 1, (int)pos.y - 1, size, size);
    }

    Predator(Pack pack) {
        super();
        id = count++;
        this.pack = pack;
        MAX_SPEED = 6.1;
        VISIBLE = 50;
        hunger = MAX_HUNGER;
    }

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