空腹ブロブKoTH


9

コンテスト終了!ブロブのコメントを読んでスコアを表示します。

このKoTHは、プライマーのナチュラルセレクションシミュレーションに大まかに影響を受けています。ボットはblobです。生き残るためには、移動に使用されるエネルギーを取り戻すためにペレットを食べる必要があります。追加のエネルギーにより、ブロブは2つに分割できます。

エネルギーと運動

ブロブは100エネルギーで各ラウンドから始まり、収集できるエネルギー量に制限はありません。各ラウンドは交互に実行され、各ブロブには、任意のターンで北、東、南、または西に移動するか、静止するオプションがあります。移動は1エネルギーを使用し、静止は0.25エネルギーを使用します。マップの辺の長さはceil(0.25 * blobCount) * 2 - 1単位、最小9単位。すべてのブロブはマップの端から始まり、各コーナーに1つ配置され、後続のすべてのブロブは他のブロブから2ユニット離れて配置されます。30ターンごとに、ペレットの波がマップの周りのランダムなスポットに配置されます。エッジから少なくとも1ユニット離れています。ペレットの波が現れるたびに、次の波のペレットの量(最初はブロブの数の2倍またはマップの幅のいずれか大きい方)が1ずつ減少し、ブロブの数は時間とともに減少します。各ペレットは5〜15のエネルギーを回復します。ブロブのエネルギーが0以下の場合、ブロブは消滅します。

食べる

2つ以上のブロブが同じ場所を占有しようとすると、エネルギーが最も多いブロブが他のブロブを食べ、エネルギーを受け取ります。両方のエネルギーが等しい場合、両方とも消えます。

検出と情報

ブロブは、4ユニット以内の距離にあるペレットや他のブロブを見ることができます。それらの関数が呼び出されると、ブロブには以下が提供されます:

  • マップの横の長さ
  • 地図上のブロブの位置
  • 検索範囲内のすべてのペレットの位置とその値
  • 検索範囲内のすべてのblobの位置、およびそれらのエネルギーとUID
  • 関数が実行されているblobのエネルギー、UID、および場所
  • blobに固有のストレージオブジェクト
  • スプリットを通じてblobに関連するすべてのblobによって共有されるストレージオブジェクト

分割

ブロブに50を超えるエネルギーがある場合、分割を選択できます。分割には50のエネルギーがかかり、残りのエネルギーは2つの塊の間で均等に分割されます。すべてのblobは、元のコピーまたは分割されたコピーであり、すべてのコピーは元のトレースに戻ります。これらはすべて「親戚」です。すべての親戚には1つの共有ストレージオブジェクトがあります。親戚は依然としてお互いを食べたり、分裂したり、自分のストレージオブジェクトを使用したり、他の人に影響を与えずにエネルギーを収集したりできます。

エネルギー移動

2つの塊が隣接している場合(移動後)、ボットの1つが他のボットにエネルギーを転送できます。これは戻すことにより行われSendNorth(amt)SendEast(amt)SendSouth(amt)、またはSendWest(amt)amtある量を表す数値が送信しました。これは、すべてのエネルギーを含む、送信者が余裕のある任意の金額にすることができます。エネルギーを受け取っているブロブは、エネルギーが転送されているときに移動しないように、共有ストレージを介して静止するように指示することをお勧めします(ただし、この場合、エネルギーは送信者の合計から差し引かれません)。

関数、ストレージ、およびUID

より複雑な学習動作を可能にするために、すべてのblobには整数のUID(Unique Identifer)が与えられます。これらのUIDは各マップにランダムに生成され、個々のターゲットに基づく戦略を防ぎます。blobの関数が呼び出されると、4つの引数が渡されます。

  1. 整数としてのマップの辺の長さ
  2. 二つの配列を持つオブジェクト:pelletsおよびblobs。どちらの配列にもオブジェクトが含まれており、どちらにもposとしてフォーマットされたペレットまたはブロブの位置を含むプロパティがあり[x,y]ます。ペレットにはenergyプロパティがあり、ブロブにはuidプロパティとプロパティがありenergyます
  3. ブロブのさまざまなプロパティを含むオブジェクトは、それに渡される:energyuid、およびposposアレイは次のようにフォーマットされています[x,y]
  4. blobの2つのストレージオブジェクトを含むオブジェクト。selfプロパティは、しかし、BLOBが(渡されたオブジェクトのプロパティを操作することによって)適合を見て変更することができる個々のストレージオブジェクトを含み、communal任意の相対によって改変することができるプロパティ。

Blobはすぐには移動されず、前後のターンが有利になるのを防ぎます。すべての動きはグループで処理されます(すべての衝突/食事、次にすべてのペレット、次に分割など)。ブロブがペレットまたは小さなブロブに着地し、そのプロセスで最後のエネルギーを使用しても、ブロブは引き続きペレット/総エネルギーが0を超えるかどうかに関係なく、エネルギー。

相対BLOBがお互いを認識するためには、各BLOBがそのUIDを配列に記録するため、または他のシステムを介して共有ストレージを使用する必要があります。

戻り値

移動または分割するには、関数の戻り値を使用します。まず、座標の観点からの基本的な方向の意味:

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

[0,0]ある左上隅あなたがダウンして行くように、とYが増加。関数の戻り値は次の規則に従う必要があります。

  • 何もしない:何も返さない、0、null、未定義、false、またはfalseに等しいその他の値
  • 移動するには:「北」、「東」、「南」、または「西」(戻り値として使用することもできます)と同じである北、東、南、または西の4つのグローバル変数のいずれかを返します。
  • 分割するには:グローバル変数SplitNorth、SplitEast、SplitSouth、またはSplitWestを返します。方向は、新しいBLOBを配置する場所を示します。

分割コマンドが返され、必要なエネルギー量がblobのエネルギー以上である場合、何も起こりません。Blobはマップから離れることができません。

定義済みのライブラリ関数

時間を節約するために、デフォルトでいくつかの基本機能が利用可能です。

taxiDist(pt1、pt2)

2点間のタクシー距離を返します(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)

ピタゴラスの定理に従って2点間の距離を返します

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が戻り値変数を変更しようとすることはありません
  • ラウンドは、残りのブロブのみが親戚になるまで続きます
  • thisキーワードを使用して値を変更する関数をパラメーターに挿入することで、Blobがデータを変更することはありません。
  • すべての提出物は、JavaScriptまたはJavaScriptとそれほど変わらない言語(Pythonなど)である必要があります。すべての回答は、コンテストのJavascriptに変換されます。
  • 勝者は、すべてのラウンドで合計で最も高いエネルギー量を収集したブロブです(ペレットから、または親類ではない小さなブロブを使用して)。

コントローラー: https : //gist.github.com/RedwolfPrograms/1facc0afe24c5dfd3ada8b8a2c493242

チャットルーム: https : //chat.stackexchange.com/rooms/93370/hungry-blobs-koth


1
これをJavaScript以外の他の言語に拡張できますか?
無知の

@EmbodimentofIgnorance選択した言語で送信してください。JSに変換します。
Redwolfプログラム

ブロブは互いに交差できますか。例:[0] [0]のブロブ1は右に移動し、[0] [1]のブロブ2は左に移動しますか、それともエネルギーの低いブロブが食べられますか?
fəˈnɛtɪk


@ fəˈnɛtɪkはい、ボットは相互に交差できます。また、関連する課題は私のものでした(:
Redwolfプログラム

回答:


3

内向的

内向性は他のブロブが好きではありません。無関係なブロブを見つけると、可能な場合はそれを食べ、できない場合はそれをしぶしぶ受け入れますが、攻撃の兆候を見つけた場合は逃げます。それは見ているときに、関連するブロブを、それが自分自身を距離。しかし、それは仕方がないので、多くを分割します。

技術的な詳細

このブロブのコア機能は、ブロブの結合されたビジョンを最大化するように分割して広げることです。また、2人がペレットをめぐって競争するのを防ぐシステムも採用しています。

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
プログラム

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

便利になるかもしれないブロブのエネルギーを見ることができ
ます

1
@RedwolfProgramsはbloblibを更新し、敵のブロブがエネルギーレベルに基づいて「脅威」であるかどうかを判断しました。
Skidsdev

ラウンドあたりの平均スコア: 7.913
プログラム

このシステムはおそらくいくつかの良いblobに使用できたかもしれませんが、これは少し奇妙に動作するように見えました。
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
}

このボットはそれほど興味深いものではありません。2つの優先順位に従って機能します。

  1. 食べないでください。
  2. 一番近いものを食べる。

他のものを食べる能力を最大にするために唾を吐くことは決してありません。


これを翻訳していきます!終了したら、JSバージョンでの編集を提案します。
Redwolfプログラム

@RedwolfProgramsいいですね、ありがとうございました。
同志SparklePony

実際に良い/悪いオブジェクトがあるかどうかを確認するには、if / elseを追加する必要があると思います。JSバージョンでいくつかの問題が発生しています。
Redwolfプログラム

@RedwolfPrograms今すぐ修正する必要があります。作成した興味深いオブジェクトと不良オブジェクトのリストをチェックして、空でないことを確認するifステートメントを追加しました。もう一度、助けてくれてありがとう。
同志SparklePony

@RedwolfPrograms JSバージョンの準備はできていますか?
RamenChef

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

コントローラーは既に実行していますが、この新しいボットを使用して後でもう一度実行する可能性があります。賞金が当たった場合に再度割り当てるのは遅すぎますが、結果について知りたいです。
Redwolfプログラム

@RedwolfPrograms目標は、賞金を獲得することではありませんでした。
fəˈnɛtɪk

私は、ちょうどあなたが知っている作る知っている(:
Redwolfプログラム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.