Blobs หิว KoTH


9

การประกวดเสร็จสิ้น! อ่านความคิดเห็นเกี่ยวกับ blobs เพื่อดูคะแนนของพวกเขา

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

พลังงานและการเคลื่อนไหว

หยดของคุณเริ่มต้นแต่ละรอบด้วยพลังงาน 100 ครั้งและไม่มีขีด จำกัด ปริมาณพลังงานที่สามารถรวบรวมได้ แต่ละรอบวิ่งเป็นรอบโดยแต่ละหยดมีตัวเลือกให้เคลื่อนที่ทิศเหนือทิศตะวันออกทิศใต้หรือทิศตะวันตกในรอบที่กำหนดหรือหยุดนิ่ง การเคลื่อนย้ายใช้พลังงาน 1 พลังงานและพลังงานนิ่งอยู่ที่ 0.25 ความยาวด้านของแผนที่คือceil(0.25 * blobCount) * 2 - 1หน่วยอย่างน้อย 9 หน่วย Blobs ทั้งหมดเริ่มต้นที่ขอบของแผนที่โดยมีหนึ่งวางในแต่ละมุมและทุกหยดถัดไปจะถูกวางไว้ 2 หน่วยจากคนอื่น ๆ ทุกๆ 30 รอบคลื่นของเม็ดจะถูกวางในจุดสุ่มรอบแผนที่อย่างน้อย 1 หน่วยจากขอบใด ๆ แต่ละครั้งที่คลื่นของเม็ดปรากฏขึ้นปริมาณของเม็ด (แต่เดิมจำนวนสองเท่าของ blobs หรือความกว้างของแผนที่แล้วแต่จำนวนใดจะใหญ่กว่า) ในคลื่นถัดไปจะลดลง 1 โดยบังคับให้จำนวน blobs ลดลงเมื่อเวลาผ่านไป เม็ดแต่ละคืนพลังงานระหว่าง 5 และ 15 เมื่อพลังงานของหยดน้อยกว่าหรือเท่ากับ 0 มันจะตาย

การรับประทานอาหาร

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

การตรวจจับและข้อมูล

Blobs สามารถเห็นเม็ดหรือ blobs อื่น ๆ ในระยะ 4 หน่วย เมื่อฟังก์ชั่นของพวกเขาถูกเรียก blobs มีให้กับ:

  • ความยาวด้านของแผนที่
  • ตำแหน่งของหยดบนแผนที่
  • ตำแหน่งของเม็ดทั้งหมดภายในรัศมีการค้นหาของพวกเขาเช่นเดียวกับค่าของพวกเขา
  • ตำแหน่งของ blobs ทั้งหมดที่อยู่ในรัศมีการค้นหารวมถึงพลังงานและ UID
  • พลังงาน UID และที่ตั้งของหยดที่มีการใช้งานฟังก์ชัน
  • วัตถุเก็บข้อมูลที่ไม่ซ้ำกับ blob
  • วัตถุหน่วยเก็บข้อมูลที่ใช้ร่วมกันโดย blobs ทั้งหมดที่เกี่ยวข้องกับ blob ผ่านการแยก

รุนแรง

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

การถ่ายโอนพลังงาน

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

ฟังก์ชั่นการจัดเก็บและ UID

เพื่อให้มีพฤติกรรมการเรียนรู้ที่ซับซ้อนยิ่งขึ้น Blobs ทั้งหมดจะได้รับ UID จำนวนเต็ม (Unique Identifer) UID เหล่านี้จะถูกสร้างแบบสุ่มในแต่ละแผนที่ป้องกันกลยุทธ์ตามเป้าหมายแต่ละเป้าหมาย เมื่อเรียกใช้ฟังก์ชันของหยดมันจะส่งผ่านอาร์กิวเมนต์สี่ตัว:

  1. ความยาวด้านของแผนที่เป็นจำนวนเต็ม
  2. วัตถุที่สองอาร์เรย์: และpellets blobsอาร์เรย์ทั้งสองมีวัตถุทั้งสองมีคุณสมบัติที่มีเม็ดหรือตำแหน่งหยดของรูปแบบเป็นpos [x,y]เม็ดจะมีenergyคุณสมบัติในขณะที่ blobs จะมีuidคุณสมบัติและenergyคุณสมบัติ
  3. วัตถุที่มีคุณสมบัติต่างๆของหยดมันก็จะผ่านไปที่: energy, และuid อาร์เรย์มีรูปแบบเป็นpospos[x,y]
  4. วัตถุที่มีวัตถุหน่วยเก็บข้อมูลสองแห่งของหยด selfคุณสมบัติมีวัตถุของแต่ละบุคคลการจัดเก็บข้อมูลที่สามารถปรับเปลี่ยนได้ แต่หยดเห็นสมควร (โดยการจัดการกับคุณสมบัติของวัตถุที่ถูกส่งผ่าน) และcommunalคุณสมบัติที่สามารถแก้ไขได้โดยญาติ ๆ

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

เพื่อให้ Blob ญาติรู้จักกันการจัดเก็บข้อมูลชุมชนจะต้องใช้สำหรับแต่ละหยดเพื่อบันทึก UID ของมันในอาร์เรย์หรือผ่านระบบอื่น ๆ

คืนค่า

ในการย้ายหรือแยกจะใช้ค่าส่งคืนของฟังก์ชัน ก่อนความหมายของทิศทางสำคัญในแง่ของพิกัด:

  • ทิศเหนือ = -Y
  • ตะวันออก = + X
  • ใต้ = + Y
  • ตะวันตก = -X

โปรดทราบว่า[0,0]เป็นมุมซ้ายด้านบนและ Y เพิ่มขึ้นเมื่อคุณลงไป ค่าที่ส่งคืนของฟังก์ชันควรเป็นไปตามกฎเหล่านี้:

  • เมื่อต้องการทำสิ่งใด:ส่งคืนสิ่งใด, 0, null, ไม่ได้กำหนด, เท็จหรือค่าอื่นใดที่เท่ากับเท็จ
  • เมื่อต้องการย้าย:ส่งกลับหนึ่งในสี่ตัวแปรทั่วโลก: เหนือ, ตะวันออก, ใต้หรือตะวันตกซึ่งเท่ากับ "เหนือ", "ตะวันออก", "ใต้" หรือ "ตะวันตก" (ซึ่งสามารถใช้เป็นค่าตอบแทนได้)
  • ในการแยก:ส่งคืนตัวแปรโกลบอล SplitNorth, SplitEast, SplitSouth หรือ SplitWest ทิศทางที่ระบุตำแหน่งที่จะวาง blob ใหม่

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

ฟังก์ชั่นห้องสมุดที่กำหนดไว้ล่วงหน้า

มีฟังก์ชั่นพื้นฐานบางอย่างที่มีอยู่โดยค่าเริ่มต้นเพื่อประหยัดเวลา:

taxiDist (pt1, pt2)

ส่งคืนระยะห่างจากรถแท็กซี่ระหว่างสองจุด (ระยะทาง X บวกระยะทาง Y)

taxiDist([0, 0], [2, 2]) //4
taxiDist([3, 4], [1, 5]) //3
taxiDist([1.25, 1.3], [1.3, 1.4]) //0.15
taxiDist([0, 0], [5, 2.5], 2.5) //3
taxiDist([0, 0], [2, 4], 2.5) //2.4

hypotDist (pt1, pt2)

ส่งคืนระยะห่างระหว่างสองจุดตามทฤษฎีบทพีทาโกรัส

hypotDist([0, 0], [5, 12]) //13
hypotDist([4, 6], [8, 9]) //5
hypotDist([0, 1], [2, 1]) //2
hypotDist([1, 1], [2, 2]) //sqrt(2)

modDir (dir, amt)

รับทิศทางที่ป้อนเข้าหมุนตามเข็มนาฬิกา 90 องศาamtจากนั้นส่งคืนค่าใหม่

modDist(North, 1) //East
modDist(East, 2) //West
modDist(West, 3) //South
modDist(South, 4) //South

ตัวอย่างหยด

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

function(map, near, me, storage) {
    if (me.energy > 150)
        return SplitNorth;
    if (!near.pellets.length)
        return null;
    var dirs = [0, 0, 0, 0];
    for (let p, i = 0; i < near.pellets.length; i++) {
        p = near.pellets[i];
        dirs[0] += me.pos[1] - p.pos[1];
        dirs[1] += p.pos[0] - me.pos[0];
        dirs[2] += p.pos[1] - me.pos[1];
        dirs[3] += me.pos[0] - p.pos[0];
    }
    return [North, East, South, West][dirs.indexOf(Math.max(...dirs))];
}

กฎระเบียบ

  • ห้ามมีช่องโหว่มาตรฐาน ยังไม่มีช่องโหว่ที่ไม่เป็นมาตรฐาน
  • ไม่มีหยดอาจพยายามแก้ไขหรืออ่านข้อมูลใด ๆ ที่ไม่ได้ส่งผ่านพารามิเตอร์
  • ไม่มี Blob ที่อาจพยายามแก้ไขตัวแปร return-value เพื่อก่อวินาศกรรม blobs อื่น ๆ
  • รอบนานจนกว่า blobs ที่เหลืออยู่เท่านั้นที่เป็นญาติ
  • หยดไม่สามารถแก้ไขข้อมูลโดยการฉีดฟังก์ชั่นเป็นพารามิเตอร์ที่แก้ไขค่าโดยใช้thisคำหลัก
  • การส่งทั้งหมดจะต้องเป็น Javascript หรือภาษาที่ไม่แตกต่างจาก Javascript (Python เป็นต้น) คำตอบทั้งหมดจะถูกแปลงเป็น Javascript สำหรับการแข่งขัน
  • ผู้ชนะคือหยดที่รวบรวมพลังงานได้สูงสุดในทุกรอบ (จากเม็ดหรือก้อนเล็ก ๆ ที่ไม่ใช่ญาติ)

ผู้ควบคุม: https://gist.github.com/RedwolfPrograms/1facc0afe24c5dfd3ada8b8a2c493242

ห้องแชท: https://chat.stackexchange.com/rooms/93370/hungry-blobs-koth


1
คุณสามารถขยายสิ่งนี้เป็นภาษาอื่น ๆ นอกเหนือจากจาวาสคริปต์ได้หรือไม่
ศูนย์รวมแห่งความไม่รู้

@EmbodimentofIgnorance ส่งเป็นภาษาใดก็ได้ที่คุณเลือกและฉันจะแปลงเป็น JS
โปรแกรม Redwolf

Blobs สามารถข้ามกันและกัน Ex: blob1 ที่ [0] [0] เคลื่อนที่ไปทางขวาและ blob2 ที่ [0] [1] จะเคลื่อนที่ไปทางซ้ายหรือหยดจะกินพลังงานที่ต่ำลงหรือไม่?
fəˈnɛtɪk


@ fəˈnɛtɪk ใช่บอทสามารถข้ามกันได้ ความท้าทายที่เกี่ยวข้องคือของฉัน (:
โปรแกรม Redwolf

คำตอบ:


3

คนเก็บตัว

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

รายละเอียดทางเทคนิค

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

function introvert(mapSize, vision, self, storage) {
  if (!storage.communal.friends)
    storage.communal.friends = {};
  if (!storage.communal.claims)
    storage.communal.claims = {};
  storage.communal.friends[self.uid] = true;
  for (var i in storage.communal.claims)
    if (storage.communal.claims[i] === self.uid) {
      storage.communal.claims = {};
      break;
    }
  var food = {};
  for (var p of vision.pellets) {
    var score = p.energy - taxiDist(p.pos, self.pos);
    if (score > 0)
      food[p.pos] = score;
  }
  var danger = {};
  for (var i = 0; i < mapSize; i++) {
    danger['-1,' + i] = true;
    danger[mapSize + ',' + i] = true;
    danger[i + ',' + mapSize] = true;
    danger[i + ',-1'] = true;
  }
  var relatives = {};
  for (var b of vision.blobs) {
    if (b.uid in storage.communal.friends) {
      relatives[b.pos] = true;
    } else if (!storage.self.justSplit && b.energy < self.energy - taxiDist(b.pos, self.pos) * 0.75) {
      var score = b.energy - taxiDist(b.pos, self.pos) * 1.25;
      if (score > 0)
        food[b.pos] = score;
    } else {
      danger[b.pos] = true;
      danger[b.pos[0] + ',' + (b.pos[1] - 1)] = true;
      danger[b.pos[0] + 1 + ',' + b.pos[1]] = true;
      danger[b.pos[0] + ',' + (b.pos[1] + 1)] = true;
      danger[b.pos[0] - 1 + ',' + b.pos[1]] = true;
    }
  }
  storage.self.justSplit = !danger[self.pos] && self.energy > 150;
  function fromData(n) {
    return n.split(',').map(s => parseInt(s));
  }
  function fs(f) {
    return food[f] / taxiDist(f, self.pos);
  }
  var target = Object.keys(food).filter(f => !(f in storage.communal.claims)).map(fromData).sort((a, b) => fs(b) - fs(a))[0];
  if (target)
    storage.communal.claims[target] = self.uid;
  function ms(m) {
    if (danger[m])
      return 99999999;
    var dists = Object.keys(relatives).map(r => hypotDist(fromData(r), m));
    return (target ? taxiDist(target, m) : 0) - (dists.length ? dists.reduce((a, b) => a + b) / dists.length : 0);
  }
  var candidates = [
    {p: self.pos},
    {p: [self.pos[0], self.pos[1] - 1], d: storage.self.justSplit ? SplitNorth : North},
    {p: [self.pos[0] + 1, self.pos[1]], d: storage.self.justSplit ? SplitEast : East},
    {p: [self.pos[0], self.pos[1] + 1], d: storage.self.justSplit ? SplitSouth : South},
    {p: [self.pos[0] - 1, self.pos[1]], d: storage.self.justSplit ? SplitWest : West}
  ];
  if (storage.self.justSplit)
    candidates.shift();
  return candidates.sort((a, b) => ms(a.p) - ms(b.p))[0].d;
}

ดูเหมือนว่าบอทที่น่ารักคนนี้! การประกวดควรจะเร็ว ๆ นี้ (เงินรางวัลจะหมดอายุในวันพรุ่งนี้)
โปรแกรม Redwolf

@ RedwolfPrograms ฉันได้ทำการทดสอบจริง ๆ ในตัวนักวิ่งและมันก็ชนะด้วยอัตรากำไรที่ค่อนข้างใหญ่
RamenChef

คะแนนเฉลี่ยต่อรอบ: 357.544
โปรแกรม Redwolf

1

มื้ออาหารแบบเคลื่อนไหว

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

function(map, near, me, storage) {
    var targs = near.pellets.map(el => taxiDist(el.pos, me.pos));
    var targ = near.pellets[targs.indexOf(Math.max(...targs))].pos;
    if (targ[0] == me.pos[0])
        return targ[1] < me.pos[1] ? North : South;
    return targ[0] < me.pos[0] ? West : East;
}

คะแนนเฉลี่ยต่อรอบ: 24.933
โปรแกรม Redwolf

และในเหตุการณ์ที่น่าประหลาดใจ, (แก้ไขเล็กน้อยเพื่อลดข้อบกพร่อง) 5 สายการบินชนะครั้งที่ 2
โปรแกรม

1

เครื่องทดสอบ bloblib

function(map, near, me, storage) {
    // BlobLib, the main purpose of this post
    const bloblib = {
        // Returns only pellets and blobs that are within the immediate neighbourhood (within 1 space of) me
        getNeighbours: (known) => {
            let neighbours = {};
            neighbours.pellets = known.pellets.filter(x => x.pos[0] >= me.pos[0] - 1 && x.pos[0] <= me.pos[0] + 1 && x.pos[1] >= me.pos[1] - 1 && x.pos[1] <= me.pos[1] + 1);
            neighbours.blobs = known.blobs.filter(x => x.pos[0] >= me.pos[0] - 1 && x.pos[0] <= me.pos[0] + 1 && x.pos[1] >= me.pos[1] - 1 && x.pos[1] <= me.pos[1] + 1);
            return neighbours;
        },
        // Gets the blob or pellet at the given location
        getByPos: (pos, known) => {
            let pellets = known.pellets.filter(x => x.pos[0] == pos[0] && x.pos[1] == pos[1]);
            let blobs = known.blobs.filter(x => x.pos[0] == pos[0] && x.pos[1] == pos[1]);
            if (blobs.length) return blobs[0];
            if (pellets.length) return pellets[0];
            return null;
        },
        // Returns a 2d array of size, containing any known blobs or pellets
        areaMatrix: (size, known) => {
            let matrix = [];
            for (let x = 0; x < size; x++) {
                let row = [];
                for (let y = 0; y < size; y++) {
                    let realPos = [me.pos[0] - (x + Math.floor(size / 2)), me.pos[1] - (y + Math.floor(size / 2))];
                    row.push(getByPos(realPos, known));
                }
                matrix.push(row);
            }
            return matrix;
        },
        // Gets a cardinal direction pointing from from to to
        cardDirTo: (to, from = me.pos) => {
            let diff = bloblib.multiDist(from, to);

            if (diff[0] == 0 && diff[1] == 0) return null;

            if (Math.abs(diff[0]) > Math.abs(diff[1])) {
                // Gunna be east or west
                return diff[0] > 0
                    ? East
                    : West;
            } else {
                return diff[1] > 0
                    ? South
                    : North;
            }
        },
        // Returns a vector of the X and Y distances between from and to
        multiDist: (from, to) => {
            return [to[0] - from[0], to[1] - from[1]]
        },
        // Gets the closest object in objs to position to
        getClosest: (objs, to = me.pos) => {
            if (!objs || !objs.length) return null;

            let sorted = objs.concat().sort((a, b) => taxiDist(a.pos, to) - taxiDist(b.pos, to));
            return sorted[0];
        },
        // Should be run at startup. Calculates which directions are unsafe to move in
        dangerSense: (origin) => {
            let neighbours = bloblib.getNeighbours(near);
            let matrix = bloblib.areaMatrix(3, neighbours);

            if (me.pos[1] == 0 || (matrix[1,0] && isThreat(matrix[1,0]))) bloblib.unsafeDirs.push(North);
            if (me.pos[0] == map - 1 || (matrix[2,1] && isThreat(matrix[2,1]))) bloblib.unsafeDirs.push(East);
            if (me.pos[0] == 0 || (matrix[0,1] && isThreat(matrix[0,1]))) bloblib.unsafeDirs.push(West);
            if (me.pos[1] == map - 1 || (matrix[1,2] && isThreat(matrix[1,2]))) bloblib.unsafeDirs.push(South);
        },
        isThreat: (blob) => {
            if (!blob.uid) return false;
            if (storage.communal.blobs.includes(blob.uid)) return true;

            return blob.energy >= me.energy - 1;
        }
        // Attempts to move in the given direction
        // Rotates the direction 90 if it can't safely move
        attemptMove: (dir = North) => {
            for (let i = 0; i < 4; i++) {
                if (bloblib.unsafeDirs.includes(dir)) dir = modDir(dir, i);
                else return dir;
            }
            return null;
        },
        // Attempts to split in the given direction
        // Rotates the direction 90 if it can't safely split
        attemptSplit: (dir = SplitNorth) => {
            for (let i = 0; i < 4; i++) {
                if (bloblib.unsafeDirs.includes(dir)) dir = modDir(dir, i);
                else return dir;
            }
            return null;
        },
        // Returns the next direction in which to move toward pos
        // Don't bother checking if we have enough energy, because if
        // we have < 1 energy we're basically dead anyway
        moveTo: (pos) => {
            return bloblib.performAction(bloblib.attemptMove(bloblib.cardDirTo(pos)));
        },
        // Simply registers the action in communal history, then returns it unmodified
        performAction: (action) => {
            storage.communal.history[me.uid].push(action);
            return action;
        },

        // Stores directions in which there is another blob
        // This wouldn't make sense to store across turns, so we don't bother
        unsafeDirs: []
    };
    bloblib.dangerSense(me.pos);

    // Register this blob
    if (!storage.communal.blobs) storage.communal.blobs = [];
    if (!storage.communal.blobs.includes(me.uid)) storage.communal.blobs.push(me.uid);

    // Register history for this blob
    if (!storage.communal.history) storage.communal.history = {};
    if (!storage.communal.history[me.uid]) storage.communal.history[me.uid] = [];

    // Split if we can and there are fewer than 10 blobs in our community
    if (me.energy > 150 && storage.communal.blobs.length < 10) {
        let split = bloblib.getSplit();
        if (split) return split;
    }

    // If we can't see any pellets or blobs, don't do anything
    if (!near.pellets.length && !near.blobs.length) return null;

    // Move toward the nearest pellet
    return bloblib.moveTo(bloblib.getClosest(near.pellets));
}

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

ในระยะสั้นบอทนี้ทำสิ่งต่อไปนี้:

If energy > 150 and blobs_in_team < 10: Try to split
If visible_pellets = 0 and visible_blobs = 0: do nothing
Move toward the closest pellet in a safe way
    that avoids moving into other stronger or equal blobs
    or off the edge of the map

ตอนนี้คุณสามารถเห็นพลังงานของหยดซึ่งอาจเป็นประโยชน์
โปรแกรม Redwolf

1
@ RedwolfPrograms ได้อัปเดต bloblib เพื่อพิจารณาว่า blobs ของศัตรูนั้นเป็น "ภัยคุกคาม" ตามระดับพลังงานหรือไม่
Skidsdev

คะแนนเฉลี่ยต่อรอบ: 7.913
โปรแกรม Redwolf

ระบบนี้อาจถูกนำมาใช้กับ blobs ที่ดี แต่ดูเหมือนว่ามันจะทำตัวแปลก ๆ
โปรแกรม Redwolf

1

โลภขี้ขลาด

import random

def greedy_coward(map_length, near, me, storage):
    interesting_objects = [] #objects I can eat
    bad_objects = [] #objects that eat me
    allowed_directions = ["North", "East", "South", "West"]

    # add pellets to objects that I'm interested in
    for i in near.pellets:
        interesting_objects.append(i)

    # figure out which blobs are good and which are bad
    for i in near.blobs:
        # if I'm under or equal powered, add it to bad_objects
        if i.energy >= me.energy: 
            bad_objects.append(i)
        # if I can eat it, add it to interesting objects.
        else:
            interesting_objects.append(i)

    # if there are any bad objects, process them.
    if not len(bad_objects) == 0:

        # find the nearest bad object and make sure I don't move towards it
        bad_objects_distances = []
        for i in bad_objects:
            bad_objects_distances.append(taxiDist(i.pos, me.pos))
        worst_object = bad_objects[bad_objects_distances.index(min(bad_objects))]

        # find the direction of the worst object
        bad_object_xy_distance = [worst_object.pos[0] - me.pos[1], worst_object.pos[1] - me.pos[1]]
        closest_number = min(bad_object_xy_distance)
        bad_object_direction_vague = [["West","East"],["North","South"]][bad_object_xy_distance.index(closest_number)]
        if closest_number < 0:
            bad_object_direction = bad_object_direction_vague[1]
        else:
            bad_object_direction = bad_object_direction_vague[0]

        # remove bad object direction from allowed directions
        allowed_directions.remove(bad_object_direction)

    # process interesting objects if they exist
    if not len(interesting_objects) == 0:

        # find the nearest interesting object
        interesting_objects_distances = []
        for i in interesting_objects:
            interesting_objects_distances.append(taxiDist(me.pos, i.pos))
            interesting_object = interesting_objects[interesting_objects_distances.index(min(interesting_objects_distances))]

        # find the direction of the best object
            good_object_xy_distance = [interesrting_object.pos[0] - me.pos[1], interesting_object.pos[1] - me.pos[1]]
            closest_number = min(good_object_xy_distance)
            good_object_direction_vague = [["West","East"],["North","South"]][good_object_xy_distance.index(closest_number)]
            if closest_number < 0:
                good_object_direction = good_object_direction_vague[1]
            else:
                good_object_direction = good_object_direction_vague[0]

        # if the good and bad objects are in the same direction, move randomly in a different direction
        if good_object_direction == bad_object_direction:
            return random.choice(allowed_directions)
        else: # otherwise go towards the good object.
            return good_object_direction

    return 0 # when in doubt, stay still

หรือใน JavaScript

function(map_length, near, me, storage) {
    var interesting_objects = []; //objects I can eat
    var bad_objects = []; //objects that eat me
    var allowed_directions = ["north", "east", "south", "west"];

    //add pellets to objects that I'm interested in
    for (let i in near.pellets) {
        interesting_objects.push(near.pellets[i]);
    }

    //figure out which blobs are good and which are bad
    for (let i in near.blobs) {
        //if I'm under or equal powered, add it to bad_objects
        if (near.blobs[i].energy >= me.energy) {
            bad_objects.push(near.blobs[i]);
        }
        //if I can eat it, add it to interesting objects.
        else {
            interesting_objects.push(near.blobs[i]);
        }
    }

    //if there are any bad objects, process them.
    if (bad_objects.length) {

        //find the nearest bad object and make sure I don't move towards it
        var bad_objects_distances = [];
        for (i in bad_objects) {
            bad_objects_distances.push(taxiDist(bad_objects[i].pos, me.pos));
        }
        var worst_object = bad_objects[bad_objects_distances.indexOf(Math.min(...bad_objects_distances))];

        //find the direction of the worst object
        var bad_object_xy_distance = [worst_object.pos[0] - me.pos[1], worst_object.pos[1] - me.pos[1]];
        var closest_number = Math.min(...bad_object_xy_distance.map(el => Math.abs(el)));
        var bad_object_direction_vague = [["west","east"],["north","south"]][bad_object_xy_distance.map(el => Math.abs(el)).indexOf(closest_number)];
        if (closest_number < 0) {
            var bad_object_direction = bad_object_direction_vague[1];
        } else {
            var bad_object_direction = bad_object_direction_vague[0];
        }

        //remove bad object direction from allowed directions
        allowed_directions = allowed_directions.filter(el => el !== bad_object_direction);

    }

    //process interesting objects if they exist
    if (interesting_objects.length) {

        //find the nearest interesting object
        var interesting_objects_distances = [];
        for (i in interesting_objects) {
            interesting_objects_distances.push(taxiDist(me.pos, interesting_objects[i].pos))
        }
        var interesting_object = interesting_objects[interesting_objects_distances.indexOf(Math.min(...interesting_objects_distances))];

        //find the direction of the best object
        var good_object_xy_distance = [interesting_object.pos[0] - me.pos[1], interesting_object.pos[1] - me.pos[1]];
        var closest_number = Math.min(...good_object_xy_distance.map(el => Math.abs(el)));
        var good_object_direction_vague = [["west","east"],["north","south"]][good_object_xy_distance.map(el => Math.abs(el)).indexOf(closest_number)];
        if (closest_number < 0) {
            var good_object_direction = good_object_direction_vague[1];
        } else {
            var good_object_direction = good_object_direction_vague[0];
        }

        //if the good and bad objects are in the same direction, move randomly in a different direction
        if (good_object_direction == bad_object_direction) {
            return allowed_directions[allowed_directions.length * Math.random() | 0];
        } else{ //otherwise go towards the good object.
            return good_object_direction;
        }

    }

    return 0; //when in doubt, stay still
}

บอทนี้ไม่น่าสนใจมาก มันทำหน้าที่ตามลำดับความสำคัญสอง:

  1. อย่ากิน
  2. กินสิ่งที่ใกล้ที่สุด

มันไม่เคยคายเพื่อเพิ่มความสามารถในการกินสิ่งอื่น ๆ


ฉันจะไปทำงานแปลสิ่งนี้! เมื่อฉันเสร็จฉันจะแนะนำการแก้ไขด้วยเวอร์ชัน JS
โปรแกรม

@ RedwolfPrograms ฟังดูดีขอบคุณมาก
สหาย SparklePony

ฉันคิดว่าคุณต้องเพิ่ม if / else เพื่อตรวจสอบว่ามีวัตถุดี / ไม่ดีจริง ๆ หรือไม่ มันทำให้เกิดปัญหาหลายประการในรุ่น JS
โปรแกรม

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

@RedwolfPrograms คุณมีรุ่น JS พร้อมหรือยัง?
RamenChef

1

SafetyBlob

บอทนี้ใช้ตรรกะเดียวกันกับ Safetycoin จาก KOTH ก่อนหน้านี้

มันทำงานอย่างไร

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

บอทนี้ไม่ได้ติดตามลูกของตัวเอง แต่พวกเขาไม่ควรชนกันเนื่องจากกลไกความปลอดภัย

 function SafetyBlob(map,local,me,stor){
  var center=(map/2|0)+1;
  var [x,y]=me.pos
  var uid=me.uid
  var others=local.blobs;
  var pellets=local.pellets;
  //Bot doesnt use storage because it just tries to find what it can.
  var willSplit=me.energy>150;
  var bestSafePelletValue=0;
  var bestSafePellet=null;
  var pellet;
  var other;
  //Head towards the best valued pellet (energy/distance) which can be reached before any larger or equal sized blobs or can be reached at the same time as smaller blobs
  for(i=0;i<pellets.length;i++){
    pellet=pellets[i]
    if(bestSafePelletValue<=pellet.energy/taxiDist(pellet.pos,me.pos)){
      for(j=0;j<others.length;j++){
        other=others[j];
        if(other.energy<me.energy){
          if(taxiDist(pellet.pos,me.pos)<=taxiDist(other.pos,pellet.pos)){
            if(taxiDist(pellet.pos,me.pos)<taxiDist(bestSafePellet.pos,me.pos)){
              bestSafePellet=pellet;
              bestSafePelletValue=pellet.energy/taxiDist(pellet.pos,me.pos);
            }
          }
        }
        if(other.energy>=me.energy){
          if(taxiDist(pellet.pos,me.pos)<taxiDist(other.pos,pellet.pos)){
            if(taxiDist(pellet.pos,me.pos)<taxiDist(bestSafePellet.pos,me.pos)){
              bestSafePellet=pellet;
              bestSafePelletValue=pellet.energy/taxiDist(pellet.pos,me.pos);
            }
          }
        }
      }
    }
  }

  if(bestSafePellet){
    [xPellet,yPellet]=bestSafePellet.pos;
    if(x<xPellet&&Math.abs(x-xPellet)>=Math.abs(y-yPellet)){
      return East;
    }
    if(x<xPellet&&Math.abs(x-xPellet)>=Math.abs(y-yPellet)){
      return West;
    }
    if(y<yPellet&&Math.abs(x-xPellet)<Math.abs(y-yPellet)){
      return South;
    }
    if(y<yPellet&&Math.abs(x-xPellet)<Math.abs(y-yPellet)){
      return North;
    }
  }
  
  var validMoves=["North","East","South","West","Stay"];
  var removeIndex=0;
  var safeEnergy;
  if(x==0)
    validMoves.splice(validMoves.indexOf("West"));
  if(x==map)
    validMoves.splice(validMoves.indexOf("East"));
  if(y==0)
    validMoves.splice(validMoves.indexOf("North"));
  if(y==map)
    validMoves.splice(validMoves.indexOf("South"));

  var possibleMoves=[...validMoves];
  possibleMoves.splice(possibleMoves.indexOf("Stay"));
  //If there is no safe pellet try to stick somewhat towards the middle
  //Ignore enemies unless at 2 distance from self and there is no safe pellet
  for(i=0;i<others.length;i++){
    other=others[i];
    safeEnergy=willSplit?(me.energy-50)/2:me.energy;
    if((other.energy>=safeEnergy)&&(taxiDist(me.pos,other.pos)<=2)){
      if(taxiDist(me.pos,other.pos)==1){
        if((removeIndex=validMoves.indexOf("Stay"))>=0){
          validMoves.splice(removeIndex,1)
        }
      }
      if(other.pos[0]<x){
        if((removeIndex=validMoves.indexOf("West"))>=0){
          validMoves.splice(removeIndex,1)
        }
      }
      if(other.pos[1]<y){
        if((removeIndex=validMoves.indexOf("South"))>=0){
          validMoves.splice(removeIndex,1)
        }
      }
      if(other.pos[0]>x){
        if((removeIndex=validMoves.indexOf("East"))>=0){
          validMoves.splice(removeIndex,1)
        }
      }
      if(other.pos[1]>y){
        if((removeIndex=validMoves.indexOf("North"))>=0){
          validMoves.splice(removeIndex,1)
        }
      }
    }
  }
  //If there are no safe moves move in a random direction (Reduce energy as much as possible with a slight chance of survival)
  if(!validMoves.length){
    switch (possibleMoves[Math.random()*possibleMoves.length|0]){
      case "North":
        return North;
      case "South":
        return South;
      case "East":
        return East;
      case "West":
        return West;
    }
  }
  //If there are safe moves bias towards moving towards the center block of 1/3 of the way from the sides
  if(!willSplit){
    //bias moving towards near the center
    biasedMoves=[];
    for(var i=0;i<validMoves.length;i++){
      switch(validMoves[i]){
        case "North":
          biasedMoves=biasedMoves.concat(y>center?"0".repeat(center/3|0).split``:"0".repeat(y-center).split``);
          break;
        case "South":
          biasedMoves=biasedMoves.concat(y<center?"2".repeat(center/3|0).split``:"2".repeat(center-y).split``);
          break;
        case "East":
          biasedMoves=biasedMoves.concat(y>center?"1".repeat(center/3|0).split``:"1".repeat(x-center).split``);
          break;
        case "West":
          biasedMoves=biasedMoves.concat(y<center?"3".repeat(center/3|0).split``:"3".repeat(center-x).split``);
          break;
        case "Stay":
          biasedMoves=biasedMoves.concat(["4"]);
          break;
      }
    }
  }
  if(willSplit){
    switch (biasedMoves[Math.random()*biasedMoves.length|0]){
      case "0":
        return SplitNorth;
      case "2":
        return SplitSouth;
      case "1":
        return SplitEast;
      case "3":
        return SplitWest;
      case "4":
        return Stay;
    }
  }
  else{
    switch (biasedMoves[Math.random()*biasedMoves.length|0]){
      case "0":
        return North;
      case "2":
        return South;
      case "1":
        return East;
      case "3":
        return West;
      case "4":
        return Stay;
    }
  }
}

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

@ RedwolfPrograms เป้าหมายไม่ได้รับรางวัล
fəˈnɛtɪk

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