배고픈 물방울 KoTH


9

컨테스트가 완료되었습니다! 점수를 보려면 얼룩에 대한 주석을 읽으십시오.

이 KoTH는 Primer의 Natural Selection Simulation에서 느슨하게 영감을 받았습니다 . 봇은 얼룩입니다. 생존하려면 에너지를 회복하기 위해 펠렛을 먹어야합니다. 여분의 에너지로 얼룩을 두 개로 나눌 수 있습니다.

에너지와 운동

Blob은 각 라운드마다 100 에너지로 시작하며, 수집 할 수있는 에너지 양에는 제한이 없습니다. 각 라운드는 차례대로 진행되며 각 블로 브는 주어진 차례마다 북쪽, 동쪽, 남쪽 또는 서쪽을 움직이거나 서있을 수 있습니다. 이동은 1 에너지를 사용하고서는 여전히 0.25 에너지를 사용합니다. 지도의 측면 길이는ceil(0.25 * blobCount) * 2 - 1최소 9 대 모든 블로 브는 맵의 가장자리에서 시작하며, 하나는 각 모서리에 배치되고 모든 후속 블로 브는 다른 장치로부터 2 단위 떨어진 곳에 배치됩니다. 매 30 턴마다, 펠릿 물결이 가장자리에서 최소 1 단위 떨어진 맵 주위에 무작위로 배치됩니다. 펠릿의 물결이 나타날 때마다 다음 물결의 펠릿 수량 (원래 블랍 수 또는 맵 너비 중 큰 쪽)이 1만큼 감소하여 블랍 수가 시간이 지남에 따라 감소합니다. 각 펠릿은 5와 15 사이의 에너지를 회복합니다. 얼룩의 에너지가 0보다 작거나 같으면 죽습니다.

먹기

두 개 이상의 얼룩이 같은 위치를 차지하려고하면 가장 많은 에너지를 가진 물방울이 다른 에너지를 섭취하여 에너지를받습니다. 둘 다 에너지가 같으면 사라집니다.

탐지 및 정보

블롭은 4 단위 거리 내에있는 펠릿 또는 다른 블랍을 볼 수 있습니다. 함수가 호출되면 Blob에는 다음이 제공됩니다.

  • 지도의 측면 길이
  • 지도에서 얼룩의 위치
  • 검색 반경 내 모든 펠릿의 위치와 값
  • 검색 반경 내 모든 Blob의 위치와 에너지 및 UID
  • 기능이 실행되는 블롭의 에너지, UID 및 위치
  • Blob에 고유 한 스토리지 객체
  • 분할을 통해 Blob과 관련된 모든 Blob이 공유하는 스토리지 오브젝트

파편

Blob의 에너지가 50 개 이상인 경우 분할을 선택할 수 있습니다. 분할 비용은 50 에너지이며 나머지 에너지는 두 얼룩 사이에 균등하게 분배됩니다. 모든 얼룩은 원본이거나 분할 복사본이며 모든 복사본은 원본으로 다시 추적됩니다. 이들 모두는 "친척"입니다. 모든 친척에게는 하나의 공동 저장 개체가 있습니다. 친척들은 여전히 ​​서로를 먹을 수 있으며, 다른 사람에게 영향을 미치지 않으면 서 분리하거나 자신의 저장 대상을 사용하거나 에너지를 수집 할 수 있습니다.

에너지 전송

두 블롭이 서로 이동 한 경우 (이동 후) 봇 중 하나가 다른 봇으로 에너지를 전송할 수 있습니다. 이것은 반환함으로써 수행된다 SendNorth(amt), SendEast(amt), SendSouth(amt), 또는 SendWest(amt)amt되는 양을 나타내는 숫자를 보냈다. 이것은 모든 에너지를 포함하여 발신자가 감당할 수있는 금액 일 수 있습니다. 에너지를받는 블롭은 공동 저장을 통해 계속 유지되도록 권장하여 에너지가 전송 될 때 이동하지 않도록합니다 (이 경우 에너지는 발신자의 총계에서 공제되지는 않지만).

기능, 스토리지 및 UID

보다 복잡한 학습 행동을 허용하기 위해 모든 블롭에 정수 UID (Unique Identifer)가 부여됩니다. 이 UID는 각 맵에 무작위로 생성되어 개별 목표에 따른 전략을 방지합니다. Blob의 함수가 호출되면 네 가지 인수가 전달됩니다.

  1. 지도의 측면 길이 (정수)
  2. 두 개의 배열이있는 객체 : pelletsblobs. 두 배열에는 모두 pos펠릿 또는 blob의 위치 형식이 포함 된 속성이 있는 객체가 포함 됩니다 [x,y]. 펠렛에는 energy속성이 있고, 블롭에는 uid속성과 energy속성이 있습니다
  3. 블롭의 다양한 속성을 포함하는 객체는 그것으로 전달된다 : energy, uid, 및 pos. pos배열로 포맷[x,y]
  4. Blob의 두 스토리지 오브젝트를 포함하는 오브젝트입니다. self속성하지만 블롭은 (전달 된 객체의 속성을 조작함으로써) 착용감을보고 수정할 수있는 개별 저장 객체를 포함하고 communal있는 상대적으로 변형 될 수있는 속성.

Blob은 이전 / 이후 회전이 유리한 점을 방지하기 위해 즉시 이동되지 않습니다. 모든 동작은 그룹으로 처리됩니다 (모든 충돌 / 먹기, 모든 펠릿, 분할 등). 블롭이 펠릿 또는 작은 블롭에 떨어지고 프로세스에서 마지막 에너지를 사용하는 경우 블롭은 여전히 ​​펠릿 / 총 에너지가 0보다 커질 지 여부에 관계없이

상대 Blob이 서로를 인식하려면 각 Blob에 공용 스토리지를 사용하여 해당 UID를 배열 또는 다른 시스템을 통해 기록해야합니다.

반환 값

이동 또는 분할하기 위해 함수의 반환 값이 사용됩니다. 첫째, 좌표 측면에서 기본 방향의 의미는 다음과 같습니다.

  • 북쪽 = -Y
  • 동쪽 = + X
  • 남쪽 = + Y
  • 서쪽 = -X

참고 [0,0]는 IS 왼쪽 상단 당신이 아래로 가서, 및 Y 증가한다. 함수의 반환 값은 다음 규칙을 따라야합니다.

  • 아무것도하지 않으려면 : 아무것도 반환하지 않음, 0, null, undefined, false 또는 false와 같은 다른 값
  • 이동 : "북쪽", "동쪽", "남쪽"또는 "서쪽"과 같은 네 개의 전역 변수 중 하나를 반환합니다 (반환 값으로도 사용 가능).
  • 분할하려면 : 새 얼룩을 배치 할 위치를 나타내는 방향 인 전역 변수 SplitNorth, SplitEast, SplitSouth 또는 SplitWest를 반환합니다 .

분할 명령이 반환되고 필요한 에너지 량이 블롭의 에너지보다 크거나 같으면 아무 일도 일어나지 않습니다. Blob은지도를 떠날 수 없습니다.

사전 정의 된 라이브러리 함수

시간을 절약하기 위해 기본적으로 사용 가능한 몇 가지 기본 기능이 있습니다.

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은 매개 변수를 통해 전달되지 않은 데이터를 수정하거나 읽으려고 시도 할 수 없습니다.
  • Blob은 다른 Blob을 방해하기 위해 반환 값 변수를 수정하려고 시도 할 수 없습니다.
  • 라운드는 남은 유일한 얼룩이 친척이 될 때까지 지속됩니다.
  • Blob은 this키워드를 사용하여 값을 수정하는 매개 변수에 함수를 삽입하여 데이터를 수정할 수 없습니다.
  • 모든 제출물은 Javascript 또는 Javascript와 너무 다르지 않은 언어 (예 : Python) 여야합니다. 모든 답변은 경쟁을 위해 Javascript로 변환됩니다.
  • 승자는 모든 라운드에서 총량의 에너지를 모은 블랍입니다 (펠릿 또는 친척이 아닌 작은 블롭을 소비 함)

컨트롤러 : https://gist.github.com/RedwolfPrograms/1facc0afe24c5dfd3ada8b8a2c493242

대화방 : https://chat.stackexchange.com/rooms/93370/hungry-blobs-koth


1
이것을 자바 스크립트 이외의 다른 언어로 확장 할 수 있습니까?
무지의 구현

@EmbodimentofIgnorance 선택한 언어로 제출하면 JS로 변환됩니다.
레드 울프 프로그램

Blob이 서로 교차 할 수 있습니까? 예 : [0] [0]의 blob1이 오른쪽으로 이동하고 [0] [1]의 blob2가 왼쪽으로 이동합니까, 아니면 에너지가 낮은 Blob을 먹을 수 있습니까?
fəˈnɛtɪk


@ fəˈnɛtɪk 예, 봇은 서로 교차 할 수 있습니다. 또한, 관련된 도전은 내 것이었다 (:
Redwolf Programs

답변:


3

내성

Introvert는 다른 얼룩을 좋아하지 않습니다. 관련되지 않은 얼룩이 보이면 가능하면 먹으며, 침략의 흔적이 보이면 도망 치지 만 그럴 수 없다면 그 존재를 받아들입니다. 그것은 볼 때 관련 방울을, 그 자체를 거리를. 그러나 도움이 될 수는 없지만 많이 분리됩니다.

기술적 세부 사항

이 Blob의 핵심 기능은 Blob의 결합 된 비전을 최대화하기 위해 분리 및 확산되는 것입니다. 또한 두 가지가 펠릿을 놓고 경쟁하는 것을 방지하는 시스템을 사용합니다.

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

이것은 꽤 좋은 봇처럼 보입니다! 컨테스트는 곧 진행될 예정입니다 (내일 현상금이 만료 됨).
레드 울프 프로그램

@ RedwolfPrograms 실제로 러너에서 테스트했으며 항상 꽤 큰 차이로 이깁니다.
RamenChef

라운드 당 평균 점수 : 357.544
레드 울프 프로그램

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
레드 울프 프로그램

그리고 놀라운 사건의 전환에서 (버그를 줄이기 위해 약간 수정 됨) 5 라이너가 2 위
Redwolf 프로그램에서

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 Programs

1
@RedwolfPrograms는 적 블롭이 에너지 레벨에 따라 "위협"인지 확인하기 위해 bloblib를 업데이트했습니다.
Skidsdev

라운드 당 평균 점수 : 7.913
Redwolf 프로그램 3:16에 19.

이 시스템은 아마도 좋은 얼룩에 사용될 수 있었지만 조금 이상하게 작동하는 것처럼 보였습니다.
레드 울프 프로그램 19 :

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 버전으로 편집을 제안합니다.
Redwolf 프로그램

@ RedwolfPrograms 좋은 소리, 정말 감사합니다.
스파클 포니 동지

실제로 좋은 / 나쁜 개체가 있는지 확인하려면 if / else를 추가해야한다고 생각합니다. JS 버전에서 몇 가지 문제가 발생합니다.
Redwolf 프로그램

@RedwolfPrograms 이제 수정해야합니다. 방금 만든 흥미롭고 나쁜 개체의 목록을 확인하여 비어 있지 않은지 확인하는 if 문을 추가했습니다. 다시 한 번 도움을 주셔서 감사합니다.
스파클 포니 동지

@RedwolfPrograms JS 버전이 준비되어 있습니까?
RamenChef 21시 57 분

1

SafetyBlob

이 봇은 이전 KOTH의 Safetycoin과 동일한 로직을 사용합니다.

그것이 작동하는 방법

이 봇은 더 큰 봇보다 먼저 또는 더 작은 봇 전에 도달 할 수있는 음식을 향해 나아갑니다. 이 기준에 맞는 음식을 볼 수 없으면 무작위 방향으로 움직입니다 (중심쪽으로 편향). 그것이 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;
    }
  }
}

컨트롤러를 이미 실행했지만 나중에이 새로운 봇으로 다시 할 수 있습니다. 현상금이 이기면 현상금을 다시 할당하기에는 너무 늦었지만 결과에 대해 궁금합니다.
레드 울프 프로그램

@RedwolfPrograms 목표는 현상금을 얻는 것이 아닙니다.
fəˈnɛtɪk

나는 단지 당신이 (:
Redwolf 프로그램
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.