Tentang yang tidak berubah: sejarah tempat ke-9 Piala AI Rusia 2019

Nama saya Andrey Rybalka, saya berpartisipasi dalam Piala AI Rusia di bawah nama panggilan lama dan saya akan memberi tahu Anda lagi bagaimana tidak memenangkan macbook. Untungnya, saya adalah orang yang berpengalaman dalam hal ini - dengan tangan ini saya belum memenangkan sebanyak 7 buah.


Jadi, tugas tahun ini adalah platformer / penembak 2D, di mana Anda harus menulis bot. Permainannya terlihat seperti ini:



Bot tampak seperti ini:



Jika Anda tertarik dengan bagaimana gambar # 2 diputar ke dalam gambar # 1, silakan, di bawah cat.


Jika Anda tidak berpartisipasi dan tidak membaca artikel lain, saya sarankan Anda melihat dulu bagaimana semuanya terlihat dalam dinamika di situs atau di tabung:



Sistem turnamen


Sebagai permulaan, lebih dari 2 minggu diberikan untuk pemrograman. Kemudian babak pertama dimulai. Itu berlangsung 2 hari dan 300 yang terbaik berlangsung. Setelah ronde, aturan permainan berubah (sekarang kami mengontrol dua karakter sekaligus) dan satu minggu lagi diberikan, setelah ronde kedua berlalu. Kemudian aturannya rumit lagi (sekarang kita bermain di peta yang jauh lebih kompleks), satu minggu lagi diberikan dan, akhirnya, kita bermain final.


Tapi ini bukan akhirnya. Setelah final ada satu minggu lagi, di mana sandbox hanya berhenti, dan 6 yang terbaik di dalamnya, tidak termasuk pemenang final, juga diberikan. Perbedaan mendasar antara final sandbox dan final kejuaraan adalah bahwa di sandbox, permainan dibuat dalam format acak, dan bukan hanya dalam format putaran saat ini.


Sejarah partisipasi


Di mana tanpa itu? Anda dapat melewati yang tidak tertarik. Bagian teknis akan lebih rendah.


Pekan Uji Beta dan Babak Pertama


Saya mulai pemrograman, tampaknya, sehari setelah dimulainya Tes Beta Terbuka. Tetapi secara pribadi, itu agak mendemotivasi bagi saya bahwa penyelenggara kali ini, tidak seperti masa lalu, memutuskan untuk kembali dari praktik penerbitan kode pseudo-simulator. Tentunya di antara peserta adalah mereka yang suka menulis simulator dengan teknik terbalik, tapi saya bukan salah satu dari mereka, dan saya bosan melakukannya. Karena ini bukan kejuaraan pertamaku, aku tahu bahwa cepat atau lambat aku akan terlibat, tetapi karena alasan yang dijelaskan di atas, aku terlambat terlibat. Akibatnya, apa yang dilakukan beberapa peserta dalam beberapa hari pertama, saya bisa memaksa diri untuk menyelesaikan hanya dalam satu setengah minggu. Sebagai hasilnya, saya menulis baris pertama kode bot 5 hari sebelum putaran pertama. Singkatnya, pada awal babak pertama, saya belum siap, dan putaran berlalu tanpa partisipasi saya. Saya memutuskan bahwa saya akan langsung masuk ke putaran kedua, melalui sambungan cepat.


Babak kedua


Pada titik ini, saya sudah memprogram secara maksimal, rata-rata 4-6 jam sehari. Beberapa hari sebelum dimulainya putaran kedua, saya mengunggah bot versi pertama. Dia segera dengan cepat naik dan dengan cepat masuk ke 10 kotak pasir teratas. Kemudian putaran dimulai, di mana saya mengambil tempat kelima.


Terakhir


Saya menghabiskan malam pertama minggu terakhir (dari empat, karena awal dijadwalkan untuk Jumat) untuk menemukan jalan. Masih ada banyak ide, tetapi apa yang harus dikonsentrasikan dan ide mana yang berpotensi memberikan hasil terbesar tidak jelas, jadi saya mencoba untuk memperbaiki apa yang menyebabkan kekalahan terbesar. Pada hari Selasa dan Rabu, ini adalah peningkatan dalam membidik dan menembak, serta mengontrol peralatan P3K.


Kemudian saya melihat sesuatu telah terjadi yang sudah lama saya harapkan, tetapi saya berharap ini tidak akan terjadi - beberapa lawan mulai aktif menggunakan ranjau.


Faktanya adalah bahwa selama OBT, panitia mendengarkan proposal para peserta dan mengubah salah satu mekanik permainan. Dalam kasus umum, ini, tentu saja, bagus ketika peserta didengarkan. Namun secara khusus kali ini kehadiran umpan balik memainkan lelucon yang kejam. Singkatnya, panitia memungkinkan ranjau diledakkan dengan tembakan.


Ini sendiri logis. Jika saya milik saya dan mereka menembaki saya, saya juga akan meledak. Tetapi masalahnya adalah bahwa kami bermain pada poin, dan poin diberikan tidak hanya untuk pembunuhan, tetapi juga untuk kerusakan. Jadi, ternyata jika Anda cukup dekat dengan musuh, meletakkan ranjau di bawah Anda dan menembak mereka, Anda membunuh musuh dan diri Anda sendiri dengan ledakan. Tidak mungkin untuk menghindar. Anda berdua mendapatkan 1000 poin untuk kedua karakter mati, tetapi Anda juga mendapatkan poin untuk kerusakan. Jadi, jika musuh sehat, Anda akan menerima 1000 poin untuk membunuh dan 100 untuk kerusakan, dan musuh - hanya 1000.


Meskipun semua orang tahu tentang itu, tetapi di atas hampir tidak ada yang menggunakan ranjau sampai yang terakhir. Saya tidak tahu bagaimana orang lain, tetapi secara pribadi, saya tidak menggunakannya hanya karena saya tidak ingin menyalahgunakan kesalahan perhitungan yang tidak disengaja. Tetapi, seperti yang mereka katakan dalam satu film, saya tahu bahwa cepat atau lambat kita akan beralih ke sampah ini.


Singkatnya, di tengah malam dari Rabu hingga Kamis, saya membuat gangguan diri. Murni situasional, tidak ada yang maju. Hanya dengan prinsip bahwa jika pada saat ini karakter saya menguntungkan untuk bunuh diri, dan dia bisa melakukannya, dia melakukannya. Seperti yang telah ditunjukkan oleh praktik, beberapa peserta lain berencana untuk menggunakan ranjau terlebih dahulu, sehingga mereka menerapkan bunuh diri yang lebih maju, tetapi secara strategis direncanakan untuk melepaskannya sebelum final. Hasilnya, ternyata apa yang terjadi - tempat ke-9 di final, serta tahun lalu.


Sandbox Finale


Setelah selesai, saya meninggalkan kota untuk liburan. Dia kembali seminggu kemudian dan pada malam pertama, secara harfiah dalam 2-3 jam kerja, tambang sangat meningkat, yang akan saya tulis lebih banyak di bagian teknis. Sisa dari perubahan terutama berkaitan dengan pengeditan bug dan penyelesaian fungsi evaluasi. Singkatnya, sedikit pemrograman dan banyak tes.


Bagian teknis


Entah kecepatan Jawa, atau jari-jari kelengkungan tangan, melainkan, keduanya bersamaan, sekali lagi tidak memungkinkan saya untuk bergaul dengan simulasi murni. Karena itu, pergerakan, pemotretan normal, dan pemasangan ranjau terpisah dari saya.


Simulasi


Melalui mata bot, dunia tampak seperti ini:



Di video, saya pikir, dan semuanya hampir jelas. Di sudut kiri atas adalah debug fungsi evaluasi. Anda dapat melihat apa Skor dari masing-masing lintasan. Siluet kuning (misalnya, pada jam 2:30) - ini adalah lintasan yang sama di 9 arah, tentang mereka akan lebih rendah. Garis dari panah di suatu tempat mulai 2:50 adalah pencarian jalan (merah - ke musuh, hijau - ke kotak P3K, kuning-hijau - ke senjata, biru - ke tambang). Kotak hijau di akhir video adalah ubin PVS saya, yang terlihat dari ubin yang dipilih. Titik-titik merah di pusatnya menunjukkan dari mana visibilitas balik berasal.


Gerakan karakter disimulasikan tanpa mikrotik. Peluru terbang juga, tetapi di dalamnya saya menggunakan beberapa peretasan sehingga situasi lebih kecil kemungkinannya terjadi ketika dengan centang penuh, peluru “menembus” karakter tanpa memukulnya, meskipun itu seharusnya menyentuhnya dengan mikrotik. Misalnya, jika Anda memikirkannya, situasi yang dijelaskan hanya dapat terjadi di sudut:



Pada tick 1, peluru berada di posisi 1, di tick 2 - di posisi 2, masing-masing. Tanpa Mikrotik - Boris-lobak - Anda dapatkan, dengan Mikrotik - tembakan telinga. Jadi, agar ini terjadi, posisi peluru pada kutu 1 dan 2 harus berada di sisi yang berbeda dari setidaknya satu wajah karakter atau ubin (persegi panjang mint). Dengan demikian, dimungkinkan untuk mensimulasikan peluru tanpa mikrotik sampai, seperti yang diterapkan pada gambar di atas, kondisi old_bullet.x > character_left_side.x != new_bullet.x > character_left_side.x , dan jika ini terjadi, maka Anda harus menganalisis centang ini dengan lebih hati-hati .


Kemudian, setiap tick, saya menghitung ulang lintasan semua peluru terbang sebelum mereka bertabrakan dengan dinding dan menyimpan posisi mereka di setiap tick dalam array, sehingga dalam simulasi Anda dapat dengan cepat memeriksa tabrakan dengan mereka.


Untuk bazoka, setelah menabrak dinding, saya secara matematis, tanpa mikrotik, menghitung titik dampak yang tepat untuk menghitung dengan tepat pusat gempa.


Juga, setiap centang yang saya isi array dodge_trajectories - disimulasikan pergerakan setiap karakter, termasuk musuh, dalam 8 arah untuk 25 ticks (siluet kuning dalam video dari visualizer, setelah mengaktifkan kotak centang traj yang mungkin. Misalnya, jam 2:30). Dan, seperti halnya peluru, dia menyimpan semua posisi yang memungkinkan di setiap tick. Itu kemudian digunakan di banyak tempat, beberapa di antaranya akan saya sebutkan.


Saya juga menghitung PVS dengan ubin sebelumnya. Untuk setiap sel, saya menyimpan daftar ubin, yang pusatnya terlihat berdiri di dalamnya. Itu dihitung dengan ray tracing. Ini bisa dilihat di video dari visualizer, di akhir. Kotak hijau adalah ubin yang terlihat dari sel yang dipilih. Titik-titik merah di pusatnya menunjukkan dari mana visibilitas balik berasal.


Cari cara


Diimplementasikan oleh algoritma Dijkstra sesuai dengan Waypoints. Ubin tempat Anda bisa berdiri dianggap Waypoint. Adaptasi algoritma untuk platformer 2D adalah miliknya sendiri, buatan sendiri, dan oleh karena itu, demi optimasi, ia dibangun di atas kruk. Tapi itu bekerja cukup cepat: Saya sebelumnya membangun Dijkstra (saya tidak tahu bagaimana mengatakannya dengan benar) dari setiap subjek di tingkat ke setiap ubin. Saya hanya membangun jalan yang memiliki kemampuan lintas negara dua arah. Ini diperlukan agar nantinya Anda bisa dengan cepat mendapatkan jalan dari ubin apa pun ke kotak P3K / senjata / tambang pertolongan pertama. Dimungkinkan untuk menyingkirkan pembatasan ini, tetapi dalam praktiknya, saya menganggap lebih baik menghabiskan waktu untuk hal-hal lain, karena tidak ada banyak kerugian dari pembatasan ini.


Selain itu, setiap kali saya beralih ke ubin lain dengan karakter apa pun (milik saya dan musuh), saya menghitung baginya jalan menuju musuh terdekat, kotak P3K, dan juga tambang dan senjata, jika dia masih membutuhkannya.


Di komputer rumah saya dalam game dengan 1000 ticks, seluruh pencarian path memakan waktu sekitar 100 ms.


Jika jalan melintasi musuh atau teman, saya cukup menambahkan beberapa lusin unit ke beratnya. Jadi, jika ada jalan memutar yang relatif singkat, atau jika setelah itu lebih menguntungkan untuk lari ke objek lain, saya akan melakukannya. Dalam video dari visualizer di atas, ini dapat dilihat pada 2:55, di mana jalan ke musuh terdekat dilewati, karena jalan lurus melintasi karakter kedua.


Visualisasi jalur pencarian:



Kotak ungu tembus adalah titik arah, mereka juga merupakan simpul dari grafik. Panah hijau limau - ujung 1 kolom 2
1 tidak menjadi bingung dengan tulang rusuk; 2 setiap kebetulan yang bersifat monarkis adalah acak [sekitar]


Gerakan


Dua karakter berjalan bergantian. Jika Anda hanya berpikir - “dan sekarang masuk ke dalam 10 besar?!”, Maka Anda berpikir dengan benar. :) Tidak ada cukup sumber daya untuk berjalan dengan keduanya. Pengecualian adalah kasus kemunculan peluru terbang baru.


Dasar untuk memilih lintasan adalah genetika tanpa persimpangan. Tetapi jika tahun lalu, dalam sepakbola, genetika menunjukkan dirinya dengan sempurna, maka tahun ini itu memberi keuntungan yang sangat kecil. Eksperimen saya menunjukkan hasil yang sangat dekat dalam genetika dan pencarian acak. Saya melihat beberapa alasan untuk ini, tetapi yang utama bagi saya adalah sebagai berikut: Dalam sepak bola, kami memiliki tujuan tetap - bola. Sebagian besar waktu perilakunya dapat ditebak - jika kami menemukan lintasan yang baik untuk memukul bola ke gawang dan mengikutinya, maka setelah 20 kutu, lintasan ini mungkin masih akan baik, karena bola tidak bisa secara spontan mengubah jalurnya. Tapi tahun ini kami bermain bukan dengan bola, tetapi dengan karakter musuh. Mereka mengubah perilaku mereka setiap kutu. Jadi relevansi lintasan tetap sangat pendek.


Saya masih menggunakan genetika karena dua alasan:


  1. Saya baru saja menyalin kodenya dari tahun lalu. Bahkan lucu betapa sedikit saya harus melakukan perubahan, dengan pengecualian fungsi evaluasi, sehingga bot mulai bergerak dengan lumayan. Singkatnya, saya menulis simulator selama satu setengah minggu, dan kemudian selama sekitar satu jam saya menyalin logika gerakan dari tahun lalu, dalam satu jam saya melemparkan perkiraan sederhana dan bot, ketika memotret a la Start Cepat, mulai menang cukup stabil dengan itu.
  2. Saya tampaknya menyukai rasa sakit itu. Kalau tidak, saya tidak tahu bagaimana menjelaskan mengapa saya menulis di Jawa lagi, dan tidak seperti semua atasan normal:


Jadi saya harus melakukan segalanya dengan segala cara sehingga strateginya tidak jatuh dengan batas waktu di setiap pertandingan pertama. Dan pendekatan dengan genetika memungkinkan saya untuk menyimpan snapshot dari simulasi dunia dan poin-poin yang dihitung, dan kemudian, ketika menghitung generasi berikutnya, untuk menonaktifkan snapshot hanya dimulai dari gen termutasi pertama.


Yaitu secara kasar, jika pada generasi pertama saya pergi 10 kutu ke kanan, dan kemudian melompat, dan pada generasi kedua saya mengevaluasi mutan yang pergi 10 kutu ke kanan dan kemudian melompat ke bawah, maka titik referensi untuk mutan akan menjadi snapshot dunia yang sebelumnya dihitung dan poin setelah 10 gerakan ke kanan. Jadi, saya mengurangi perhitungan secara signifikan.


Igogo, algoritme gerakan perkiraan:


  1. Kami menghasilkan N genotipe acak. Masing-masing terdiri dari gen acak M. Setiap gen adalah angka yang dikodekan dengan tindakan: satu angka bertanggung jawab untuk arah gerakan, yang kedua adalah untuk melompat / berjalan / melompat ke bawah, yang ketiga adalah untuk pemotretan dasar (murni untuk fungsi evaluasi, algoritma penembakan dasar akan dijelaskan di bawah), keempat untuk jumlah pengulangan dari ini tindakan. Jumlah total tindakan dalam genotipe, bersama dengan pengulangan, tidak melebihi kedalaman simulasi - 40 ticks.
  2. Kami menambahkan sejumlah genotipe kode-keras kepada mereka: gerakan langsung dalam 9 arah (8 sisi + diam) dan beberapa preset sederhana, yang dalam praktik membantu untuk keluar dari beberapa situasi khas di labirin sedikit lebih cepat. Sebagai contoh, ini adalah lintasan: ⮤ ⮥
  3. Tambahkan genotipe terbaik dari langkah sebelumnya.
  4. Evaluasi semuanya, tinggalkan yang terbaik.
  5. Kami menciptakan generasi berikutnya di mana dalam setiap genotipe satu atau lebih gen bermutasi.
  6. Kami menambahkannya ke kumpulan umum, yang sudah berisi M terbaik dari generasi terakhir.
  7. Kami ulangi, mulai dari poin 4, beberapa kali lagi.

Fungsi evaluasi


Sebenarnya, tempat strategi itu tinggal.


Sepanjang kejuaraan, sejumlah besar semua jenis metrik ditambahkan (tepatnya, 57). Beberapa dari mereka tidak hidup untuk melihat final. Bagian lain selamat, tetapi dengan latar belakang inflasi Skor selama kejuaraan, sebagai hasilnya, secara praktis tidak mempengaruhi hasilnya, tetapi sisanya, dari urutan 20-25, justru bertanggung jawab untuk gerakan dan penembakan dasar.


Saya akan memberikan beberapa contoh metrik penting, secara acak:


  1. Hukuman untuk ledakan peluru / bazooka pada saya.
  2. Bonus untuk derajat kebebasan. Yaitu untuk jumlah arah (atas / bawah / kiri / kanan) tempat saya dapat bergerak dari ubin saat ini. Seperti yang Anda duga, semakin banyak derajat kebebasan - semakin banyak peluang untuk menghindari peluru. Bonus ini memaksa bot untuk menempel pada platform dan tangga. Bonusnya tiga kali lebih tinggi jika lawan memiliki bazoka.
  3. Penalti untuk jarak (melalui pencarian jalan) ke kotak P3K terdekat; untuk jarak rata-rata (melalui pencarian jalur) ke semua kotak P3K; karena jalan dari dia ke kotak P3K yang paling dekat dengannya kurang dari jalur dari saya ke kotak P3K (!).
  4. Hukuman atas kenyataan bahwa musuh melihat kepalaku.
  5. Hukuman untuk fakta bahwa musuh melihat kaki saya (poin 4 dan 5 memaksa bot untuk bersembunyi di balik tempat berlindung sebagian).
  6. Bonus serangan saat memuat ulang senjata musuh.
  7. Bonus untuk tembakan yang dilakukan.
  8. Hukuman untuk terlalu banyak atau terlalu sedikit jarak dari musuh. Itu tergantung pada beberapa faktor: kesehatan keduanya, apakah senjata keduanya dimuat ulang, dll.
  9. Bonus untuk kondisi kerja berbahaya.
  10. Hukuman untuk keadaan jatuh dan untuk keadaan terbang pada jumppad (karena kedua negara ini tidak dapat diganggu, dan oleh karena itu, mereka lebih kecil kemungkinannya untuk menghindari peluru).
  11. Bonus untuk jumlah kit pertolongan pertama yang berada di sisi saya yang berlawanan, dibandingkan dengan musuh (mis., Misalnya, jika musuh ada di sebelah kanan saya, maka saya akan mendapatkan bonus untuk jumlah kit pertolongan pertama yang ada di sebelah kiri saya. Ini pada dasarnya masuk akal di Babak 1 dan 2, di mana satu-satunya jalan dari musuh ke kotak P3K adalah melalui saya).
  12. Bonus untuk mengikuti jalur ke musuh, ke kotak P3K (jika saya terluka), ke tambang (jika saya memiliki kurang dari dua), untuk senjata (jika tidak ada).
  13. Hukuman untuk kedekatan dinding jika musuh memiliki bazoka. Lebih khusus, saya mempertimbangkan berapa banyak kutu roket musuh, jika melepaskannya, akan terbang ke dinding di dekat saya, dan berdasarkan ini, bahwa zona di dekat dinding dari mana mustahil untuk melarikan diri dari ledakan itu dianggap berbahaya dan saya menerima denda karena berada di dalamnya.
  14. Bonus Tahun Baru.

Evasion Peluru


Ini terjadi secara otomatis, karena hal di atas


Bertujuan


Ada banyak hal yang terjadi. Mungkin yang paling penting adalah algoritma sederhana dan efektif yang memutuskan apakah saya harus mengarahkan senjata ke musuh (karena bertujuan meningkatkan penyebaran senjata):


  1. Kami mempertimbangkan sudut antara (last_angle - min_spread) dan (last_angle + max_spread).
  2. Kami menembakkan sinar dari pusat karakter saya ke dua sudut musuh AABB yang paling dekat dengan garis tegak lurus. Jika salah satu dari mereka berada di luar kisaran (last_angle - min_spread) ... (last_angle + max_spread), kami memotong rentang ini.
  3. Kami mempertimbangkan sudut antara sinar-sinar ini.
  4. Bagi sudut kedua pertama dengan yang pertama, kita mendapatkan Cakupan (cakupan). Merupakan probabilitas saat ini dalam persen bahwa lintasan peluru yang ditembakkan akan berpotongan dengan kotak lawan.
  5. Kami mensimulasikan Aksi yang bertujuan membidik musuh, bersama dengan perubahan sebaran.
  6. Ulangi langkah 1..4 untuk set baru [last_angle, min_spread, max_spread]. Karenanya, kami mempertimbangkan cakupan apa yang akan kami jaga jika kami bertujuan.
  7. Akibatnya, kami memiliki jangkauan saat ini, serta cakupan yang diprediksi jika kami mengarahkan senjata ke musuh. Jika perkiraan cakupan lebih besar dari saat ini, kami bertujuan.

Demo 2 poin:



Jika garisnya berwarna hijau, maka musuh jatuh sepenuhnya ke area tujuan. Oranye - sebagian, merah - tidak jatuh sama sekali.


Tetapi saya biasanya tidak mengarah pada perut musuh, tetapi pada titik yang lebih optimal.


Untuk pistol dan senapan serbu, jika musuh ada di udara, saya mempertimbangkan berapa banyak kutu peluru akan mencapai posisi saat ini, maka saya mengambil dari array dodge_trajectories dijelaskan di atas semua posisi yang mungkin melalui jumlah kutu, rata-rata semua 8 posisi dan, ketika membidik, saya mempertimbangkan bahwa musuh berada pada titik rata-rata ini.


Jika dia berdiri di tanah, aku membidik "di kepala", atas dasar pertimbangan bahwa dia hanya bisa melompat ke atas, sehingga tembakan di kepala jauh lebih sulit untuk dihindari daripada tembakan di perut, dan bahkan lebih lagi, di kaki.


Untuk bazoka, saya juga mengambil 8 posisi yang mungkin melalui kutu sebanyak roket mencapai musuh. Bagi mereka, saya membangun kerucut (lebih tepatnya, sektor lingkaran) yang menggambarkan semua posisi ini dan di dalam kerucut ini saya memilah-milah lintasan dengan beberapa langkah. Untuk setiap lintasan, saya mensimulasikan penerbangan roket, bersama dengan ledakan jika terjadi tabrakan di dinding. Lintasan di mana musuh memiliki peluang paling sedikit untuk menghindar, saya gunakan untuk membidik.


Bahkan dalam beberapa kasus, untuk jatuh dan terbang dari jumppad (yaitu, negara-negara yang tidak dapat disela musuh), saya cukup mempertimbangkan titik intersepsi oleh peluru musuh, dengan menyelesaikan sistem persamaan gerak. Kode tersebut disalin dari bot hoki 2014 miliknya, tempat kode itu digunakan untuk mencegat keping. :)


Antara lain, dalam situasi tertentu saya membatalkan membidik jika ada posisi di jalur saya untuk 10 ticks berikutnya di mana sinar dari pusat posisi ini ke arah last_angle saat ini bersinggungan dengan musuh. Ini memungkinkan saya untuk membidik dengan gerakan, tanpa mengubah sudut, dan karenanya, tanpa meningkatkan penyebaran.


Menembak


Penembakan dasar dijahit ke lintasan yang ditemukan dan murni situasional. Tetapi juga, setiap centang bot saya mencoba menghitung apakah masuk akal untuk menembak sekarang, dan jika berhasil, ia akan menembak. Sebagai contoh:


  • jika musuh tidak dijamin menghindar;
  • jika cakupan di atas beberapa nilai tetap.

Juga, jika senjata saya adalah bazoka, saya mensimulasikan semua jenis lintasan dalam penyebaran jika terjadi tembakan langsung, dengan beberapa langkah. Dan jika hasilnya menunjukkan bahwa manfaat potensial melebihi potensi bahaya, saya menembak. Saya mengevaluasi manfaat dengan 4 metrik dalam urutan yang penting bagi saya dan musuh: jaminan kematian (milik saya atau musuh), kemungkinan kematian, kerusakan terjamin, kemungkinan kerusakan. Jika ada setidaknya satu lintasan di mana, misalnya, saya dijamin akan bunuh diri dan hanya mungkin membunuh musuh, saya tidak menembak.


Ada cek lain. Misalnya, saya bisa membatalkan pemotretan jika pada tick berikutnya dari lintasan saya, cakupan potensial lebih tinggi daripada yang ada sekarang.


Secara umum, logika mengatakan kepada saya bahwa pemotretan dasar harus dimatikan, tetapi tes menunjukkan sebaliknya. Saya tidak bisa membayangkan mengapa.


Tambang


Pada saat final, mereka masih bayi: Saya menandai setiap centang apa yang akan terjadi jika saya menempatkan 1 atau 2 ranjau sekarang, tergantung pada kesehatan lawan, dan menembak mereka. Jika saya dijamin untuk membunuh musuh dan jika itu menguntungkan bagi saya (baik pada poin, atau karena hanya musuh akan mati), saya melakukannya.


Setelah tahun baru, kembali dari perjalanan, saya menulis algoritma malam pertama, yang membawa saya ke 2-4 tempat di tabel. Algoritma itu sederhana: Saya hanya mensimulasikan setiap centang apa yang akan terjadi jika saya segera beralih ke mode berserker dan berlari ke arah musuh untuk meledakkannya dengan ranjau di kesempatan paling awal. Untuk musuh, saya mensimulasikan penghindaran sederhana menggunakan dodge_trajectories yang sama: Saya mengambil tiga lintasan yang meningkatkan jarak dari saya. Misalnya, jika saya berada di sebelah kiri musuh, maka saya menganalisis tiga kasus: musuh melarikan diri ke kanan; musuh berlari ke kanan dan melompat; berlari ke kanan dan melompat ke bawah. Jika dalam ketiga kasus saya dijamin punya waktu untuk membunuhnya dengan tambang dan dia dijamin tidak bisa menempatkan tambang di hadapanku, aku yang melakukannya.


Algoritme juga dapat melompat atau melompat pada level strategi Mulai Cepat - hanya berdasarkan pada perbedaan koordinat Y.


Hasilnya, pada peta terakhir, hampir setiap pertandingan berakhir dengan kurang dari 1000 kutu dengan peledakan otomatis dari kedua karakter saya.


Pasifisme


Melihat seberapa efektif ranjau saya, saya memutuskan untuk memeriksa asumsi saya yang dibuat sebelumnya pada saluran telegram bahwa pada akhirnya dimungkinkan untuk mengambil tempat di atas tanpa menembak sama sekali. Jadi saya hanya mengambil dan mematikan penembakan di bot saya, kecuali tembakan ranjau. Satu-satunya adalah - agar tidak kehilangan peringkat, mode ini diaktifkan hanya jika saya memiliki cukup ranjau untuk membunuh musuh.


Singkatnya, bot saya telah menjadi pasifis. Untuk menunjukkan kedamaian dan kerendahan hatinya, dia bahkan tidak melihat musuh (lihat video). Yah, dia terkadang menembak ranjau, menurutmu. Saya tidak menembak lawan! Dan jika mereka mati pada saat yang sama - yah, apa yang bisa Anda lakukan, kecelakaan tragis.


Secara umum, saya mengunggah versi ini ke situs, membuat 4 game dengan masing-masing 3 teratas dan ...



... memenangkan 3 dari 4 pertandingan melawan masing-masing. Secara umum, aneh bahwa tetangga tidak datang untuk mengeluh tentang tawa homeric saya di tengah malam. :)


Kagumi diri Anda sendiri:



Eh, jika saya menghabiskan 2-3 jam sebelum final, dan bukan setelahnya, mungkin artikel ini akan memberi tahu cara memenangkan MacBook, dan bukan bagaimana cara menghindarinya dengan segala cara, siapa tahu. Sayangnya, sejarah tidak tahu mood subjungtif.


Pengujian


Secara umum, saya menguji setiap perubahan berkali-kali sehingga hasilnya signifikan secara statistik. Lebih tepatnya, batas bawah interval kepercayaan harus melebihi 50%. Untuk final kotak pasir, skrip memilih koefisien. Pada tahun-tahun sebelumnya saya mencoba genetika, tetapi itu bekerja buruk - untuk hasil yang normal, Anda harus bermain terlalu banyak permainan. Jadi kali ini saya hanya mengubah satu koefisien pada satu waktu dan memenangkan kembali 200 pertandingan. Dalam kasus ketika hasilnya bagus, saya melakukan tes tambahan. Singkatnya, dibiarkan semalam koefisien dua lusin dan memiliki hasil di pagi hari.


Kesimpulannya


Entah bagaimana itu semua berhasil dengan setengah kesedihan.


Dalam beberapa hari terakhir sebelum akhir kotak pasir, saya menghabiskan sebagian besar waktu di tempat kedua dalam tabel dengan selisih yang signifikan dari yang ketiga, tetapi beberapa jam sebelum akhir kotak pasir saya kurang beruntung dan saya memulai serangkaian permainan sesuai dengan aturan putaran 1 dan 2, sementara strategi saya paling dimainkan oleh aturan finale. Sebagai contoh, di sini dari 13 pertandingan hanya ada 1 sesuai dengan aturan final. Jadi saya juga, tingkat kemenangan saya dalam permainan ini keluar jauh lebih buruk dari biasanya. Secara umum, Yang Mahakuasa acak:



Akibatnya, saya kehilangan terlalu banyak pertandingan, kehilangan semua keunggulan saya dan jatuh dari 2 ke 4 tempat, dan tidak punya waktu untuk pulih, karena kejuaraan telah berakhir. Ada baiknya bahwa kotak pasir tidak kehilangan tempat pertama dalam daftar pemenang.


Sekali lagi, saya ingin berterima kasih kepada Mail.ru Group atas kejuaraan indah berikutnya. , , , ( 1100 ). — , . , . , , , !


, . , , . " 8 ".

Source: https://habr.com/ru/post/id485372/


All Articles