Codémon, aku memilihmu!


55

Tetangga Anda yang baik hati, Dokter Pohon, baru saja memberi Anda tiga makhluk ajaib yang disebut Codémon. Ada turnamen pertempuran di kota Colorville terdekat. Apakah Anda yang terbaik, seperti tidak ada yang pernah ada?

Gambaran

Ini adalah turnamen pertempuran. Setiap pemain mengendalikan tim yang terdiri dari tiga monster, dan tujuannya adalah untuk melumpuhkan (membunuh) tim lainnya. Ada 100 ronde, dengan poin diberikan untuk kemenangan dan dasi. Tim dengan poin terbanyak menang!

Monster

Codémon adalah makhluk kecil yang rumit. Ada lima jenis (elemen) untuk dipilih, tiga statistik, dan tiga slot gerak di masing-masing.

Jenis

Setiap Codémon ditugaskan satu jenis. Lima jenis itu adalah Normal, Psikis, Api, Air, dan Rumput. Masing-masing memiliki kekuatan dan kelemahannya. Kerusakan didasarkan pada grafik berikut:

jenis-bagan

Angka-angka adalah pengganda kerusakan. Misalnya, Fire attacking Water memiliki 0,5 modifier (setengah kerusakan), sedangkan Fire attacking Grass dua kali lipat (2).

Statistik

Setiap monster memiliki tiga statistik yang menentukan kemampuan bertarungnya. Serangan meningkatkan kerusakan yang terjadi. Pertahanan menurunkan kerusakan yang terjadi. Kecepatan memungkinkannya bergerak di depan mereka yang memiliki Kecepatan lebih rendah.

Setiap monster memiliki nilai awal 50 untuk setiap stat, dan maksimum 100. Saat Anda membuat monster, Anda akan dapat menetapkan 80 poin stat tambahan (masing-masing). Ingatlah bahwa tidak ada stat individual yang dapat melebihi 100. Jadi, Anda dapat memiliki distribusi 100/80/50, 90/80/60, atau 65/65/100, tetapi 120/50/60 ilegal. Setiap tim dengan statistik ilegal didiskualifikasi. Anda tidak diharuskan untuk menggunakan semua 80 poin, tetapi Anda mungkin tidak harus pergi dengan minimum 50/50/50.

Anda juga dapat mempertimbangkan HP sebagai stat, tetapi setiap Codémon memiliki 100 HP yang tidak dapat dimodifikasi. Ketika HP turun ke nol, mereka tidak dapat melanjutkan pertempuran. HP diisi ulang hingga 100 sebelum setiap pertempuran.

Bergerak

Setiap monster tahu tiga gerakan pertempuran. Tiga yang dipilih harus berbeda, jadi tidak ada Punch / Punch / Punch.

Ada 15 gerakan, tiga dari setiap jenis. Setiap jenis memiliki serangan langsung, serangan lebih lemah dengan efek, dan efek bergerak tunggal.

id  name        type    power   uses    usable  effect

0   Punch       N       20      -       NFWG
1   Heal        N        0      3       NFWG    Heals 50 HP
2   Slow        N       10      5       NFWG    Enemy speed x0.8
3   Pain        P       20      -       PFWG
4   Sleep       P        0      3       PFWG    No enemy action until wake
5   Weaken      P       10      5       PFWG    Enemy Atk x0.8
6   Fireball    F       20      -       NPFW
7   Burn        F        0      3       NPFW    Enemy -10 HP each turn
8   Sharpen     F       10      5       NPFW    Own Atk x1.25
9   Watergun    W       20      -       NPWG    
10  Confuse     W        0      3       NPWG    Enemy may strike itself (10 power)
11  Shield      W       10      5       NPWG    Own Def x1.25
12  Vine        G       20      -       NPFG
13  Poison      G        0      3       NPFG    Enemy -5xTurns HP each turn
14  Sap         G       10      5       NPFG    Enemy Def x0.8

typemengacu pada jenis langkah. poweradalah kekuatannya yang mencolok. usesmenunjukkan berapa kali dapat digunakan per pertempuran ( -tidak terbatas). usablemenunjukkan jenis apa yang dapat digunakan oleh (misalnya, Punch tidak dapat diberikan ke jenis Psikis, karena tidak ada P). effectmenunjukkan efek apa yang dimiliki oleh gerakan. Ada kemungkinan 75% dari setiap efek bekerja, kecuali Heal, yang selalu berhasil.

Untuk efek yang mengubah statistik monster, efek dapat ditumpuk . Misalnya, menggunakan Weaken dua kali dapat menurunkan serangan lawan menjadi 0,64 efektivitas. Efek yang tidak mengubah statistik monster (Sleep, Burn, dll) tidak menumpuk .

Tidur membuat lawan tertidur, dengan kemungkinan 60% terbangun di awal setiap belokan. Tidak ada tindakan yang akan dilakukan oleh monster yang tidur.

Membakar merusak 10 HP lawan di akhir setiap belokan saat aktif . Racun bekerja dengan cara yang sama, tetapi mengambil jumlah yang meningkat setiap belokan. Pada belokan pertama, ini 5, dan mendapat 5 setiap belokan sesudahnya. Jadi, pada giliran keempat, itu akan merusak untuk 20. Ini adalah kerusakan datar, tidak terpengaruh oleh tipe monster atau dikenakan bonus.

Kebingungan dapat membuat monster menyerang dirinya sendiri daripada melakukan apa yang diperintahkan untuk dilakukan. Serangan ini memiliki kekuatan 10, dan memiliki peluang 30% terjadi pada giliran yang diberikan.

Agar jelas, efek bertahan hingga akhir pertempuran (kecuali Tidur, seperti disebutkan di atas).

Bergerak juga menerima 20% peningkatan kekuatan jika digunakan oleh monster dari tipe yang sesuai. Misalnya, monster Grass menggunakan Vine ditingkatkan, saat menggunakan Punch dia tidak.

Statistik Rahasia

Statistik dan tipe (tetapi tidak bergerak) dari setiap monster adalah pengetahuan umum. Lawan Anda akan dapat melihat apa yang mereka lawan, untuk memilih tindakan terbaik. Namun, ada juga bonus yang tersedia yang disembunyikan.

Khususnya, setelah setiap dua pertempuran, Anda akan diberikan satu poin status "bonus" untuk setiap monster di tim Anda. Poin diberikan kepada semua monster, hidup atau mati, pemenang atau pecundang. Anda dapat menetapkan ini ke salah satu dari tiga statistik yang Anda pilih. Anda tidak dapat menumpuknya di satu monster; setiap monster mendapat satu setiap kali. Poin-poin ini kebal terhadap batas 100. Karena akan ada 100 ronde pertempuran, ini berarti Anda bisa mendapatkan satu stat hingga 149 jika Anda membagikan semua bonus Anda untuk itu. Sekali lagi, lawan hanya akan melihat statistik "basis" Anda, jadi semakin jauh ke dalam turnamen Anda, semakin jauh pengetahuan mereka menyimpang dari kebenaran.

Pertarungan

Pertempuran terjadi antara tim tiga, dengan satu aktif di masing-masing tim sekaligus. Pada awalnya, Anda akan ditunjukkan tim lawan dan diminta untuk memilih monster mana yang akan menjadi pemain "aktif" pertama Anda.

Setelah itu, belokan dilakukan dengan langkah-langkah berikut:

  • Switch: Switch monster wajib berlangsung (jika ada)
  • Pilih aksi pertempuran
  • Switch: Setiap switch monster opsional (dipilih sebagai aksi pertempuran) berlangsung
  • Pemeriksaan Tidur: Peluang untuk bangun dari tidur
  • Serangan 1: Jika mampu, monster yang lebih cepat menggunakan gerakan yang dipilihnya
  • Serangan 2: Jika bisa, monster lain menggunakan gerakan yang dipilihnya
  • Efek kerusakan: Berikan kerusakan luka bakar / racun pada monster hidup

"Speedier" berarti monster dengan kecepatan lebih tinggi. Jika kedua statistik kecepatan sama, itu dipilih oleh PRNG coin flip setiap belokan.

Di akhir setiap giliran di mana monster aktif Anda mati, Anda akan diminta untuk memilih yang baru aktif. Anda juga dapat memilih untuk mengganti monster aktif sebagai gerakan Anda untuk setiap belokan (asalkan Anda memiliki lebih dari satu yang hidup). Sekali lagi, jika Anda beralih sebagai gerakan Anda, Anda tidak akan membuat gerakan pertempuran yang berubah.

Monster tidak "diproses" saat tidak aktif. Ini berarti mereka tidak mengambil luka bakar / kerusakan racun, penghitung racun tidak akan menumpuk, tidak bangun dari tidur, dll. Tidak ada efek yang dihapus atau diubah ketika beralih . Ini bukan game pertarungan monster lainnya . Jika Anda beralih dengan serangan yang dibesarkan dan dibakar, mereka akan tetap ada ketika Anda kembali.

Efek damage terjadi baik Anda membunuh lawan aktif Anda atau tidak. Dengan cara ini, anggota dari kedua tim dapat mati dalam satu giliran.

Ketika satu tim kehabisan monster yang dapat digunakan, mereka kalah. Jika kedua tim kehabisan pada gilirannya yang sama, itu seri. Jika pertempuran berlangsung selama 1000 putaran, itu seri.

Formula untuk menentukan kerusakan adalah:

floor((effAttack / effDefense) * movePower * typeMultiplier * moveBoost)

effAttackdan effDefenseadalah efektif statistik untuk monster. Serangan efektif diperoleh dengan menambahkan Serangan dan Serangan Bonus, kemudian mengalikan (dengan 0,8 atau 1,25) jika ada efek mengubahnya. Ingatlah bahwa efek ini dapat ditumpuk.

Kerusakan hanya dapat 0 ketika pengubah tipe adalah 0 (Normal <--> Psikis) atau Kekuatan gerakan adalah 0 (Sembuhkan, Bakar, dll). Kalau tidak, minimum diberlakukan pada 1.

Turnamen

Turnamen berlangsung selama 100 putaran. Di setiap babak, tim dikocok dan dipasangkan satu sama lain secara acak. Jika ada jumlah tim yang ganjil, sisanya menerima bye (skor sebagai seri). Memenangkan pertempuran menghasilkan tim 2 poin, ikatan bernilai 1 , dan tidak kehilangan apa pun. Tim dengan poin terbanyak di akhir menang!

Jika tim terikat, turnamen dengan hanya tim yang terikat untuk tempat pertama akan dilakukan untuk menentukan urutan tiebreak.

Protokol

Pengontrol akan mengirimkan program Anda satu dari empat perintah. Karakter pertama menentukan jenis perintah, dengan data berikut jika perlu.

Program Anda akan menerima perintah sebagai argumen, dan akan merespons pada STDOUT dalam satu detik . Jangan tetap hidup mendengarkan STDIN, itu tidak akan ada di sana. Setiap perintah akan menghasilkan proses baru.

Anda dapat menulis data / status ke disk. Tempatkan file apa pun dalam subfolder dengan nama yang sama dengan tim Anda. Jangan menulis lebih dari 32 kilobyte data, atau Anda akan didiskualifikasi. Data akan bertahan di antara babak, tetapi akan dihapus di antara turnamen.

Perintah

Data Tim

Ini dikirim sekali pada awal turnamen untuk mendaftarkan tim Anda. Balasan Anda harus konstan , tidak berbeda untuk setiap turnamen.

Pertanyaan:

T

Tanggapan:

name|member0|member1|member2

nameadalah string dengan nama tim Anda. Harap gunakan hanya alfanumerik, untuk kemudahan parsing. memberNadalah string anggota, yang memberikan detail setiap monster:

String anggota:

name:typeid:attack:defense:speed:moveid0:moveid1:moveid2

Sekali lagi, 'nama' adalah string, kali ini dengan nama monster ini. typeidadalah tipenya. Id jenis berada dalam urutan yang ditunjukkan pada bagan di atas, dengan Normal = 0 dan Rumput = 4.

Tiga bidang berikutnya adalah statistik dasar Anda. Ingat batas yang dijelaskan di bagian statistik di atas.

Tiga yang terakhir adalah gerakan monster Anda. ID ditunjukkan pada diagram langkah di atas.

Contoh balasan data tim mungkin terlihat seperti ini:

DummyTeam|DummyA:0:50:60:70:0:1:2|DummyB:0:50:60:70:0:1:2|DummyC:0:50:60:70:0:1:2

Tim mana pun yang mengirim kembali sampah, format tidak benar, atau data ilegal di sini tidak akan berpartisipasi sebelum diperbaiki.

Pilih Aktif

Ini dikirim pada awal setiap pertempuran, dan ketika monster mati dan perlu diganti.

Pertanyaan:

C#battleState

battleStatemenunjukkan keadaan pertempuran saat ini. Bersabarlah dengan saya di sini, ini jelek:

yourTeamState#theirTeamState

Di mana XteamStateterlihat seperti:

name:activeSlot|member0state|member1state|member2state

activeSlotmenunjukkan monster mana yang sedang aktif (0-2). Negara-negara anggota datang dalam dua rasa. Jika itu tim Anda , itu memberikan informasi tambahan. Begitu,

Status member Anda :

name:id:attack:defense:speed:hp:typeid:poisonedturns:moveCount0:moveCount1:moveCount2:bonusAttack:bonusDefense:bonusSpeed:effectid:effectid:effectid

MemberXstate mereka :

name:id:attack:defense:speed:hp:typeid:poisonedturns:effectid:effectid:effectid

idhanyalah pengenal integer yang dapat Anda gunakan untuk melacak monster jika Anda tidak suka menggunakannya name.

attack:defense:speedadalah statistik dasar Anda .

poisonedturns memberi tahu Anda berapa banyak belokan yang telah diracuni.

moveCountXmemberi tahu berapa banyak kegunaan yang tersisa untuk setiap gerakan. Jika 0, itu tidak dapat digunakan. Untuk gerakan tanpa batas, ini akan menjadi negatif.

bonus(stat) adalah jumlah poin bonus yang telah Anda tetapkan untuk setiap stat.

effectidadalah daftar efek berukuran variabel yang telah diterapkan pada monster Anda. Ada akan tidak menjadi trailing :pada string, apakah ada efek yang aktif hadir atau tidak. Jika ada efek bertumpuk, mereka akan muncul sebagai beberapa efek dalam daftar.

Id efeknya adalah:

0  NONE           (should not appear, internal use)
1  POISON
2  CONFUSION 
3  BURN 
4  SLEEP 
5  HEAL           (should not appear, internal use)
6  ATTACK_UP
7  ATTACK_DOWN
8  DEFENSE_UP
9  DEFENSE_DOWN
10 SPEED_DOWN

Tanggapan:

memberSlot

Satu-satunya respons yang diperlukan adalah nomor tunggal 0,1,2, yang memberi tahu anggota mana yang ingin Anda aktifkan. Ini harus menjadi anggota yang mampu bertarung. Jangan kirim kembali 1jika anggota 1 sudah mati.

Aksi Pertempuran

Setiap belokan, Anda harus memutuskan apa yang harus dilakukan.

Pertanyaan:

A#battleState

Di battleStatesini persis seperti yang dijelaskan di atas.

Tanggapan:

Untuk menggunakan gerakan, kirim kembali slot yang digunakan. Misalnya, jika saya menetapkan Punch ke slot 0, mengirim 0melakukan Punch.

Untuk beralih ke anggota lain, kirim slot anggota plus sepuluh . Jadi untuk beralih ke anggota 2, kirim 12.

Apa pun yang tidak dalam [0,1,2,10,11,12] dianggap tidak valid dan tidak akan melakukan tindakan apa pun dalam belokan ini.

Statistik Bonus

Setelah setiap dua pertempuran, Anda menerima poin bonus rahasia untuk setiap anggota tim.

Pertanyaan:

B#yourTeamState

Status tim Anda sama seperti yang ditunjukkan di atas, jangan buat saya mengulanginya.

Tanggapan:

stat0:stat1:stat2

Respons Anda akan menunjukkan status apa yang harus ditingkatkan untuk setiap anggota tim. Serangan 0, Pertahanan 1, Kecepatan 2.

Jadi untuk meningkatkan kecepatan anggota, serangan anggota dua, dan pertahanan anggota tiga, Anda akan merespons dengan:

2:0:1

Pengendali

Pengontrol dapat ditemukan di BitBucket: https: //Geobits@bitbucket.org/Geobits/codemon.git

Lemparkan saja semua file kelas yang dikompilasi, pengiriman, dan players.conf ke dalam folder dan jalankan.

Kelas utama pengendali disebut Tournament. Penggunaannya adalah:

java Tournament [LOG_LEVEL]

Level log dari 0-4 memberikan peningkatan informasi. Level 0 menjalankan turnamen secara diam-diam dan hanya memberikan hasilnya, di mana level 3 memberikan komentar bergantian. Level 4 adalah output debug.

Anda dapat menambahkan kiriman ke turnamen di players.confCukup tambahkan string baris perintah yang diperlukan untuk menjalankan program, satu per baris. Baris yang dimulai dengan #adalah komentar.

Dalam posting Anda, sertakan perintah yang perlu saya tambahkan ke saya players.conf, dan setiap langkah kompilasi (jika diperlukan).

Termasuk adalah tim dummy yang terdiri dari semua anggota Normal dengan tiga gerakan Normal. Mereka memilih bergerak secara acak dan memiliki statistik mengerikan. Bersenang-senang mengalahkan mereka.

Aturan Lain-lain

  • Anda tidak boleh membaca atau menulis ke sumber daya eksternal apa pun (kecuali dalam subfolder Anda sendiri, hingga 32 kB seperti disebutkan di atas).

  • Tim Anda harus masuk ke turnamen "buta". Itu berarti Anda tidak dapat menganalisis sumber orang lain untuk mengetahui apa yang akan dilakukan tim / monster tertentu dalam situasi tertentu. Anda dapat menganalisis pergerakan / statistik lawan dan terus mengikuti perkembangan turnamen, tetapi tidak ada hardcoding informasi ini di.

  • Jangan mengganggu proses / pengajuan lainnya. Tidak meminta mereka, menggunakan refleksi untuk mendapatkan data mereka, dll. Jangan main-main dengan komputer saya. Hanya saja, jangan mencobanya. Ini adalah kebijaksanaan saya. Pelanggar dapat dilarang masuk di masa depan.

  • Kontestan dibatasi hingga maksimal dua entri. Jika Anda mengirim lebih banyak, saya hanya akan mencetak dua yang pertama dikirimkan. Jika Anda ingin mencabut satu, hapus itu.

  • Entri mungkin tidak ada hanya untuk menopang entri lain. Juga, Anda tidak boleh mencoba mendiskualifikasi kontestan lain secara tidak langsung (misalnya, menggunakan nama tim karakter 27M untuk pemain DQ yang mencoba menulis ini ke disk). Setiap kiriman harus dimainkan untuk menang berdasarkan kemampuannya sendiri.

  • Program Anda dapat menghasilkan maksimum satu proses anak pada satu waktu (total keturunan, tidak langsung). Baik proses anak utama dan apa saja harus diakhiri secara langsung setelah memberikan hasil. Either way, pastikan Anda tidak melewati batas waktu.

  • Turnamen akan diadakan di komputer saya yang menjalankan Ubuntu dengan prosesor Intel i7 3770K.

Hasil

Ini adalah hasil dari pemain saat ini. Ini sangat dekat di antara para pesaing utama, dan saya berpikir tentang menabrak jumlah putaran hingga 500 (dan menyesuaikan jarak poin bonus untuk mencocokkan). Ada keberatan, komentar?

------- Final Results -------

158     Happy3Campers
157     LittleKid
71      InsideYourHead
68      HardenedTrio
46      BitterRivals

Hasil play-by-play penuh di Google Drive


62
Saya ingin menjadi yang terbaik / Seperti tidak pernah ada kode / Untuk tidak crash adalah pengujian saya / Untuk men-debug adalah penyebab saya! / Saya akan melakukan perjalanan melintasi LAN / Scripting jauh dan luas / Berusaha keras untuk memahami / Mengapa BIOS saya digoreng! / Codémon, ini kau dan aku / Golf bisa melihat semua mata / Codémon, kau sahabatku / Setelah program berakhir! / Codémon, bahasa yang sangat benar / Tidak ada kesalahan akan menarik kita melalui / Anda mengajar saya dan saya akan mengajar Anda / Codémon, harus bermain golf semua!
Kaz Wolfe

1
Alih-alih meningkatkan putaran menjadi 500, akan lebih baik jika satu putaran terdiri dari semua orang yang bertarung dengan semua orang. Jadi tidak ada lagi byeuntuk jumlah pesaing yang tidak merata dan akan dipastikan bahwa pasangan pertandingan adil dan merata.
foobar

@foobar Saya ingin menghindari itu karena skala pertempuran dengan n^2bukan n. Dengan hanya 7 pesaing saat ini dan 100 putaran, itu adalah 2100 pertempuran (vs 300 apa adanya, dan 1500 dengan 500 putaran). Itu hanya menjadi lebih buruk karena lebih banyak entri yang masuk. Saya dapat mengurangi # putaran, tetapi saya ragu untuk melakukannya karena variabilitas yang melekat (mengenai status esp), dan memiliki kelipatan 50 (untuk poin bonus) lebih mudah.
Geobits

Tidakkah tantangan ini membutuhkan pembaruan? :)
GholGoth21

@ GholGoth21 Ya, saya yakin begitu. Saya mungkin tidak bisa melakukannya hari ini, tapi mungkin besok atau lusa. Ping saya dalam obrolan jika tidak diperbarui pada hari Kamis atau lebih jika Anda mau.
Geobits

Jawaban:


16

Selamat 3 berkemah - PHP

Sekelompok pengecut yang suka melempari lawan dengan mantra melemahkan dan menonton mereka membusuk.

EDIT : Mr. Lumpy telah dihukum berat dan tidak akan mengatakan kata-kata buruk lagi


BergunaBergunaGrass - atk:50 def:99 spd:81 Confuse Poison Heal

Berang-berang tanpa senjata berbisa yang suka membingungkan orang-orang dengan jabat tangan bermasalah


FlippyFlippyWater - atk:50 def:99 spd:81 Confuse Burn Heal

Seorang veteran papan buletin dengan titik lemah untuk pembicaraan membosankan dan perang api.


PedasPedasFire - atk:50 def:99 spd:81 Burn Poison Heal

Senjata pemusnah massal adalah permen favoritnya.


KentalKentalPhp - lines:500 clarity:05 spd:01 Gather Guess Store

Berkat IQ 2 digit dan memori fenomenalnya yang hampir, Lumpy dapat menebak pergerakan musuh. Yah, kebanyakan.


Strategi

Strateginya adalah membuat musuh diracuni, dibakar, dan dikacaukan sesegera mungkin.
Tidur tidak digunakan karena sepertinya kurang kuat daripada 3 mantra di atas.
Dalam jangka panjang, kebingungan akan mematikan, karena mengurangi serangan hingga 30% (baik Damage Damage dan Spell Casting), mencegah healer dari menyembuhkan diri mereka sendiri dan membahayakan pemukul berat parah (50 def / 100 atk monster akan memberikan 20 poin kerusakan pada dirinya sendiri. ).

Setelah musuh disisipkan dengan seksama, berkemah saya hanya melihatnya mendesis, membusuk dan meninju dirinya sendiri sampai mati.

Pertahanan dan penyembuhan tinggi digunakan untuk mengurangi kerusakan yang masuk selama penderitaan.

Sementara 3 kemahku bertarung, Lumpy the magic deer mengawasi musuh setiap gerakan, dan terkadang berhasil mengidentifikasi mereka. Informasi tersebut diumpankan kembali ke para pejuang kami, yang melakukan yang terbaik untuk memanfaatkannya.

Setelah pertahanan, kecepatan adalah stat yang paling penting untuk ditingkatkan.
Inisiatif sangat penting untuk menerapkan penyembuhan sebelum pukulan berikutnya datang.

Serangan tidak digunakan sama sekali.

Apakah mantra senjata pamungkas?

Mantra seperti racun, terbakar, dan bingung lolos dari logika batu / kertas / gunting keseluruhan dari serangan lain.

Setelah monster terpengaruh, ia akan terus kehilangan HP bahkan setelah perapal mantra mati. Seolah hantu kastor terus menyerangnya.
Selain itu, racun menjadi cepat lebih kuat daripada serangan besar-besaran penuh (di atas 50 poin setelah 5 putaran).

Harapan hidup monster beracun dan terbakar tidak melampaui 8 putaran, bahkan dengan 3 penyembuhan.

Seperti yang ditunjukkan oleh bot Martin , keseimbangan gim ini cukup bagus.
Ini pada dasarnya inisiatif yang akan memberi keseimbangan antara perapal mantra murni dan penyerang murni.

Kode

Ajak dengan php campers.php

Ini adalah kekacauan yang jelek, tetapi terus terang antarmuka tidak membantu.

Sekarang setelah kompetisi yang agresif muncul, saya menerapkan tebakan musuh yang telah lama direncanakan.
Menganalisis serangan membutuhkan berbagai pemotongan aerobatik dan penyimpanan terus-menerus dari keadaan belokan terakhir, yang berarti perang skala penuh dengan antarmuka pengontrol paranoid.
Itu juga bukan barang yang cantik dan tidak ada jackrabbit berkaki enam, tapi itu pekerjaan yang memadai.

<?php

// ============================================================================
// Game
// ============================================================================
class G {
    static $code_type = array ("Normal", "Psychic", "Fire", "Water", "Grass", "?", "self"); 
    static $code_move = array    ("Punch", "Heal", "Slow", "Pain", "Sleep", "Weaken", "Fireball", "Burn", "Sharpen", "Watergun", "Confuse", "Shield", "Vine", "Poison", "Sap", "?", "self", "pass");
    static $move_uses = array (1000,3,5,1000,3,5,1000,3,5,1000,3,5,1000,3,5,   2000,2000);
    static $move_type      = array (0,0,0,1,1,1,2,2,2,3,3,3,4,4,4, 5,5,5);
    static $move_dmg       = array (20,0,10,20,0,10,20,0,10,20,0,10,20,0,10,  20,10,0);
    static $move_forbidden = array (1,1,1,0,0,0,4,4,4,2,2,2,3,3,3);
    static $code_effect = array ("N", "Poison", "Confuse", "Burn", "Sleep", "H", "Sharpen", "Weaken", "Shield", "Sap", "Slow"); 
    static $decode_type, $decode_move, $decode_effect;
    static $damage_multiplier = array (
        array (2, 0, 1, 1, 1, 0),
        array (0, 2, 1, 1, 1, 0),
        array (1, 1,.5, 2,.5, 0),
        array (1, 1,.5,.5, 2, 0),
        array (1, 1, 2,.5,.5, 0),
        array (2, 2, 2, 2, 2,-1),
        array (9, 9, 9, 9, 9, 9, 1));
    static $atk_score = array ("Poison"=> 1002, "Confuse"=>1001, "Burn"=>1000);
    static $status_field = "atk:def:spd:hp:type:Pturns";
    static $all_moves, $strong_moves, $medium_moves, $effect_moves, $possible_moves;

    function init()
    {
        self::$status_field = explode (":", self::$status_field);
        foreach (array ("type", "move", "effect") as $table) self::${"decode_$table"} = array_flip (self::${"code_$table"});
        foreach (self::$code_move as $c=>$m)
        {
            if ($m == "?") break;
            self::$all_moves[] = new Move($m);
            if (self::$move_uses[$c] >  5) self::$strong_moves[] = $m;
            if (self::$move_uses[$c] == 5) self::$medium_moves[] = $m;
            if (self::$move_uses[$c] == 3) self::$effect_moves[] = $m;
            for ($type = 0 ; $type != 5 ; $type++) if ((self::$move_uses[$c] >  5) && (self::$move_forbidden[$c] != $type)) self::$possible_moves[$type][] = $m;
        }
    }

    function __construct ($name, $team)
    {
        $this->turn = 0;
        $this->name = $name;
        $this->team = $team;
        $this->results_pending = false;
    }

    function parse_team ($tpack, $own_team)
    {
        $pack = explode ("|", $tpack);
        list ($name,$active) = explode (":", array_shift($pack));
        if ($own_team)
        {
            $team = $this->team;
        }
        else
        {
            if (!isset($this->enemies[$name])) $this->enemies[$name] = new Team(array (new Monster (), new Monster (), new Monster ()));
            $team = $this->foes = $this->enemies[$name];
        }
        $team->active = $active;
        foreach ($pack as $i=>$mpack) $team->monster[$i]->parse_monster ($own_team, $mpack);
    }

    function choose_active ()
    {
        // detect start of round
        $team = $this->team;
        $foes = $this->foes;
        foreach ($team->monster as $i=>$m) if ($m->hp > 0) $candidate[$i] = $m;
        if (count ($candidate) == 3)
        {
            $this->results_pending = false;
            $this->round++;

            // reinitialize all monsters
            foreach (array($team, $foes) as $t)
            foreach ($t->monster as $m)
                $m->start_round();

            // guess initial opponent
            $opponent = $foes->initial_opponent();
        }
        else
        {
            $this->analyze_last_round();
            $opponent = $foes->active();
        }
        return $this->do_switch ($opponent);
    }

    function choose_attacker ($foe)
    {
        foreach ($this->team->monster as $i=>$m) if ($m->can_attack($foe)) $candidate[$i] = $m;
        if (isset($candidate))
        {
            uasort ($candidate, function ($a,$b) use ($foe) { return ($a->atk_score != $b->atk_score) ? $b->atk_score - $a->atk_score : $b->life_expectancy($foe) - $a->life_expectancy($foe); });
            return key($candidate);
        }
        return -1;
    }

    function do_switch ($foe)
    {
        $replacement = $this->choose_attacker ($foe);
        if ($replacement < 0)
        {
            $candidate =  $this->team->monster;
            uasort ($candidate, function ($a,$b) use ($foe) { return $b->life_expectancy($foe) - $a->life_expectancy($foe); });
            $replacement = key($candidate);
        }

        $this->old_own = $this->team->monster[$replacement];
        $this->old_own->attack = "pass";
        return $replacement;
    }

    function choose_action ()
    {
        $this->analyze_last_round();
        $own = $this->team->active();
        $foe = $this->foes->active();
        $this->old_own = $own;

        if ($own->hp <= $own->max_damage($foe) && $own->can_do ("Heal")) return $own->execute("Heal");
        if ($attack = $own->can_attack($foe)) return $own->execute($attack);
        if ($own->hp <= 50 && $own->can_do ("Heal")) return $own->execute("Heal");

        return 10 + $this->do_switch ($foe);    
    }

    function choose_bonus()
    {
        foreach ($this->team->monster as $m)
        {
            if ($m->spd_b == 0) { $m->spd_b++; $res[] = 2; }
            else                { $m->def_b++; $res[] = 1; }
        }
        return implode (":", $res);
    }

    function parse ($parts)
    {
        self::parse_team ($parts[1], true);
        self::parse_team ($parts[2], false);    
    }

    function analyze_last_round()
    {
        if ($this->results_pending)
        {
            $this->results_pending = false;

            $foes = $this->foes;
            $foe = null;
            foreach ($foes->monster as $m) if ($m->hp != $m->old->hp) $foe = $m;
            if ($foe === null) $foe = $foes->monster[$foes->active];

            $this->old_own->guess_attack($foe);
        }
    }

    function process ($line)
    {
        $parts = explode ("#", $line);
        switch ($parts[0])
        {
        case "T": // register for tournament
            echo "$this->name|$this->team";
            break;
        case "C": // designate active monster
            $this->parse ($parts);
            echo $this->choose_active();
            break;
        case "A": // choose round action
            $this->parse ($parts);
            echo $this->choose_action();

            // save current state
            foreach (array($this->team, $this->foes) as $t)
            foreach ($t->monster as $m)
            {
                unset ($m->old);
                $m->old = clone ($m);
            }
            $this->results_pending = true;
            break;
        case "B": // distribute stat bonus
            echo $this->choose_bonus();
            break;
        }

    }
}
G::init();

// ============================================================================
// Move
// ============================================================================
class Move {
    function __construct ($move)
    {
        $this->register($move);
    }

    function register ($move)
    {
        $this->type = G::$decode_move[$move];
        $this->reinit();
    }

    function reinit()
    {
        $this->uses = G::$move_uses[$this->type];
    }

    function __tostring() { return G::$code_move[$this->type]."($this->uses)"; }
}

// ============================================================================
// Monster
// ============================================================================
class Monster { 
    function __construct ($name="?", $type="?", $atk=100, $def=100, $spd=100, $m0="?", $m1="?", $m2="?")
    {
        $this->name = $name;
        $this->type = G::$decode_type[$type];
        $this->atk  = $atk;
        $this->def  = $def;
        $this->spd  = $spd;
        $this->hp   = 100;
        $this->move = array (new Move($m0), new Move($m1), new Move($m2));
        $this->atk_b = 0;
        $this->def_b = 0;
        $this->spd_b = 0;
        foreach (G::$code_effect as $e) $this->$e = 0;
    }

    function __tostring ()
    {
        return implode (":", array (
            $this->name,
            $this->type,
            $this->atk,
            $this->def,
            $this->spd,
            $this->move[0]->type,
            $this->move[1]->type,
            $this->move[2]->type));
    }

    function start_round()
    {
        foreach ($this->move as $m) $m->reinit();
    }

    function parse_monster ($own_team, $spack)
    {
        $pack = explode (":", $spack);
        $name = array_shift ($pack); // get name
        array_shift ($pack); // skip id
        if ($this->name == "?") $this->name = $name; // get paranoid
        else if ($this->name != $name) die ("expected $this->name, got $name");

        // store updated values
        foreach (G::$status_field as $var) $this->$var = array_shift ($pack);
        if ($own_team)
        {
            foreach ($this->move as $m) $m->new_count = array_shift($pack);
            $pack = array_slice ($pack, 3); // these are maintained internally
        }
        $var = array();
        foreach ($pack as $e) @$var[G::$code_effect[$e]]++; 
        foreach (G::$code_effect as $e) $this->$e = @$var[$e]+0;
    }

    function damage_recieved ($attack, $foe=null)
    {
        if ($attack == "self") $foe = $this;
        $a = G::$decode_move[$attack];
        $type = G::$move_type[$a];
        $dmg = g::$move_dmg[$a];

        if ($dmg == 0) return 0;

        $atk = ($foe ->atk+$foe ->atk_b) * pow (.8, ($foe ->Weaken - $foe ->Sharpen));
        $def = ($this->def+$this->def_b) * pow (.8, ($this->Sap    - $this->Shield ));

        $boost = ($foe->type == $type) ? 1.2 : 1;
        return max (floor ($dmg * $atk / $def * $boost * G::$damage_multiplier[$this->type][$type]), 1);
    }

    function guess_attack_from_effect ($attacks)
    {
        foreach ($attacks as $status) if ($this->$status != $this->old->$status) return $status;
        return "?";
    }

    function guess_attack_from_damage ($foe, $damages)
    {
        $select = array();
        foreach (G::$possible_moves[$foe->type] as $attack)
        {
            $dmg = $this->damage_recieved ($attack, $foe);
            foreach ($damages as $damage) if ($damage != 0 && abs ($dmg/$damage-1) < 0.1) $select[$attack] = 1;
        }
        $res = array();
        foreach ($select as $a=>$x) $res[] = $a;
        return $res;
    }

    function guess_attack ($foe)
    {
        $attempt = G::$decode_move[$this->old->attack];
        $success = ($this->old->attack == "pass");
        foreach ($this->move as $m)
        {
            if ($m->type == $attempt)
            {
                if ($m->new_count == $m->uses-1)
                {
                    $m->uses--;
                    $success = true;
                }
                break;
            }
        }

        $possible = array();
        $attack = $this->guess_attack_from_effect (array("Burn", "Confuse", "Poison", "Sleep", "Slow", "Weaken", "Sap"));
        if ($attack == "?") $attack = $foe->guess_attack_from_effect (array("Sharpen", "Shield"));
        if ($attack == "?")
        {
            $foe_damage = $this->old->hp - $this->hp - (10 * $this->Burn + 5 * $this->Pturns*$this->Poison);
            if ($this->old->attack == "Heal" && $success) $foe_damage += 50;
            $possible_dmg[] = $foe_damage;
            //;!;if ($this->Confuse) $possible_dmg[] = $foe_damage + $this->damage_recieved ("self");
            $possible = $this->guess_attack_from_damage ($foe, $possible_dmg);
            if (count ($possible) == 1) $attack = $possible[0];
        }
        if ($attack == "?")
        {
            $own_damage = $foe->old->hp - $foe->hp 
                        - (10 * $foe->Burn + 5 * $foe->Pturns*$foe->Poison)
                        + $foe->damage_recieved ($this->attack);
            if (abs ($own_damage/50+1) < 0.1) $attack = "Heal";
        }
        if ($attack != "?")
        {
            $type = G::$decode_move[$attack];
            if ($attack != "?")
            {
                foreach ($foe->move as $m) if ($m->type == $type) goto found_old;
                foreach ($foe->move as $m) if ($m->type == 15) { $m->register($attack); goto found_new; }
            }
            found_new:
            found_old:
        }
    }

    function max_damage($foe)
    {
        $dmg = 0;
        foreach ($foe->move as $m) $dmg = max ($dmg, $this->damage_recieved (G::$code_move[$m->type], $foe));
        return $dmg;
    }

    function expected_damage ($foe)
    {
        return $this->max_damage($foe) + 10 * $this->Burn + 5 * ($this->Pturns+1);
    }

    function life_expectancy ($foe)
    {
        $hp = $this->hp;
        $poison = $this->Pturns;
        $heal = $this->can_do ("Heal");
        $dmg = $this->max_damage($foe);
        for ($turn = 0 ; $hp > 0 && $turn < 10; $turn++)
        {
            $hp -= 10 * $this->Burn + 5 * $poison;
            if ($poison > 0) $poison++;
            $hp -= $dmg;
            if ($hp <= 0 && $heal > 0) { $hp+=50; $heal--; }
        }
        return 100 * $turn + $this->hp;
    }

    function can_attack ($foe)
    {
        $attack = false;
        if ($this->hp > 0)
        {
            if      (!$foe->Poison  && $this->can_do ("Poison" )) $attack = "Poison";
            else if (!$foe->Confuse && $this->can_do ("Confuse")) $attack = "Confuse";
            else if (!$foe->Burn    && $this->can_do ("Burn"   )) $attack = "Burn";
        }
        $this->atk_score = ($attack === false) ? 0 : G::$atk_score[$attack];
        return $attack;
    }

    function can_do($move)
    {
        $type = G::$decode_move[$move];
        foreach ($this->move as $m) if ($m->type == $type && $m->uses > 0) return $m->uses;
        return false;
    }

    function execute($move)
    {
        $type = G::$decode_move[$move];
        foreach ($this->move as $i=>$m) if ($m->type == $type) 
        { 
            if ($m->uses > 0)
            {
//;!;               $m->uses--;
                $this->attack = $move;
            }
            else $this->attack = "pass";
            return $i; 
        }
        die ("$this asked to perform $move, available ".implode(",", $this->move));
    }
}

// ============================================================================
// Team
// ============================================================================
class Team {
    function __construct ($members)
    {
        $this->monster = $members;
    }

    function __tostring()
    {
        return implode ("|", $this->monster);
    }

    function active ()
    {
        return $this->monster[$this->active];
    }

    function initial_opponent()
    {
        return $this->monster[0];
    }
}

// ============================================================================
// main
// ============================================================================
$input = $argv[1];

$team_name = "H3C";
$mem_file = "$team_name/memory.txt";
$trc_file = "$team_name/trace.txt";
if (!file_exists($team_name)) mkdir($team_name, 0777, true) or die ("could not create storage directory '$team_name'");
if ($input == "T") array_map('unlink', glob("$team_name/*.txt"));

if (file_exists($mem_file)) $game = unserialize (file_get_contents ($mem_file));
else
{
    $team = new Team (
        array (
            new Monster ("Handy" , "Grass" , 50, 99, 81, "Confuse", "Poison", "Heal"),
            new Monster ("Nutty" , "Fire"  , 50, 99, 81, "Burn"   , "Poison", "Heal"),
            new Monster ("Flippy", "Water" , 50, 99, 81, "Confuse" , "Burn" , "Heal")));
    $game = new G($team_name,$team);
}

$game->process ($input);
file_put_contents ($mem_file, serialize($game));

Hasil

LittleKid masih mengancam, tetapi trio saya mengalahkan orang aneh berbisa dengan margin yang adil.

Bot Martin ditakdirkan oleh kurangnya inisiatif mereka, dan meningkatkan kecepatan mereka akan diperlukan untuk menurunkan serangan, yang akan menumpulkan keunggulan mereka dalam kapasitas menangani kerusakan.

Pesaing baru dari planet JavaScript setara dengan tim dalam pertandingan satu lawan satu, tetapi mereka lebih buruk dibandingkan pesaing lainnya. Mereka benar-benar membantu mengurangi skor LittleKid :).

Jadi sepertinya teman-teman saya yang suka diemong tetap menjadi raja bukit - untuk saat ini ...

170             H3C
158             Nodemon
145             LittleKid
55              InsideYourHead
42              HardenedTrio
30              BitterRivals

Dan saya juga tidak punya PHP. Saya berharap Anda untuk mengepel lantai dengan Metapods, karena mereka mengambil jalan yang lambat dan akan diracuni sampai mati.
Sp3000

... * dan * dibakar hingga garing: D. Itulah masalah dengan aturan yang rumit: strategi dominan sangat mungkin muncul. Karena tidak ada perlindungan terhadap mantra-mantra ini, mereka mungkin pria gemuk dan anak lelaki kodon.

Saya akan membandingkannya lebih banyak dengan permainan non-transitif seperti gunting, kertas, batu - karena efek butuh waktu, tim serangan penuh harus dapat menjatuhkan Anda :)
Sp3000

2
Ya, inilah yang saya bayangkan segera setelah saya melihat tidak ada obat untuk Poison and Burn. Terima kasih telah mewujudkan mimpiku.
justhalf

1
Itulah Mr. Lumpy yang mengungkapkan kekesalannya ketika dia mendeteksi lebih dari 3 serangan berbeda dari musuh yang sama :). Saya memiliki versi tetap yang hampir selesai, tetapi saya berada di tengah-tengah beberapa hal lain sekarang, jadi perbaikannya akan diposting dalam satu hari atau lebih.

7

HardenedTrio, Python 3

Karena Geobits cukup baik untuk memberi kami dua kiriman, saya pikir saya akan mengirimkan sesuatu yang konyol untuk yang pertama: P

Pesta adalah tiga Codemon (Metapod1, Metapod2, Metapod3) dengan statistik dan gerakan yang sama:

  • 80 serangan, 100 pertahanan, 50 kecepatan
  • Punch, Heal, Shield Harden

Semua poin bonus juga ditugaskan untuk pertahanan.


from collections import namedtuple
import sys

BattleState = namedtuple("BattleState", ["us", "them"])
TeamState = namedtuple("TeamState", ["name", "active", "members"])
MemberState = namedtuple("MemberState", ["name", "id", "attack", "defense", "speed", "hp",
                                         "typeid", "poisonedturns", "otherstats"])

def parse_battle_state(state):
    return BattleState(*map(parse_team_state, state.split("#")))

def parse_team_state(state):
    na, *members = state.split("|")
    name, active = na.split(":")
    return TeamState(name, int(active), list(map(parse_member_state, members)))

def parse_member_state(state):
    name, id_, attack, defense, speed, hp, typeid, poisonedturns, *rest = state.split(":")
    return MemberState(name, int(id_), float(attack), float(defense), float(speed),
                       float(hp), int(typeid), int(poisonedturns), rest)

command = sys.argv[1].strip()

if command.startswith("T"):
    print("HardenedTrio|Metapod1:0:80:100:50:0:1:11|"
          "Metapod2:0:80:100:50:0:1:11|Metapod3:0:80:100:50:0:1:11")

elif command.startswith("C"):
    battle_state = parse_battle_state(command[2:])

    for i, codemon in enumerate(battle_state.us.members):
        if codemon.hp > 0:
            print(i)
            break

elif command.startswith("A"):
    battle_state = parse_battle_state(command[2:])
    current_codemon = battle_state.us.members[battle_state.us.active]

    if current_codemon.hp < 50 and int(current_codemon.otherstats[1]) > 0:
        print(1) # Heal up if low

    elif int(current_codemon.otherstats[2]) > 0:
        print(2) # Harden!

    else:
        print(0) # Punch!

elif command.startswith("B"):
    print("1:1:1")

Jalankan dengan

py -3 <filename>

(atau dengan python/ python3bukannya pytergantung pada instalasi Anda)



1
@FryAmTheEggman Metapod,
Sp3000

Saya mencoba membaca kode Anda, tetapi bingung int(current_codemon.otherstats[1])>0. Itu mengembalikan benar jika dia memiliki efek status? Dan dia hanya menggunakan harden jika dia memiliki dua efek status?
Mooing Duck

@ MoooDuck Untuk Codemon Anda, Anda punya moveCountsebelum effectids, jadi memeriksa apakah masih bisa menggunakan Harden. Saya menjadi malas dengan penguraian, itulah sebabnya itu disamakan ke sana.
Sp3000

@ Sp3000: Oh! Baik! HA HA HA!
Mooing Duck

6

Di dalam Kepalamu, Ruby

  • Brian : Psikis, Serangan: 100, Pertahanan: 50, Kecepatan: 80, Pain, Fireball, Watergun
  • Elemon1 : Psikis, Serangan: 100, Pertahanan: 50, Kecepatan: 80, Fireball, Watergun, Vine
  • Elemon2 : Psikis, Serangan: 100, Pertahanan: 50, Kecepatan: 80, Fireball, Watergun, Vine
TEAM_SPEC = "InsideYourHead"+
            "|Brian:1:100:50:80:3:6:9"+
            "|Elemon1:1:100:50:80:6:9:12"+
            "|Elemon2:1:100:50:80:6:9:12"

def parse_battle_state request
    request.map do |team_state|
        state = {}
        parts = team_state.split '|'
        state[:active] = parts.shift.split(':')[1].to_i
        state[:monsters] = parts.map do |monster_state|
            monster = {}
            parts = monster_state.split(':')
            monster[:name] = parts[0]
            monster[:hp] = parts[5].to_i
            monster[:type] = parts[6].to_i
            monster
        end
        state
    end
end

request = ARGV[0].split '#'
case request.shift
when 'T'
    puts TEAM_SPEC
when 'C'
    battle_state = parse_battle_state request
    my_state = battle_state[0]
    puts my_state[:monsters].find_index {|monster| monster[:hp] > 0}
when 'A'
    battle_state = parse_battle_state request
    my_state, their_state = *battle_state
    my_monster = my_state[:monsters][my_state[:active]]
    their_monster = their_state[:monsters][their_state[:active]]
    puts [1,0,1,2,0][their_monster[:type]]
when 'B'
    puts '0:0:0'
end

Jalankan dengan

ruby InsideYourHead.rb

Ini tidak bekerja dengan baik melawan bot Manu, tetapi mengalahkan tiga lainnya. Nama tim dan monster itu cukup acak ... Aku mungkin mengubahnya jika aku menemukan sesuatu yang lebih baik

Strateginya cukup sederhana: serang!Ketiga monster hanya memiliki gerakan serangan murni, dan mereka memilih gerakan mereka berdasarkan tipe monster lawan.

Saya mungkin bereksperimen dengan melempar Heal nanti.


1
Hehe ini menjadi lebih menarik. Saya tahu saya bisa mengandalkan Anda untuk itu, Martin :)

6

LittleKid, Jawa

Seorang anak kecil menemukan 3 codem identik dan melatihnya. Mereka sangat mengganggu dengan menyembuhkan + racun serangan mereka. Hanya menggunakan kodon tipe normal menghilangkan kebutuhan untuk memasangkannya dengan musuh tertentu, karena racun bekerja dengan baik terhadap semua jenis.

public class LittleKid {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("Geobits says you can't do this.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String me, them, out = "";
        switch(sections[0]){
            case "T":
                out = "LittleKid";
                out += "|Poisoner:0:80:100:50:0:1:13";
                out += "|Poisoner:0:80:100:50:0:1:13";
                out += "|Poisoner:0:80:100:50:0:1:13";
                break;
            case "B":
                out = "1:1:1";
                break;
            case "C":
                me = sections[1];
                them = sections[2];
                int pick = 0;

                if(!isAlive(me, pick)){
                    for(int i=0;i<3;i++){
                        if(isAlive(me,i))
                            pick = i;
                    }
                }

                out = String.valueOf(pick);
                break;
            case "A":
                me = sections[1];
                them = sections[2];
                int active = getActive(me);
                int enemyActive = getActive(them);
                if (getField(me, HP, active) < 50 && getField(me, MOVE1, active) != 0) {
                    out = "1";
                } else if (getEffectCount(them, POISON, enemyActive, false) < 1 && getField(me, MOVE2, active) != 0) {
                    out = "2";
                } else {
                    out = "0";
                }
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }

    static boolean isAlive(String teamState, int who){
        return getField(teamState, HP, who) > 0;
    }

    static int getActive(String teamState){
        return Integer.parseInt(teamState.split("\\|")[0].split(":")[1]);
    }

    static int getField(String teamState, int field, int who){
        String[] fields = teamState.split("\\|")[who+1].split(":");
        return Integer.parseInt(fields[field]);
    }

    static int getEffectCount(String teamState, int effect, int who, boolean mine){
            String[] fields = teamState.split("\\|")[who+1].split(":");
            int count = 0;
            for(int i=mine?14:8;i<fields.length;i++){
                if(Integer.parseInt(fields[i]) == effect)
                    count++;
            }
            return count;
    }

    final static int ID =       1; 
    final static int ATTACK =   2; 
    final static int DEFENSE =  3; 
    final static int SPEED =    4; 
    final static int HP =       5; 
    final static int TYPE =     6;
    final static int MOVE0 =    8; 
    final static int MOVE1 =    9; 
    final static int MOVE2 =    10;

    final static int POISON =           1;
}

5
" Geobits bilang kamu tidak bisa melakukan ini ": D
Geobits

Tampaknya racun adalah bom atom yang sebenarnya dalam game ini :)

5

Nodémon - Javascript

Karena status tampaknya menjadi strategi yang dominan, tim ini berfokus pada kecepatan untuk mendapatkan status seperti racun dan kebingungan pada lawan terlebih dahulu, dan kemudian berhenti dengan menyembuhkan dan / atau tidur sementara lawan buang.

Saya tidak menginstal PHP jadi ini tidak diuji terhadap Campers, tetapi tampaknya menjadi pesaing yang layak untuk LittleKid dalam uji coba saya (dan menipiskan Pesaing Pahit).

/*jshint node:true*/
'use strict';

var fs = require('fs');

var dataFile = 'Nodemon/data.json';
function getData(callback) {
  fs.readFile(dataFile, 'utf8', function(err, contents) {
    var data = {round: 0};

    if(!err) {
      data = JSON.parse(contents);
    }

    callback(data);
  });
}

function saveData(data, callback) {
  fs.mkdir('Nodemon', function() {    
    fs.writeFile(dataFile, JSON.stringify(data), callback);
  });
}

var effect = {
  poison: '1',
  confusion: '2',
  burn: '3',
  sleep: '4',
  heal: '5',
  attackUp: '6',
  attackDown: '7',
  defenseUp: '8',
  defenseDown: '9',
  speedDown: '10'
};

function parseMemberCommon(args) {
  return {
    name: args[0],
    id: args[1],
    baseAttack: +args[2],
    baseDefense: +args[3],
    baseSpeed: +args[4],
    hp: +args[5],
    typeId: args[6],
    poisonedTurns: +args[7],
    effects: args.slice(8)
  };
}

function parseOwnMember(arg) {
  var args = arg.split(':');

  var ownArgs = args.splice(8, 6);

  var member = parseMemberCommon(args);

  member.moveCount = [
    +ownArgs[0],
    +ownArgs[1],
    +ownArgs[2]
  ];

  member.bonusAttack = +ownArgs[3];
  member.bonusDefense = +ownArgs[3];
  member.bonusSpeed = +ownArgs[3];

  return member;
}

function parseOpponentMember(arg) {
  return parseMemberCommon(arg.split(':'));
}

function parseTeamStateCommon(arg, memberParse) {
  var args = arg.split(':');
  var state = {
    name: args[0],
    members: []
  };
  args = arg.substring(state.name.length + 1).split('|');
  var activeSlot = args[0];
  for(var index = 1; index < args.length; index++) {
    state.members.push(memberParse(args[index]));
  }
  state.activeMember = state.members[activeSlot];
  return state;
}

function parseOwnState(arg) {
  return parseTeamStateCommon(arg, parseOwnMember);
}

function parseOpponentState(arg) {
  return parseTeamStateCommon(arg, parseOpponentMember);
}

function parseBattleState(arg) {
  var args = arg.split('#');
  return {
    own: parseOwnState(args[0]),
    opponent: parseOpponentState(args[1])
  };
}

function teamData() {

  saveData({round:0}, function() {
    console.log('Nodemon|' + 
      'Charasaur:0:50:80:100:10:13:1|' +
      'Bulbtortle:4:50:80:100:10:13:1|' +
      'Squirtmander:1:50:80:100:10:13:4');
  });
}

function getActiveIndex(battleState) {
  for(var index = 0; index < battleState.own.members.length; index++) {
    var member = battleState.own.members[index];
    if(member.hp > 0) {
      return index;
    }
  }
}

function chooseActive(arg) {
  var battleState = parseBattleState(arg);

  getData(function(data) {
    var allFull = true;
    for(var index = 0; index < battleState.opponent.members.length; index++) {
      var member = battleState.opponent.members[index];
      if(!data.maxSpeed || member.baseSpeed > data.maxSpeed) {
        data.maxSpeed = member.baseSpeed;
      }
      if(member.hp < 100) {
        allFull = false;
      }
    }

    if(allFull) {
      data.round++;
    }

    saveData(data, function() {
      console.log(getActiveIndex(battleState));
    });    
  });
}

function useMove(moves, battleState) {
  var fighter = battleState.own.activeMember;

  for(var moveIndex = 0; moveIndex < moves.length; moveIndex++) {
    var move = moves[moveIndex];
    if(fighter.moveCount[move]) {
      return move;
    }

    for(var memberIndex = 0; memberIndex < battleState.own.members.length; memberIndex++) {
      var member = battleState.own.members[memberIndex];

      if(member.hp > 0 && member.moveCount[move] > 0) {
        return 10 + memberIndex;
      }
    }
  }

  return -1;  //do nothing
}

function battleAction(arg) {
  var battleState = parseBattleState(arg);

  var fighter = battleState.own.activeMember;
  var opponent = battleState.opponent.activeMember;

  var attemptedMoves = [];

  if(opponent.effects.indexOf(effect.poison) === -1) {
    attemptedMoves.push(1);
  }

  if(opponent.effects.indexOf(effect.confusion) === -1) {
    attemptedMoves.push(0);
  }

  if(fighter.name === 'Squirtmander') {
    //sleep
    if(opponent.effects.indexOf(effect.sleep) === -1) {
      attemptedMoves.push(2);
    }
  }
  else {
    //heal
    if(fighter.hp <= 60) {
      attemptedMoves.push(2);
    }
  }

  console.log(useMove(attemptedMoves, battleState));
}

function bonusStats(arg) {
  var teamState = parseOwnState(arg);

  getData(function(data) {
    var result = '1:';

    if(data.round % 4 === 0) {
      result += '1:';
    }
    else {
      result += '2:';
    }
    if(teamState.members[2].baseSpeed + teamState.members[2].bonusSpeed > data.maxSpeed + (data.round / 2)) {
      result += '1';
    }
    else {
      result += '2';
    }
    console.log(result);
  });
}

var actions = {
  'T': teamData,
  'C': chooseActive,
  'A': battleAction,
  'B': bonusStats
};

var arg = process.argv[2];
actions[arg[0]](arg.substring(2));

Jalankan dengan

node nodemon

PS Meminta maaf pada nodemon .


Ini meningkat menjadi perang global skrip sisi-server: D

4

Saingan Pahit - Jawa

Tim Rumput / Api / Air yang suka mengubahnya.

Greenosaurus

Setidaknya memiliki cakupan netral pada siapa pun. Kecepatan tinggi untuk menebus kurangnya pertahanan.

Type: Grass
Attack:   80     Vine
Defense:  50     Punch
Speed:   100     Pain

Searizard

Mencoba musuh Sap dengan serangan rendah. Luka Bakar dan Bola Api setelah itu.

Type: Fire
Attack:  100     Fireball
Defense:  50     Burn
Speed:    80     Sap

Blastshield

Menggunakan Shield untuk meningkatkan pertahanannya yang sudah tinggi. Sembuh saat diperlukan.

Type: Water
Attack:   80     Watergun
Defense: 100     Shield
Speed:    50     Heal

Kode

Ini juga termasuk dengan controller. Ini adalah tim yang bersaing, tidak seperti DummyTeam. Perintah yang dibutuhkan players.confadalah:

java BitterRivals

public class BitterRivals {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("You're not doing this right. Read the spec and try again.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String me, them, out = "";
        switch(sections[0]){
            case "T":
                out = "BitterRivals";
                out += "|Greenosaur:4:80:50:100:12:0:3";
                out += "|Searizard:2:100:50:80:6:7:14";
                out += "|Blastshield:3:80:100:50:9:11:1";
                break;
            case "B":
                out = "2:0:1";
                break;
            case "C":
                me = sections[1];
                them = sections[2];

                int pick = 0;
                switch(getField(them, TYPE, getActive(them))){
                    case 0:
                    case 1:
                    case 3:
                        pick = 0;
                        break;
                    case 2:
                        pick = 2;
                        break;
                    case 4:
                        pick = 1;
                        break;
                }

                if(!isAlive(me, pick)){
                    for(int i=0;i<3;i++){
                        if(isAlive(me,i))
                            pick = i;
                    }
                }

                out = pick + "";
                break;
            case "A":
                me = sections[1];
                them = sections[2];
                int active = getActive(me);
                int oType = getField(them, TYPE, getActive(them));
                switch(active){
                    case 0:         // Greenosaur
                        switch(oType){
                            case 0:
                            case 4:
                                out = "1";
                                break;
                            case 1:
                                out = "2";
                                break;
                            case 3:
                                out = "0";
                                break;
                            case 2:
                                if(isAlive(me, 2)){
                                    out = "12";
                                } else if(isAlive(me, 1)){
                                    out = "11";
                                } else {
                                    out = "1";
                                }
                                break;
                        }
                        break;
                    case 1:         // Searizard
                        if(oType == 3){
                            if(isAlive(me, 0)){
                                out = "10";
                                break;
                            } else if(isAlive(me, 2)){
                                out = "12";
                                break;
                            }
                            if(getEffectCount(them, BURN, getActive(them), false) < 1 && getField(me, MOVE1, active) > 0){
                                out = "1";
                            } else if(getField(me, MOVE2, active) > 0){
                                out = "2";
                            } else {
                                out = "3";
                            }                           
                        } else {
                            if(getField(them, ATTACK, getActive(them)) < 80){
                                if(getEffectCount(them, DEFENSE_DOWN, getActive(them), false) < 1 && getField(me, MOVE2, active) > 0){
                                    out = "2";
                                    break;
                                } else if(getEffectCount(them, BURN, getActive(them), false) < 1 && getField(me, MOVE1, active) > 0){
                                    out = "1";
                                    break;
                                }
                            }
                            out = "0";
                        }
                        break;
                    case 2:         // Blastshield
                        if(oType == 4){
                            if(isAlive(me, 1)){
                                out = "11";
                                break;
                            } else if(isAlive(me, 0)){
                                out = "10";
                                break;
                            }
                        }
                        if(getField(me, HP, active) < 50 && getField(me, MOVE2, active) > 0){
                            out = "2";
                        } else if(getEffectCount(me, DEFENSE_UP, active, true) < 3 && getField(me, MOVE1, active) > 0){
                            out = "1";
                        } else {
                            out = "0";
                        }
                        break;
                }
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }

    static boolean isAlive(String teamState, int who){
        return getField(teamState, HP, who) > 0;
    }

    static int getActive(String teamState){
        return Integer.parseInt(teamState.split("\\|")[0].split(":")[1]);
    }

    static int getField(String teamState, int field, int who){
        String[] fields = teamState.split("\\|")[who+1].split(":");
        return Integer.parseInt(fields[field]);
    }

    static int getEffectCount(String teamState, int effect, int who, boolean mine){
            String[] fields = teamState.split("\\|")[who+1].split(":");
            int count = 0;
            for(int i=mine?14:8;i<fields.length;i++){
                if(Integer.parseInt(fields[i]) == effect)
                    count++;
            }
            return count;
    }

    final static int ID =       1; 
    final static int ATTACK =   2; 
    final static int DEFENSE =  3; 
    final static int SPEED =    4; 
    final static int HP =       5; 
    final static int TYPE =     6; 
    final static int PTURNS =   7; 
    final static int MOVE0 =    8; 
    final static int MOVE1 =    9; 
    final static int MOVE2 =    10; 
    final static int HA =       11; 
    final static int HD =       12; 
    final static int HS =       13; 

    final static int POISON =           1;
    final static int CONFUSION =        2;
    final static int BURN =             3;
    final static int SLEEP =            4;
    final static int ATTACK_UP =        6;
    final static int ATTACK_DOWN =      7;
    final static int DEFENSE_UP =       8;
    final static int DEFENSE_DOWN =     9;
    final static int SPEED_DOWN =       10;
}

4

Kesalahan 310: Terlalu Banyak Pengalihan - C ++

Tim yang sangat terlatih dan terorganisir untuk melawan kerusakan akibat racun

Selama tiga minggu, saya hampir tidak melatih codemon saya. Saya membentuk beberapa tim. Dan akhirnya, saya siap menghadapi tantangan ini. Untuk menjawab semua lawan peracunku, aku membentuk tim dengan codemmon yang sangat berbeda, masing-masing dengan peran tertentu.


Penangkal(gambar)

Type : Normal - atk:50 def:100 spd:80 - Poison/Burn/Heal

Penangkal suka racun. Sedemikian rupa sehingga saya tidak bisa menghentikannya dari bergegas ke serangan racun.


Zen(gambar)

Type : Fire - atk:100 def:80 spd:50 - Poison/Vine/Heal

Zen adalah codémon yang sangat mengejutkan yang mengakomodasi semua efek. Dia lebih suka melihat musuh-musuhnya berjuang dan menguras keheningannya.


Triforce(gambar)

Type : Psychic - atk:88 def:60 spd:82 - Fireball/Watergun/Vine

Triforce adalah codémon klasik, selalu siap bertarung. Yang satu ini menggunakan kekuatan psikisnya untuk mengendalikan tiga elemen dan menimbulkan kerusakan sebanyak mungkin.


Anda dapat mengunduh tim di sini:

Linux:

http://dl.free.fr/iHYlmTOQ2

memulai dengan ./Error310TMR

Windows:

http://dl.free.fr/vCyjtqo2s

memulai dengan ./Error310TMR.exe

Kode adalah proyek c ++ lengkap. Saya tidak tahu bagaimana mempublikasikannya.

$ wc -l src/*
    165 src/BruteForce.cpp
     26 src/BruteForce.h
    349 src/Codemon.cpp
     77 src/Codemon.h
     21 src/Logger.cpp
     35 src/Logger.h
    105 src/NoTimeToExplain.cpp
     27 src/NoTimeToExplain.h
    240 src/Recoverator.cpp
     31 src/Recoverator.h
     26 src/StrManip.cpp
     16 src/StrManip.h
    303 src/Team.cpp
     68 src/Team.h
     88 src/TooManyRedirects.cpp
     24 src/TooManyRedirects.h
     87 src/Unrecoverable.cpp
     27 src/Unrecoverable.h
     59 src/enums.cpp
    119 src/enums.h
     68 src/main.cpp
   1961 total

Tetapi ini sangat efektif:

------- Final Results -------

176     Error310TMR
131     H3C
130     LittleKid
121     Nodemon
58      InsideYourHead
47      HardenedTrio
37      BitterRivals

2

Dongeng

Tim tengah yang cukup generik. Berdasarkan tiga arketipe yang mencoba melakukan hal mereka, dan beralih jika mereka tidak dapat melakukan hal sama sekali.

Tim ini dibuat sebelum sepertinya racun adalah meta baru, saya belum benar-benar mengikuti perubahan tim saya sejak saya awalnya membuatnya, sebagian besar waktu dihabiskan hanya untuk mencoba mengurai. Saya belum bisa menjalankan Turnamen untuk mengujinya, tapi ini minggu yang cukup sibuk. Jika yang ini tidak benar-benar berfungsi seperti yang terlihat pada data pengujian saya, saya akan menerapkan lebih bersinar setelah bekerja.

#!/bin/perl
use 5.20.0;
use strict;

use constant MINE => 0;
use constant THEIRS => 1;

$_ = $ARGV[0];

if(/^T/){
    say 'FairyTale|Fairy:1:89:90:51:3:4:13|Dragon:2:100:50:80:6:1:8|Assassin:0:70:60:100:0:1:10';

} elsif(/^C#(.*)/){
    my $state = readBattleState($1);
    if($state->[MINE]->{$state->[MINE]->{slot}}{hp}){
        say $state->[MINE]->{slot};
    } elsif($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp}){
        say (($state->[MINE]->{slot}+1)%3);
    } else {
        say (($state->[MINE]->{slot}+2)%3);
    }

} elsif(/^A#(.*)/){
    my $state = readBattleState($1);
    my @actives = (
        $state->[MINE]->{$state->[MINE]->{slot}},
        $state->[THEIRS]->{$state->[THEIRS]->{slot}}
    );
    if($state->[MINE]->{slot} == 0){
        if(!exists($actives[THEIRS]{effects}{4}) && $actives[MINE]{pp}->[1]){
            say 1;
        } elsif(!exists($actives[THEIRS]{effects}{1}) && $actives[MINE]{pp}->[2]) {
            say 2;
        } elsif(!$actives[THEIRS]{type}) {
            if($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp} > 0){
                say (($state->[MINE]->{slot}+1)%3);
            } elsif($state->[MINE]->{($state->[MINE]->{slot}+2)%3}{hp} > 0) {
                say (($state->[MINE]->{slot}+2)%3);
            } else {
                say 0;
            }
        } else {
            say 0;
        }
    } elsif($state->[MINE]->{slot} == 1){
        if(!exists($actives[MINE]{effects}{6}) && $actives[MINE]{pp}->[2]){
            say 2;
        } elsif ($actives[MINE]{hp} > 10 && $actives[MINE]{hp} < 50 && $actives[MINE]{pp}->[1]){
            say 1;
        } else {
            say 0;
        }
    } elsif($state->[MINE]->{slot} == 2){
        if(!exists($actives[MINE]{effects}{6}) && $actives[MINE]{pp}->[2]){
            say 2;
        } elsif ($actives[MINE]{hp} > 10 && $actives[MINE]{hp} < 50 && $actives[MINE]{pp}->[1]){
            say 1;
        } elsif($actives[THEIRS]{type} == 1) {
            if($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp} > 0){
                say (($state->[MINE]->{slot}+1)%3);
            } elsif($state->[MINE]->{($state->[MINE]->{slot}+2)%3}{hp} > 0) {
                say (($state->[MINE]->{slot}+2)%3);
            } else {
                say 0;
            }
        } else {
            say 0;
        }
    }

} elsif(/^B#(.*)/){
    my $state = readTeam($1, 1);
    say '1:0:2';
}

sub readBattleState {
    local $_ = $_[0];
    if(/^(.*?)#(.*?)$/){
        my @teams;
        $teams[0] = readTeam($1, 1);
        $teams[1] = readTeam($2, 0);
        return \@teams;
    }
}

sub readTeam {
    my $isMine = $_[1];
    local $_ = $_[0];
    if(/.*?:(?<slot>.*?)\|(.*?)\|(.*?)\|(.*?)$/){
        my %team;
        $team{slot} = $1;
        $team{0} = $isMine ? readYourMember($2) : readTheirMember($2);
        $team{1} = $isMine ? readYourMember($3) : readTheirMember($3);
        $team{2} = $isMine ? readYourMember($4) : readTheirMember($4);
        return \%team;
    }
    return 0;
}

sub readYourMember {
    local $_ = $_[0];
    if(/(?<name>.*?):(?<id>.*?):(?<atk>.*?):(?<def>.*?):(?<spd>.*?):(?<hp>.*?):(?<type>.*?):(?<poison>.*?):(?<move0>.*?):(?<move1>.*?):(?<move2>.*?):(?<batk>.*?):(?<bdef>.*?):(?<bspd>.*?)(?<effects>(?::.*)|$)/){
        my %effects = map { $_ => 1 } readEffects($+{effects});
        my %member = (
            name   => $+{name},
            id     => $+{id},
            hp     => $+{hp},
            atk    => $+{atk}+$+{batk},
            def    => $+{def}+$+{bdef},
            spd    => $+{spd}+$+{bspd},
            type   => $+{type},
            pp     => [$+{move0}, $+{move1}, $+{move2}],
            poistrn=> $+{poison},
            effects=> \%effects
        );
        return \%member;
    }
}

sub readTheirMember {
    local $_ = $_[0];
    if(/(?<name>.*?):(?<id>.*?):(?<atk>.*?):(?<def>.*?):(?<spd>.*?):(?<hp>.*?):(?<type>.*?):(?<poison>.*?)(?<effects>(?::.*)|$)/){
        my %effects = map { $_ => 1 } readEffects($+{effects});
        my %member = (
            name   => $+{name},
            id     => $+{id},
            hp     => $+{hp},
            atk    => $+{atk},
            def    => $+{def},
            spd    => $+{spd},
            type   => $+{type},
            poistrn=> $+{poison},
            effects=> \%effects
        );
        return \%member;
    }
    return 0;
}

sub readEffects {
    local $_ = $_[0];
    my @retval = /:([^:]*)/g;
    if(!@retval){
        @retval = (0);
    }
    return @retval;
}

Jalankan dengan

perl fairytale.pl

Bot ini dikeluarkan karena mencoba 'memilih anggota mati yang aktif' setelah yang pertama mati. Tidak pernah melewati pertempuran pertama yang bisa saya lihat.
Geobits

Benarkah? Saya pikir saya telah mendapatkan bug yang berhasil sebelumnya, mungkin ini adalah versi yang lebih lama dari kode itu ...
mezzoEmrys

Jangan lupa bahwa ketika sebuah codemon tersingkir, healpoint-nya berkurang pada 0 atau kurang . Jadi if($state->[MINE]->{$state->[MINE]->{slot}}{hp})pernyataan itu tidak akan berfungsi dengan benar tanpa >0.
GholGoth21

Ah, ya, itu akan berhasil.
mezzoEmrys

0

Tim Dummy - Jawa

(CW yang tidak bersaing)

Ini adalah tim boneka untuk berlatih. Itu semua tipe normal, yang memilih secara acak antara gerakan mereka (Punch, Heal, Slow) setiap belokan. Bersenang-senanglah dengan itu.

public class DummyTeam {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("You need to run this from the tournament. Try to keep up.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String out = "";
        switch(sections[0]){
            // team data
            //      sends back all Normal types with minimum stats and Normal moves (randomized name suffixes to distinguish in tests)
            case "T":
                out = "DummyTeam";
                for(int i=0;i<3;i++)
                    out += "|Dummy"+((char)(Math.random()*26)+65) + i + ":0:50:50:50:0:1:2";
                break;
            // bonus points
            //      shoves them all in defense every time
            case "B":
                out = "1:1:1";
                break;
            // choose active
            //      picks last active if alive, otherwise loops to find first living member
            case "C":
                String[] team = sections[1].split("\\|");
                int current = Integer.parseInt(team[0].split(":")[1]);
                if(Integer.parseInt(team[current+1].split(":")[5]) > 0){
                    out = current + "";
                } else {
                    for(int i=1;i<team.length;i++){
                        if(Integer.parseInt(team[i].split(":")[5]) > 0){
                            out = (i - 1) + "";
                        }
                    }
                }               
                break;
            // choose action
            //      chooses a random move. does not check if it ran out of uses, so wastes turns quite often
            case "A":
                out = ((int)(Math.random()*3)) + "";
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }


}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.