Hungry Blobs KoTH


9

Yarışma Tamamlandı! Puanlarını görmek için lekeler hakkındaki yorumları okuyun.

Bu KoTH, Primer'in Doğal Seleksiyon Simülasyonundan gevşek bir şekilde esinlenmiştir . Botun bir damla. Hayatta kalmak için, hareket etmek için kullanılan enerjiyi geri kazanmak için peletler yemelisiniz. Ekstra enerji ile lekeler ikiye ayrılabilir.

Enerji ve Hareket

Blobunuz her turda 100 enerji ile başlar ve toplayabileceği enerji miktarı üzerinde bir sınırı yoktur. Her tur sırayla yapılır, her bir damla herhangi bir sırayla Kuzey, Doğu, Güney veya Batı'yı hareket ettirme veya hareketsiz durma seçeneğine sahiptir. Hareket etmek 1 enerji kullanır ve ayakta durmak 0.25 enerji kullanır. Haritanın yan uzunluğu:ceil(0.25 * blobCount) * 2 - 1birim, en az 9 birim. Tüm damlalar haritanın kenarında başlar, her köşeye birer tane yerleştirilir ve sonraki tüm damlalar diğerlerinden 2 birim uzağa yerleştirilir. Her 30 turda, bir pelet dalgası haritanın etrafında rastgele noktalara yerleştirilir, herhangi bir kenardan en az 1 birim. Bir pelet dalgası her göründüğünde, bir sonraki dalgadaki pelet miktarı (orijinal olarak lekelerin sayısının iki katı veya haritanın genişliğinin hangisi daha büyükse) 1 azalır ve lekelerin sayısını zamanla azalmaya zorlar. Her pelet 5 ila 15 enerji geri yükler. Bir blobun enerjisi 0'a eşit veya 0 olduğunda, ölür.

Yemek yiyor

İki veya daha fazla leke aynı yeri işgal etmeye çalışırsa, en fazla enerjiye sahip olan, enerjilerini alarak diğerlerini yiyecektir. Her ikisinin de eşit enerjisi varsa, her ikisi de yok olur.

Tespit ve Bilgi

Lekeler 4 birim mesafede herhangi bir topak veya diğer lekeleri görebilir. İşlevleri çağrıldığında, lekelere aşağıdakiler sağlanır:

  • Haritanın yan uzunluğu
  • Blobun haritadaki konumu
  • Arama yarıçaplarındaki tüm peletlerin konumları ve değerleri
  • Tüm yarıçapların arama yarıçaplarındaki konumları, ayrıca enerji ve UID'leri
  • İşlevi yürütülen blobun enerjisi, UID'si ve konumları
  • Lekeye özgü bir depolama nesnesi
  • Bölme ile kabarcık ile ilgili tüm damlalar tarafından paylaşılan bir depolama nesnesi

bölme

Bir damla 50'den fazla enerjiye sahipse, bölünmeyi seçebilir. Bölme işlemi 50 enerjiye mal olur ve kalan enerji iki damla arasında eşit olarak bölünür. Tüm lekeler orijinal veya bölünmüş kopyadır, her kopya orijinale kadar izlenir. Bunların hepsi birlikte "akraba". Tüm akrabaların bir ortak depolama nesnesi vardır. Akrabalar hala birbirlerini yiyebilir ve başkalarını etkilemeden bölünebilir, kendi depolama nesnelerini kullanabilir veya enerji toplayabilir.

Enerji transferi

Yan yana iki damla varsa (hareket ettikten sonra), botlardan biri diğerine enerji aktarabilir. Bu dönen yapılır SendNorth(amt), SendEast(amt), SendSouth(amt)veya SendWest(amt)birlikte amtolmak miktarını temsil eden bir sayı gönderilen. Bu, göndericinin tüm enerjisi dahil olmak üzere alabileceği herhangi bir miktar olabilir. Enerji alan blobun, ortak depolama yoluyla hareketsiz kalması söylenir, böylece enerji aktarılırken uzaklaşmaz (bu durumda enerji gönderenin toplamından düşülmez).

İşlevler, Depolama ve UID'ler

Daha karmaşık öğrenme davranışlarına izin vermek için, tüm bloblara bir tamsayı UID'si (Benzersiz Tanımlayıcı) verilecektir. Bu UID'ler her haritayı rastgele oluşturularak bireysel hedeflere dayalı stratejileri önleyecektir. Bir blobun işlevi çağrıldığında, dört argüman geçirilir:

  1. Haritanın tamsayı olarak yan uzunluğu
  2. İki dizili bir nesne:, pelletsve blobs. Her iki dizide de, her ikisi posde pelet veya damla şeklini içeren bir özelliğe sahip nesneler bulunur [x,y]. Peletler bir energymülke sahip olacak , lekeler bir uidmülke ve bir energymülke sahip olacak
  3. Damla çeşitli özelliklerini içeren bir nesne geçirilir: energy, uidve pos. posDizi olarak biçimlendirilir[x,y]
  4. Blobun iki depolama nesnesini içeren bir nesne. Bir selfözellik, değiştirilebilen ayrı bir depolama nesnesi içerir, ancak damla uygun görür (iletilen nesnenin özelliklerini communaldeğiştirerek) ve herhangi bir akraba tarafından değiştirilebilen bir özellik.

Lekeler, daha erken / daha sonraki dönüşlerin avantajlı olmasını önlemek için hemen hareket ettirilmez. Tüm hareketler gruplar halinde işlenir (Tüm çarpışmalar / yeme, sonra tüm peletler, daha sonra bölünme, vb.) Bir damla bir pelete veya daha küçük bir damla üzerine düşerse ve süreçte son enerji pelet / bunun toplam enerjisini 0'ın üzerine getirip getirmeyeceğinden bağımsız olarak enerji.

Göreli blobların birbirini tanıması için, her blobun UID'sini bir dizide veya başka bir sistemde kaydetmek için ortak depolama kullanılmalıdır.

Dönüş Değerleri

Taşımak veya bölmek için, işlevin dönüş değeri kullanılır. İlk olarak, kardinal yönlerin koordinatlar açısından anlamı:

  • Kuzey = -Y
  • Doğu = + X
  • Güney = + Y
  • Batı = -X

Not [0,0]olan sol üst köşe aşağı giderken, ve Y artar. İşlevin dönüş değeri şu kurallara uymalıdır:

  • Yapılacak bir şey yok: 0, null, undefined, false veya false değerine eşit olan başka bir değer döndürmez
  • Taşımak için: Dört küresel değişkenden birini döndürün: Kuzey, Doğu, Güney veya Batı, "kuzey", "doğu", "güney" veya "batı" (dönüş değeri olarak da kullanılabilir)
  • Bölmek için: Genel bloğu SplitNorth, SplitEast, SplitSouth veya SplitWest olarak döndürün; yeni blobun nereye yerleştirileceğini gösterir

Bölünmüş bir komut döndürülürse ve gereken enerji miktarı blobun enerjisinden büyük veya ona eşitse, hiçbir şey olmaz. Lekeler haritayı terk edemez.

Önceden Tanımlı Kütüphane İşlevleri

Biraz zaman kazanmak için varsayılan olarak birkaç temel işlev vardır:

taxiDist (pt1, pt2)

İki nokta arasındaki taksi mesafesini döndürür (X mesafesi artı Y mesafesi).

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)

Pisagor teoremine göre iki nokta arasındaki mesafeyi döndürür

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)

Girilen yönü alır, saat yönünde 90 derece döner amt, ardından yeni değeri döndürür.

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

Örnek Blob

Bu damla yakındaki bir peleti bulana kadar hareket etmeyecektir. Daha sonra, ödüllendirmenin en muhtemel olduğunu düşündüğü yönde hareket edecektir. Enerjisi 150'den fazla olursa, bölünecektir.

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

kurallar

  • Standart Loopholes yasaktır. Ayrıca, Standart Dışı Loopholes yok.
  • Hiçbir blob, parametreleri aracılığıyla kendisine aktarılmayan verileri değiştirmeye veya okumaya çalışamaz
  • Hiçbir damla diğer damlaları sabote etmek için bir dönüş-değer değişkenini değiştirmeye çalışamaz
  • Geri kalan tek lekeler akraba olana kadar bir tur sürer
  • Hiçbir damla kullanarak değerleri değiştirebilir kendi parametrelerine fonksiyonlarını enjekte ederek verileri değiştirebilir thisanahtar kelime
  • Tüm gönderimler ya Javascript ya da Javascript'ten çok farklı olmayan bir dilde olmalıdır (örneğin, Python). Tüm cevaplar yarışma için Javascript'e dönüştürülecektir.
  • Kazanan, tüm turlarda (peletlerden veya akraba olmayan daha küçük lekeler tüketerek) toplamda en yüksek miktarda enerji toplayan damladır.

Denetleyici: https://gist.github.com/RedwolfPrograms/1facc0afe24c5dfd3ada8b8a2c493242

Sohbet odası: https://chat.stackexchange.com/rooms/93370/hungry-blobs-koth


1
Javascript dışında başka dillere de genişletebilir misiniz?
Cehaletin Somutlaştırılması

@EmbodimentofIgnorance İstediğiniz dilde gönderin, JS'ye dönüşümü yapacağım.
Redwolf Programları

Lekeler birbirini kesebilir Örn: [0] [0] 'daki blob1 sağa, [0] [1]' deki blob2 sola hareket eder mi yoksa daha düşük enerjili damla yenir mi?
fəˈnəˈtɪk


@ fəˈnɛtɪk Evet, botlar birbirlerinin üzerinden geçebilir. Ayrıca, ilgili zorluk benim (:
Redwolf Programları

Yanıtlar:


3

içine kapanık kimse

Introvert diğer lekeleri sevmez. Akraba olmayan bir leke gördüğünde, eğer mümkünse onu yiyor ve saldırganlık belirtileri görüyorsa kaçıyor olsa da, eğer yapamazsa varlığını cesaretle kabul ediyor. İlişkili bir damla gördüğünde kendini uzaklaştırır. Ancak, yardım edemez ama çok bölünür.

Teknik detaylar

Bu blobun temel özelliği, kabarcıkların birleşik görüşünü en üst düzeye çıkarmak için bölünmek ve yaymaktır. Ayrıca, ikisinin bir pelet üzerinde rekabet etmesini önleyen bir sistem kullanır.

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

Bu oldukça hoş bir bot gibi görünüyor! Yarışma yakında olmalı (ödül yarın sona eriyor).
Redwolf Programları

@RedwolfPrograms Aslında koşucuda test ettim ve her zaman oldukça büyük bir farkla kazanır.
RamenChef

Tur Başına Ortalama Puan: 357.544
Redwolf Programları

1

Animasyonlu Yemek

Basit bir bot, sadece yarışmaya başlamak için. En yakın jetonu bulur ve ona doğru gider. Örnek bot temel alınmıştır.

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

Tur Başına Ortalama Puan: 24.933
Redwolf Programları

Ve, şaşırtıcı bir olayda, (hataları azaltmak için biraz değiştirilmiş) 5-liner 2. kazandı
Redwolf Programları

1

bloblib test cihazı

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

Gerçek bot oldukça basittir, ancak bu daha çok bir bot kanıtı, bloblibdiğer botlarda kullanmayı ve geliştirmeyi planladığım bir işlevler ve işlevsellik koleksiyonu olarak tasarlanmıştır (kullanmaktan çekinmeyin / kendiniz de genişletin)

Kısacası, bu bot aşağıdakileri yapar:

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

Artık bir
blobun

1
@RedwolfPrograms, düşman lekelerinin enerji seviyelerine göre bir "tehdit" olup olmadığını belirlemek için bloblib'i güncelledi.
Skidsdev

Tur Başına Ortalama Puan: 7.913
Redwolf Programları

Bu sistem muhtemelen bazı iyi lekeler için kullanılabilirdi, ancak bu biraz garip davranıyordu.
Redwolf Programları

1

Açgözlü Korkak

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

Veya JavaScript'te,

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
}

Bu bot çok ilginç değil. İki önceliğe göre hareket eder:

  1. Yemek yemeyin.
  2. En yakın şeyi ye.

Başka şeyler yeme yeteneğini en üst düzeye çıkarmaya asla tükürmez.


Bunu çevirerek işe başlayacağım! İşimi bitirdiğimde, JS sürümü ile bir düzenleme önereceğim.
Redwolf Programları

@RedwolfPrograms Kulağa hoş geliyor, çok teşekkür ederim.
SparklePony Yoldaş

Gerçekten iyi / kötü nesneler olup olmadığını kontrol etmek için bir if / else eklemeniz gerektiğini düşünüyorum. JS sürümünde çeşitli sorunlara neden oluyor.
Redwolf Programları

@RedwolfPrograms Şimdi düzeltilmelidir. Ben sadece boş olmadığından emin olmak için ilginç ve kötü nesnelerin oluşturulmuş listelerini kontrol eden bir if ifadesi ekledim. Tekrar, yardım için teşekkürler.
SparklePony Yoldaş

@RedwolfPrograms JS sürümünüz var mı?
RamenChef

1

SafetyBlob

Bu bot, önceki KOTH'deki Safetycoin ile aynı mantığın bazılarını kullanıyor.

Nasıl çalışır?

Bu bot, daha büyük botlar yapmadan önce veya aynı zamanda / daha küçük bir bottan önce ulaşabileceği yiyeceklere yönelecektir. Bu kriterleri karşılayan herhangi bir yiyecek göremezse, rastgele bir yönde hareket eder (merkeze doğru eğimli). 150 enerjiye ulaşırsa ve güvenli yiyecekleri göremezse, taşınması güvenli olarak etiketlendiği yönlerden birine bölünecektir.

Bu bot kendi çocuklarını takip etmez, ancak güvenlik mekanizmaları nedeniyle herhangi bir şekilde çarpışmamalıdır.

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

Denetleyiciyi zaten çalıştırdım, ancak daha sonra bu yeni botla tekrar yapabilirim. Kazanırsa ödülü yeniden atamak için çok geç, ama sonucu merak ediyorum.
Redwolf Programları

@RedwolfPrograms Amaç, ödül kazanmak değildi.
fəˈnəˈtɪk

Biliyorum, sadece bildiğinizden emin olmak (:
Redwolf Programları
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.