饥饿的斑点


9

比赛结束!阅读有关Blob的评论以查看其得分。

此KoTH受到Primer自然选择模拟的大致启发。您的漫游器是一个Blob。为了生存,您必须吃掉颗粒以重新获得用于移动的能量。有了额外的能量,斑点可以一分为二。

能量与运动

您的Blob每回合都会以100的能量开始,并且对其可以收集的能量数量没有限制。每个回合都是轮流进行,每个Blob可以选择在任意给定的回合中向北,向东,向南或向西移动,或保持静止。移动消耗1能量,而静止不动使用0.25能量。地图的边长是ceil(0.25 * blobCount) * 2 - 1单位,最少9个单位。所有Blob都始于地图的边缘,每个角处都放置一个Blob,随后的每个Blob都应与其他Blob放置2个单位。每30圈,一阵子弹便被放置在地图周围的任意位置,距离任意边缘至少1个单位。每次出现一波颗粒波时,下一波中的颗粒数量(最初为斑点数的两倍或图的宽度(以较大者为准))减少1,迫使斑点数随时间减少。每个药丸可恢复5至15的能量。当Blob的能量小于或等于0时,它就会死掉。

如果两个或多个Blob试图占据同一位置,则能量最大的一个将吞噬其他能量,并吸收它们的能量。如果两者具有相等的能量,则两者都会消失。

检测与信息

斑点可以在4个单位的距离内看到任何颗粒或其他斑点。调用其函数时,将为blob提供:

  • 地图的边长
  • 斑点在地图上的位置
  • 所有小球在其搜索半径内的位置及其值
  • 所有Blob在其搜索半径内的位置,以及它们的能量和UID
  • 执行功能的Blob的能量,UID和位置
  • Blob唯一的存储对象
  • 通过拆分由与该blob相关的所有blob共享的存储对象

分裂

如果斑点的能量超过50,则可以选择拆分。拆分会消耗50能量,并且所有剩余能量将在两个Blob之间平均分配。所有blob都是原始副本或拆分副本,每个副本都可追溯到原始副本。所有这些都是“亲戚”。所有亲戚都有一个公共存储对象。亲戚仍然可以互相吃饭,可以分裂,使用自己的存储对象或收集能量而不会影响他人。

能量转移

如果两个Blob彼此相邻(移动后),则其中一个机器人可以将能量传递给另一个机器人。这是通过返回完成SendNorth(amt)SendEast(amt)SendSouth(amt),或SendWest(amt),其中amt是代表所述量的号码发送。这可以是发件人可以负担的任何金额,包括其所有能量。建议告知接收能量的斑点在公共存储中保持静止,以使其在转移能量时不会移开(尽管在这种情况下不会从发送者的总量中扣除能量)。

函数,存储和UID

为了允许更复杂的学习行为,所有Blob都将被赋予一个整数UID(唯一标识符)。这些UID将在每个地图上随机生成,从而防止基于单个目标的策略。调用Blob的函数时,将为其传递四个参数:

  1. 地图的边长(整数)
  2. 具有两个数组的对象:pelletsblobs。两个数组都包含对象,两个对象都具有一个pos属性,该属性包含格式为的颗粒或团块位置[x,y]。丸粒将具有energy属性,而斑点将具有uid属性和energy属性
  3. 含有团块的各种属性的对象它被传递给:energyuid,和pos。该pos阵列被格式化为[x,y]
  4. 包含Blob的两个存储对象的对象。一个self属性包含一个可以修改的单独存储对象,但是blob认为合适(通过操纵所传递对象的communal属性),以及一个可以被任何亲戚修改的属性。

斑点不立即移动以防止较早/较晚的转弯具有优势。所有运动均按组进行处理(所有碰撞/进食,然后是所有药丸,然后分裂,等等)。如果某个药丸落在药丸或较小药丸上,并且在此过程中使用了其最后的能量,药丸仍将消耗药丸/能量,而不管其总能量是否大于0。

为了使相对Blob能够相互识别,必须为每个Blob使用公用存储,以在阵列中或通过其他系统记录其UID。

返回值

为了移动或拆分,使用了函数的返回值。首先,基本方向在坐标方面的含义:

  • 北= -Y
  • 东= + X
  • 南= + Y
  • 西= -X

请注意,它[0,0]左上角,并且Y随您的下降而增加。函数的返回值应遵循以下规则:

  • 不执行任何操作:不返回任何内容,0,null,undefined,false或任何其他等于false的值
  • 移动:返回四个全局变量之一:北,东,南或西,它们等于“北”,“东”,“南”或“西”(也可用作返回值)
  • 要拆分:返回全局变量SplitNorth,SplitEast,SplitSouth或SplitWest,其方向指示将新Blob放置在何处

如果返回拆分命令,并且所需能量大于或等于斑点的能量,则不会发生任何事情。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

示例Blob

直到找到附近的沉淀,该团块才会移动。然后,它将朝着它认为最有可能奖励它的方向移动。如果其能量超过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关键字来修改值
  • 所有提交都必须使用Java脚本或与Java脚本没有太大区别的语言(例如Python)。所有答案都将转换为Javascript以进行比赛。
  • 胜利者是Blob,它在所有回合中总计收集了最多的能量(来自颗粒或消耗的不是亲戚的较小Blob)

控制器: https : //gist.github.com/RedwolfPrograms/1facc0afe24c5dfd3ada8b8a2c493242

聊天室: https //chat.stackexchange.com/rooms/93370/hungry-blobs-koth


1
您可以将其扩展为除javascript之外的其他语言吗?
无知的体现,

@EmbodimentofIgnorance以您选择的任何语言提交,我将转换为JS。
Redwolf节目,

Blob可以彼此交叉吗?例如:[0] [0]处的blob1向右移动,[0] [1]处的blob2向左移动?还是会吃掉能量较低的Blob?
fəˈnɛtɪk


@ fəˈnɛtɪk是的,机器人可以相互交叉。同样,相关的挑战是我的(:
Redwolf Programs

Answers:


3

性格内向

内向的人不喜欢其他斑点。当它看到一个无关的斑点时,它会尽可能地吃掉它,如果不能,则不情愿地接受它的存在,但是如果看到侵略的迹象就会逃之away。看到相关的斑点时,它会自行拉开距离。但是,它不免分开很多。

技术细节

该斑点的核心特征是分开并散开,以使斑点的组合视觉最大化。它还采用了一种系统来防止两个人竞争一个小球。

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

实际的bot相当简单,但这更多是作为概念验证bloblib,我计划在其他bot上使用和开发的功能和功能的集合(也可以自己使用/扩展)。

简而言之,该机器人可以执行以下操作:

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,以根据其能量水平确定敌人的blob是否是“威胁”。
Skidsdev,

平均每回合得分: 7.913
Redwolf计划

该系统可能已经用于一些不错的Blob,但此举似乎有些奇怪。
Redwolf节目,

1

贪婪的ward夫

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听起来不错,非常感谢。
“ SparklePony同志” 19年

我认为您需要添加一个if / else来检查是否确实存在任何好/坏对象。导致JS版本中出现多个问题。
Redwolf计划,

@RedwolfPrograms应该现在修复。我刚刚添加了一条if语句,该语句检查创建的有趣和坏对象列表以确​​保它们不是空的。再次感谢您的帮助。
“ SparklePony同志” 19年

@RedwolfPrograms您准备好JS版本了吗?
拉面厨师

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

我已经运行了控制器,但是稍后可能会用这个新的bot再做一次。如果赢了,现在重新分配赏金为时已晚,但我对结果感到好奇。
Redwolf计划,

@RedwolfPrograms目标不是赢得赏金。
fəˈnɛtɪk

我知道,只要确保您知道(:
Redwolf Programs
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.