Açlık Oyunları - Ye ya da Öl


60

Açlık Oyunları - Ye ya da Öl

Yemek yemezsen ölürsün. Eğer yersen, yaşarsın (ölene kadar). Sen olacak die, bu yüzden son ölmeye çalışın.

genel bakış

Bir av hayvanları sürüsü ile dolu bir ada var. Beş avcı paketini kontrol ediyorsun. Amacınız, paketinizi canlı tutmaktır. Bunu av yiyerek yapın. Av avcılardan kaçma eğilimindedir, aksi halde sürünün içinde kalmaya çalışır. Tabi ki, paketin diğer paketlerle aynı alanda olacak, bu yüzden yarışma sizden önce onları yemeye çalışacak. Bunun sizi cesaret kırmasına izin vermeyin, yoksa açlıktan öleceksiniz.

Nasıl oynanır

Paketinizi yönlendirmek için bir komut satırı programı oluşturun ve gönderin. STDIN üzerindeki kontrol programından ve STDOUT'daki çıkış komutlarından durum bilgisi alacak. Format aşağıda ayrıntılı olarak açıklanmıştır. Her program sadece bir kez yürütülecek ve daha fazla paket üyesi bulunmayana kadar çalışmaya devam etmelidir . Girdileri girerken okumanız ve hızlı bir şekilde yanıtlamanız gerekecektir. Her cevap için 200ms'lik kesin bir zaman aşımı süresi vardır. O zamana kadar cevap vermediyseniz, paketiniz geçerli dönüş için yeni talimatlar almayacaktır.

Programınız denetleyici tarafından çalıştırılamazsa, geçerli sayılmaz. Lütfen gönderinizi çalıştırmak için kullanmam gereken komut satırı dizesini ekleyin. Herhangi bir özel talimat varsa (derleyici kurulumu, vb.), Lütfen bunları ekleyin. Çalışmasını sağlayamazsam, sizden yorumlarda yardım isteyeceğim. Cevap vermezseniz, gönderinizi kabul edemeyeceğim.

Turnuva 64bit bir Linux sisteminde yapılacaktır. Gerekli yönergeleri verirken bunu aklınızda bulundurun.

ayrıntılar

  • Her bir yaratığın konumu ve yönü , sırasıyla doublekendilerini xve ykoordinatlarını temsil eden bir çift duyarlıklı kayan nokta sayısı (örn. ) Şeklindedir.

  • Her yaratık bir nokta olarak kabul edilir. Bu, aynı alanı üst üste getirip işgal edebilecekleri anlamına gelir. Kenara atılmayacaksınız ve diğer canlılarla çarpışma kavramı yok.

  • Ada bir taraftır, bir tarafına 500 birimdir. Bu sınırların ötesine girmeye çalışırsanız, kenara kenetleneceksiniz. Kökeni {0,0}sol üstte, xsağa doğru ve yaşağı doğru artıyor. Yine, harita kaydırmaz .

  • Oyun 1500 + (packCount * 50) av hayvanları ile başlar. Adanın merkezinde toplanacaklar, ancak hızla hareket etmeye başlamaya karar verecekler.

  • Paketler, çevre etrafındaki eşit aralıklarla yerleştirilmiş bir dairede düzenlenecektir. Paket sırası karıştırılır, bu nedenle belirli bir yerden başlamaya güvenmeyin.

  • Av hayvanları 30 birim yarıçapındaki diğer tüm hayvanları görebilir . Tur başına maksimum 6,0 birim hareket edebilirler .

  • Avcılar diğer tüm hayvanları 50 birim yarıçapında görebilirler . Her turda maksimum 6,1 birimde hareket edebilirler . Bu, görülmeden önce avı görebilecekleri ve (zorlukla) onları geçebilecekleri anlamına gelir.

  • Avcılar, açlık seviyelerine göre yaşar ve ölürler . 1000'de başlar ve her turda bir azalır. Hareketten sonra, bir avcı 1 birim av içindeyse, otomatik olarak onu yer. Bu avını kaldırır ve avcının açlığını 1000'e ayarlar. Her avcı, dönüş başına sadece bir av yiyebilir. Menzilde birden fazla varsa, ilmek için ilk önce hangisini alırsa mutlaka yenecektir (mutlaka en yakın olan değil). Bir avcı açlığı sıfıra ulaşırsa ölür.

  • Paketler her biri beş üyeyle başlar . Her 5000 turda hala oyunda olan tüm paketler bir yeni üyeye dönüşecek. Diğer bir paket üyesinin görünür aralığına yerleştirilecektir. Girişlerinizin beşten fazla üyeyle iş yapabildiğinden emin olun.

  • Her 1000 turda daha fazla av ortaya çıkacak. Yeni av sayısı eksi olan canlı avcı sayısı olacaktır.

  • Avcılar diğer avcılara saldıramaz. Avlandıklarında avlarını yer. Bu kadar.

  • Bir sıra içindeki sipariş:

    • Bütün avlar karar verir.
    • Bütün avcılar karar verir
    • Tüm av hareketleri
    • Bütün avcılar taşınır / yer
  • Her paketin kararlarını / hamlelerini aldığı sıra, her seferinde rasgele seçilecektir.

Protokol (Genel)

Tüm iletişim dizge biçiminde yapılır US-ASCII. Sayılar, Java Double.toString()veya kullanarak dizgelere dönüştürülür Integer.toString(). Çıktınız, Java tarafından okunabilecek şekilde Double.valueOf(String)(tamsayılar çıkarmayacaksınız) biçimlendirilmelidir . Ayrıştırılabilir formatlarla ilgili ayrıntılar için belgelerine bakınDouble . Bir satırda tüm alanlar standart ayrılır \tkarakteri, ve satırbaşları vardır \n. Tüm dize sonlandırılacak, boş bir bayt olacaktır \0.

Aşağıdaki örneklerde, <>okunabilirlik uğruna alanları işaretlemek için kullanıyorum . Bunlar gerçek dizgelerde mevcut değil.

Protokol (Giriş)

Giriş dizesinin, paketinizde kaç tane canlı göründüğüne bağlı olarak uzunluğu değişir. 100k karakteri geçebilir, bu yüzden hazırlıklı olun. Temel kurulum:

  • Satır 0: Oyun hakkında temel bilgiler. turngeçerli dönüş numarasıdır ve sayımlar , sahada kalan av ve avcıların toplam sayısıdır. Bunlar integerstring biçimindedir.

    <turn>\t<preyCount>\t<predatorCount>\n
    
  • Satır 1: Paket üyelerinizin benzersiz kimlikleri ve açlık seviyeleri. Bunlar edilir değil her giriş için aynı sırayla verilmiştir. Girdide göründükleri sırayı değil , tek tek üyeleri izlemek için benzersiz kimlikleri kullanın . Yine, bunlar integerdizge gibidir. İkili paket için bu şöyle olur:

    <id[0]>\t<hunger[0]>\t<id[1]>\t<hunger[1]>\n
    
  • Satır 2: Paket üyelerinizin pozisyonları, 1. satırda verilen sırayla . Bunlar doublestring olarak:

    <x[0]>\t<y[0]>\t<x[1]>\t<y[1]>\n
    

Aşağıdaki satırlar her bir paket üyesinin görünürlüğünü, 1. satırda verilenle aynı sırada gösterir . Bunlar üye başına iki satır olarak verilecek.

Her biri için birincisi görebileceği avın bulunduğu yerlerden oluşur . İkincisi, avcıların görebileceği yerler. Bu yerler bir bütün olarak benzersiz değildir. Örneğin, iki paket üyesi aynı hayvanı görebiliyorsa, her iki üyenin dizisinde olacaktır. Ayrıca, kendi paket üyeleriniz de eklenecek. Bunları hariç tutmak istiyorsanız, konumları kendi üyelerinizle karşılaştırmak isteyebilirsiniz. Tüm konumlar doubledizge biçimindedir.

Her yaşayan üye için:

<prey[0].x>\t<prey[0].y>\t<prey[1].x>\t<prey[1].y>\n
<predator[0].x>\t<predator[0].y>\t<predator[1].x>\t<predator[1].y>\n

Son olarak, son karakter \0, bir sonraki satırın başında olacak .

İstisna: Girdiyi alırsanız dead\0paketiniz ölür. Lütfen programınızı dikkatlice sonlandırın, lütfen. Kontrolör gerektiğini kapatıldığında bütün canlı işlemleri kapatıldı, ama yerine her yere zombi süreçleri istemem. Bir nezaket olarak, bir giriş zaman aşımı içerebilir. Mesela, benim örnek sınıfım 15 saniye girdi almazsa biter.

Protokol (Çıktı)

Çıktı basittir. doubleHer canlı paket üyesi için bir çift değer vereceksin . Bunlar, bu dönüşü üstlenmelerini istediğiniz hareketi temsil eder. Örneğin, eğer yaratıcınız şu anda çalışıyorsa {100.0, 100.0}ve onlara bir komut verirseniz {-1.0, 1.0}, onlar taşınacaktır {99.0, 101.0}. Tüm sayılar sekmeyle ayrılmış tek bir satırda olacaktır.

Örneğin, hayatta 3 paket üyeniz varsa, bu geçerli bir cevap olacaktır:

1.0\t-1.0\t2.0\t-2.0\t3.0\t-3.0\0

Bu ederek yaratıkları taşımak istiyorsunuz {1.0,-1.0}, {2.0,-2.0}ve {3.0,-3.0}. Sipariş, girişte alınan ile aynıdır. Sonunu unutma \0!

Geçersiz giriş yaparsanız, hatalı sonuçlar izleyecektir. Tek bir sayı a ile ayrıştırılamazsa doublesıfır olur. Dize bir bütün olarak ayrıştırılamazsa, yeni bir talimat verilmeyecek ve paketinizin tamamı önceki sıradaki yönergeleri kullanacaktır.

Her yöne maksimum 6.1 ünite mesafeye kadar kenetlenecektir. İsterseniz bundan daha yavaş hareket edebilirsiniz. Örneğin, {1, 0}size bir birim taşıyacak. {6,8}(mesafe 10) yalnızca 6.1 ünite taşıyacak ve etrafa düşecektir {3.66, 4.88}. Yön sabit kalır.

Önemli: Kontrol programı STDOUT hem okur ve STDERR. Bir istisna atarsanız ve STDERR'ye yazdırırsanız, iletinin geçerli bir yanıt şeklinde olması pek olası değildir. Bunu yapmaktan kaçının.

Kontrol Programı / Test

Kontrolörün kaynağı burada bitbucket.org adresinde bulunabilir . Çalıştırmadan önce derlemeniz gerekecektir. Ana sınıf Gameve tüm sınıflar varsayılan pakette. Çalıştırmak için her paketin komutunu ayrı bir argüman olarak ekleyin. Örneğin, bir Java ChaserPack ve bir Python LazyPack.py çalıştırmak istiyorsanız, şunları kullanabilirsiniz:

java Game "java ChaserPack" "python LazyPack.py"

Haritada avlar yeşil renkte, avcılar kırmızı renkte görünür. Ancak, hangi paket argüman olarak verilen ilk paket ise bunun yerine mavi renkle gösterilir. Bu, test amacıyla onları daha kolay ayırt etmek için tasarlanmıştır. Avcılar, yediklerinde beş kare boyunca beyaz renkte yanıp söner.

Oyun, son avcı aç olana kadar devam edecek, açlık veya tükenme olayları meydana geldiğinde konsola yazacaksınız. Oyun tamamlandıktan sonra, her paket için puan verilecek. Açlık / tükenme olaylarını görmek istemiyorsanız, -silentargümanı kullanabilirsiniz . O zaman sadece final skorunu verir. Bunu ilk argüman olarak geçmelisiniz :

java Game -silent "java ChaserCat" "./someOtherPack"

Dahil bir iskelet Java paketi GenericPack. Gerekli temel giriş / çıkış işlemlerini içerir. Nasıl ayrıştırılacağına ve cevaplandığına dair net bir örnek vermek gerekirse. Başka bir dilde bir şablon eklemek isterseniz, bana bildirin.

Ayrıca, şablona dayanan bir yırtıcı hayvandır ChaserPack. Turnuvaya dahil edilmeyecek ve yalnızca test amaçlı dahil edilecektir. Kasıtlı bir hedefleme hatası nedeniyle oldukça kötü bir performans sergiliyor. Eğer yenemezsen, denemeye devam et.

Aşağıda, kontrol programına ait örnek bir çalışma bulunmaktadır (video için tıklayınız). Video kalitesi mükemmel değil (üzgünüm), ancak avın nasıl hareket ettiği hakkında bir fikir edinebilirsiniz. ( dikkat: ses )

ekran görüntüsü

puanlama

Kazanan, her raundda puan kazanarak turnuva tarafından belirlenir.

Her tur tüm avcılar ölünceye kadar ilerler. Her paket, son üyesinin açlıktan öldüğü zamana göre puanlanacak. Daha sonra siparişe göre puanlar verilir. On tur için puan toplanacak ve victor en yüksek puan alan pakettir.

Her tur için ilk sırayı 100 puan alırsınız. Bundan sonraki her yer için ödül% 20 oranında azaltılır (aşağı yuvarlanır). Bu, puan sıfıra ulaşana kadar devam edecektir (17. sıradan sonra). 18+ ve üstü yerler tur için puan alamaz. Bağlanan paketler eşit puan alır. Örneğin:

1st : 100
2nd : 80
3rd : 64 (T)
3rd : 64 (T)
4th : 51
...
17th: 1
18th: 0
19th: 0

Turnuva boyunca mümkün olan en yüksek puanlar, her 10 seferde birincilikten itibaren 1000'dir.

Birden fazla program ilk etapta bağlı olan turnuvayı sonlandırırsa, sadece sunulan ilk etapta girişlerle on turluk bir turnuva daha düzenlenecektir . Bu, bir zafer kazanana kadar devam edecek.

Her hafta kabaca bir turnuva yapmaya çalışacağım ya da yeni başvurular geldiğinde.

Ek Kurallar (adil oyun!)

  • Herhangi bir harici kaynağı okuyamaz veya yazamazsınız. Programınızın çoklu zamanlarını çağırmayacağınız için, herhangi bir durum bilgisi dahili olarak saklanabilir.

  • Diğer işlemlere / gönderimlere müdahale etmeyin. Bu mu değil avlarını çalmaya kalkmayın demek, o sürecin çalışan engel olmadığı anlamına gelir vb Onlardan kurtulmak. Bu benim takdirime bağlı.

  • Yarışmacılar en fazla üç girişle sınırlıdır . Daha fazla gönderirseniz, sadece gönderilen ilk üç puanı alırım. Birini iptal etmek istiyorsanız, silin.

  • Girişler yalnızca diğer girişleri desteklemek için bulunmayabilir. Her biri kendi yararına kazanmak için oynamalıdır.

  • Programınız (bir defada bir alt sürecin en fazla spawn toplam torunları, doğrudan değil). Her iki durumda da, zaman aşımını aşmadığınızdan emin olun. GameHerhangi bir şekilde sınıfın kendisini davet edemezsiniz.

Sonuçlar - 29 Nisan 2014

İşte son on tur turnuvasının sonuçları:

Clairvoyant         : 1000
EcoCamels           : 752
Netcats             : 688
RubySpiders         : 436
RubyVultures        : 431
CivilizedBeasts     : 382
LazyPack            : 257

EDT 2014/04 / 29'dan önce 09: 00'dan önce gönderilen paketler bu çalışmaya dahil edilir.

Ayrıca her turun detaylarını görüntüleyebilirsiniz . Nedense turları geriye doğru saymaya karar verdim, bu yüzden "10. tur" ile başlıyor.

Güncellemeler

2014/04/23: FGreg , zaman aşımları ile ilgili bir hata bildirdi (teşekkürler!). Bir düzeltme uygulandı, bu nedenle test uzmanları kontrol program kodlarını güncellemek isteyeceklerdir.


28
Tepenin bu kralı sorularından hoşlanıyorum!
Cruncher

2
@Manu Örnek botları Windows 7'de yazdım ve hem win hem de linux üzerinde test ettim. Onlarla ne gibi problemlerin var?
Geobits

2
Tepenin bu kralı soruları oldukça harika ve bu kesinlikle ilginç. Şimdi eserlerde iki farklı paketim var!
mackthehobbit

2
@githubphagocyte Gerçekten ilk zaman aşımına uğrayan bir paketi öldürmek istemiyorum, çünkü basit programlar bile her 40k + turda veya bir kez zaman aşımına uğradı. Kontrol cihazında isim değişikliği yaptım. Artık, herhangi bir yerde bir şey kaçırmadıkça, dönüşler programın dönüşleri olarak bilinir.
Geobits

2
@Geobits eh, benim için sorun değil. Bilirsin, bu gerçekten fizik profesörümün yazdığı bir konuda yardımcı olabileceğim bir araştırma projesine benziyor. Mümkünse biraz sonra açıklayacağım.
krs013

Yanıtlar:


10

görülemeyen şeyleri görebilen

AbleDogs ile yüzleşmek üzere kod güncellendi

Woo hoo! Sonunda Netcats! Gelecekteki bu öngörme paketini oluşturmak için küçük bir değişiklikle mevcut kodu (Geobits'e kredi!) Genişlettim Hiçbir şey, avın nereye taşınacağını bilen avcıları yenemez!

Yaptığım iki testten sonra paketim her zaman Netcats'e karşı kazandı. Ancak, eğer başka paket yoksa, bu kadar iyi performans göstermeyecektir, çünkü yakınlarda çok fazla başka av varsa, tahmin hala başarısız olmaktadır.

Muhtemelen ilk birkaç bin dönüş sırasında av sayısını azaltmak için CivilizedBeasts hilesini içerebilir.

5.21 dakikada tamamlandı
Beklenti (1): 9270 Dönüş: Puan 100
EcoCamel.pl (3): 8118 çevir: Skor 80
Netcats (0): Dönüş 6111: Puan 64
RubyVultures.rb (5): Dönüş 4249: Puan 51
RubySpiders.rb (4): Dönüş 3495: Puan 40
CivilizedBeasts (2): Dönüş 3176: Puan 32
ChaserPack (6): 2492 çevirin: Puan 25

Paketimin isminden hangi stratejiyi kullandığımı bilmelisin = D

Düzenle :

  • Aynı avı kovalamamak için güncellenmiş paket yönetim sistemi (ve aynı zamanda en iyi eşleşmeyi bulmaya çalış!)
  • Av sayısı az olduğunda gezinme sürecini iyileştirin (bu kazanmak için çok önemlidir!).
  • Önceki sürüm köşeye sıkıştığında özel durumları iyileştirin.
  • Yırtıcı hayvan algılama algoritmasındaki bir hata düzeltildi (şimdi oldukça doğru!)
  • Dahil edilen av flock[ALIGN]faktörü
  • Yiyecek kıtsa, avını evcil hayvan olarak sakla
  • Paketin avlarını avlayacağı bir yer yarat
  • Yakında bulunan avcıyı, kazanamayacakları avımızı kovalamaya sürükleyin.

Her paketin ne kadar av yediğini saydım ve işte sonuç:

Clairvoyant (1) 9270 turda 916 av tüketmiştir (0.099 av / dönüş)
EcoCamel.pl (3) 8118 turda 73 av tüketmiştir (0.009 av / tur)
Netcats (0) 6111 turda 563 av tüketmiştir (0.092 av / dönüş)
RubyVultures.rb (5), 4249 turda 77 av tüketmiştir (0.018 av / dönüş)
RubySpiders.rb (4) 3495 turda 293 av tüketmiştir (0.084 av / dönüş)
CivilizedBeasts (2), 3176 turda 10 av tüketmiştir (0.003 av / dönüş)
ChaserPack (6) 2492 turda 43 av tüketmiştir (0.017 av / dönüş)

Paketim çok agresif, ve 916'nın çoğu, Netcats'ten avlarını çalmaktan kazanıyor, tıpkı RubySpiders gibi.

CivilizedBeasts ne yazık ki EcoCamel'in merkezi deve yüzünden kaybediyor.

Ve EcoCamel (açlık kritik 500 ile) oldukça verimlidir, sonuna kadar hayatta kalmak için yeterli miktarda yer.

Ayrıca bu güncellenmiş Clairvoyant ile oyun ancak 10.000 sıraya ulaşıyor.

Kod:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.TreeSet;

public class Clairvoyant extends GenericPack {
    private static final double MAX_SPEED = 6.1;

    private TreeSet<Animal> foods = new TreeSet<Animal>(new AnimalComparator());
    private TreeSet<Animal> predators = new TreeSet<Animal>(new AnimalComparator());

    private XY abattoirCorner;
    private double abattoirRadius = 100;

    private MyMember[] myMembers = new MyMember[100];

    public class AnimalComparator implements Comparator<Animal>{

        @Override
        public int compare(Animal arg0, Animal arg1) {
            if(arg0.x < arg1.x){
                return -1;
            } else if (arg0.x > arg1.x){
                return 1;
            } else {
                if(arg0.y < arg1.y){
                    return -1;
                } else if(arg0.y > arg1.y){
                    return 1;
                } else {
                    return 0;
                }
            }
        }
    }

    public class MyMember extends Member{
        public XY target;
        public XY herdPos;
        public double herdRadius; 
        public boolean mayEat;
        public XY pos;
        public ArrayList<MyAnimal> closestPreys;
        public boolean outdated;

        public MyMember(int id) {
            super(id);
            this.pos = new XY(x, y);
            closestPreys = new ArrayList<MyAnimal>();
            mayEat = true;
            outdated = true;
        }

        public MyMember(Member member){
            super(member.id);
            this.pos = new XY(x, y);
            closestPreys = new ArrayList<MyAnimal>();
            mayEat = true;
            outdated = true;
        }

        public MyMember(Member member, Animal target){
            super(member.id);
            this.target = new XY(target.x, target.y);
            this.pos = new XY(x, y);
            closestPreys = new ArrayList<MyAnimal>();
            mayEat = true;
            outdated = true;
        }

        public void reset(Member me){
            x = me.x;
            y = me.y;
            pos = new XY(x, y);
            closestPreys.clear();
            mayEat = true;
            outdated = true;
        }
    }

    public class MyAnimal extends Animal{
        public ArrayList<MyMember> chasers;
        public XY pos;
        public boolean resolved;

        public MyAnimal(double x, double y){
            super(x, y);
            pos = new XY(x, y);
            chasers = new ArrayList<MyMember>();
            resolved = false;
        }

        public MyAnimal(Animal ani){
            super(ani.x, ani.y);
            pos = new XY(x, y);
            chasers = new ArrayList<MyMember>();
            resolved = false;
        }
    }

    public static void main(String[] args){
        new Clairvoyant().run();
    }

    public Clairvoyant(){
        for(int i=0; i<100; i++){
            nextIdx[i] = 0;
        }
        int cornerIdx = (int)Math.floor(Math.random()*4);
        switch (cornerIdx){
        case 0: abattoirCorner = new XY(0,0); break;
        case 1: abattoirCorner = new XY(500,0); break;
        case 2: abattoirCorner = new XY(500,500); break;
        case 3: abattoirCorner = new XY(0,500); break;
        }
    }

    @Override
    public void respond(){
        updateData();
        goToTarget();
    }

    private void updateData(){
        for(int i=0; i<100; i++){
            if(myMembers[i]!=null){
                myMembers[i].pos = null;
            }
        }
        foods.clear();
        predators.clear();
        for(Member me: members){
            foods.addAll(me.foods);
            predators.addAll(me.others);
            predators.add(new Animal(me.x, me.y));
            if(myMembers[me.id] != null){
                myMembers[me.id].reset(me);
            } else {
                myMembers[me.id] = new MyMember(me);
            }
        }
        for(int i=0; i<100; i++){
            if(myMembers[i]!=null && myMembers[i].pos == null){
                myMembers[i] = null;
            }
        }

        TreeSet<MyAnimal> closestPreys = new TreeSet<MyAnimal>(new AnimalComparator());
        for(int i=0; i<100; i++){
            if (myMembers[i]==null) continue;
            MyMember me = myMembers[i];
            ArrayList<Animal> animals = findClosest(foods, me.pos, members.size());
            boolean first = true;
            for(Animal ani: animals){
                MyAnimal myAni = new MyAnimal(ani);
                if(closestPreys.contains(ani)){
                    myAni = closestPreys.ceiling(myAni);
                } else {
                    closestPreys.add(myAni);
                }
                if(first){
                    myAni.chasers.add(me);
                    first = false;
                }
                me.closestPreys.add(myAni);
            }
        }
        performMatching();
        for(int i=0; i<100; i++){
            if (myMembers[i] == null) continue;
            MyMember me = myMembers[i];
            if(!me.outdated) continue;
            if(me.closestPreys.size() == 0) continue;
            MyAnimal closestPrey = me.closestPreys.get(0);
            if(closestPrey.resolved) continue;
            if(closestPrey.chasers.size() > 1){
                MyMember hungriest = me;
                MyMember closest = me;
                for(MyMember otherMe: closestPrey.chasers){
                    if(sqDist(closestPrey.pos, otherMe) < sqDist(closestPrey.pos, closest)){
                        closest = otherMe;
                    }
                    if(otherMe.hunger < hungriest.hunger){
                        hungriest = otherMe;
                    }
                }
                if(hungriest.hunger > 200){ // Nobody's critically hungry, the closest takes the prey
                    closest.target = closestPrey.pos;
                    closest.mayEat = true;
                    closest.herdPos = abattoirCorner;
                    closest.herdRadius = abattoirRadius;
                    closest.outdated = false;
                } else {
                    if(hungriest == closest){
                        closest.target = closestPrey.pos;
                        closest.mayEat = true;
                        closest.herdPos = abattoirCorner;
                        closest.herdRadius = abattoirRadius;
                        closest.outdated = false;
                    } else {
                        closest.target = closestPrey.pos;
                        closest.mayEat = false;
                        closest.herdPos = hungriest.pos;
                        closest.herdRadius = 0;
                        closest.outdated = false;
                        hungriest.target = closestPrey.pos;
                        hungriest.mayEat = true;
                        hungriest.herdPos = abattoirCorner;
                        hungriest.herdRadius = 10;
                        hungriest.outdated = false;
                    }
                }
                closestPrey.resolved = true;
            } else {
                me.target = closestPrey.pos;
                me.herdPos = abattoirCorner;
                me.herdRadius = abattoirRadius;
                me.mayEat = true;
                me.outdated = false;
            }
        }
        for(int i=0; i<100; i++){
            if (myMembers[i] == null) continue;
            MyMember me = myMembers[i];
            if(me.outdated){
                me.target = null;
                me.outdated = false;
            }
        }
    }

    private void goToTarget(){
        for(Member me: members){
            MyMember mem = myMembers[me.id];
            if(mem.target == null){
                wander(me, 2*(me.id%2)-1);
                continue;
            } else {
                nextIdx[me.id] = 0;
                XY[] nearestHostile = new XY[100];
                for(Animal other: me.others){
                    XY otherPos = new XY(other.x, other.y);
                    boolean isMember = false;
                    for(Member otherMember: members){
                        if(other.x==otherMember.x && other.y==otherMember.y){
                            isMember = true;
                            break;
                        }
                    }
                    if(!isMember){
                        if(nearestHostile[me.id] == null || XY.sqDistance(mem.pos, otherPos) < XY.sqDistance(mem.pos,  nearestHostile[me.id])){
                            nearestHostile[me.id] = otherPos;
                        }
                    }
                }

                // Go towards the target by predicting its next position
                XY target = predictNextPos(mem.target, me);

                me.dx = (target.x - me.x);
                me.dy = (target.y - me.y); 

                // Try to herd the target to our abattoir if this member is not too hungry
                // and if there is no other hostile predator who is closer to the target than us
                // This will make the other hostile predator to keep targeting this target, while
                // it is certain that we will get the target.
                // This is a win situation for us, since it will make the other predator wasting his turn.
                if((me.hunger <= 200 && XY.sqDistance(mem.target, mem.pos) > 400) || me.hunger <= 50 ||
                        (nearestHostile[me.id] != null && Math.sqrt(XY.sqDistance(mem.target, nearestHostile[me.id])) < Math.sqrt(XY.sqDistance(mem.target, mem.pos)))){
                    continue;
                }

                // Don't eat if not threatened nor hungry
                if(me.hunger > 50 && (nearestHostile[me.id] == null ||
                        Math.sqrt(XY.sqDistance(mem.target, nearestHostile[me.id])) > Math.sqrt(XY.sqDistance(mem.target, mem.pos)) + 6)){
                    mem.mayEat = false;
                }

                // Herd to abattoir corner
                double distFromHerd = Math.sqrt(XY.sqDistance(target, mem.herdPos));
                XY oppositeAbattoirCorner = new XY(500-abattoirCorner.x, 500-abattoirCorner.y);
                double distFromOpposite = Math.sqrt(XY.sqDistance(target, oppositeAbattoirCorner));
                if((me.dx*me.dx+me.dy*me.dy > 64 && distFromHerd > mem.herdRadius && distFromOpposite > abattoirRadius)
                        || (preyCount < 5*predCount)){
                    double herdDistance = 4*(distFromHerd-mem.herdRadius)/(Island.SIZE-mem.herdRadius);
                    if(!mem.mayEat) herdDistance = 4;
                    XY gradient = target.minus(abattoirCorner);
                    me.dx += gradient.x*herdDistance/distFromHerd;
                    me.dy += gradient.y*herdDistance/distFromHerd;
                }
            }
        }
    }

    private void performMatching(){
        for(int i=0; i<100; i++){
            if (myMembers[i] == null) continue;
            MyMember me = myMembers[i];
            if(me.closestPreys.size()==0) continue;
            MyAnimal closestPrey = me.closestPreys.get(0);
            if(closestPrey.chasers.size() > 1){
                resolveConflict(closestPrey);
            }
        }
    }

    private void resolveConflict(MyAnimal prey){
        ArrayList<MyMember> chasers = prey.chasers;
        MyMember winner = null;
        double closestDist = Double.MAX_VALUE;
        for(MyMember me: chasers){
            if(sqDist(prey.pos, me) < closestDist){
                closestDist = sqDist(prey.pos, me);
                winner = me;
            }
        }
        for(int i=chasers.size()-1; i>=0; i--){
            MyMember me = chasers.get(i);
            if(me!=winner){
                me.closestPreys.get(0).chasers.remove(me);
                me.closestPreys.add(me.closestPreys.remove(0));
                me.closestPreys.get(0).chasers.add(me);
            }
        }
    }

    private Animal findClosest(Collection<Animal> preys, XY me){
        Animal target = null;
        double cDist = Double.MAX_VALUE;
        double x, y, sqDist;
        for (Animal food : preys) {
            x = food.x - me.x;
            y = food.y - me.y;
            sqDist = x * x + y * y + Double.MIN_NORMAL;
            if (sqDist < cDist) {
                cDist = sqDist;
                target = food;
            }
        }
        return target;
    }

    private ArrayList<Animal> findClosest(Collection<Animal> preys, XY me, int num){
        ArrayList<Animal> result = new ArrayList<Animal>();
        for(Animal food: preys){
            int addIdx = -1;
            for(int i=0; i<num && i<result.size(); i++){
                Animal regFood = result.get(i);
                if(sqDist(me, food) < sqDist(me, regFood)){
                    addIdx = i;
                    break;
                }
            }
            if(addIdx == -1){
                result.add(food);
            } else {
                result.add(addIdx, food);
            }
            if(result.size() > num){
                result.remove(num);
            }
        }
        return result;
    }

    private Member findClosestToTarget(Collection<Member> members, Animal target){
        Member member = null;
        double cDist = Double.MAX_VALUE;
        double x, y, sqDist;
        for (Member me : members) {
            x = me.x - target.x;
            y = me.y - target.y;
            sqDist = x * x + y * y + Double.MIN_NORMAL;
            if (sqDist < cDist) {
                cDist = sqDist;
                member = me;
            }
        }
        return member;
    }

    private static final XY[] CHECKPOINTS = new XY[]{
        new XY(49.5,49.5),
        new XY(450.5,49.5),
        new XY(450.5,100),
        new XY(49.5,100),
        new XY(49.5,150),
        new XY(450.5,150),
        new XY(450.5,200),
        new XY(49.5,200),
        new XY(49.5,250),
        new XY(450.5,250),
        new XY(450.5,300),
        new XY(49.5,300),
        new XY(49.5,350),
        new XY(450.5,350),
        new XY(450.5,400),
        new XY(49.5,400),
        new XY(49.5,450.5),
        new XY(450.5,450.5)};
    private int[] nextIdx = new int[100];

    private int advanceIdx(int idx, int sign, int amount){
        return sign*(((Math.abs(idx)+CHECKPOINTS.length-1+sign*amount) % CHECKPOINTS.length) + 1);
    }

    private void wander(Member me, int sign) {
        if(preyCount > 20*predCount){
            if (me.dx == 0 && me.dy == 0) {
                me.dx = 250 - me.x;
                me.dy = 250 - me.y;
                return;
            }

            double lx, ly, px, py;
            lx = me.dx / 4;
            ly = me.dy / 4;
            boolean dir = Math.random() < 0.5 ? true : false;
            px = dir ? ly : -ly;
            py = dir ? -lx : lx;

            me.dx += px;
            me.dy += py;
        } else {
            if(nextIdx[me.id]==0){
                XY farthest = new XY(2000,2000);
                int farthestIdx = -1;
                for(int i=0; i<CHECKPOINTS.length; i++){
                    if(sign*sqDist(CHECKPOINTS[i], me) > sign*sqDist(farthest, me)){
                        farthest = CHECKPOINTS[i];
                        farthestIdx = i+1;
                    }
                }
                nextIdx[me.id] = farthestIdx*sign;
                for(Member mem: members){
                    if(mem.id == me.id) continue;
                    if(nextIdx[mem.id]==nextIdx[me.id]){
                        nextIdx[me.id] = advanceIdx(nextIdx[me.id], sign, 5); 
                    }
                }
            }
            if(sqDist(CHECKPOINTS[Math.abs(nextIdx[me.id])-1],me) < 1){
                nextIdx[me.id] = advanceIdx(nextIdx[me.id], sign, 1);
            }
            me.setDirection(CHECKPOINTS[Math.abs(nextIdx[me.id])-1].x-me.x,
                    CHECKPOINTS[Math.abs(nextIdx[me.id])-1].y-me.y);
        }
    }

    private double sqDist(XY me, Animal target){
        double dx = me.x-target.x;
        double dy = me.y-target.y;
        return dx*dx + dy*dy + Double.MIN_NORMAL;
    }

    private double sqDist(XY me, Member target){
        double dx = me.x-target.x;
        double dy = me.y-target.y;
        return dx*dx + dy*dy + Double.MIN_NORMAL;
    }

    private double sqDist(Animal target, Member me){
        double dx = me.x-target.x;
        double dy = me.y-target.y;
        return dx*dx + dy*dy + Double.MIN_NORMAL;
    }

    private List<Animal> getNeighbors(double radius, XY pos, Collection<Animal> candidates) {
        List<Animal> neighbors = new ArrayList<Animal>();
        for(Animal neighbor: candidates){
            if(sqDist(pos, neighbor) < radius * radius){
                neighbors.add(neighbor);
            }
        }
        return neighbors;
    }

    final double[] weights = { 1, 1, 0.96, 2, 4 };
    double weightSum;

    static final int ALIGN = 0;
    static final int SEPARATE = 1;
    static final int COHESION = 2;
    static final int FLEE = 3;
    static final int WALL = 4;
    static final int VISIBLE = 30;
    static final int VISIBLE_PRED = 50;

    private HashMap<Member, List<Animal>> prevPreys = new HashMap<Member, List<Animal>>();

    private XY matchPreys(List<Animal> prevs, List<Animal> curs, XY prey){
        XY result = new XY();
        double sqDist = 0;
        Animal candidate;
        XY otherPos;
        for(Animal otherPrey: curs){
            otherPos = new XY(otherPrey.x, otherPrey.y);
            sqDist = XY.sqDistance(prey, otherPos);
            if(sqDist > VISIBLE * VISIBLE)
                continue;
            candidate = findClosest(getNeighbors(6, otherPos, prevs), prey);
            if(candidate == null){
                return null;
            }
            result.add(otherPos.x-candidate.x, otherPos.y-candidate.y);
        }
        return result;
    }

    private XY predictNextPos(XY prey, Member me) {
        List<Animal> preys = getNeighbors(VISIBLE_PRED, prey, foods);
        List<Animal> preds = getNeighbors(VISIBLE, prey, predators);

        XY flock[] = new XY[weights.length];
        for (int i = 0; i < weights.length; i++)
            flock[i] = new XY();

        double dx, dy, dist, sqDist;
        for (Animal otherPrey : preys) {
            sqDist = XY.sqDistance(prey, new XY(otherPrey.x, otherPrey.y));
            if(sqDist > VISIBLE * VISIBLE)
                continue;
            dx = otherPrey.x - prey.x;
            dy = otherPrey.y - prey.y;
            flock[COHESION].add(dx*sqDist, dy*sqDist);
            flock[SEPARATE].add(-dx*(1d/sqDist), -dy*(1d/sqDist));
            flock[ALIGN].add(new XY(prey.x-me.x,prey.y-me.y));
        }

        if(sqDist(prey, me) < 400){
            if(prevPreys.get(me) == null){
                prevPreys.put(me, preys);
            } else {
                XY flockAlign = matchPreys(prevPreys.get(me), preys, prey);
                if(flockAlign == null){
                    prevPreys.put(me , null);
                } else {
                    flock[ALIGN] = flockAlign;
                    prevPreys.put(me, preys);
                }
            }
        }

        flock[ALIGN].unitize().multiply(5);
        flock[COHESION].unitize().multiply(5);
        flock[SEPARATE].unitize().multiply(5);

        for (Animal predator : preds){
            flock[FLEE].add(prey.x-predator.x, prey.y-predator.y);
        }

        dx = Island.CENTER.x - prey.x;
        dy = Island.CENTER.y - prey.y;
        dist = Math.max(Math.abs(dx), Math.abs(dy));
        if(dist > 240){
            flock[WALL].x = dx * dist;
            flock[WALL].y = dy * dist;
            flock[WALL].unitize().multiply(5);
        }

        XY vec = new XY();
        vec.x = 0;
        vec.y = 0;
        for (int i = 0; i < flock.length; i++) {
            flock[i].multiply(weights[i]);
            vec.add(flock[i]);
        }
        limitSpeed(vec);
        return vec.add(prey);
    }

    private XY limitSpeed(XY move) {
        if (move.x*move.x+move.y*move.y > MAX_SPEED*MAX_SPEED)
            move.unitize().multiply(MAX_SPEED);
        return move;
    }
}

1
Çok güzel gözüküyor, seninki benim oyunumdaki fileli ağlardan daha iyi. Ama diğer avcıları yönetememekten nefret ediyorum, çünkü canavarlarım istatistiklerinizde gerçekten kötü bir iş çıkarıyor (kötülükler çok iyi olsa da). Belki bir perl derleyicisi kurmaya çalışmalıyım.
Herjan

Evet, cevabınızda da tartışıldığı gibi, ortada bir avcı varsa, yönteminizin işe yaramadığını düşünüyorum. Sizinkine benzer davranışlarda bulunan başka bir sürümü uygulamaya çalıştım. Mevcut avcı sayısına bağlı olarak formasyonu değiştirebilir, bu yüzden sizinkinden daha iyi olmasa da izlemek oldukça eğlenceli.
justhalf

Evet, stratejim üyelerimden başka miktarlarda olan diğer oluşumlar gibi birçok yönden yükseltilebilir, çünkü hayvanlarım <4 avcıyla mahkumdur. Veya örneğin toplanması gereken (sadece orta yerine) rastgele yerler. Ama bunu (şimdi) uygulamak için çok tembelim. Asla bunun kadar iyi olmayacak çünkü av azalırsa taktiğim işe yaramaz. O zaman seninki gibi bir canavara ihtiyacın olduğunda (benim taktiğime başlamak için zaten bahsettin ve avı bu taktiği kullanmak için düşük olduğunda). Sanırım bunu zaten düşündün.
Herjan

Şu anda başka bir zorlukla karşı karşıyayım ve GeoBits bu konuya olan ilgisini kaybetmiş gibi görünüyor, bu yüzden sonuçlar güncellenmediği sürece bir süre oturmasına izin vereceğim. Birkaç başka sunum için fikirlerim var, bu yüzden bu zorluğun hayatta kalmasını umuyorum. Tabii ki güncellemenize bir göz atacağım.

15

Netcats

İşte başlamanıza yardımcı olacak bir paket. GenericPackKontrol programına dahil edilen sınıfı genişletir . Orijinal gönderimden bu yana geliştirilmiştir ve artık seyrek bir sürü ile açlık çekmemektedir.

Netcats, avdaki köşeyi avlamak için damar şeklinde bir ağ oluşumu kullanır ve burada onları boş zamanlarında yiyebilirler. Ağ, merkezde bir "kafa" elemanı ile oluşturulmaktadır. Kafa bir kez yemek yediğinde, en erken paket üyesi ile yer değiştirir, çünkü kafa normalde ilk yemek yeme fırsatını elde eder.

Ağ oldukça küçük başlar, ancak alanı daha verimli bir şekilde taramak için sürü küçüldüğünde genişler.

Av görülemiyorsa, formasyon adanın çoğunu kapsayan naif bir arama modelinde genişler.

Paket iki üyeye indiğinde, ağ çalışmıyor. Bu noktada her biri kendi yoluna gider, açgözlülükle bulabileceği en yakın şeyi yiyor ve aksi takdirde yarı-rastgele bir yürüyüşe çıkıyor.

Bu sürüm , söz konusu videoda görülen saf Netcats'ten çok daha iyi hayatta kalır .

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class Netcats extends GenericPack {

    boolean seeking;
    Member head = null;
    Set<Animal> foods;

    public static void main(String[] args) {
        new Netcats().run();
    }

    @Override
    public void respond() {
        if (foods == null)
            foods = new HashSet<Animal>();
        else
            foods.clear();
        for (Member member : members)
            foods.addAll(member.foods);

        if (members.size() < 3) {
            soloRun();
        } else {
            head = setHead();
            setHeadVec();
            for (int i = 1; i < members.size(); i++) {
                setMemberVec(i);
            }
        }
    }

    Member setHead() {
        if (!members.contains(head))
            return members.get(0);

        Member hungry = head;
        int idx = 0;
        for (int i = 0; i < members.size(); i++) {
            Member me = members.get(i);
            if (me.hunger < hungry.hunger) {
                hungry = me;
                idx = i;
            }
        }

        if (hungry != head) {
            members.remove(hungry);
            members.remove(head);
            members.add(0, hungry);
            members.add(idx, head);
            return hungry;
        }
        return head;
    }

    void setHeadVec() {
        double x = 0, y = 0;

        Collection<Animal> yummy = getFoods(head);

        seeking = false;
        if (yummy.size() == 0) {
            scoutHead();
            return;
        }

        if (members.size() == 1)
            if (findFood(head))
                return;

        for (Animal food : yummy) {
            x += food.x - head.x;
            y += food.y - head.y;
        }
        x *= 10000000;
        y *= 10000000;

        head.dx = x;
        head.dy = y;
        if (members.size() > 1)
            limitSpeed(head, MAX_SPEED * HEAD_MULT);
    }

    void scoutHead() {
        seeking = true;
        head.dy = 250 - head.y;
        head.dx = round % 80 < 40 ? -head.x : 500 - head.x;
    }

    void setMemberVec(int idx) {
        Member me = members.get(idx);
        Member leader;
        leader = idx < 3 ? members.get(0) : members.get(idx - 2);
        if (findFood(me))
            return;

        double lx, ly, px, py, tx, ty, dist;
        lx = -leader.dx;
        ly = -leader.dy;
        dist = Math.sqrt(lx * lx + ly * ly) + Double.MIN_NORMAL;
        lx /= dist;
        ly /= dist;
        px = idx % 2 == 0 ? ly : -ly;
        py = idx % 2 == 0 ? -lx : lx;

        tx = leader.x + leader.dx;
        ty = leader.y + leader.dy;
        int xtrack = seeking ? COMB : preyCount > 400 ? ASIDE : MID_SIDE;
        tx += lx * BEHIND + px * xtrack;
        ty += ly * BEHIND + py * xtrack;

        me.dx = tx - me.x;
        me.dy = ty - me.y;
        limitSpeed(me, MAX_SPEED * (idx < 3 ? MID_MULT : 1));
    }

    Collection<Animal> getFoods(Member me) {
        return me.foods.size() == 0 ? foods : me.foods;
    }

    boolean findFood(Member me) {
        if (me.hunger > 500)
            return false;

        Collection<Animal> yummy = getFoods(me);
        if (yummy.size() == 0)
            return false;

        double x, y, sqDist, cDist = 10 * 10;
        Animal target = null;
        for (Animal food : me.foods) {
            x = food.x - me.x;
            y = food.y - me.y;
            sqDist = x * x + y * y + Double.MIN_NORMAL;
            if (sqDist < cDist) {
                cDist = sqDist;
                target = food;
            }
        }

        if (target == null)
            return false;

        if (cDist < 5 * 5 || me.hunger < 200) {
            me.dx = (target.x - me.x) * 10000000d;
            me.dy = (target.y - me.y) * 10000000d;
            return true;
        }
        return false;
    }

    void soloRun() {
        double x, y, sqDist, cDist;
        for (Member me : members) {
            Collection<Animal> yummy = getFoods(me);
            if (yummy.size() == 0) {
                wander(me);
                continue;
            }

            Animal target = null;
            cDist = Double.MAX_VALUE;
            for (Animal food : yummy) {
                x = food.x - me.x;
                y = food.y - me.y;
                sqDist = x * x + y * y + Double.MIN_NORMAL;
                if (sqDist < cDist) {
                    cDist = sqDist;
                    target = food;
                }
            }

            me.dx = (target.x - me.x) * 100000d;
            me.dy = (target.y - me.y) * 100000d;
        }
    }

    void wander(Member me) {
        if (me.dx == 0 && me.dy == 0) {
            me.dx = 250 - me.x;
            me.dy = 250 - me.y;
            return;
        }

        double lx, ly, px, py;
        lx = me.dx / 4;
        ly = me.dy / 4;
        boolean dir = Math.random() < 0.5 ? true : false;
        px = dir ? ly : -ly;
        py = dir ? -lx : lx;

        me.dx += px;
        me.dy += py;
    }

    void limitSpeed(Member me, double max) {
        double x = me.dx, y = me.dy;
        double dist = Math.sqrt(x * x + y * y) + Double.MIN_NORMAL;
        if (dist > max) {
            x = (x / dist) * max;
            y = (y / dist) * max;
        }
        me.dx = x;
        me.dy = y;
    }

    final static double MAX_SPEED = 6.1;
    final static double HEAD_MULT = 0.85;
    final static double MID_MULT = 0.92;
    final static int BEHIND = -25;
    final static int ASIDE = 15;
    final static int MID_SIDE = 30;
    final static int COMB = 150;
}

11

Ruby Spiders

Bazen daha az daha fazla olduğu gibi birçok çözüm de avı köşeye sıkıştırmaya çalışacaktır ...

Paketimin ayrılıp başkalarının işi yapmasını bekleyebileceğini düşündüm.

gets
print "3.0\t3.0\t3.0\t-3.0\t-3.0\t-3.0\t-3.0\t3.0\t0.0\t0.0\0"
STDOUT.flush

Uyarı: Çalışmaya devam etmiyor, içeri girerken okunanları okumuyor veya hızlı bir şekilde tepki vermiyor. Yine de, denetleyiciyle iyi çalıştığı için, başka ayarlamalar yapmadan kalifiye olduğunu umuyorum.


4
+1 ilk parazit çözümü. Bence bu tür bir cevap, boşlukları yavaş yavaş ortadan kaldırarak diğer cevapların kalitesini
artıracaktır

@githubphagocte Akılda daha akıllı bir parazit vardı ama bu canlı zaman / kod satırları açısından daha verimli. Umarım uygulamak için zaman bulurum.
Legat

Belki @Synthetica şu anda fikrimi kodluyor. Veya onun fikri başka bir fikir ise, yakında avcılardan sonra daha fazla parazit olabilir;)
Legat

1
@githubphagocyte üç giriş yapmamıza izin veriliyor, bu yüzden hazır olunca başka bir paket göndereceğim. Yine de, bu arada kodlanmış olması ilginç ve daha etkili olduğunu kanıtlayabilirim. Netcats'ten gerçekten çok iyi yararlanıyor ve aslında ilk avcı paketimden daha fazla yararlanıyor.
Legat

3
Bu olduğu gibi girebilir, nedenini anlamam bir saniye sürse bile. Eklediğiniz Netcats (daha mantıklı) daha iyi yapmak gibi görünüyor. Benden +1, köşelerden kaçınmak için nasıl bir avcının
çıktığını görelim

11

CivilizedBeasts

Sonunda, canavarlarımı gösterme zamanı!

Cinsim avlanmanın biraz ilkel olduğunu düşünüyor, bu yüzden birlikte 4 kişilik bir ekip halinde çalışıyorlar ve 5. müttefiklerini de terk ediyorlar, çünkü: daha az avcı = kendileri için daha fazla av. Temel olarak yaptıkları şey, insanların yaptıkları, avlarını yakaladıkları ve sığırlarına iyi baktıkları;)

public class CivilizedBeasts extends GenericPack{

    private static int TL = 0, TR = 0, BL = 0, BR = 0; // TopLeft/BotRight
    private static int teamSize = 0, turnsWaiting = 0, turnsToWait = 20;

    private boolean out = true;
    private double maxSpeed = 6.1, mapSize = 500;

    public CivilizedBeasts(){
    }

    @Override
    public void respond(){
        if(teamSize > members.size()){

            Member check = getMemberById(TL);
            totalLoop:
            if(check == null){
                for (Member member : members) {
                    if(member.id != TR && member.id != BL && member.id != BR){
                        TL = member.id;
                        break totalLoop;
                    }
                }

                TL = 0;
            }

            check = getMemberById(TR);
            totalLoop:
            if(check == null){
                for (Member member : members) {
                    if(member.id != TL && member.id != BL && member.id != BR){
                        TR = member.id;
                        break totalLoop;
                    }
                }

                TR = 0;
            }

            check = getMemberById(BL);
            totalLoop:
            if(check == null){
                for (Member member : members) {
                    if(member.id != TL && member.id != TR && member.id != BR){
                        BL = member.id;
                        break totalLoop;
                    }
                }

                BL = 0;
            }

            check = getMemberById(BR);
            totalLoop:
            if(check == null){
                for(Member member : members) {
                    if(member.id != TL && member.id != TR && member.id != BL){
                        BR = member.id;
                        break totalLoop;
                    }
                }

                BR = 0;
            }
        }else if(teamSize < members.size()){
            for(Member member : members) {
                if(member.id != TL && member.id != TR && member.id != BL && member.id != BR){
                    if(TL == 0)
                        TL = member.id;
                    else if(TR == 0)
                        TR = member.id;
                    else if(BL == 0)
                        BL = member.id;
                    else if(BR == 0)
                        BR = member.id;
                }
            }
        }

        teamSize = members.size();

        double border = 1;
        double x, y;
        boolean reached = true;

        double distance = 16.3;

        for (Member member : members) {
            boolean doesNotCount = false;
            x = 0; y = 0;
            if(member.id == TL){
                if(out){
                    x = -(member.x - border);
                    y = -(member.y - border);
                }else{
                    x = ((mapSize/2 - distance) - member.x);
                    y = ((mapSize/2 - distance) - member.y);
                }
            }else if(member.id == TR){
                if(out){
                    x = (mapSize - member.x - border);
                    y = -(member.y - border);
                }else{
                    x = ((mapSize/2 + distance) - member.x);
                    y = ((mapSize/2 - distance) - member.y);
                }
            }else if(member.id == BL){
                if(out){
                    x = -(member.x - border);
                    y = (mapSize - member.y - border);
                }else{
                    x = ((mapSize/2 - distance) - member.x);
                    y = ((mapSize/2 + distance) - member.y);
                }
            }else if(member.id == BR){
                if(out){
                    x = (mapSize - member.x - border);
                    y = (mapSize - member.y - border);
                }else{
                    x = ((mapSize/2 + distance) - member.x);
                    y = ((mapSize/2 + distance) - member.y);
                }
            }else{
                double dist = 50, temp = 0;
                int index = -1;
                for(int i = 0; i < member.foods.size(); i++){
                    temp = (Math.abs(member.foods.get(i).x - member.x)+Math.abs(member.foods.get(i).y - member.y));
                    if(temp < dist){
                        dist = temp;
                        index = i;
                    }
                }
                if(index != -1){
                    x = (member.foods.get(index).x - member.x);
                    y = (member.foods.get(index).y - member.y);
                }
                doesNotCount = true;
            }

            if(!doesNotCount && Math.abs(x)+Math.abs(y) > maxSpeed)
                reached = false;
            member.setDirection(x,y);
        }

        if(reached){
            if(!out){ // in the middle.
                if(teamSize < 4){
                    int temp = TL;
                    TL = BR;
                    BR = temp;
                    temp = TR;
                    TR = BL;
                    BL = temp;
                    out = true;
                }else{
                    turnsWaiting++;
                }
            }else // no need to wait in the corners
                out = false;

            if(turnsWaiting >= turnsToWait){
                turnsToWait = 15;
                out = true;
                turnsWaiting = 0;
            }

        }

    }

    public static void main(String[] args){
        new CivilizedBeasts().run();
    }
}

Göğüslerimin oyunda sadece düşman Netcats ile + -12.000 sıralarında 200'den az avla hayatta kalması oldukça zorlaşıyor. Bu cinsle mutlu olacaksınız çünkü bu, başka hiçbir cinsin yapamayacağı gibi büyük miktarlarda avı gerçekten yok ediyor (hızlı ve büyük katliamların zaferi kazanması değil, bir turun hatırı sayılır derecede uzun sürmesini etkiliyor).


3
" Onlara iyi bak " derken, " tekrar tekrar ortalara sürün ve katledin / yiyin " anlamına geliyorsa , evet, bunu iyi yaparlar. +1
Geobits

Komik, Evil Develerin mutasyona uğramamış (orijinal) versiyonuyla, medeni taktikleri, 'merkez deve' yüzünden tamamen yetersiz.
user2846289

1
@VadimR Crap, devenizi güncellediğiniz için teşekkür ederiz: PI Java olmadığından test edemez, ancak stratejimin
bölgemin

5
Yine Herjan! Ayrıca " Göğüslerimin 200 avdan daha az hayatta kalması oldukça zorlaşıyor " (vurgu vurgusu). Göğüslerinizin canlılığının bir bilgisayar simülasyonundaki av sayısına bağlı olduğunu farketmedim ....
Justin

5

Ruby Vultures

İşte daha aktif parazitler paketi . Onlar çalışıyoruz yakın hareket eden yırtıcı çevreleyen onlar, böylece avını çalmak . Kimin takip edeceğini seçmenin akıllıca bir yolu olmadığı için genellikle biraz bağımlılar ama genellikle kovalayanları ve bazen de örümcekleri dövdüler .

Tempoyu itmek için bunu yayınladığım gibi onlar çok bitmedi :)

Ümit ediyorum:

  • görüş alanı dışındaki avcıları aramalarını sağlayın
  • Avı hesaba katın - çoğu bunlardan biri başka bir paketle av arasındadır!
  • diğerleri iyi beslendiğinde açlıktan kaçınmak için onları döndürmeye başlayın

22 Nisan 2014: Daha az yapışkan olmalarını sağlayan ve kendi başlarına avlanmalarını ve avcıları aramalarını sağlayan sıkıntı , eklendi.

class Animal
  attr_accessor :x, :y
end

class Hunter < Animal
  attr_accessor :id, :bored

  def initialize diff
   @diff = diff
   @lastGoal = nil
   @bored = false
  end

  def move goal
    if not goal.nil? 
      if @bored or goal != @lastGoal
        @lastGoal = goal
        return [goal.first - x + @diff.first, goal.last - y + @diff.last]
      end
    end
    [250 - x + 3*@diff.first, 250.0 - y + 3*@diff.last]
  end
end

class Pack
  def initialize
    @file = File.open "pack_log", "w"
    @count = 0
    @pack = []
    @order = []
    @hunters = []
    @closest = nil
    @random_goal = [250.0, 250.0]
    @locations = []
    @timer = 0
    d = 25.0
    diffs = [[d, d], [d, -d], [-d, -d], [-d, d], [0.0, 0.0]]
    5.times do |i|
      @pack << (Hunter.new diffs[i])
    end
    line = 0
    s = gets
    loop do
      s = gets
      if not (s =~ /dead\0/).nil?
        break
      end
      if line == 0
        get_structure s
      elsif line == 1
        get_positions s
      end
      @pack.length.times do |i|
        if line == i*2 + 3
          look_for_hunters s
          if @count <= i+1
            @closest = closest_hunter
            move
          end
        end
      end
      if not (s =~ /\0/).nil?
        line = 0
        @hunters = []
      else
        line += 1
      end
    end
  end

  def member_by_id id
    member = nil
    @pack.each do |v|
      if v.id == id
        member = v
        break
      end
    end
    member
  end

  def member_by_order index
    member_by_id @order[index]
  end

  def distance a, b
    Math.sqrt((a.first - b.first)**2 + (a.last - b.last)**2)
  end

  def bored?
    bored = true
    l1 = @locations.first
    @locations.each do |l2|
      if distance(l1, l2) > 20
        bored = false
      end
    end 
    bored
  end

  def bored_move v
    if @timer <= 0
      @random_goal = [rand(1000).to_f - 250, rand(1000).to_f - 250]
      @pack.each do |m|
        m.bored = true
      end
      @timer = 250 
    else
      @timer -= 1
    end
    v.move @random_goal
  end

  def move
    first_one = true
    answer = ""
    @order.each do |id|
      v = member_by_id id
      x, y = 0, 0
      if bored?
        x, y = (bored_move v)
      elsif @timer > 0
        @location = []
        x, y = (bored_move v)
      else
        @pack.each do |m|
          m.bored = false
        end
        @timer = 0
        x, y = v.move @closest
      end
      if not first_one
        answer << "\t"
      end
      answer << "#{x.to_i}.0\t#{y.to_i}.0"
      first_one = false
    end
    answer << "\0"
    print answer
    STDOUT.flush
  end

  def get_structure line
    @order = []
    if @pack.first.id.nil? 
      @count = 0
      line.split.each_with_index do |v, i|
        if i % 2 == 0
          @order << v.to_i
          @pack[i/2].id = v.to_i
          @count += 1
        end
      end
    else
      @count = 0
      line.split.each_with_index do |v, i|
        if i % 2 == 0
          @order << v.to_i
          @count += 1
        end
      end
    end
  end

  def get_positions line
    if not @order.empty?
      line.split.each_with_index do |v, i|
        if i % 2 == 0
          member_by_order(i/2).x = v.to_f
        else
          member_by_order(i/2).y = v.to_f
        end
      end
    end
  end

  def look_for_hunters line
    line.split.each_with_index do |v, i|
      if i % 2 == 0
        @hunters << [v.to_f]
      else
        @hunters.last << v.to_f
      end
    end
  end

  def closest_hunter
    mass_center
    closest = nil
    bestDist = 500*500
    if not @hunters.nil? and not @hunters == []
      @hunters.each do |h|
        our = false
        @pack.each do |v|
          if h.first == v.x and h.last == v.y
            our = true
          end
        end
        if our
          next
        end
        sqDist = (@mass_center.first - h.first)**2 + (@mass_center.last - h.last)**2
        if sqDist < bestDist
          closest = []
          closest << h.first
          closest << h.last
        end
      end
    end
    closest
  end

  def mass_center
    center_x = 0
    center_y = 0
    @pack.each do |v|
      center_x += v.x
      center_y += v.y
    end
    @mass_center = [center_x.to_f / @count, center_y.to_f / @count]
    if @locations.length > 30
      @locations.shift
      @locations << @mass_center
    else
      @locations << @mass_center
    end
  end
end

Pack.new

Kesinlikle karışımda daha fazla "avcıya" ihtiyacınız var. Olduğu gibi, bunlar diğer parazitlere bağlanma eğilimindedir (çünkü sahadaki çoğunluk budur). Yine de onları izlemeyi seviyorum ve farklı bir rakipler karışımı ile nasıl etkili olabileceklerini görebiliyorum.
Geobits

Evet, test ortamımda iki tane daha avcı paketim var. Onlarsız akbabalar muhtemelen oldukça ipucu. Özellikle fileler, ortasından görülmeden köşeleri hızlıca çalıştırabilir.
Legat

Sanırım, özellikle onları rahatsız eden şeyleri biliyorum. Kötü develerin savaş dansı. @Geobits, dövüşleri Youtube’a koymaya ne dersin? 10 tur izlenebilir kalmak için çok fazla değil. Tabii ki, HQ gerekli olacaktır. Milyonlarca izleyici beklememekle birlikte, paketlerinizin nasıl performans gösterdiğini görmek ve biraz da onları neşelendirmek için eğlenceli olurdu :)
Legat

1
Turnuvanın tamamı dikkatini çekmek için biraz uzun olabilir (şimdiki turda ~ 8 dakika), ancak bir "seyirci" turu kaydetmek işe yarayabilir. Gelecekteki koşuları için bir düşünce vereceğim.
Geobits

@Geobitler 8 dakikalık bir tur boyunca hız çok mu değişiyor? Dönüş başına bir kare kaydetmeye değip değmeyeceğini merak ediyorum, bu yüzden hesaplama yoğun parçaları sırasında yavaşlamak yerine, sabit bir oranda oynatılabilirler. YouTube amaçları için demek istiyorum.
trichoplax

5

Evil Eko Develer

Düzenleme: Mutasyon # 2. Oh, hayır, Netcats'ı ilk yenen avlanma hareketi tahmini uygulamasına geç kaldım. Tamam, öyleyse yap.

Bu mutasyon $hunger_criticaldeğişkendir (sabit). Bunu 1000'in üzerindeki bir değere değiştirmek Develerin Clairvoyants gibi her zaman avlanmasına neden olur. Sonra:

Done in 11.93 minutes
camels1.pl(0)                   : Turn 23112    : Score 100
Netcats(1)                      : Turn 22508    : Score 80

Eğer $hunger_critical500 (aşağıda) örneğin ayarlandığında, (dehşetinden gördükten sonra sonra benim Develer medeniyet ) yalnızca aç (dolayısıyla onların cins ismi değişti), yani onlar öldürmek Çevre dostu bir şekilde davranmaya çalışıyorum. Acıkmazlarsa, diğer avcılar tarafından anlamsız kasaplaşmayı önlemek için kritik Ada bölgelerini (merkez ve köşeler) devriye geziyorlar. Eh, merkez ile, az ya da çok çalışır. Köşelerde daire çizme fikri, avı uzaklaştırmak ve Kediler ve parazitler için hayatı zorlaştırmaktı. İşe yaramıyor. Aptal av, yine de köşelere gider.

Ayrıca ilginç, flock[ALIGN]bileşenin sadece avcılar tarafından tahmin edilebildiği ve benim uygulamamın adhalflerden farklı olduğu da ilginç. Benim bazı küçük hata var korkuyorum soygun durugörürler vs Camel bireysel avcılık karşılaştıran / izlerken, Geobits' kod uygulanması.

Program şimdi çok uzun, üzgünüm.


Düzenleme: Mutasyon # 1. Ada oldukça radyoaktif olduğu ortaya çıkıyor (bu, bitki örtüsünün olmayışını ve 'av' yaratıklarının açıklanamaz doğasını açıklar), bu yüzden Develerimin ilk mutasyonu. Bunlardan herhangi biri, açsa veya herkes için boş köşe yoksa, yalnız avcı olabilir. Hunter aktif olarak yakındaki avını takip etmeye çalışıyor. Hiçbiri yoksa, adanın merkezinin etrafındaki geniş dairede devriye gezer, sonra bulduğu zaman en yakın yaratığı kovalar. Maalesef avın yönü, sürünün yakınında olduğu zaman (araştırmaya değer…) tahmin edilemez hale geliyor, bu yüzden solo kovalamaca çok verimli değil. Fakat başarılı olursa, Deve en yakın serbest köşeye (eğer varsa) sindirir. Açlık seviyesi belli bir seviyenin altına düştüğünde, herhangi bir Deve köşesinden vazgeçer (muhtemelen Netcats'i küfrederek ('yemek nerede?'). )) ve kendi kendine dolaşım serbesttir. Ve bunun gibi.


Aynı şakanın iki kez söylendiği komik değildi, ama (1) Bir yerden başlamak zorunda kaldım ve bu şeylerde yeniyim, (2) Dürüst olmak gerekirse, Ruby'den önce Netcats izleyerek köşe taktiklerini düşündüm (ve kim yapmadı?) Örümcekler adada göründü.

Ee, hiç etobur deve duydun mu? Zavallı hayvanlar bir gün bu tanrı-terkedilmiş adada hiç ot ya da ağaç bulamadığı için uyandı, ama yenilebilir hızlı hareket eden (oldukça can sıkıcı) küçük şeyler olsa da bol miktarda garip yeşil vardı. Avlanma alışkanlıklarına sahip olmadan (ama yakında değişecekler, umarım), Develerim hayatta kalmak için çok kötü bir şema geliştirdi: her birini 4 köşeden birine böler ve beşincisi merkeze gider (önce orada ölmek üzere) ortaya çıkıyor). Gidecekleri yerde sabırla beklerler, bir tür deve savaş dansı yaparlar ya da belki de oradaki diğer hayvanlara, örümceklere ve diğerlerine basmaya çalışmamaya çalışırlar ...

#!/usr/bin/env perl
use strict;
use warnings;

binmode STDOUT;
binmode STDIN;
$| = 1;
$, = "\t";

my $hunger_critical = 500;
my %pack;
my ($turn, $prey_count, $predators_count);
my $patrol_radius_hunt = 150;
my $patrol_radius_corner = 16;
my $patrol_radius_center = 1;
my @roles = qw/C LL LR UL UR/; # or P (patrol if > 5), H (hunt)
my %places = (
    UL => {x =>   1 + $patrol_radius_corner, y =>   1 + $patrol_radius_corner},
    UR => {x => 499 - $patrol_radius_corner, y =>   1 + $patrol_radius_corner},
    LR => {x => 499 - $patrol_radius_corner, y => 499 - $patrol_radius_corner},
    LL => {x =>   1 + $patrol_radius_corner, y => 499 - $patrol_radius_corner},
    C  => {x => 250, y => 250},
);

sub sq_dist {
    my ($x1, $y1, $x2, $y2) = @_;
    return ($x1 - $x2)**2 + ($y1 - $y2)**2
}

sub distance {
    return sqrt(&sq_dist)
}

sub assign_role {
    my $camel = shift;
    if (@roles) {
        my %choice = (d => 1000, i => 0);
        for my $i (0..$#roles) {
            my $r = $roles[$i];
            if ($r eq 'C') {
                if ($prey_count > 700) {
                    $choice{i} = $i;
                    last
                }
                else {
                    next
                }
            }
            my $d = distance($camel->{x}, $camel->{y}, $places{$r}{x}, $places{$r}{y});
            if ($d < $choice{d}) {
                @choice{qw/d i/} = ($d, $i)
            }
        }
        return splice @roles, $choice{i}, 1
    }
    else {
        return 'P'
    }
}

sub xy_average {
    my $xy = shift;
    my $x = my $y = 0;
    if ($xy && @$xy) {
        for my $item (@$xy) {
            $x += $item ->{x};
            $y += $item->{y}
        }
        $x /= @$xy;
        $y /= @$xy
    }
    return $x, $y
}

sub patrol {
    my ($xc, $yc, $radius, $camel) = @_;
    my ($x, $y) = ($camel->{x} - $xc, $camel->{y} - $yc);
    my $d = distance(0, 0, $x, $y);
    my $a = atan2($y, $x);
    if (abs($d - $radius) < 3) {
        $a += 6 / $radius
    }
    return $radius * cos($a) - $x, $radius * sin($a) - $y
}

while (1) {

    # Get input

    my @in;
    # Line 0 - turn, counts
    $_ = <>;
    die if /dead/;
    ($turn, $prey_count, $predators_count) = /\0?(\S+)\t(\S+)\t(\S+)/;
    # Line 1 - pack's ids and hunger
    $_ = <>;
    while (/(\S+)\t(\S+)/g) {
        push @in, {id => $1, hunger => $2}
    };
    # Line 2 - positions
    $_ = <>;
    for my $animal (@in) {
        /(\S+)\t(\S+)/g;
        ($animal->{x}, $animal->{y}) = ($1, $2);
    }
    # 2 lines per member, visible prey and predators
    for my $animal (@in) {
        $_ = <>;
        my @prey;
        while (/(\S+)\t(\S+)/g) {
            push @prey, {x => $1, y => $2}
        };
        $animal->{prey} = \@prey;
        $_ = <>;
        my @beasts;
        while (/(\S+)\t(\S+)/g) {
            push @beasts, {x => $1, y => $2}
        };
        $animal->{beasts} = \@beasts
    }
    # trailing \0 zero will be prepended to next turn input

    # Update my pack

    for my $n (0..$#in) {
        my $animal = $in[$n];
        my $id = $animal->{id};
        # old average prey position
        my @opp = xy_average($pack{$id}{prey});
        # new average prey position
        my @npp = xy_average($animal->{prey});
        # average prey displacement
        my %apd = (x => $npp[0] - $opp[0], y => $npp[1] - $opp[1]);
        $pack{$id}{apd}    = \%apd;
        $pack{$id}{hunger} = $animal->{hunger};
        $pack{$id}{x}      = $animal->{x};
        $pack{$id}{y}      = $animal->{y};
        $pack{$id}{prey}   = $animal->{prey};
        $pack{$id}{beasts} = $animal->{beasts};
        $pack{$id}{num}    = $n;
        $pack{$id}{dead}   = 0
    }

    # Bury dead animals, retrieve their roles

    while (my ($id, $camel) = each %pack) {
        if ($camel->{dead}) {
            my $role = $camel->{role};
            push @roles, $role if $role ne 'P' and $role ne 'H';
            delete $pack{$id};
        }
        else {
            $camel->{dead} = 1
        }
    }

    # See that everyone has a role and lives accordingly

    my @out;
    for my $camel (values %pack) {
        my $role = $camel->{role} ||= assign_role($camel);
        if ($camel->{hunger} < $hunger_critical and $role ne 'H') {
            push @roles, $role if $role ne 'P';
            $role = $camel->{role} = 'H'
        }
        if ($camel->{hunger} > $hunger_critical and ($role eq 'H' or $role eq 'P') and $prey_count > 400) {
            $role = $camel->{role} = assign_role($camel)
        }
        my @vector = (0, 0);
        if ($role eq 'H') {
            my @prey = @{$camel->{prey}};
            if (@prey) {
                my %nearest = (p => undef, dd => 2500);
                for my $prey (@prey) {
                    my $dd = sq_dist($camel->{x}, $camel->{y}, $prey->{x}, $prey->{y});
                    if ($dd <= $nearest{dd}) {
                        @nearest{qw/p dd/} = ($prey, $dd)
                    }
                }
                my $target = $nearest{p};
                if ($nearest{dd} > 900) {
                    @vector = ($target->{x} - $camel->{x}, $target->{y} - $camel->{y})
                }
                else {
                    my @vect = map{{x => 0, y => 0}}1..5;
                    my $n = 0;
                    for my $prey (@prey) {
                        next if $prey eq $target;
                        my $dd = sq_dist($target->{x}, $target->{y}, $prey->{x}, $prey->{y}) + 1/(~0);
                        next if $dd > 900;
                        $n ++;
                        my $dx = $prey->{x} - $target->{x};
                        my $dy = $prey->{y} - $target->{y};
                        $vect[1]{x} -= $dx / $dd;
                        $vect[1]{y} -= $dy / $dd;
                        $vect[2]{x} += $dx * $dd;
                        $vect[2]{y} += $dy * $dd
                    }
                    $vect[0] = {x => $n * $camel->{apd}{x}, y => $n * $camel->{apd}{y}};
                    my $dx = abs(250 - $target->{x});
                    my $dy = abs(250 - $target->{y});
                    my $d = $dx > $dy ? $dx : $dy;
                    if ($d > 240) {
                        $vect[4]{x} = $dx * $d;
                        $vect[4]{y} = $dy * $d;
                    }
                    for my $v (@vect) {
                        my $d = sqrt($v->{x}**2 + $v->{y}**2) + 1/(~0);
                        $v->{x} /= $d;
                        $v->{y} /= $d;
                    }
                    for my $beast (@{$camel->{beasts}}, $camel) {
                        my $dd = sq_dist($target->{x}, $target->{y}, $beast->{x}, $beast->{y});
                        next if $dd > 900;
                        $vect[3]{x} += $target->{x} - $beast->{x};
                        $vect[3]{y} += $target->{y} - $beast->{y};
                    }
                    $vector[0] = 5 * 1   * $vect[0]{x}
                               + 5 * 1   * $vect[1]{x}
                               + 5 * .96 * $vect[2]{x}
                               + 1 * 2   * $vect[3]{x}
                               + 5 * 4   * $vect[4]{x};
                    $vector[1] = 5 * 1   * $vect[0]{y}
                               + 5 * 1   * $vect[1]{y}
                               + 5 * .96 * $vect[2]{y}
                               + 1 * 2   * $vect[3]{y}
                               + 5 * 4   * $vect[4]{y};
                    my $dd = $vector[0]**2 + $vector[1]**2;
                    if ($dd > 36) {
                        my $d = sqrt($dd);
                        @vector = map {$_ * 6.1 /$d} @vector
                    }
                }
            }
            else {
                @vector = patrol(250, 250, $patrol_radius_hunt, $camel)
            }
        }
        elsif ($role eq 'P') {
            @vector = patrol(250, 250, $patrol_radius_hunt, $camel)
        }
        else {
            my $r = $role eq 'C' 
                ? $patrol_radius_center 
                : $patrol_radius_corner;
            @vector = patrol($places{$role}{x}, $places{$role}{y}, $r, $camel)
        }
        my $id_x = $camel->{num} << 1;
        my $id_y = $id_x + 1;
        @out[$id_x, $id_y] = @vector
    }

    # And let the cruel world know about it

    print @out;
    print "\0"
}

__END__

5
Bu, bugüne kadar bu sitede gördüğüm en okunur perl betiği olmalı.
Geobits

Onları etkili bir şekilde vurmak için tam olarak köşeye gitmeniz gerekir, aksi halde Netcats kasabasına katılacaksınız, haha
justhalf

Adalet, Söylediğim gibi: plan işe yaramadı. Köşelerde oturan parazitler de avı uzaklaştırmadı. Hm-m, belki bir köşesinde devriye gezen 2 veya daha fazla canavar yardımcı olacaktır.
user2846289

Develerin aslında oldukça iyi! Neyse ki (benim için) Clairvoyants'ımı geliştirdim, bu yüzden çoğu zaman (her zaman değil), son savaş sırasında paketim sizinkine karşı kazanıyor. İlginç!
justhalf

1
Avdan 8 (20-2 * 6) birimden daha yakınsanız, avımızın 30 birimi içerisinde bulunan diğer tüm avların mevcut sırayla herhangi bir hareketini görebiliriz. Ve vecözellik temelde sadece önceki dönüşten mevcut dönüşe kaymadır. Dediğim gibi, biz do eşleşen biz yırtıcı sırasına güvenemez hangi yöne gider av bulmak için önceki çevirmek dan. Bu mümkündür, çünkü avlar genellikle (tipik senaryoda) birbirlerinden yeterince uzak kalırlar (> 12 birim) ve bu nedenle çoğu zaman avları şu anki sırayla eşleştirebiliriz.
justhalf

4

AbleDogs - PHP

Bu güzel köpekler avın buzağılarını duvarlar boyunca gezdirmek için nasıl ısırılacağını öğrendi. Ayrıca meralarda yeni av arayışında dolaşmayı da seviyorlar. Son olarak, gerçekten kalorilere ihtiyaç duymadıkları sürece yemekten kaçınmaları öğretildi.

Kodu bir AbleDogsdosyaya koyun ve çalıştırınphp AbleDogs

<?php
// simulation parameters

define ("ARENA_SIZE", 500);

define ("HUNGER_MAX", 1000);

define ("PREY_SPEED", 6);
define ("PRED_SPEED", 6.1);

define ("PREY_VISION", 30);
define ("PRED_VISION", 50);

define ("WALL_BOUNCE", 10); // distance from a wall from which a prey starts bouncing

// derived constants

define ("PRED_SPEED2" , PRED_SPEED  * PRED_SPEED );
define ("PRED_VISION2", PRED_VISION * PRED_VISION);
define ("PREY_VISION2", PREY_VISION * PREY_VISION);

// grid to speedup preys lookup

define ("GRID_SIZE", ceil (ARENA_SIZE/PRED_VISION));
define ("GRID_STEP", ARENA_SIZE/GRID_SIZE);

// search patterns

define ("SEARCH_OFFSET", WALL_BOUNCE+PRED_VISION/sqrt(2));
define ("SEARCH_WIDTH" , 2*sqrt(PRED_VISION2-PRED_SPEED2/4));
define ("SEARCH_HEIGHT", ARENA_SIZE-2*SEARCH_OFFSET);
define ("SEARCH_SIZE"  , ceil(SEARCH_HEIGHT/SEARCH_WIDTH));
define ("SEARCH_STEP"  , SEARCH_HEIGHT/SEARCH_SIZE);
define ("SEARCH_LEGS"  , 2*SEARCH_SIZE+1);

// tracking

define ("MAX_TRACK_ERROR", 10); // max abs distance for prey tracking correlation
define ("TRACKING_HUNGER_START", HUNGER_MAX*.9); // hunger limit to try and eat the tracked prey (start of game)
define ("TRACKING_HUNGER_END", 4);     // idem, for endgame
define ("TRACKING_DISTANCE", PREY_SPEED*2.5);
define ("TRACKING_DISTANCE2", TRACKING_DISTANCE * TRACKING_DISTANCE);

class Point {
    public $x = 0;
    public $y = 0;

    function __construct ($x=0, $y=0)
    {
        $this->x = (float)$x;
        $this->y = (float)$y;
    }

    function __toString() // for comparisons
    {
        return "$this->x,$this->y";
    }

    function multiply ($scalar)
    {
        return new Point ($this->x * $scalar, $this->y * $scalar);
    }

    function add ($v)
    {
        return new Point ($this->x + $v->x, $this->y + $v->y);
    }

    function dot($v)
    {
        return $this->x * $v->x + $this->y * $v->y;
    }

    function rotate90()
    {
        return new Point (-$this->y, $this->x);
    }

    function vector_to ($goal)
    {
        return new Point ($goal->x - $this->x, $goal->y - $this->y);
    }

    function norm2 ()
    {
        return $this->dot ($this);
    }

    function norm ()
    {
        return sqrt ($this->norm2());
    }

    function normalize ($norm = 1)
    {
        $n = $this->norm();
        if ($n != 0) $n = $norm/$n;
        return $this->multiply ($n);
    }

    function limit ($norm)
    {
        return $this->norm() > $norm
             ? $this->normalize($norm)
             : clone $this;
    }
}

class Search {

    function __construct ($direction)
    {
        switch ($direction % 4)
        {
            case 0: $this->pos = new Point (          0,           0); break;
            case 1: $this->pos = new Point (SEARCH_SIZE,           0); break;
            case 2: $this->pos = new Point (SEARCH_SIZE, SEARCH_SIZE); break;
            case 3: $this->pos = new Point (          0, SEARCH_SIZE); break;
        }
        $this->start();
    }

    private function start ()
    {
        $this->dir = $this->pos->x == $this->pos->y;
        $this->adj = $this->pos->x ? -1 : 1;
        $this->target = new Point ($this->pos->x * SEARCH_STEP + SEARCH_OFFSET,
                                   $this->pos->y * SEARCH_STEP + SEARCH_OFFSET);
        $this->leg = 0;
    }

    function point ($pos)
    {
        if ($pos == $this->target)
        {
            if ($this->leg % 2)
            {
                if ($this->dir) $this->pos->y+= $this->adj;
                else            $this->pos->x+= $this->adj;
            }
            else
            {
                if ($this->dir) $this->pos->x = $this->pos->x ? 0 : SEARCH_SIZE;
                else            $this->pos->y = $this->pos->y ? 0 : SEARCH_SIZE;
            }
            $this->leg++;
            if ($this->leg == SEARCH_LEGS) $this->start();
            $this->target = new Point ($this->pos->x * SEARCH_STEP + SEARCH_OFFSET,
                                       $this->pos->y * SEARCH_STEP + SEARCH_OFFSET);
        }
        return $this->target;
    }
}

class Pack {

    public static $turn;   // turn number
    public static $size;   // number of live members
    public static $member; // array of members

    public static $prev_preys;     // previous coordinates of all preys
    public static $prev_preds;     // previous coordinates of foreign predators

    public static $n_preys; // total number of preys     (including those not currently seen)
    public static $n_preds; // total number of predators (including those not currently seen)

    public static $preys;     // coordinates of all preys
    public static $preds;     // coordinates of all predators
    public static $own_preds; // coordinates of all predators in our pack
    public static $foe_preds; // coordinates of all foreign predators

    public static $arena_center; // arena center

    private static $output_order; // to send output according to input order

    function init ()
    {
        Pack::$member = array();
        Pack::$arena_center = new Point (ARENA_SIZE/2, ARENA_SIZE/2);
    }

    function read_line ($line)
    {
        $values = array();
        if ($line == "") return $values;
        $input = explode ("\t", $line);
        $num = count($input);
        if ($num % 2) panic ("read_line: invalid input $line num $num");
        $num /= 2;
        for ($i = 0 ; $i != $num ; $i++)
        {
            $values[] = new Point ($input[$i*2  ], $input[$i*2+1]);
        }
        return $values;
    }

    function read_input ()
    {
        // read controller input (blocking)
        $input = "";
        while (($in = fread(STDIN, 1)) !== false)
        {
            if ($in == "\0") break;
            $input .= $in;
        }

        // check extinction
        if ($input == "dead") return false;
        $lines = explode ("\n", $input);

        // save previous predators and preys positions
        Pack::$prev_preys = Pack::$preys;
        Pack::$prev_preds = Pack::$foe_preds;

        // line 0: turn, preys, predators
        list (self::$turn, Pack::$n_preys, Pack::$n_preds) = explode ("\t", $lines[0]);

        // line 1: list of ids and hunger levels
        $id = array();
        Pack::$size = 0;
        Pack::$output_order = array();
        foreach (Pack::read_line($lines[1]) as $i=>$v)
        {
            $id[$i] = $v->x;
            Pack::$output_order[] = $id[$i];

            if (!isset (Pack::$member[$id[$i]])) Pack::$member[$id[$i]] = static::new_member();
            Pack::$size++;
            Pack::$member[$id[$i]]->hunger = $v->y;
            Pack::$member[$id[$i]]->ttl = self::$turn;
        }

        // line 2: member positions
        Pack::$own_preds = array();
        foreach (Pack::read_line($lines[2]) as $i=>$pos)
        {
            Pack::$member[$id[$i]]->pos = $pos;
            Pack::$own_preds[] = $pos;
        }

        // lines 3 to 2*#members+3: coordinates of all visible preys and predators
        $preys = array();
        $preds = array();
        $y_seen = array();
        $d_seen = array();
        for ($i = 0 ; $i != Pack::$size ; $i++)
        {
            // visible preys
            foreach (Pack::read_line($lines[2*$i+3]) as $coords)
            {
                if (!in_array ($coords, $preys) || !isset($y_seen[(string)$coords]))
                {
                    $preys[] = $coords;
                }
            }
            foreach ($preys as $p) $y_seen[(string)$p] = true;

            // visible predators
            foreach (Pack::read_line($lines[2*$i+4]) as $coords)
            {
                if (!in_array ($coords, $preds) || !isset($d_seen[(string)$coords]))
                {
                    $preds[] = $coords;
                }
            }
            foreach ($preds as $p) $d_seen[(string)$p] = true;
        }

        // remove dead members
        foreach (Pack::$member as $k => $m)
        {
            if ($m->ttl != self::$turn)
            {
                unset (Pack::$member[$k]);
            }
        }

        // filter out own positions from predators list
        Pack::$foe_preds = array_diff ($preds, Pack::$own_preds);
        Pack::$preds = Pack::$foe_preds;
        foreach (Pack::$own_preds as $p) Pack::$preds[] = $p;
        Pack::$preys = $preys;

        // done
        return true;
    }

    function output_moves ()
    {
        $output = array();
        foreach (Pack::$output_order as $i)
        {
            $output[] = Pack::$member[$i]->move->x;
            $output[] = Pack::$member[$i]->move->y;
        }
        echo implode ("\t", $output) . "\0";
    }

    static function point_closest_to_walls ($pos)
    {
        $delta = $pos->vector_to (Pack::$arena_center);
        if (abs ($delta->x) > abs ($delta->y))
        {
            $y = $pos->y;
            $x = $delta->x > 0 ? -1 : ARENA_SIZE+1;
        }
        else
        {
            $x = $pos->x;
            $y = $delta->y > 0 ? -1 : ARENA_SIZE+1;
        }
        return new Point ($x, $y);
    }

    static function in_arena ($pos)
    {
        $delta = $pos->vector_to (Pack::$arena_center);
        return abs ($delta->x) <= ARENA_SIZE/2 && abs ($delta->y) <= ARENA_SIZE/2;
    }

    static function clamp_to_arena (&$pos)
    {
        // mimics the slightly strange behaviour of the Java engine setInZeroBounds function
        if ($pos->x >= ARENA_SIZE) $pos->x = ARENA_SIZE-1; // should rather be ARENA_SIZE
        if ($pos->x <           0) $pos->x = 0;
        if ($pos->y >= ARENA_SIZE) $pos->y = ARENA_SIZE-1;
        if ($pos->y <           0) $pos->y = 0;
    }

    function get_closest ($pos, $set, $max_dist)
    {
        // check for empty set
        if (count ($set) == 0) return null;

        // construct an array of distances with the same indexes as the points
        $dist = array();
        $max_dist *= $max_dist;
        foreach ($set as $k=>$pt)
        {
            $d = $pos->vector_to($pt)->norm2();
            if ($d <= $max_dist) $dist[$k] = $d;
        }
        if (count($dist) == 0) return false;

        // get the key of the smallest distance and use it to retrieve the closest point
        $keys = array_keys ($dist, min($dist));
        return $set[$keys[0]];
    }

    function get_visible ($pos, $set)
    {
        $res = array();
        $skipped = false;
        $pts = 0;
        foreach ($set as $point)
        {
            $d = $pos->vector_to($point)->norm2();
            if ($d == 0 && !$skipped)
            {
                $skipped = true;
                continue; // skip ourself
            }
            if ($d > PREY_VISION2) continue; // skip far points
            $res[] = $point;
            if ($pts++ > 10) break; // too many points are useless since prediction will go haywire anyway
        }
        return $res;
    }
}
Pack::init();

class PackMember {
    public $pos; // current position
    public $ttl; // last turn reported alive

    function move_to ($goal)
    {
        $this->move = $this->pos->vector_to ($goal);
    }

    function intercept ($target_pos, $target_speed)
    {
        // change reference to position difference
        $delta = $this->pos->vector_to($target_pos);
        $i = $delta->normalize();
        $j = $i->rotate90();

        // match tangential speeds
        $vj = $target_speed->dot ($j);

        // deduce axial speed
        $vi = PRED_SPEED2 - $vj*$vj; // this should always be positive since predators are faster than preys
        $vi = sqrt ($vi);

        // return intercept speed in original reference coordinates
        return $i->multiply($vi)->add($j->multiply($vj));
    }
}

class Target {
    public $pos;      // current position
    public $pos_next; // predicted position
    public $speed;    // estimated speed

    function __construct ($pos)
    {
        $this->pos    = $pos;
        $this->speed  = new Point(0,0);
        $this->predict();
    }

    private function predict()
    {
        // predators contribution
        $preds = Pack::get_visible ($this->pos, Pack::$preds);
        $this->preds = count ($preds);
        $res = new Point();
        foreach ($preds as $predator)
        {
            $res = $res->add ($predator->vector_to ($this->pos));
        }
        $res = $res->multiply (2);

        // preys contribution
        $preys = Pack::get_visible ($this->pos, Pack::$preys);
        $this->preys = count ($preys);

        $f_cohesion  = new Point;
        $f_separate  = new Point();
        foreach ($preys as $prey)
        {
            $delta = $this->pos->vector_to ($prey);
            $d2 = $delta->norm2();
            if ($d2 != 0)
            {
                $f_cohesion  = $f_cohesion ->add ($delta->multiply ($d2));
                $f_separate  = $f_separate ->add ($delta->multiply (-1/$d2));
            }
        }

        $res = $res
        ->add ($this->speed->normalize(5*.96)) // assume all preys have same speed as target
        ->add ($f_cohesion ->normalize(5*1))
        ->add ($f_separate ->normalize(5*1));
        $delta = $this->pos->vector_to(Pack::$arena_center);
        $dist = max (abs($delta->x), abs($delta->y));
        if ($dist > (ARENA_SIZE/2-WALL_BOUNCE))
        {
            $res = $res->add ($delta->normalize(5*4));
        }

        $this->raw_speed = $res;
        $this->speed = $res->limit(PREY_SPEED);
        $this->pos_next = $this->pos->add ($this->speed);
        Pack::clamp_to_arena ($this->pos_next);
    }

    function track ()
    {
        // see if we can find our prey at the start of a new turn
        $min = 1e10;
        foreach (Raptors::$free_preys as $k=>$prey)
        {
            $dist = abs ($this->pos_next->x - $prey->x) + abs ($this->pos_next->y - $prey->y);
            if ($dist < $min)
            {
                $min = $dist;
                $new_pos = $prey;
                $new_k = $k;
                if ($min < .001) break;
            }
        }
        if ($min > MAX_TRACK_ERROR) return false;

        // remove this prey from free preys
        unset(Raptors::$free_preys[$new_k]);

        $delta = $new_pos->vector_to($this->pos_next);

        // update postion and speed
        if ($this->speed->norm2() == 0)
        {
            // this can be either an endgame prey not yet moving
            // OR initial speed for a new target
            $this->speed = $this->pos->vector_to ($new_pos);
        }
        $this->pos = $new_pos;

        // predict speed and position
        $this->predict();
        return true;
    }
}

class Raptor extends PackMember {

    // possible states
    const IDLE     = 1;
    const TRACKING = 2;
    const HUNTING  = 3;
    const RUSHING  = 4;
    public $state;

    public  $target;  // current prey
    public  $patrol;  // patrol governor

    private static $id_gen;

    function __construct ()
    {
        $this->patrol = new Search (++self::$id_gen);
        $this->target  = null;
        $this->state = Raptor::IDLE;
        $this->pos = null;
        $this->hunger = HUNGER_MAX;
    }

    function __destruct ()
    {
        $this->tracking_lost();
    }

    function tracking_lost()
    {
        $this->target  = null;
        $this->state = Raptor::IDLE;
    }

    function track_prey()
    {
        // stop tracking if hunger went back to max
        if ($this->hunger == HUNGER_MAX)
        {
            $this->tracking_lost();
        }

        // try to acquire a new target
        if (!$this->target)
        {
            $victim = Pack::get_closest ($this->pos, Raptors::$free_preys, PRED_VISION);
            if (!$victim) return;
            $this->target = new Target ($victim);
            $this->state = Raptor::TRACKING;
        }

        // track prey
        if (!$this->target->track (Pack::$preys))
        {
            // prey was eaten or move prediction failed
            $this->tracking_lost();
        }
    }

    function beat_competition ()
    {
        if ($this->target === null) return;
        $pm = $this->target->pos_next->vector_to ($this->pos);
        $dm = $pm->norm2();
        foreach (Pack::$foe_preds as $f)
        {
            $pf = $this->target->pos_next->vector_to($f);
            $df = $pf->norm2();
            if ($df > PRED_VISION2) continue;
//          if ($df < ($dm*2))
            {
                $this->state = Raptor::RUSHING;
                return;
            }
        }
        if ($this->state == Raptor::RUSHING) $this->state = Raptor::TRACKING;
        return;
    }
}

class Raptors extends Pack {
    public static $free_preys; // coordinates of all preys that are not targeted

    // allows generic Pack to create a proper pack member instance
    static function new_member()
    {
        return new Raptor();
    }

    // main AI loop
    static function think ()
    {
        $hunger_limit = Pack::$n_preys > 2 * Pack::$n_preds ? TRACKING_HUNGER_START : TRACKING_HUNGER_END;
        self::$free_preys = static::$preys;

        // update targets and members states
        foreach (Pack::$member as $m)
        {
            // track current targets
            $m->track_prey();

            // rush to target if a competitor draws near
            $m->beat_competition();

            // hunt if hungry enough
            if ($m->state == Raptor::TRACKING && $m->hunger < $hunger_limit)
            {
                $m->state = Raptor::HUNTING;
            }
        }

        // move members
        foreach (Pack::$member as $m)
        {
            switch ($m->state)
            {
            case Raptor::IDLE:
                $destination = $m->patrol->point($m->pos);
                break;
            case Raptor::TRACKING:
                $wall_point = Pack::point_closest_to_walls ($m->target->pos_next);
                $destination = $wall_point->vector_to ($m->target->pos_next)->normalize (TRACKING_DISTANCE)->add($m->target->pos_next);
                break;
            case Raptor::HUNTING:
                $wall_point = Pack::point_closest_to_walls ($m->target->pos_next);
                $to_hunter = $m->target->pos_next->vector_to ($m->pos);
                $dist_to_target = $to_hunter->norm();

                if ($dist_to_target > (PREY_VISION-PREY_SPEED)) // intercept the prey
                {
                    // use actual speed (i.e. true position delta, including wall stops)
                    $target_true_speed = $m->target->pos->vector_to ($m->target->pos_next);
                    $intercept_speed = $m->intercept ($m->target->pos, $target_true_speed);
                    $destination = $m->pos->add ($intercept_speed);
                }
                else if ($dist_to_target < PRED_SPEED) // pounce on the prey!
                {
                    $destination = $m->target->pos_next;
                }
                else if ($to_hunter->dot($m->target->speed) > 0)
                {
                    $destination = $m->target->pos_next;
                }
                else // goad the prey
                {
                    $to_wall = $m->target->pos->vector_to ($wall_point);
                    $wall_point = $wall_point;
                    $raw_speed = $m->target->raw_speed->add($m->target->pos->vector_to($m->pos)->multiply(2))->multiply (-0.5);
                    $wpd_t = $m->target->pos->vector_to ($wall_point)->normalize()->rotate90(); // wpd = Wanted Prey Direction
                    $delta = $wpd_t->multiply ($raw_speed->dot ($wpd_t));
                    $destination = $delta->vector_to ($m->target->pos_next);
                    if (!Pack::in_arena ($destination)) $destination = $m->target->pos_next;
                }
                break;
            case Raptor::RUSHING:
                $destination = $m->target->pos_next;
                break;
            }
            $m->move_to ($destination);
        }
    }
}

while (Raptors::read_input())
{
    Raptors::think();
    Raptors::output_moves();
}
?>

Genel Değerlendirmeler

  • Önemli olan son oyun. Şimdiye kadarki en akıllı av algoritmasına sahip olabilirsiniz, eğer son birkaç tek avı muhalefetten daha hızlı tespit edemez ve yakalayamazsanız, kaybedersiniz.

  • Eğer avcılarınız bir avı yalnız başına (ya da en azından çiftler halinde) yakalayamazlarsa, av yoğunluğu kör şansa ya da avları köşelere tıkamak için yeterince düşük düşerse tost yaparsınız.

  • Bir av hareketi tahmincisi temel olarak zorunludur. Kendi öngörücünüz olmadan bir yordayıcı tabanlı programı yenmeyi düşünemiyorum.

Kuyruk kovalamaca

Bir avı yakalamanın en verimsiz yolu kuyruğunu kovalamaktır. Tek bir avcının tek bir avı kovalayıp dış etkenleri (duvarlar, diğer avlar, vb.) Kovalamadığını varsayarsak, kuyruk kovalamacı sonsuza kadar sürebilir. 30 birimin av görme yarıçapına girer girmez av, 6.1'iniz için hız 6'ya çıkar. Böylece tur başına 0.1 mesafe kazanırsınız: düz bir çizgide, elde etmek için yaklaşık 300 tur gerekir.

Arena büyüklüğü hesaba katıldığında, bir av, en fazla 117 dönüş yapacak bir duvara veya köşeye çarpmadan önce, 500 birim karenin köşegeninin en köşesinde seyahat eder.

Kazanan strateji, avlarını yavaşlatmanın bir yolunu bulmaktır, yani önünde başka bir avcı ya da duvar / köşe olması.

Predictor

Avlanma hızı 6 olan av, karesi 36 * pi birim alana hareket edebilir. 1 yakalama yarıçapı ile avın bir sonraki nerede olacağına dair kör bir tahmin başarılı olmak için 1/36 * pi (yaklaşık% 1) şansa sahiptir. Açıkçası bunu geliştirmek için bir şeyler yapılmalı!

Simülasyon motoru koduna bakarak, girişlerin aşağıdaki gibi olduğunu görebilirsiniz:

  • görünür av ve avcı pozisyonları
  • önceki av hızları

Tüm pozisyonlar mevcut olsa da, önceki av hızları mevcut değil. Bu hızları hesaplamanın tek yolu, her bir avı bir turdan diğerine izlemektir, ki bunu yapmak neredeyse imkansızdır (çok akıllı bir hareket izleme algoritması uygulamadığınız sürece). Böylece bir tahminci, tahmin edilmesi gereken hız katkısı hariç, hesaplamanın tüm koşullarını kolayca yeniden üretebilir.

Tek bir av durumunda, süratten izole edilen bir avı yakalamak için "mükemmel" bir tahmin yapmayı sağlayan çok fazla sorun olmadan hız izlenebilir. Avlar birbirleriyle etkileşime giremeyecek kadar az olduğunda, oyunun sonu için ihtiyacınız olan tek şey bu. Avlar bolsa ve sürü etkisi, tahmin ediciyi kandıracak kadar güçlü olduğunda avların yoğun yoğunluğu hataları telafi edecektir (hedeflediğiniz birini yakalayamazsanız, en yakın arkadaşlardan birini elde edersiniz. ).

Goading avlar

Av hızı hesaplamasının tam olarak bilinmesi ile, avcının pozisyonunu ayarlayarak verilen avı istenen yöne yönlendirmek mümkündür.

Bu, bir avı bir duvara tutturmayı veya başka bir paket elemanına doğru yönlendirmeyi sağlar. İki paket üyesi arasında av avlamak gibi bazı zarif stratejiler denedim. Ne yazık ki, bu, mevcut "pim ve tarama" rutinden daha az etkili olduğunu kanıtladı, çünkü iki avcının tek bir avı kovalamak için meşgul olmasını sağlamak, muhalefeti meraları araştırmak için çok fazla avcının serbest bırakmasını sağlıyor.

Av çalmak

Av davranışının bir özelliği, avcının etkisinin avla olan mesafesine orantılı olarak artmasıdır (av görme yarıçapı içinde kalması şartıyla). Bir avcıya en yakın av, en azından av ondan uzaklaşır.

İki avcı bir av yakalamak için rekabet ettiğinde, ilk önce onu almak için en yakının bağlı olduğu anlamına gelir. Avcı / av ekseninin hemen önünde kendini konumlandırabilecek süper zeki bir yarışmacı bile avı yarışmacının çenelerine korkuturdu.

Bir av çalmayı başarmak için, en az bir çift yırtıcı hayvan gerekir. Biri öldürmeye gidecek ve diğeri (ler) sadece avı görme yarıçapı içinde kalacaktır, etkiyi en üst düzeye çıkarmak ve avı avcıya doğru yutmak için avı mümkün olduğu kadar oluştururlar.

Ayrıca, her yön değişikliği, yarışmanın köşeyi avına doğru kesmesine izin verecek ve yarışmacının gerisinde kalması ancak "avcı" eylemin başlangıcında avına yeterince yakınsa mümkün olacaktır.

Bu yüzden av çalmanın, "hırsızların" ilk pozisyonları uygunsa ve en az ikinci bir avcıyı koruyabiliyorsanız başarılı olma şansı vardır. Tecrübelerime göre, bu karmaşıklığa değmez.

Önerilen değişiklikler

Daha karmaşık stratejilere izin vermek için, avcıyı av hızının üstünde hareket ettirmek, aşırı hız ile orantılı olarak açlık noktalarında bir maliyete sahip olabilir. Örneğin, hız 6'ya kadar hareket etmenin serbest olduğunu ve 6'nın üzerindeki her hız noktasının 100 açlık puanı (örneğin 6.3'e dönüş başına 30 açlık maliyeti olduğunu, 1000 açlık puanının yakılmasının bir dönüş için 16 hızına ulaşmasına izin vereceğini - söylerseniz öleceğini varsayalım. böyle bir av yakalamıyorum!).

Birden fazla av yemek için yeterince yakın olduğunda, öldürmeyi rastgele bir avcıya vermek yerine, kazancı bölmeyi öneririm (örneğin 3 avcı her birine 333.33 puan kazandıracak). Bu, daha iç içe geçmiş oyun sonu stratejilerine izin verir (örneğin, bir düşman avcısının gölgelenmesi, örneğin daha fazla açlık puanınız olduğunu düşünüyorsanız).

İlk paket için özel renk görmek oldukça zor. Mavi yerine mavi veya turuncu öneriyorum.


Sonunda başka bir rakip! Şu anki yan etkiden memnun kaldığım av çalma hariç her noktayı bilerek uyguladım. Yorumlarınıza göre Clairvoyant'ıma karşı kazanıyorsunuz? Bu ilginç, yarın kontrol edeceğim. = D. Ayrıca, daha iyi (en azından bana göre) grafikler görmek için GUI güncellememi deneyebilirsiniz.
justhalf

Ben her zaman kazanmıyorum. Kim doğduğunda son avlara en yakın olana bağlı. Benim yetenekli köpeklerimin istatistiksel bir kenarı olabilir. Ayrıca, her bir ekibi farklı bir renkte göstermek için simülasyon motorunu değiştirdim, ama sonunda zevkime göre çok renkli oldu, bu yüzden 1. takım için turuncu yerine turuncuya yerleştim, ve diğer tüm kırmızılar.

Vay canına, gönderiminizi yaptım. Bu delilik, hala dua etmenin böyle yapabileceğini bilmiyordum. Ve avın tam olarak en uç noktasında avcılarımın onları tespit edemeyeceğini biraz aldattığımı hissettim, bu kesinlikle benim için büyük bir dezavantaj.
justhalf

Bu sizin için vektörel aritmetik :). Yazımda anlatmaya çalıştığım şey buydu: tek bir av için, tüm hareket parametrelerini (önceki hız dahil) biliyorsunuz, böylece bir duvarın yakınında durması için uygun av hızını üretecek bir avcı pozisyonu hesaplayabilirsiniz.

1
Peki denklem çözümü kodlanmıştır (yineleme gerekmez). Temel olarak, avcınız orada değilse, avın bir sonraki dönüş hızı için kullanması gereken vektörü hesaplarsınız. Avın gitmesini istediğiniz yön dikkate alındığında, av hızını bu yönde yapmak için gereken vektör farkını ortaya çıkarırsınız. Bu vektör farkı size avına göre yırtıcı konumunu verir. Bu, sizi (belli sınırlar içinde) avdan bir mesafe seçmenize izin veren bir serbestlik derecesine bırakır.

3

Tembel Paketi Haskell

import Control.Monad
import Control.Concurrent

main :: IO ()
main=do
    t<-forkIO $ forever $ (putStrLn "Pack is paralyzed with indecision.\0")
    loop
    killThread t
        where
            loop=do
                line <- getLine
                case line of
                    "dead\0" -> return ()
                    _        -> loop

Bunu çalıştırmak için haskell platformuna ihtiyacınız olacak . Sonra runhaskellçalıştırmak için komutu kullanın. Paketim avın onlara gelmesini bekler.


Yeni bir dilde iskelet çözümü için +1. Muhtemelen, bunun üzerine insanların yeni stratejiler geliştirmesi için mutlusun?
trichoplax

Tabii neden olmasın. (Her ne kadar, sabit çıktı üretmek ve "ölü \ 0" da bırakmak dışında hiçbir şey yapmaz, bu yüzden çok kullanışlı olup olmadığından emin değilim.)
PyRulez

Yine de bu -silentseçeneği kullanan herkese bu seçeneği kullanmalarını tavsiye ediyorum ...
Geobits

3

Bir giriş değil, her zaman olan her katılımcı için özelleştirilmiş renk eklemekle ilgileniyorum ;)

Ve ayrıca yeme süreci rengini değiştirerek değil, boyutlarını değiştirerek görselleştirilir, böylece kısa sürede çok sayıda yeme olayını görebiliriz.

Game.java

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.JFrame;

public class Game {

    static int preyStartCount = 0; // 0 means 1500 + (packs * 50)
    static int turn;
    static boolean silent = false;
    long startTime;

    JFrame frame;
    BufferedImage img;
    Color[] colors;

    Island map;
    List<Prey> preys;
    List<Predator> predators;
    List<Pack> packs;
    List<Pack> initPacks;

    public static void main(String[] args) throws InterruptedException {

        Game game = new Game();
        game.init(args);
        if (game.packs.size() > 0){
            game.run();
            game.score();
        }
        game.end();
    }

    void end() {
        frame.setVisible(false);
        frame.dispose();
        for (Pack pack : packs)
            pack.handler.end();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        } finally {
            for (Pack pack : packs)
                pack.handler.shutdown();
        }

        System.exit(0);
    }

    void score() {
        Collections.sort(initPacks);
        int score = 100;
        initPacks.get(0).score = score;
        for (int i = 1; i < initPacks.size(); i++) {
            Pack pack = initPacks.get(i);
            if (pack.extinctionTurn < initPacks.get(i - 1).extinctionTurn)
                score = score < 1 ? score : score * 80 / 100;
            pack.score = score;
        }
        print("", true);
        print("Done in " + getElapsedTime(), true);
        for (Pack pack : initPacks)
            print(pack.toString() + "\t: Turn " + pack.extinctionTurn + "\t: Score " + pack.score, true);
    }

    String getElapsedTime(){
        double elapsed = (System.currentTimeMillis() - startTime) / 1000d;
        if(elapsed < 60)
            return String.format("%.2f", elapsed) + " seconds";
        elapsed /= 60;
        if(elapsed < 60)
            return String.format("%.2f", elapsed) + " minutes";
        elapsed /= 60;
        return String.format("%.2f", elapsed) + " hours";       
    }


    public Game() {
        initPacks = new ArrayList<Pack>();
        packs = new ArrayList<Pack>();
        preys = new ArrayList<Prey>();
        predators = new ArrayList<Predator>();
    }

    void run() throws InterruptedException {
        frame.setVisible(true);
        turn = 0;
        Graphics2D g = img.createGraphics();

        printStatus();
        while (true) {
            turn++;

            getAllMoves();
            moveAll();
            spawn();
            removeDead();
            shuffle();

            if (turn % 500 == 0)
                printStatus();
            paint(frame, g);
            Thread.sleep(5);
            if (packs.size() < 1)
                break;
        }
    }

    void getAllMoves(){
        for (Prey prey : preys)
            prey.setNextMove();
        for (Pack pack : packs){    
            pack.talk(preys.size(), predators.size(), turn);
        }
        while(true){
            int doneCount = 0;
            for(Pack pack : packs)
                if(pack.doneTalking)
                    doneCount++;
            if(doneCount >= packs.size())
                break;
            try {Thread.sleep(1);}catch(InterruptedException e){}
        }
    }

    void moveAll(){
        for (Creature prey : preys) 
            prey.move();
        for(Pack pack : packs){
            for (Predator predator : pack.members) {
                predator.move();
                predator.eatOrStarve();
            }
        }
    }

    void paint(JFrame frame, Graphics2D g){
        g.setPaint(Color.BLACK);
        g.fillRect(0, 0, img.getWidth(), img.getHeight());

        for(Prey prey : preys)
            prey.paint(g);
        for(Pack pack : packs)
            for(Predator predator : pack.members)
                predator.paint(g);

        frame.repaint();
    }

    List<Prey> deadPreys;
    List<Predator> deadPredators;
    List<Pack> deadPacks;

    void removeDead(){
        deadPreys.clear();
        for (Prey prey : preys)
            if (!prey.alive)
                deadPreys.add(prey);
        preys.removeAll(deadPreys);

        deadPredators.clear();
        for (Predator predator : predators)
            if (!predator.alive)
                deadPredators.add(predator);
        predators.removeAll(deadPredators);

        deadPacks.clear();
        for (Pack pack : packs)
            if (!pack.alive)
                deadPacks.add(pack);
        packs.removeAll(deadPacks);

        for (Pack pack : packs) {
            pack.members.removeAll(deadPredators);
        }

        map.rebuildLists(preys, predators);
    }

    void shuffle(){
        Collections.shuffle(packs);
        for(Pack pack : packs)
            Collections.shuffle(pack.members);
    }

    void spawn(){
        if(turn % 5000 == 0)
            addPredators(1);
        if(turn % 1000 == 0)
            populatePrey(predators.size()-1, false);
    }

    void addPredators(int count){
        for(Pack pack : packs){
            if(!pack.alive)
                continue;
            if(pack.aliveCount == 0)
                continue;
            Predator parent = null;
            for(Predator predator : pack.members)
                if(predator.alive)
                    parent = predator;
            if(parent != null){
                for(int i=0;i<count;i++){
                    XY pos = new XY(Math.random() * 30, Math.random()   * 30);
                    pos.add(parent.pos);
                    pos.setInZeroBounds(Island.SIZE, Island.SIZE);
                    Predator child = new Predator(pack);
                    child.color = colors[pack.id];
                    child.moveTo(pos, Island.getCellByPosition(pos));
                    predators.add(child);
                    pack.members.add(child);
                    pack.aliveCount++;
                }
            }
        }
    }

    Color[] generateColors(int n){
        Color[] result = new Color[n];
        double maxR = -1000;
        double minR = 1000;
        double maxG = -1000;
        double minG = 1000;
        double maxB = -1000;
        double minB = 1000;
        double[][] colors = new double[n][3];
        for(int i=0; i<n; i++){
            double cos = Math.cos(i * 2 * Math.PI / n);
            double sin = Math.sin(i * 2 * Math.PI / n);
            double bright = 1;
            colors[i][0] = bright + sin/0.88;
            colors[i][1] = bright - 0.38*cos - 0.58*sin;
            colors[i][2] = bright + cos/0.49;
            maxR = Math.max(maxR, colors[i][0]);
            minR = Math.min(minR, colors[i][0]);
            maxG = Math.max(maxG, colors[i][1]);
            minG = Math.min(minG, colors[i][1]);
            maxB = Math.max(maxB, colors[i][2]);
            minB = Math.min(minB, colors[i][2]);
        }
        double scaleR = 255/(maxR-minR);
        double scaleG = 255/(maxG-minG);
        double scaleB = 255/(maxB-minB);
        for(int i=0; i<n; i++){
            int R = (int)Math.round(scaleR*(colors[i][0]-minR));
            int G = (int)Math.round(scaleG*(colors[i][1]-minG));
            int B = (int)Math.round(scaleB*(colors[i][2]-minB));
            result[i] = new Color(R,G,B);
        }
        return result;
    }

    void populatePredators(String[] args) {
        int start = 0;
        if(args[0].equals("-silent")){
            silent = true;
            start = 1;
        }

        colors = generateColors(args.length-start);
        if(colors.length==1){
            colors[0] = Color.BLUE;
        }

        for (int i = start; i < args.length; i++) {
            Pack pack = new Pack(args[i]);
            if (pack.handler.init()) {
                packs.add(pack);
                initPacks.add(pack);
            }
        }
        Collections.shuffle(packs);
        XY[] positions = map.getPackStartLocations(packs.size());
        XY offset = new XY(-15, -15);
        for(int i=0;i<packs.size();i++){
            Pack pack = packs.get(i);
            for (Predator predator : pack.members) {
                predator.color = colors[pack.id];
                XY pos = new XY(Math.random() * 30, Math.random()   * 30);
                pos.add(positions[i]);
                pos.add(offset);
                pos.setInZeroBounds(Island.SIZE, Island.SIZE);
                predator.moveTo(pos, Island.getCellByPosition(pos));
                predators.add(predator);
            }
        }
        deadPredators = new ArrayList<Predator>(predators.size());
        deadPacks = new ArrayList<Pack>(packs.size());
    }

    void populatePrey(int count, boolean center) {
        XY pos = new XY();
        for (int i = 0; i < count; i++) {
            Prey prey = new Prey();
            if(center){
                pos.x = Math.random() * 100 + 200;
                pos.y = Math.random() * 100 + 200;
            } else {
                pos.x = Math.random() * 500;
                pos.y = Math.random() * 500;
            }

            prey.moveTo(pos, Island.getCellByPosition(pos));
            preys.add(prey);
        }
        deadPreys = new ArrayList<Prey>(preys.size());
    }

    static void print(String txt){
        print(txt, false);
    }

    static void print(String txt, boolean override){
        if(!silent || override)
            System.out.println(txt);
    }

    void printStatus(){
        print("Turn " + turn + " : Prey " + preys.size()
                + " : Predators " + predators.size() + " (" + getElapsedTime() + " elapsed)");
    }

    @SuppressWarnings("serial")
    void init(String[] args) {
        startTime = System.currentTimeMillis();
        map = new Island();
        populatePredators(args);
        if (preyStartCount == 0)
            preyStartCount = 1500 + (packs.size() * 50);

        populatePrey(preyStartCount, true);
        map.rebuildLists(preys, predators);
        img = new BufferedImage(Island.SIZE, Island.SIZE, 1);
        frame = new JFrame() {
            @Override
            public void paint(Graphics g) {
                g.drawImage(img, 32, 32, null);
            }
        };
        frame.setSize(Island.SIZE+64, Island.SIZE+64);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                for (Pack pack : packs)
                    pack.handler.end();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                } finally {
                    for (Pack pack : packs)
                        pack.handler.shutdown();
                }
            }
        });
    }
}

Predator.java

import java.awt.Graphics2D;


public class Predator extends Creature {

    static int count = 0;

    int id;
    int hunger;
    Pack pack;

    public Prey eatOrStarve() {
        for (Prey prey : preys) {
            if (prey.alive && pos.isCloserThan(prey.pos, eatDist)) {
                prey.die();
                hunger = MAX_HUNGER;
                return prey;
            }
        }
        if (hunger-- < 1)
            die();
        return null;
    }

    @Override
    public void die() {
        super.die();
        pack.aliveCount--;
        Game.print(pack.toString() + " starved! " + pack.aliveCount + " members remaining.");
    }

    @Override
    void paint(Graphics2D g){
        g.setPaint(color);
        int size = ((hunger + 10) > MAX_HUNGER && Game.turn > 10) ? 3+(int)Math.pow((hunger+10-MAX_HUNGER)/4,3) : 3;
        g.drawOval((int)pos.x - 1, (int)pos.y - 1, size, size);
        g.fillOval((int)pos.x - 1, (int)pos.y - 1, size, size);
    }

    Predator(Pack pack) {
        super();
        id = count++;
        this.pack = pack;
        MAX_SPEED = 6.1;
        VISIBLE = 50;
        hunger = MAX_HUNGER;
    }

    final double eatDist = 1;
    final static int MAX_HUNGER = 1000;
}
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.