KoTH: Politik Simülatör

Oct 28 2020

Seçim zamanı ve senin işin rakibini kafa kafaya bir rekabette yenmek! İkiniz de 16x16 boyutlarında 256 kişilik bir şehri kazanmaya çalışıyorsunuz. Şu anda, şehir henüz oy verme bölgelerine bölünmedi, ancak gerrymandering becerileriniz burada devreye giriyor! Ayrıca destek almak için şehrin keyfi bölgelerinde de kampanya yapabilirsiniz.

Genel

Tüm botlar (JS işlevleri) oyun başına bir kez diğer tüm botlara karşı çalıştırılacaktır. Her oyunda, şehir tüm seçmenler tarafsız olacak şekilde başlayacak. Oyun, her seçmen için kimi desteklediklerini belirleyen bir sayı izleyecektir. Belirli bir bot açısından pozitif bir sayı, seçmenin onlara oy vereceği anlamına gelirken, negatif bir sayı rakibe oy verir. Sıfır tarafsızdır.

Şehir, tamamı 4x4 kare olan 16 bloğa bölünmüştür. Oy verme bölgeleri bir veya daha fazla bloktan oluşur. Başlangıçta 16 tane var, her bloğun kendi bölgesi var.

Her iki bot da 100 $ ile başlar ve tur başına bir kez hareket edebilir. Bu hareketler eşzamanlı olarak etkili bir şekilde yürütülür, bu nedenle ilk dönüş avantajı yoktur. Hamle dört kategoriye ayrılır:

  • Kampanya: Bu, belirli bir alandaki herkesin kampanya yapan adaya desteğini artırmasına neden olacaktır. Değiştiği miktar komşularına bağlıdır.
  • Anket: Bu, her bir kişinin belirli bir alanda aday için desteğini alacaktır.
  • Rüşvet: Bu, belirli bir kişinin adaya olan desteğini artırmasına neden olacaktır.
  • Bölge Birleştirme / Birleştirme: Bu, oylama bölgelerini yeniden şekillendirecektir.

Her turun sonunda, her iki aday da taşındıktan sonra, her ikisi de 10 $ alacak.

Detaylar

Aşağıdaki hareketlere izin verilir. Geçersiz bir hareket verilirse (yetersiz para veya geçersiz koordinatlar), botun sırası atlanacaktır.

Tüm koordinatlar içinde 0 <= n < 16ve ikinci çift için dikdörtgen sınır alanlarında olmalıdır 0 <= n <= 16(bunlar hariçtir ).

  • campaign([x, y], [x, y]): İki koordinat çifti tarafından belirlenen sınır içindeki kampanya
    • Etkilenen kişi başına 1 ABD doları maliyet
    • Bölgedeki her kişi, desteğini aşağıdaki kurallara göre değiştirecektir:
      • Ortogonal olarak (çaprazlar dahil) bitişik tüm komşular için, çoğunluk desteği (ağırlıklı) olan aday için 0,1 destek veya o aday için toplam desteği en az 2 ise 0,2 ekleyin
      • Kampanya yapan aday için 0.25 ekleyin
  • poll([x, y], [x, y]): İki koordinat çifti tarafından belirlenen sınır içindeki anket
    • Ankete alınan kişi başına yuvarlanmış 0,25 ABD doları maliyet
    • Bir sonraki turda, alandaki her kişi hakkında (rakibin hamlesinden sonra) aşağıdaki bilgiler verilir:
      • Pozitif sayıların kendileri için bir oyu ve negatif sayıların rakip için bir oyu gösterdiği oylama adayına verdikleri destek
  • bribe([x, y]): Koordinat çifti tarafından belirlenen konumda kişiye rüşvet verin
    • En az 5 $ maliyeti
      • Oylama bloğu (içinde bir kişinin her zaman için değil oylama bölge) rüşvet edilmiştir $ 1 eklemek
    • Rüşvet veren aday için 3,5'e kadar destek ekleyin
      • Oylama bloğundaki bir kişiye her rüşvet verildiğinde, eklenen destek 0,15 azaltılır
      • Sonunda, bu , adaya olan desteğini azaltmak için bir oylama bloğundaki birine rüşvet verilmesine neden olabilir.
  • merge([x, y], [x, y]): İki koordinat çifti tarafından belirlenen oylama bölgelerini birleştirin
    • Yeni oluşturulan bölgedeki her blok için 25 $ maliyeti (bir blok ücretsizdir)
    • Dokunmak için belirtilen iki kişiyi içeren bölgeleri gerektirir
      • Koordinatların bloklara değil insanlara karşılık geldiğini unutmayın. Bir bloğa referans vermek için koordinatlarını 4 ile çarpmanız yeterli
  • unmerge([x, y]): Koordinat çifti tarafından belirlenen oylama bölgesini ayırın
    • Bölgedeki her blok için 25 $ maliyeti
    • Bölgedeki her blok kendi bölgesi olur

Her iki bot da aynı dönüşte birleştirme veya ayırma girişiminde bulunursa (müdahale etmeyecek olsalar bile), her iki dönüş de atlanır ve hiçbir şey ödemez. Hareketler aşağıdaki sıraya göre işlenecektir (geri kalanların sırası önemli değildir):

  1. Rüşvet
  2. Kampanyalarda komşulardan destek
  3. Kamping konusunda adaylardan destek

Kazanan

Her turun sonunda, her iki aday da taşındıktan sonra, tüm bölgelerin oyları eklenecektir. Her kişi, ne kadar olduğuna bakılmaksızın bir adaya oy verecek veya tarafsız olacaktır (yani, +0.05 veya +30 puan burada aynı olacaktır). Aşağıdaki koşullar yerine getirilirse, bir seçim yapılacak ve kazanan seçilecektir:

  • Tüm bölgeler yarı tarafsız seçmenlerden oluşuyor
  • Her adaya oy veren bölge sayısı bağlı değildir

G / Ç

Tüm botlar Javascript fonksiyonları şeklinde sunulmalıdır. Aşağıdaki bilgiler işleve argümanlar olarak sağlanacaktır:

  • Aşağıdaki özelliklere sahip nesneler olarak temsil edilen bir dizi oylama bölgesi:
    • blocks: [x, y]Sol üstteki kişinin koordinatları olarak gösterilen bir dizi oylama bloğu ( [4, 0]veya gibi [12, 12])
    • number_neutral: Bölgede tarafsız olan insan sayısı
    • number_you: Bölgede bot için oy veren kişi sayısı
    • number_opponent: Bölgede botun rakibine oy veren kişi sayısı
    • absolute_average: Bir aday için insanların desteğinin ortalama mutlak değeri
      • Daha yüksek sayılar, kampanya veya rüşvet vermenin genellikle daha az etkili olacağını gösterir
      • Tam olarak 0, bölgedeki herkesin tarafsız olduğu anlamına gelir
  • Botun sahip olduğu para miktarı
  • Son hareketin sonuçlarını içeren bir nesne (anket olmadığı sürece boş)
    • Bir dizi people, sorgulanan her kişiyi temsil eden nesneleri içerir:
      • position: Kişinin şu şekilde biçimlendirilmiş koordinatları [x, y]
      • region: Kişinin bulunduğu bölgenin numaralı kimliği (ilk bağımsız değişkendeki bölgenin dizini)
      • support: Kişinin tarafsız mı (0), bota mı (pozitif) yoksa botun rakibine mi (negatif) oy verdiğini gösteren bir sayı
    • amountsAşağıdaki özellikleri içeren bir nesne :
      • number_neutral: Bölgede tarafsız olan insan sayısı
      • number_you: Bölgede bot için oy veren kişi sayısı
      • number_opponent: Bölgede botun rakibine oy veren kişi sayısı
      • absolute_average: Bir aday için insanların desteğinin ortalama mutlak değeri
  • Dönüşler arasında depolama için kullanılabilen bir nesne (ancak turlar / oyunlar arasında değil)

Taşımak için yukarıdaki işlevlerden birinin sonucu döndürülmelidir. Örneğin:

{
    "Example": (regions, money, result, storage) => {
        storage.block = ((storage.block || 0) + 1) % 16;
    
        return campaign(
            [(storage.block / 4 | 0) * 4, (storage.block % 4) * 4],
            [(storage.block / 4 | 0) * 4 + 4, (storage.block % 4) * 4 + 4]
        );
    }
}

Kurallar

  • Botların çalışması makul bir süre almalıdır
  • Botlar adil oynamalı, burada izin verilmeyen şekillerde denetleyiciyi veya diğer gönderimleri manipüle etmemelidir.
  • Her bot diğer botlara karşı bir kez çalıştırılacak ve kazanan en çok kazanan bot olacaktır.
    • Beraberlik durumunda, önceki bot kazanır
  • Geçersiz dönüş değerleri veya hatanın dönüş için hareket olmadığını varsayacağı botlar
  • Botlar deterministik olmalıdır

HyperNeutrino'nun meydan okuma fikri ve orijinal sanal alan önerisi.

Denetleyici: https://redwolfprograms.github.io/political-simulator
Sohbet Odası: Burada
Son Tarih: 5 Kasım 2020, Perşembe, UTC Öğlen (08:00 EST)

Yanıtlar

2 EthanChapman Nov 02 2020 at 23:04

Abotcus

Randgrab kadar iyi veya ondan daha iyi olmak için çok fazla süslü özelliğe ihtiyacınız olmadığı ortaya çıktı! Abotcus, başlangıçta bir alanı kapar, ardından her bloğu ağırlıklandırmak için basit bir formül uygular ve en iyi ağırlığa sahip bloğu seçer. Orada gereksiz şeyler var gibi görünüyorsa, bunun nedeni çok daha fazla süslü özellik eklemeyi beklememden kaynaklanıyor ... ama but \ _ (ツ) _ / ¯ ihtiyacım yoktu.

(regions, money, result, storage) => {
    
    if(money == 100) {return campaign([9,1],[15,15])}
    
    var map = [[,,,],[,,,],[,,,],[,,,]];
    var weights = [[,,,],[,,,],[,,,],[,,,]];
    var blocks = [];
    
    for(var r of regions) {
        for(var b of r.blocks) {
            map[b[1]/4][b[0]/4] = b;
            weights[b[1]/4][b[0]/4] = weight(r.number_you, r.number_opponent, r.number_neutral, r.absolute_average)/r.blocks.length;
            blocks.push([b, weights[b[1]/4][b[0]/4]]);
        }
    }
    
    blocks.sort((a,b) => {
        return b[1]-a[1];
    });
    
    var start_block = blocks[0][0];
    
    console.log(blocks);
    
    if(money >= 16) {
        return campaign(start_block, [start_block[0]+4, start_block[1]+4]);
    } else {
        return campaign(start_block, [start_block[0]+3, start_block[1]+3]);
    }
    
    function weight(own, opp, neut, avg) {
        var tot = own+opp+neut;
        var cat = 0;
        if(opp > tot/2) {
            cat = 1;
        } else if(own > tot/2) {
            cat = 5;
        }
        return 1/(1+avg+cat);
    }
}
```
6 pppery Oct 28 2020 at 06:30

Landgrab

Stratejinin kısa açıklaması:

  1. İlk dönüşte, tüm ilk parayı kullanarak merkezde büyük bir kampanya yapın.
  2. Aksi takdirde 2'den fazla tarafsız seçmenin olduğu bir bölge varsa en tarafsız seçmenin olduğu bölgede kampanya yapın.
  3. Aksi takdirde benim ve rakibimin aynı sayıda seçmen olduğu bir bölge varsa o bölgede kampanya yap.
  4. Aksi takdirde, en tarafsız seçmenlerin olduğu bölgede kampanya.

Bu, tarafsız seçmenler iddia etmenin, rakibinize zaten oy verecek olan seçmenlere göre çok daha kolay olduğu gerçeğine dayanır. Gerrymandering hakkında bir şey bilmiyor, bu yüzden birisi oy verme bölgelerini karıştırırsa pek iyi sonuç vermeyebilir ama bu bir başlangıçtır.

(regions, money, result, storage) => {
   if(money == 100) { return campaign([2, 2], [12, 12]); }
   var best = regions[0];
   var tied;
   for (var i = 0; i < regions.length; i++) {
      if(regions[i].number_neutral > best.number_neutral) {
         best = regions[i];
      }
      if(regions[i].number_neutral == 0 && regions[i].number_you == regions[i].number_opponent) {
        tied = regions[i];
      }
   }
   var b;
   if (tied && best.number_neutral > 2) {
     b = tied.blocks[money % tied.blocks.length];
   } else {
     b = best.blocks[money % best.blocks.length];
   } 
   if (money >= 16) {
        return campaign(b, [b[0] + 4, b[1] + 4])
   } else if (money % 2 == 0) {
        return campaign(b, [b[0] + 3, b[1] + 3])
   } else {
        return campaign([b[0] + 1, b[1] + 1], [b[0] + 4, b[1] + 4])
   }
}
4 aerik Oct 30 2020 at 00:25

Sol Politika

v1.1

Haritanın sol tarafını tutar, ardından sağ tarafını gerrymanders. Bunu başardıktan sonra, çıkmazdan kaçınmak için yavaş yavaş sağ tarafa saldıracaktır.

(regions, money, result, storage) => {
        storage.phase = storage.phase || 0;
        storage.merge = storage.merge || 0;

        if (storage.phase == 0){
            storage.phase+=2;
            return campaign([1,2],[5,14]);
        }

        if (storage.phase <= 6) {
            var result = campaign([storage.phase,1],[storage.phase+1,15]);
            if(money >= 14) storage.phase++;
            return result;
            
        }


        if(storage.phase == 7){

            if(storage.merge < 4){
                var result; 
                if(money >= 25){ 
                    result = merge([9,(storage.merge*4)+1],[15,(storage.merge)*4+1])
                    storage.merge++;
                    storage.phase = 1
                }
                return result;
            }
            else if(regions.filter(r => r.blocks[0][0] <= 5)
                           .filter(r => r.number_you > r.number_opponent + r.number_neutral).length >= regions.length / 2){ 
                area = (storage.merge % 4)*4;
                if(money >= 18){
                    storage.merge++;
                    storage.phase = 1;
                    return campaign([9,area],[15,area+3]);
                }
            }
            else{
                
                storage.phase = 1;
                var result = campaign([storage.phase,1],[storage.phase+1,15]);
                if(money >= 14) storage.phase++;
                return result;
            }
        }
    }

Şu anda sadece örnek botu yeniyor. Strateji çok kazanmak için çok yavaş.

4 EthanChapman Oct 30 2020 at 12:15

Randgrab

Rastgeleliği artırmak için Landgrab'ın bir evrimi olarak başladı, ardından diğer tüm yarışmacıları yenene kadar yavaşça daha fazla özellik ekledi (Landgrab, Leftist Policy 1.1 ve Greedy Campaign 9).

Özellikler şunları içerir:

  • Başlangıçta paradan tasarruf etmek için daha az arazi kapmak
  • Yeterli paramız varsa bitişik alanları bir kerede kapmak
  • Kazanmaya yetecek kadar önümüze sahip olduğumuz ve rakibimizin henüz sefer yapmadığı alanları önceliklendirin
  • Oyun en yakın olduğu alanlara öncelik verin (isterseniz "değişken durumlar")
  • 3x3 yaparken iddia etmek için dört köşeden herhangi birini rastgele seçmek dahil daha fazla rastgelelik
  • rTüm rastgeleliği kontrol eden oldukça kaotik (ama yine de deterministik!) Bir değişken

Zayıf yönler şunları içerir:

  • Kararsız durumlara yeterince öncelik vermemek
  • Kampanya dışı işlevlerden yararlanmamak
  • Bölge değişiklikleri tarafından atılabilir, ancak bu kısmen düzeltilmiştir.
  • Sınırlara iyi uymayan iddialar tarafından reddedilebilir
(regions, money, result, storage) => {
    if(money == 100) {return campaign([4, 4], [12, 12]);}
    var r = money + money * regions.length;
    regions.forEach(reg => r += reg.blocks[0][0] * reg.number_neutral + reg.blocks[0][1] * reg.number_you + money * reg.number_opponent + reg.blocks.length * reg.absolute_average);
    r = Math.floor(r);
    var tied = [];
    var best = [regions[r % regions.length]];
    var closest = [regions[(2*r) % regions.length]];
    for (var i = 0; i < regions.length; i++) {
        if(regions[i].number_neutral > best[0].number_neutral && !(regions[i].number_you > 8 && regions[i].number_opponent == 0)) {
            best = [regions[i]];
        } else if(regions[i].number_neutral == best[0].number_neutral && !(regions[i].number_you > 5 && regions[i].number_opponent == 0)) {
            best.push(regions[i]);
        }
        if(regions[i].number_neutral == 0 && regions[i].number_you == regions[i].number_opponent) {
            tied.push(regions[i]);
        }
        if(regions[i].number_opponent > regions[i].number_you && regions[i].absolute_average < closest[0].absolute_average) {
            closest = [regions[i]];
        } else if(regions[i].number_opponent > regions[i].number_you && regions[i].absolute_average == closest[0].absolute_average) {
            closest.push(regions[i]);
        }
    }
    var b;
    var choice;
    if (tied.length > 0 && best[0].number_neutral > 4) {
        choice = tied;
    } else {
        choice = (best[0].number_neutral > 2 ? best : closest);
    }
    console.log(choice);
    bt = choice[r % choice.length];
    b = bt.blocks[r % bt.blocks.length];
    var x = Math.floor(r/2) % 2;
    var y = Math.floor(r/4) % 2;
    if (money >= 18 && choice) {
        for(var i = 0; i < choice.length; i++) {
            for(var j = 0; j < choice[i].blocks.length; j++) {
                var c = choice[i].blocks[j];
                if(c[0] == b[0]-4 && c[1] == b[1]) {
                    return campaign([c[0]+1, c[1]], [b[0]+3, b[1]+3]);
                } else if(c[0] == b[0]+4 && c[1] == b[1]) {
                    return campaign([b[0]+1, b[1]], [c[0]+3, c[1]+3]);
                } else if(c[0] == b[0] && c[1] == b[1]-4) {
                    return campaign([c[0], c[1]+1], [b[0]+3, b[1]+3]);
                } else if(c[0] == b[0] && c[1] == b[1]+4) {
                    return campaign([b[0], b[1]+1], [c[0]+3, c[1]+3]);
                }
            }
        }
    }
    if (money >= 16) {
        return campaign(b, [b[0] + 4, b[1] + 4]);
    } else {
        return campaign([b[0] + x, b[1] + y], [b[0] + 3 + x, b[1] + 3 + y]);
    }
}
3 tsh Oct 29 2020 at 18:06

Her bölge için açgözlü kampanya 9

  • Her turda en az 10 dolarımız var. Bu, 3x3 bir alanda kampanyayı mümkün kılar.
  • Her bölgede sadece 9 kuşak gerektiğinden. Biz sadece ilk 3x3'ü kampanyalıyoruz ama sağda veya altta olanlardan vazgeçiyoruz.
  • Her fırsatta, açgözlü bir kampanya konumu seçeriz: Bir sonraki sırada ne kadar çok bölge bizi desteklerse, O kadar iyi.
(regions, money, result, storage) => {
  const turn = storage.turn = storage.turn + 1 || 1;
  const gh = money < 21 ? 1 : 2;
  const h = 4 * gh - 1;
  const gw = 77 <= money ? 3 : 49 <= money ? 2 : 1;
  const w = 4 * gw - 1;
  const candidate = [];
  for (let i = 0; i <= 4 - gw; i++) {
    for (let j = 0; j <= 4 - gh; j++) {
      let s = gw * gh;
      for (let k = 0; k < gw; k++) {
        for (let l = 0; l < gh; l++) {
          let bx = i + k, by = j + l;
          let region = regions.find(r => r.blocks.some(block => block == [bx * 4, by * 4] + ''));
          let { number_neutral: n, number_opponent: o, number_you: y } = region;
          if (y <= o) {
            if (n + y > o) s += 1;
            if (n + y == o) s += 0.5;
            if (n + y < o) s += 0.5 ** (o - y - n / 2);
          } else {
            if (n + o > y) s += 0.5;
            if (n + o < y) s += -(0.5 ** (y - o - n / 2));
            if (n + o == y) s += 0.25;
          }
        }
      }
      candidate.push({ s, x: i, y: j });
    }
  }
  const ts = Math.max(...candidate.map(c => c.s));
  const best = candidate.filter(c => c.s === ts);
  const { x: tx, y: ty } = best[turn % best.length];
  return campaign([tx * 4, ty * 4], [tx * 4 + w, ty * 4 + h]);
}
2 aerik Nov 05 2020 at 12:09

Liberal Gündem

Solcu Politikanın manevi halefi. Kampanyalar sol tarafın tamamı bire döner, ardından sağ üstteki her iki bloğu da birleştirir, sonra sol tarafı korumaya geri döner. Solun örtülü olduğundan son derece emin olduktan sonra, sağa doğru hareket eder.

    (regions, money, result, storage) => {
        storage.merge = (storage.merge||0)
        if(money >= 100){
            return campaign([1,1],[7,15])
        }
        else {
            var map = [];
            regions.forEach(reg => {
                reg.blocks.forEach(b => {
                    map.push({
                        "pos": b,
                        "abs_avg":reg.absolute_average,
                        "num_you":reg.number_you / reg.blocks.length,
                        "num_opp":reg.number_opponent / reg.blocks.length,
                        "num_neu":reg.number_neutral / reg.blocks.length,
                        "won": (reg.number_neutral>=reg.number_you+reg.number_opponent) ? 0 : reg.number_you/ reg.blocks.length - reg.number_opponent / reg.blocks.length
                    });
                });
            });
            map = map.sort((a,b)=>a.abs_avg-b.abs_avg).sort((a,b)=>a.won - b.won);
            var leftmap = map.filter(b=>b.pos[0]<8)
            if(money >= 25){
                if(storage.merge == 0){
                    storage.merge++
                    return merge([8,0],[12,0])
                }
                return campaign([leftmap[0].pos[0],leftmap[0].pos[1]],[leftmap[0].pos[0]+4,leftmap[0].pos[1] + 4])
            }
            
            if(leftmap.every(b=> b.abs_avg > 3)) return campTarget3by3(map[0].pos).filter(b=>b.won<1)
            return campTarget3by3(leftmap[0].pos)
        }

        function campTarget3by3(pos){
            var a1,a2,b1,b2
            if(pos[0]==0){
                a1 = 1
                b1 = 4
            }
            else {
                a1 = pos[0]
                b1 = pos[0] + 3
            }
            if(pos[1]==0){
                a2 = 1
                b2 = 4
            }
            else {
                a2 = pos[1]
                b2 = pos[1] + 3
            }

            return campaign([a1,a2],[b1,b2])
        }
    }

İronik bir şekilde, Solcu Politikanın yenebileceği tek şey bu!