Pengurai aturan umum untuk aturan permainan papan RPG - bagaimana melakukannya?

19

Saya ingin membuat parser aturan umum untuk sistem RPG gaya pena dan kertas. Suatu aturan biasanya melibatkan 1 hingga N entitas 1 hingga N peran dadu dan menghitung nilai berdasarkan beberapa atribut entitas.

Sebagai contoh:

Pemain memiliki STR 18, senjatanya yang dilengkapi saat ini memberinya bonus +1 STR tetapi malus dari DEX -1. Ia menyerang entitas monster dan logika game sekarang diperlukan untuk menjalankan serangkaian aturan atau tindakan:

Pemain melempar dadu, jika ia mendapatkan misalnya 8 atau lebih (nilai serangan dasar yang ia harus lewati adalah salah satu atribut dasarnya!) Serangannya berhasil. Monster itu kemudian melempar dadu untuk menghitung jika serangan melewati baju besinya. Jika ya kerusakan diambil jika bukan serangan itu diblokir.

Selain itu aturan matematika sederhana juga dapat memiliki kendala seperti menerapkan hanya untuk kelas pengguna tertentu (misalnya prajurit vs penyihir) atau atribut lainnya. Jadi ini tidak hanya terbatas pada operasi matematika.

Jika Anda terbiasa dengan sistem RPG seperti Dungeon dan Dragons, Anda akan tahu apa yang saya lakukan.

Masalah saya sekarang adalah bahwa saya tidak memiliki petunjuk bagaimana tepatnya membangun ini dengan cara terbaik. Saya ingin orang-orang dapat mengatur segala jenis aturan dan kemudian hanya melakukan tindakan seperti memilih pemain dan monster dan menjalankan tindakan (seperangkat aturan seperti serangan).

Saya kurang meminta bantuan dengan sisi database tetapi lebih lanjut tentang cara membuat struktur dan parser agar aturan saya fleksibel. Omong-omong, pilihan untuk ini adalah php.

Edit I:

Biarkan saya memperbaiki tujuan saya: Saya ingin membuat antarmuka yang ramah pengguna (yang tidak mengharuskan seseorang untuk belajar bahasa pemrograman) untuk membangun aturan permainan yang lebih atau kurang kompleks. Alasan sederhananya: Penggunaan pribadi untuk tidak perlu mengingat semua aturan sepanjang waktu, kita tidak bermain sesering itu dan merupakan penghenti untuk melihatnya setiap kali. Juga: Sepertinya tugas yang menyenangkan untuk dilakukan dan belajar sesuatu. :)

Apa yang saya coba sejauh ini: Hanya memikirkan sebuah konsep daripada membuang-buang waktu membangun arsitektur yang salah. Sejauh ini saya memiliki ide untuk memungkinkan pengguna untuk membuat atribut sebanyak yang mereka inginkan dan kemudian menetapkan atribut sebanyak yang mereka inginkan untuk semua jenis entitas. Entitas dapat menjadi pemain, monster, item, apa saja. Sekarang ketika menghitung sesuatu data tersedia untuk parser aturan sehingga aturan parser harus dapat melakukan hal-hal seperti jika Player.base_attack + dadu (1x6)> Monster.armor_check lalu Monster.health - 1; Pertanyaannya di sini adalah tentang cara membuat parser itu.

Edit II:

Berikut adalah contoh nilai yang cukup mendasar tetapi untuk menghitungnya dengan benar ada banyak hal dan variabel yang perlu dipertimbangkan:

Bonus Serangan Dasar (Jangka) Bonus serangan dasar Anda (biasanya disebut sebagai BAB oleh komunitas d20) adalah bonus serangan gulungan yang berasal dari kelas dan level karakter. Bonus serangan dasar meningkat pada tingkat yang berbeda untuk kelas karakter yang berbeda. Seorang karakter mendapat serangan kedua per putaran ketika bonus serangan dasarnya mencapai +6, yang ketiga dengan bonus serangan dasar +11 atau lebih tinggi, dan yang keempat dengan bonus serangan dasar +16 atau lebih tinggi. Bonus serangan basis diperoleh dari kelas yang berbeda, seperti untuk karakter multikelas, stack. Bonus serangan basis karakter tidak memberikan serangan lagi setelah mencapai +16, tidak boleh kurang dari +0, dan tidak meningkat karena level kelas setelah level karakter mencapai 20. Bonus serangan dasar minimum diperlukan untuk prestasi tertentu.

Anda dapat membacanya di sini http://www.dandwiki.com/wiki/Base_Attack_Bonus_(Term) termasuk tautan ke kelas dan prestasi yang memiliki lagi aturan mereka sendiri untuk menghitung nilai yang diperlukan untuk serangan dasar.

Saya mulai berpikir bahwa menjaganya se generik mungkin juga akan membuat sulit untuk menyelesaikan aturan parser yang baik.

burzum
sumber
2
Saya benar-benar berpikir tentang masalah seperti ini pagi ini (tidak terkait dengan RPG, tetapi mengatur mesin pemroses) dan mencoba memikirkan pendekatan mesin non-negara untuk pemrosesan aturan dan bagaimana parser kombinatori sangat efektif dalam menyelesaikan tugas yang biasanya dilakukan oleh mesin negara. Saya pikir ada banyak kemungkinan bagi kombinator monadik untuk mendekati sebagian besar masalah mesin negara secara lebih bersih. Itu mungkin terdengar seperti omong kosong tapi saya pikir ada sesuatu untuk ide ini, hanya 2 sen saya. Sistem RPG adalah masalah praktik klasik yang menyenangkan yang saya suka coding, mungkin saya akan mencoba pendekatan ini.
Jimmy Hoffa
1
@jk. artikel itu mengingatkan saya pada suatu pola yang saya sukai untuk penguraian argumen program baris perintah, menggunakan kamus Funcyang menginisialisasi status program berdasarkan argumen sebagai kunci ke kamus. Terkejut saya tidak pernah menemukan posting itu dari Yegge sebelumnya, sangat keren, terima kasih telah menunjukkannya.
Jimmy Hoffa
4
Saya tidak begitu yakin mengapa ini ditutup sebagai "bukan pertanyaan nyata". Ini pertanyaan "papan tulis" tingkat yang lebih tinggi tentang bagaimana merancang aplikasi yang memiliki serangkaian persyaratan khusus (sistem aturan RPG). Saya telah memilih untuk membukanya kembali, tetapi masih akan membutuhkan 4 suara lainnya untuk dibuka kembali.
Rachel
1
Jujur saya pikir situs ini tepat untuk pertanyaan konseptual semacam ini sementara stackoverflow.com dianggap untuk masalah kode / implementasi.
burzum

Jawaban:

9

Apa yang Anda minta pada dasarnya adalah bahasa khusus domain — bahasa pemrograman kecil untuk tujuan yang sempit, dalam hal ini mendefinisikan aturan P&P RPG. Merancang bahasa pada prinsipnya tidak sulit, tetapi ada banyak pengetahuan di muka yang harus Anda peroleh agar sama sekali produktif. Sayangnya, tidak ada referensi sentral untuk hal ini — Anda harus mengambilnya melalui uji coba, kesalahan, dan banyak penelitian.

Pertama, temukan satu set operasi primitif di mana operasi lain dapat diimplementasikan. Sebagai contoh:

  • Dapatkan atau atur properti pemain, NPC, atau monster

  • Dapatkan hasil die roll

  • Mengevaluasi ekspresi aritmatika

  • Mengevaluasi ekspresi kondisional

  • Lakukan percabangan bersyarat

Desain sintaksis yang mengekspresikan primitif Anda. Bagaimana Anda merepresentasikan angka? Seperti apa pernyataan itu? Apakah pernyataan diakhiri dengan tanda koma? Dihentikan baris baru? Apakah ada struktur balok? Bagaimana Anda menunjukkannya: melalui simbol atau lekukan? Apakah ada variabel? Apa yang merupakan nama variabel hukum? Apakah variabel bisa berubah? Bagaimana Anda mengakses properti objek? Apakah objek kelas satu? Bisakah Anda membuatnya sendiri?

Tulis parser yang mengubah program Anda menjadi pohon sintaksis abstrak (AST). Pelajari tentang pernyataan parsing dengan parser keturunan rekursif. Pelajari tentang bagaimana parsing ekspresi aritmatika dengan penurunan rekursif mengganggu, dan operator parser diutamakan operator top-down (Pratt parser) dapat membuat hidup Anda lebih mudah dan kode Anda lebih pendek.

Tulis penerjemah yang mengevaluasi AST Anda. Ini hanya dapat membaca setiap node di pohon dan melakukan apa yang dikatakannya: a = bmenjadi new Assignment("a", "b")menjadi vars["a"] = vars["b"];. Jika itu membuat hidup Anda lebih mudah, ubah AST menjadi bentuk yang lebih sederhana sebelum evaluasi.

Saya sarankan merancang hal paling sederhana yang akan bekerja dan tetap dapat dibaca. Berikut adalah contoh dari bagaimana rupa suatu bahasa. Desain Anda tentu akan berbeda berdasarkan kebutuhan dan preferensi spesifik Anda.

ATK = D20
if ATK >= player.ATK
    DEF = D20
    if DEF < monster.DEF
        monster.HP -= ATK
        if monster.HP < 0
            monster.ALIVE = 0
        end
    end
end

Atau, pelajari cara menyematkan bahasa skrip yang ada seperti Python atau Lua ke dalam aplikasi Anda, dan gunakan itu. Kelemahan dari menggunakan bahasa tujuan umum untuk tugas khusus domain adalah abstraksi yang bocor: semua fitur dan gotcha bahasa masih ada. Sisi positifnya adalah Anda tidak harus mengimplementasikannya sendiri — dan itu adalah sisi positif yang signifikan. Pikirkan itu.

Jon Purdy
sumber
2
Bukan pendekatan yang buruk tapi saya secara konsisten skeptis terhadap DSL, mereka banyak pekerjaan yang harus dilakukan dengan benar (terutama jika Anda berbicara tentang DSL sejati dengan sintaks khusus dan semua, sebagai lawan dari hanya beberapa API lancar yang dimiliki orang-orang mulai memanggil "DSL" s), jadi Anda lebih baik memastikan Anda akan menggunakan sih itu, jika Anda maka itu sepadan. Sering kali saya pikir orang ingin mencoba DSL di mana mereka hanya akan menggunakannya untuk mesin aturan kecil. Inilah aturan praktis saya: Jika implementasi + penggunaan DSL adalah kode kurang dari tidak ada DSL, lakukanlah, saya tidak berpikir akan seperti itu dalam kasus ini.
Jimmy Hoffa
1
@JimmyHoffa: Cukup adil. Sudah menjadi sifat saya untuk meraih solusi berbasis bahasa, terutama untuk game. Saya mungkin meremehkan kesulitan membuat sesuatu yang kecil dan fungsional karena saya sudah melakukannya berkali-kali. Namun, sepertinya rekomendasi yang tepat dalam kasus ini.
Jon Purdy
Saya kira saya harus mengatakan itu adalah pendekatan yang tepat untuk masalah semacam ini, tetapi itu didasarkan pada orang yang melakukan implementasi sebagai seseorang dengan keterampilan yang memadai. Untuk belajar, DSL sangat bagus untuk junior, tetapi untuk produk yang sebenarnya dapat dirilis saya tidak akan pernah ingin melihat siapa pun di bawah level senior menulis DSL, dan untuk junior masalah DSL yang dapat dipecahkan harus diselesaikan dengan cara yang berbeda.
Jimmy Hoffa
Setelah membaca ini saya pikir saya bisa hanya eval lua skrip untuk itu. Kelemahan di sini adalah bahwa pengguna harus mampu menulis skrip lua. Tujuan pribadi saya adalah menulis antarmuka yang dapat digunakan tanpa pengetahuan pemrograman, seperti pembuat aturan di magento (aplikasi e-niaga). Karena saya ingin orang dapat menambahkan aturan mereka sendiri. Saya tidak menerapkan apa pun yang komersial, hanya alat untuk membiarkan saya dan teman-teman saya memasukkan aturan sistem RPG yang kami mainkan pada basis yang tidak teratur dan kembali ke aturan dan menerapkannya adalah rasa sakit setelah beberapa waktu ...
burzum
1
@burzum: Bagaimana kalau antarmuka Anda menghasilkan skrip lua?
TMN
3

Saya akan mulai dengan menentukan "Fase" yang berbeda dari setiap tindakan.

Misalnya, Fase Tempur mungkin melibatkan:

GetPlayerCombatStats();
GetEnemyCombatStats();
GetDiceRoll();
CalculateDamage();

Masing-masing metode ini akan memiliki akses ke beberapa objek yang cukup umum, seperti Playerdan Monster, dan akan melakukan beberapa pemeriksaan yang cukup umum yang entitas lain dapat gunakan untuk memodifikasi nilai.

Misalnya, Anda mungkin memiliki sesuatu yang terlihat seperti ini termasuk dalam GetPlayerCombatStats()metode Anda :

GetPlayerCombatStats()
{
    Stats tempStats = player.BaseStats;

    player.GetCombatStats(player, monster, tempStats);

    foreach(var item in Player.EquippedItems)
        item.GetCombatStats(player, monster, tempStats);
}

Ini memungkinkan Anda untuk dengan mudah menambahkan entitas apa pun dengan aturan tertentu, seperti Kelas Pemain, monster, atau bagian Peralatan.

Sebagai contoh lain, anggaplah Anda menginginkan Pedang Membunuh Segalanya Kecuali Squid , yang memberi Anda +4 terhadap segalanya, kecuali benda itu memiliki tentakel, dalam hal ini Anda harus menjatuhkan pedang Anda dan mendapatkan -10 dalam pertempuran.

Kelas perlengkapanmu untuk pedang ini mungkin memiliki sesuatu GetCombatStatsyang terlihat seperti ini:

GetCombatStats(Player player, Monster monster, Stats tmpStats)
{
    if (monster.Type == MonsterTypes.Tentacled)
    {
        player.Equipment.Drop(this);
        tmpStats.Attack -= 10;
    }
    else
    {
        tmpStats.Attack += 4;
    }
}

Ini memungkinkan Anda untuk dengan mudah memodifikasi nilai pertempuran tanpa perlu tahu tentang sisa logika pertempuran, dan memungkinkan Anda untuk dengan mudah menambahkan potongan baru ke aplikasi karena rincian dan logika implementasi Peralatan Anda (atau entitas apa pun itu) hanya perlu ada di kelas entitas itu sendiri.

Hal-hal kunci untuk dipecahkan adalah pada titik mana nilai dapat berubah, dan elemen apa yang memengaruhi nilai-nilai itu. Setelah Anda memilikinya, membangun komponen individual Anda harus mudah :)

Rachel
sumber
Itulah caranya. Di sebagian besar RPG Pena & Kertas, ada beberapa fase dalam perhitungan, yang umumnya ditulis dalam buku panduan. Anda juga dapat menempatkan urutan panggung dalam daftar yang dipesan untuk membuatnya lebih umum.
Hakan Deryal
Ini kedengarannya cukup statis bagi saya dan tidak memungkinkan pengguna untuk hanya memasukkan / membuat aturan yang diperlukan dalam UI? Apa yang Anda gambarkan terdengar lebih seperti aturan yang dikodekan dengan keras. Ini juga dapat dilakukan dengan memiliki daftar aturan yang disarangkan. Saya tidak ingin meng-hardcode aturan apa pun. Jika saya bisa melakukan semuanya dalam kode saya tidak perlu mengajukan pertanyaan itu, itu akan mudah. :)
burzum
@burzum Ya ini berarti aturan akan ditentukan oleh kode, namun itu membuatnya sangat dapat dikembangkan dari kode. Misalnya, jika Anda ingin menambahkan tipe kelas baru, atau bagian peralatan baru, atau tipe monster baru, Anda hanya perlu membangun objek kelas untuk entitas itu dan mengisi metode yang sesuai di kelas Anda dengan logika Anda.
Rachel
@burzum Saya baru saja membaca hasil edit untuk pertanyaan Anda. Jika Anda ingin mesin aturan hanya untuk penggunaan UI, saya akan mempertimbangkan untuk membuat kolam entitas ( Player, Monster, Dice, dll), dan menyiapkan sesuatu yang memungkinkan pengguna untuk potongan badan drag / drop ke daerah "persamaan", mengisi parameter entitas (seperti mengisi player.base_attack), dan tentukan operator sederhana tentang bagaimana potongan-potongan tersebut cocok. Saya sebenarnya memiliki sesuatu yang diposting di blog saya yang mem-parsing persamaan matematika yang mungkin dapat Anda gunakan.
Rachel
@Rachel apa yang Anda gambarkan adalah OOP mudah mati, bahkan ada banyak contoh di alam liar yang menggunakan hal-hal seperti RPG sebagai contoh untuk mengajar OOP. Memiliki benda-benda ini dan bekerja dengannya adalah bagian yang mudah, saya dapat membangunnya dengan cepat berdasarkan data dari database. Masalah dalam pendekatan Anda adalah aturan hardcorded seperti GetEnemyCombatStats () apa pun metode ini perlu didefinisikan di suatu tempat melalui UI dan disimpan dalam db. Artikel Anda tampaknya mirip dengan github.com/bobthecow/Ruler atau github.com/Trismegiste/PhpRules itu .
burzum
0

Saya akan melihat maptool khususnya kerangka kerja ke-4 Rumble . Ini sistem terbaik yang pernah saya lihat untuk mengatur apa yang Anda bicarakan. Sayangnya yang terbaik masih crufty mengerikan. Sistem "makro" mereka telah ... katakanlah ... berkembang seiring waktu.

Adapun "parser aturan" Saya hanya akan tetap dengan bahasa pemrograman apa pun yang Anda merasa nyaman, bahkan jika itu PHP. Tidak akan ada cara yang baik untuk menyandikan semua aturan sistem Anda.

Sekarang, jika Anda ingin pengguna Anda dapat menulis aturan MEREKA SENDIRI, maka Anda sedang mencari cara untuk mengimplementasikan bahasa skrip Anda sendiri. Para pengguna membuat skrip tindakan tingkat tinggi mereka sendiri, php Anda mengartikannya menjadi sesuatu yang benar-benar memengaruhi nilai-nilai basis data, dan kemudian melemparkan banyak kesalahan karena itu adalah sistem kekasaran mengerikan yang telah ditanduk sepatu pada tempatnya selama bertahun-tahun. Sungguh, jawaban Jon Purdy tepat pada waktunya.

Philip
sumber
0

Saya pikir Anda harus dapat berpikir secara abstrak tentang hal-hal yang akan terjadi di ruang masalah Anda, menghasilkan beberapa model dan kemudian mendasarkan DSL Anda pada itu.

Misalnya Anda mungkin memiliki entitas entitas, tindakan, dan acara di tingkat atas. Gulungan mati adalah peristiwa yang terjadi sebagai akibat dari tindakan. Tindakan akan memiliki kondisi yang menentukan apakah mereka tersedia dalam situasi tertentu dan "skrip" hal-hal yang terjadi ketika tindakan diambil. Hal yang lebih kompleks adalah kemampuan untuk menentukan urutan fase di mana tindakan yang berbeda dapat terjadi.

Setelah Anda memiliki semacam model konseptual (dan saya sarankan Anda menuliskannya dan / atau menggambar diagram untuk mewakilinya), Anda dapat mulai melihat berbagai cara untuk mengimplementasikannya.

Satu rute adalah untuk menentukan apa yang disebut DSL eksternal di mana Anda mendefinisikan sintaks Anda dan menggunakan alat seperti antlr untuk menguraikannya dan memanggil logika Anda. Rute lain adalah menggunakan fasilitas yang ada dalam bahasa pemrograman untuk menentukan DSL Anda. Bahasa seperti Groovy dan Ruby sangat bagus di ruang ini.

Satu jebakan yang perlu Anda hindari adalah mencampurkan logika tampilan Anda dengan model permainan yang diterapkan. Saya akan memilih agar tampilan membaca model Anda dan menampilkannya dengan tepat daripada mencampurkan kode tampilan Anda dicampur dengan model Anda.

Peter Kelley
sumber