Đói bụng KoTH


9

Cuộc thi kết thúc! Đọc bình luận trên các đốm màu để xem điểm của họ.

KoTH này được lấy cảm hứng lỏng lẻo từ Mô phỏng chọn lọc tự nhiên của Primer . Bot của bạn là một blob. Để sống sót, bạn phải ăn viên để lấy lại năng lượng, được sử dụng để di chuyển. Với năng lượng bổ sung, các đốm màu có thể chia thành hai.

Năng lượng và chuyển động

Blob của bạn bắt đầu mỗi vòng với 100 năng lượng, và nó không có giới hạn về lượng năng lượng mà nó có thể thu thập. Mỗi vòng được chạy theo lượt, với mỗi đốm màu có tùy chọn di chuyển Bắc, Đông, Nam hoặc Tây trong bất kỳ lượt nào, hoặc đứng yên. Di chuyển sử dụng 1 năng lượng, và đứng yên sử dụng 0,25 năng lượng. Chiều dài bên của bản đồ làceil(0.25 * blobCount) * 2 - 1đơn vị, với tối thiểu 9 đơn vị. Tất cả các đốm màu bắt đầu ở rìa bản đồ, với một đốm được đặt ở mỗi góc và mỗi đốm màu tiếp theo được đặt cách xa bất kỳ đơn vị nào khác. Cứ sau 30 lượt, một làn sóng viên được đặt vào các điểm ngẫu nhiên trên bản đồ, ít nhất 1 đơn vị từ bất kỳ cạnh nào. Mỗi khi một làn sóng xuất hiện, số lượng viên (ban đầu gấp đôi số lượng đốm hoặc chiều rộng của bản đồ, tùy theo số lượng lớn hơn) trong sóng tiếp theo sẽ giảm đi 1, buộc số lượng đốm sáng giảm theo thời gian. Mỗi viên phục hồi từ 5 đến 15 năng lượng. Khi năng lượng của một blob nhỏ hơn hoặc bằng 0, nó sẽ chết.

Ăn

Nếu hai hoặc nhiều đốm màu cố gắng chiếm cùng một vị trí, người có nhiều năng lượng nhất sẽ ăn những người khác, nhận năng lượng của họ. Nếu cả hai có năng lượng bằng nhau, cả hai đều biến mất.

Phát hiện và thông tin

Blobs có thể nhìn thấy bất kỳ viên hoặc các đốm màu khác trong khoảng cách 4 đơn vị. Khi các chức năng của chúng được gọi, các đốm màu được cung cấp với:

  • Chiều dài bên của bản đồ
  • Vị trí của blob trên bản đồ
  • Vị trí của tất cả các viên trong bán kính tìm kiếm của chúng, cũng như các giá trị của chúng
  • Vị trí của tất cả các đốm màu trong bán kính tìm kiếm của họ, cũng như năng lượng và UID của họ
  • Năng lượng, UID và vị trí của blob có chức năng đang được thực thi
  • Một đối tượng lưu trữ duy nhất cho blob
  • Một đối tượng lưu trữ được chia sẻ bởi tất cả các đốm màu liên quan đến blob thông qua việc chia tách

Tách

Nếu một đốm màu có hơn 50 năng lượng, nó có thể chọn tách. Tách 50 chi phí năng lượng, và bất kỳ năng lượng còn lại được chia đều giữa hai đốm màu. Tất cả các đốm màu đều là bản gốc hoặc bản sao tách, với mỗi bản sao truy nguyên về bản gốc. Tất cả những thứ này cùng nhau là "họ hàng". Tất cả người thân có một đối tượng lưu trữ chung. Người thân vẫn có thể ăn thịt lẫn nhau và có thể chia tách, sử dụng đối tượng lưu trữ của riêng họ hoặc thu thập năng lượng mà không ảnh hưởng đến người khác.

Chuyển giao năng lượng

Nếu hai đốm màu nằm cạnh nhau (sau khi di chuyển), một trong các bot có thể truyền năng lượng cho nhau. Này được thực hiện bằng cách quay SendNorth(amt), SendEast(amt), SendSouth(amt), hay SendWest(amt), với amtviệc một số đại diện cho số tiền gửi. Đây có thể là bất kỳ số tiền nào mà người gửi có thể đủ khả năng, bao gồm tất cả năng lượng của họ. Chúng tôi đề nghị rằng các blob đang nhận năng lượng được yêu cầu ở yên trong kho lưu trữ chung, để nó không bị mất đi khi năng lượng được truyền đi (mặc dù năng lượng sẽ không được khấu trừ khỏi tổng số của người gửi trong trường hợp này).

Chức năng, lưu trữ và UID

Để cho phép các hành vi học tập phức tạp hơn, tất cả các đốm màu sẽ được cung cấp một UID số nguyên (Định danh duy nhất). Các UID này sẽ được tạo ngẫu nhiên mỗi bản đồ, ngăn chặn các chiến lược dựa trên các mục tiêu riêng lẻ. Khi hàm blob được gọi, nó được truyền bốn đối số:

  1. Độ dài cạnh của bản đồ là một số nguyên
  2. Một đối tượng có hai mảng: pelletsblobs. Cả hai mảng đều chứa các đối tượng, cả hai đều có một thuộc postính chứa vị trí của viên hoặc blob được định dạng là [x,y]. Pellets sẽ có một energytài sản, trong khi các đốm màu sẽ có một uidtài sản và một energytài sản
  3. Một đối tượng có chứa các thuộc tính khác nhau của blob nó sẽ chuyển qua: energy, uid, và pos. Các posmảng được định dạng như[x,y]
  4. Một đối tượng chứa hai đối tượng lưu trữ của blob. Một thuộc selftính chứa một đối tượng lưu trữ riêng lẻ có thể được sửa đổi tuy nhiên blob thấy phù hợp (bằng cách thao tác các thuộc tính của đối tượng được truyền) và một thuộc communaltính có thể được sửa đổi bởi bất kỳ người thân nào.

Blobs không được di chuyển ngay lập tức để ngăn chặn các lượt trước / sau có lợi thế. Tất cả các chuyển động được xử lý theo nhóm (Tất cả các va chạm / ăn, sau đó tất cả các viên, sau đó tách ra, v.v.) Nếu một đốm rơi vào một viên hoặc các đốm nhỏ hơn và, trong quá trình sử dụng năng lượng cuối cùng của nó, blob vẫn sẽ tiêu thụ viên / năng lượng độc lập cho dù điều đó sẽ mang lại tổng năng lượng của nó trên 0.

Để các đốm tương đối nhận ra nhau, bộ lưu trữ chung phải được sử dụng cho mỗi đốm để ghi UID của nó trong một mảng hoặc thông qua một số hệ thống khác.

Giá trị trả về

Để di chuyển hoặc phân chia, giá trị trả về của hàm được sử dụng. Đầu tiên, ý nghĩa của các hướng hồng y về mặt tọa độ:

  • Bắc = -Y
  • Đông = + X
  • Nam = + Y
  • Tây = -X

Lưu ý rằng đó [0,0]là góc trên cùng bên trái và Y tăng khi bạn đi xuống. Giá trị trả về của hàm phải tuân theo các quy tắc sau:

  • Không làm gì: Trả về không có gì, 0, null, không xác định, sai hoặc bất kỳ giá trị nào khác tương đương với false
  • Di chuyển: Trả về một trong bốn biến toàn cầu: Bắc, Đông, Nam hoặc Tây, tương đương với "bắc", "đông", "nam" hoặc "tây" (cũng có thể được sử dụng làm giá trị trả về)
  • To Split: Trả về biến toàn cục SplitNorth, SplitEast, SplitSouth hoặc SplitWest, hướng cho biết nơi đặt blob mới

Nếu một lệnh tách được trả về và lượng năng lượng cần thiết lớn hơn hoặc bằng năng lượng của blob, sẽ không có gì xảy ra. Blobs sẽ không thể rời khỏi bản đồ.

Chức năng thư viện được xác định trước

Có một số chức năng cơ bản có sẵn theo mặc định, để tiết kiệm thời gian:

taxiDist (pt1, pt2)

Trả về khoảng cách taxi giữa hai điểm (khoảng cách X cộng với khoảng cách 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)

Trả về khoảng cách giữa hai điểm theo định lý pythagore

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)

Thực hiện hướng nhập, xoay 90 độ theo chiều kim đồng hồ amt, sau đó trả về giá trị mới.

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

Ví dụ Blob

Blob này sẽ không di chuyển cho đến khi nó tìm thấy một viên gần đó. Sau đó, nó sẽ di chuyển theo hướng mà nó nghĩ là có khả năng thưởng cho nó nhất. Nếu năng lượng của nó vượt quá 150, nó sẽ phân tách.

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))];
}

Quy tắc

  • Lỗ hổng tiêu chuẩn bị cấm. Ngoài ra, không có lỗ hổng không chuẩn.
  • Không có blob nào có thể cố gắng sửa đổi hoặc đọc bất kỳ dữ liệu nào không được truyền cho nó thông qua các tham số của nó
  • Không có blob nào có thể cố gắng sửa đổi biến giá trị trả về để phá hoại các đốm màu khác
  • Một vòng kéo dài cho đến khi các đốm màu còn lại là người thân
  • Không có blob nào có thể sửa đổi dữ liệu bằng cách đưa các hàm vào các tham số của nó để sửa đổi các giá trị bằng thistừ khóa
  • Tất cả các bài nộp phải bằng Javascript hoặc ngôn ngữ không quá khác so với Javascript (ví dụ: Python). Tất cả các câu trả lời sẽ được chuyển đổi thành Javascript cho cuộc thi.
  • Người chiến thắng là blob đã thu được lượng năng lượng cao nhất trong tổng số tất cả các vòng (từ các viên hoặc tiêu thụ các đốm nhỏ hơn không phải là họ hàng)

Trình điều khiển: https://gist.github.com/RedwolfPrograms/1facc0afe24c5dfd3ada8b8a2c493242

Phòng chat: https://chat.stackexchange.com/rooms/93370/hungry-blobs-koth


1
Bạn có thể mở rộng ngôn ngữ này sang các ngôn ngữ khác ngoài javascript không?
Hiện thân của sự thiếu hiểu biết

@EmbodimentofIgnorance Gửi nó bằng bất kỳ ngôn ngữ nào bạn chọn và tôi sẽ thực hiện chuyển đổi sang JS.
Chương trình Redwolf

Các đốm màu có thể giao thoa với nhau Ex: blob1 tại [0] [0] di chuyển sang phải và blob2 tại [0] [1] di chuyển sang trái hay các blob có năng lượng thấp hơn sẽ bị ăn?
fnɛtɪk


@ fəˈnɛtɪk Có, các bot có thể giao thoa với nhau. Ngoài ra, thử thách liên quan là của tôi (:
Chương trình Redwolf

Câu trả lời:


3

Sống nội tâm

Người hướng nội không thích những đốm màu khác. Khi nó nhìn thấy một đốm màu không liên quan, nó ăn nó nếu có thể, và chấp nhận sự hiện diện của nó nếu không thể, mặc dù chạy đi nếu thấy có dấu hiệu xâm lược. Khi nó nhìn thấy một đốm màu liên quan , nó sẽ tự xa. Tuy nhiên, nó không thể giúp gì ngoài việc chia tách nhiều.

Chi tiết kỹ thuật

Tính năng cốt lõi của blob này là tách ra và trải ra để tối đa hóa tầm nhìn kết hợp của các đốm màu. Nó cũng sử dụng một hệ thống để ngăn chặn hai trong số chúng cạnh tranh với nhau.

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;
}

Điều này trông giống như một bot khá đẹp! Cuộc thi sẽ sớm diễn ra (tiền thưởng sẽ hết hạn vào ngày mai).
Chương trình Redwolf

@RedwolfPrograms Tôi thực sự đã thử nghiệm nó trong trình chạy và nó luôn giành chiến thắng với một tỷ lệ khá lớn.
RamenChef

Điểm trung bình mỗi vòng: 357,544
Chương trình Redwolf

1

Bữa ăn hoạt hình

Một bot đơn giản, chỉ để bắt đầu cuộc thi. Tìm đồng tiền gần nhất, và đi về phía nó. Dựa trên bot ví dụ.

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;
}

Điểm trung bình mỗi vòng: 24.933
Chương trình Redwolf

Và, trong một sự kiện đáng ngạc nhiên, (5 sửa đổi một chút để giảm lỗi) chiến thắng lần thứ 2
Chương trình Redwolf

1

thử nghiệm 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));
}

Bot thực tế khá đơn giản, nhưng nó được thiết kế nhiều hơn như một bằng chứng về khái niệm bloblib, một bộ các chức năng và chức năng tôi dự định sử dụng và phát triển trên các bot khác (cũng tự mình sử dụng / mở rộng trên nó)

Nói tóm lại, bot này thực hiện như sau:

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

Bây giờ bạn có thể thấy năng lượng của một đốm màu, có thể có ích
Các chương trình Redwolf

1
@RedwolfPrograms đã cập nhật bloblib để xác định xem các đốm màu của kẻ thù có phải là "mối đe dọa" dựa trên mức năng lượng của chúng hay không.
Skidsdev

Điểm trung bình mỗi vòng: 7.913
Chương trình Redwolf

Hệ thống này có thể đã được sử dụng cho một số đốm màu tốt, nhưng hệ thống này dường như hành động hơi kỳ lạ.
Chương trình Redwolf

1

Hèn nhát tham lam

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

Hoặc, trong 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
}

Bot này không thú vị lắm. Nó hoạt động theo hai ưu tiên:

  1. Đừng ăn.
  2. Ăn những thứ gần nhất.

Nó không bao giờ phun ra để tối đa hóa khả năng ăn những thứ khác.


Tôi sẽ làm việc để dịch cái này! Khi tôi hoàn thành, tôi sẽ đề xuất chỉnh sửa với phiên bản JS.
Chương trình Redwolf

@RedwolfPrograms Âm thanh tốt, cảm ơn bạn rất nhiều.
Đồng chí SparklePony

Tôi nghĩ bạn cần thêm một if / other để kiểm tra xem thực sự có bất kỳ đối tượng tốt / xấu nào không. Nó gây ra một số vấn đề trong phiên bản JS.
Chương trình Redwolf

@RedwolfPrograms Nó nên được sửa ngay bây giờ. Tôi vừa thêm một câu lệnh if kiểm tra danh sách các đối tượng thú vị và xấu được tạo để đảm bảo chúng không trống. Một lần nữa, cảm ơn bạn đã giúp đỡ.
Đồng chí SparklePony

@RedwolfPrograms Bạn đã có phiên bản JS chưa?
RamenChef

1

SafetyBlob

Bot này sử dụng một số logic tương tự như Safetycoin từ KOTH trước.

Nó hoạt động như thế nào

Bot này sẽ hướng tới thực phẩm mà nó có thể tiếp cận trước khi bất kỳ bot lớn hơn làm hoặc cùng một lúc / trước một bot nhỏ hơn. Nếu nó không thể nhìn thấy bất kỳ thực phẩm nào đáp ứng các tiêu chí này, nó sẽ di chuyển theo hướng ngẫu nhiên (thiên về phía trung tâm). Nếu nó đạt tới 150 năng lượng và không thể nhìn thấy thực phẩm an toàn, nó sẽ phân chia theo một trong những hướng mà nó được dán nhãn là an toàn để di chuyển.

Bot này không theo dõi con của chính nó nhưng dù sao chúng cũng không nên va chạm do các cơ chế an toàn.

 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;
    }
  }
}

Tôi đã chạy bộ điều khiển, nhưng tôi có thể làm lại sau với bot mới này. Đã quá muộn để chỉ định lại tiền thưởng nếu chiến thắng, nhưng tôi tò mò về kết quả.
Chương trình Redwolf

@RedwolfPrograms Mục tiêu không giành được tiền thưởng.
fnɛtɪk

Tôi biết, chỉ cần chắc chắn rằng bạn biết (:
Chương trình Redwolf
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.