Ini adalah proyek untuk tesis master saya. Siapapun yang tertarik untuk membuat Mahjong AI yang kuat dipersilakan untuk memperpanjang agen saya. Untuk rincian lebih lanjut tentang algoritma yang diterapkan dan alasan mengapa algoritma tersebut digunakan, silakan hubungi saya melalui E-Mail.
Jika Anda ingin mengembangkan agen Mahjong Anda sendiri, Repo ini juga dapat digunakan sebagai Kerangka untuk pengujian waktu nyata ( dengan pemain manusia sungguhan ). Kemudian Anda dapat menghemat seluruh waktu Anda untuk menemukan strategi terbaik untuk agen Anda. Selanjutnya perpustakaan pengembangan (perayapan dan pra-pemrosesan log permainan, penghitungan shantin dan skor kemenangan, dll.) kini tersedia di: https://github.com/erreurt/MahjongKit
Pembaruan Berikutnya segera hadir :
Rekayasa fitur yang lebih baik diperlukan Putuskan apakah akan memanggil meld/memanggil Riichi atau tidak menggunakan Random Forest (Alih-alih aturan kondisi).
Sedang berlangsung : Melatih model prediksi ubin menunggu dengan LSTM.
Perhatian : Jika Anda menguji bot Anda secara paralel dengan lebih dari 4 akun dengan alamat IP yang sama, alamat IP Anda akan diblokir oleh tenhou.net selama 24 jam. (Saya tidak tahu persis tentang aturan pelarangan pemain, tapi itu semua disimpulkan dari pengamatan saya.)
Pengarang | Jianyang Tang (Thomas) |
---|---|
[email protected] |
Mahjong adalah permainan strategi empat pemain dengan informasi yang tidak sempurna. Tantangan utama dalam mengembangkan agen Mahjong yang cerdas misalnya aturan permainan yang rumit, ruang pencarian yang sangat besar, banyak lawan, dan informasi yang tidak sempurna. Beberapa karya yang ada telah mencoba untuk mengatasi masalah ini melalui simulasi pohon Monte Carlo, penyesuaian fungsi utilitas dengan pembelajaran yang diawasi atau model lawan dengan algoritma regresi. Meski demikian, kinerja agen permainan Mahjong yang cerdas masih jauh dari kinerja pemain manusia terbaik. Berdasarkan analisis statistik untuk permainan Mahjong dan pengetahuan ahli manusia, agen Mahjong yang cerdas diusulkan dalam pekerjaan ini. Untuk mengatasi masalah karya mutakhir, teknologi heuristik dan model lawan yang ditingkatkan dicapai dengan mengadopsi pengantongan perceptron multilayer diterapkan pada karya ini. Eksperimen menunjukkan bahwa agen yang diusulkan mengungguli agen yang canggih, dan model lawan yang diterapkan memiliki pengaruh positif yang signifikan terhadap kinerja agen. Selain itu, beberapa poin menarik dapat dilihat dari eksperimen tersebut, yang cukup berarti untuk pekerjaan di masa depan.
Lihat https://en.wikipedia.org/wiki/Japanese_Mahjong untuk aturan permainan Riichi Mahjong Jepang.
Klien yang diimplementasikan memungkinkan seseorang untuk menjalankan agen Mahjong secara langsung melalui programnya, daripada melakukan hal ini di browser web. Situs untuk bermain online Riichi Mahjong Jepang adalah http://tenhou.net/
Sisi kiri adalah pemandangan khas meja Riichi Mahjong Jepang. Gambar ini adalah tangkapan layar dari GUI yang diimplementasikan untuk penggunaan debugging.
Agen Mahjong yang diusulkan telah diuji di tenhou.net. Pengujian dilakukan dalam dua versi, yaitu satu dengan model pertahanan dan satu lagi tanpa model pertahanan. Log permainan mentah dan hasil permainan antara dapat ditemukan di repositori saya yang lain: https://github.com/erreurt/Experiments-result-of-mahjong-bot. Eksperimen dilakukan dengan versi agen di eksperimen_ai.py .
Untuk versi dengan model pertahanan dimainkan sebanyak 526 permainan, dan untuk versi tanpa model pertahanan dimainkan sebanyak 532 permainan. Ini memang tidak sebanyak dua karya terkait, namun seperti yang ditunjukkan pada gambar perilaku konvergensi kinerja agen, 526 game sudah cukup.
Karya Mizukami yang diperluas saat ini dapat dilihat sebagai agen Mahjong terbaik dan paling dapat diandalkan dalam sastra Inggris. Berikut perbandingan kinerja agen Mahjong saya dan kinerja Mizukami:
[1] | [2] | [3] | [4] | |
---|---|---|---|---|
Permainan dimainkan | 526 | 532 | 2634 | 1441 |
peringkat tempat pertama | 23,95% | 22,65% | 24,10% | 25,30% |
peringkat tempat ke-2 | 26,62% | 25,92% | 28,10% | 24,80% |
peringkat tempat ke-3 | 31,75% | 25,71% | 24,80% | 25,10% |
peringkat tempat ke-4 | 17,68% | 25,71% | 23,00% | 24,80% |
tingkat kemenangan | 24,68% | 26,50% | 24,50% | 25,60% |
tingkat kekalahan | 13,92% | 20,21% | 13,10% | 14,80% |
tingkat tetap | 2.21 Dan | 0.77 Dan | 1.14 Dan | 1.04 Dan |
[1] Agen Mahjong saya dengan model pertahanan
[2] Agen Mahjong saya tanpa model pertahanan
[3] Karya lanjutan Mizukami : Mizukami N., Tsuruoka Y.. Membangun pemain mahjong komputer berdasarkan simulasi monte carlo dan model lawan. Dalam: Konferensi IEEE 2015 tentang Kecerdasan Komputasi dan Permainan (CIG), hlm.275–283. IEEE (2015)
[4] Mizukami dkk. al. : N. Mizukami, R. Nakahari, A. Ura, M. Miwa, Y. Tsuruoka, dan T. Chikayama. Mewujudkan program mahjong komputer empat pemain melalui pembelajaran yang diawasi dengan aspek multi-pemain yang terisolasi. Transaksi Masyarakat Pemrosesan Informasi Jepang, vol. 55, tidak. 11, hlm. 1–11, 2014, (dalam bahasa Jepang).
Perhatikan bahwa saat bermain Mahjong, turun ke posisi ke-4 jelas merupakan hal yang tabu, karena poin levelnya akan berkurang. Akibatnya, tingkat jatuhnya pemain ke posisi ke-4 sangat penting untuk kinerjanya secara keseluruhan. Bot saya memiliki level tetap yang lebih baik karena tingkat tempat ke-4 yang rendah.
Untuk menjalankan agen Mahjong, kita harus menentukan beberapa konfigurasi. Seperti yang ditunjukkan pada contoh berikut dari main.py:
def run_example_ai ():
ai_module = importlib . import_module ( "agents.random_ai_example" )
ai_class = getattr ( ai_module , "RandomAI" )
ai_obj = ai_class () # [1]
player_module = importlib . import_module ( "client.mahjong_player" )
opponent_class = getattr ( player_module , "OpponentPlayer" ) # [2]
user = "ID696E3BCC-hLHNE8Wf" # [3]
user_name = "tst_tio" # [4]
game_type = '1' # [5]
logger_obj = Logger ( "log1" , user_name ) # [6]
connect_and_play ( ai_obj , opponent_class , user , user_name , '0' , game_type , logger_obj ) # play one game
def run_jianyang_ai ():
ai_module = importlib . import_module ( "agents.jianyang_ai" )
waiting_prediction_class = getattr ( ai_module , "EnsembleCLF" )
ensemble_clfs = waiting_prediction_class ()
ai_class = getattr ( ai_module , "MLAI" )
ai_obj = ai_class ( ensemble_clfs ) # [1]
opponent_class = getattr ( ai_module , "OppPlayer" ) # [2]
user = "ID696E3BCC-hLHNE8Wf" # [3]
user_name = "tst_tio" # [4]
game_type = '1' # [5]
logger_obj = Logger ( "log_jianyang_ai_1" , user_name ) # [6]
connect_and_play ( ai_obj , opponent_class , user , user_name , '0' , game_type , logger_obj )
Contoh AI : Sebuah contoh kelas dari agen Mahjong. Dalam repositori ini disediakan tiga versi agen Mahjong. Yang pertama ada di Agent.random_ai_example.py , ini adalah kelas demo untuk menunjukkan kepada calon pengembang cara mengimplementasikan agen mereka sendiri. Yang kedua ada di Agent.experiment_ai.py dan hasil eksperimen yang diberikan di bagian 4 dihasilkan oleh AI ini. Yang ketiga adalah AI terkini dan ada di Agent.jianyang_ai.py .
Kelas pemain lawan : Kelas pemain lawan. Seseorang dapat menggunakan kelas default OpponentPlayer di client.mahjong_player . Jika seseorang telah memperluas kelas OpponentPlayer karena kebutuhan tambahan, variabel ini harus disetel ke kelas yang sesuai.
ID Pengguna : Token dalam bentuk seperti yang ditunjukkan pada contoh yang didapat setelah mendaftar di tenhou.net. PERHATIAN: Silakan gunakan ID pengguna Anda sendiri. Jika ID yang sama terlalu sering digunakan dengan alamat IP yang berbeda, akun akan diblokir sementara oleh tenhou.net.
Nama pengguna : Nama pengguna terkait yang Anda buat saat mendaftar di tenhou.net. Variabel ini hanya untuk mengidentifikasi log pengujian Anda.
Jenis permainan : Jenis permainan dikodekan sebagai bilangan bulat 8-bit. Berikut adalah deskripsi untuk setiap bit.
Misalnya:
- Tenhou.net does not provide all possibility of the above specified combinations. Most online players play on configurations for example "1", "137", "193", "9"
Logger : Diperlukan dua parameter untuk menginisialisasi logger. Yang pertama adalah ID logger yang ditentukan pengguna, sehingga pengembang dapat dengan bebas memberi nama riwayat pengujiannya.
Setelah menentukan semua konfigurasi ini, cukup masukkan semua parameter ini ke connect_and_play() . Maka saatnya menonton pertunjukan agen Mahjong Anda!!!
Empat fungsi harus diimplementasikan untuk bot Mahjong, seperti yang ditunjukkan pada kelas "antarmuka" di Agent.ai_interface . Direkomendasikan agar agen Anda merupakan warisan AIInterface. Untuk penjelasan lebih mendalam dan contoh sederhana fungsi-fungsi ini, silakan lihat dokumentasi di Agent.random_ai_example.py .
class AIInterface ( MainPlayer ):
def to_discard_tile ( self ):
raise NotImplementedError
def should_call_kan ( self , tile136 , from_opponent ):
raise NotImplementedError
def try_to_call_meld ( self , tile136 , might_call_chi ):
raise NotImplementedError
def can_call_reach ( self ):
raise NotImplementedError
to_discard_tile : Berdasarkan semua informasi yang dapat diakses tentang status permainan, fungsi ini mengembalikan ubin untuk dibuang. Pengembaliannya adalah bilangan bulat dalam kisaran 0-135. Ada total 136 ubin dalam permainan Mahjong, yaitu 34 jenis ubin dan 4 salinan untuk setiap jenisnya. Dalam kesempatan yang berbeda kami menggunakan bentuk 34 (setiap nomor berhubungan dengan satu jenis ubin) atau bentuk 136 (setiap nomor berhubungan dengan satu ubin). Perhatikan bahwa di sini pengembaliannya harus dalam bentuk 136.
must_call_kan : https://en.wikipedia.org/wiki/Japanese_Mahjong#Making_melds_by_calling. Fungsi ini harus memutuskan apakah agen harus memanggil kan(Quad) meld. tile136 adalah singkatan dari ubin yang telah dibuang oleh beberapa lawan, yang dapat digunakan oleh agen untuk membentuk kan meld. from_opponent menunjukkan apakah agen membentuk kan meld dengan membuang lawan (tiga ubin di tangan dan lawan membuang yang keempat) atau ubin sendiri (keempat ubin di tangan).
coba_to_call_meld : https://en.wikipedia.org/wiki/Japanese_Mahjong#Making_melds_by_calling. Fungsi ini memutuskan apakah agen harus memanggil gabungan Pon(Triplet)/Chi(Sequence). tile136 adalah singkatan dari ubin dalam bentuk 136 yang telah dibuang oleh beberapa lawan. might_call_chi menunjukkan apakah agen dapat memanggil gabungan Chi, karena gabungan Chi hanya dapat dipanggil dengan membuang lawan di kursi kiri.
can_call_reach : https://en.wikipedia.org/wiki/Japanese_Mahjong#R%C4%ABchi. Fungsi ini memutuskan apakah agen harus mengklaim Riichi.
Ketika kelas agen Mahjong adalah subkelas dari kelas AIInterface , informasi yang tercantum sebagai berikut dapat diakses di dalam kelas agen sebagaimana ditentukan.
Mengakses | Tipe data | Yg mungkin berubah | Deskripsi |
---|---|---|---|
self.tiles136 | daftar bilangan bulat | Y | ubin tangan dalam bentuk 136 |
diri.tangan34 | daftar bilangan bulat | N | ubin tangan dalam bentuk 34 (tile34 = ubin136//4) |
self.discard136 | daftar bilangan bulat | Y | pembuangan agen di 136-dari |
mandiri.buang34 | daftar bilangan bulat | N | pembuangan agen dalam bentuk 34 |
diri.meld136 | daftar instance Meld | Y | gabungan yang disebut agen, contoh kelas Meld di client.mahjong_meld.py |
mandiri.total_melds34 | daftar daftar bilangan bulat | N | gabungan yang disebut agen dalam bentuk 34 |
mandiri.meld34 | daftar daftar bilangan bulat | N | yang disebut pon/chow melds dari agen dalam bentuk 34 |
mandiri.pon34 | daftar daftar bilangan bulat | N | yang disebut pon melds dari agen dalam bentuk 34 |
mandiri.chow34 | daftar daftar bilangan bulat | N | yang disebut chow melds dari agen dalam bentuk 34 |
mandiri.minkan34 | daftar daftar bilangan bulat | N | gabungan minkan dari agen dalam bentuk 34 |
mandiri.ankan34 | daftar daftar bilangan bulat | N | yang disebut ankan gabungan agen dalam bentuk 34 |
nama diri | rangkaian | Y | nama akun |
diri.tingkat | rangkaian | Y | tingkat akun |
diri.kursi | bilangan bulat | Y | ID kursi, agen selalu memiliki 0 |
self.dealer_seat | bilangan bulat | Y | ID kursi dealer |
self.is_dealer | boolean | N | apakah agen tersebut dealer atau bukan |
self.reach_status | boolean | Y | menunjukkan apakah agen tersebut telah mengklaim Riichi |
mandiri.just_reach() | boolean | N | apakah agen tersebut baru saja mengaku Riichi |
self.tmp_rank | bilangan bulat | Y | peringkat agen dalam game saat ini |
diri.skor | bilangan bulat | Y | skor agen dalam permainan saat ini |
self.is_open_hand | boolean | N | apakah agen telah memanggil penggabungan terbuka |
self.turn_num | bilangan bulat | N | jumlah belokan saat ini |
self.player_wind | bilangan bulat | N | pemain angin adalah salah satu jenis yaku |
self.round_wind | bilangan bulat | N | angin bulat adalah salah satu jenis yaku |
self.bonus_honors | daftar bilangan bulat | Y | semua ubin karakter yang memiliki yaku |
Seseorang dapat mengakses instance kelas lawan dengan memanggil self.game_table.get_player(i) dengan i sama dengan 1,2,3, yang menunjukkan id lawan yang sesuai.
Mengakses | Tipe data | Yg mungkin berubah | Deskripsi |
---|---|---|---|
.buang136 | daftar bilangan bulat | Y | buangan lawan yang diamati dalam 136-dari |
.buang34 | daftar bilangan bulat | N | buangan lawan yang diamati dalam bentuk 34 |
.meld136 | daftar instance Meld | Y | gabungan yang disebut dari lawan yang diamati |
.total_melds34 | daftar daftar bilangan bulat | N | gabungan yang disebut dari lawan yang diamati dalam bentuk 34 |
.meld34 | daftar daftar bilangan bulat | N | yang disebut perpaduan pon/chow dari lawan yang diamati dalam bentuk 34 |
.pon34 | daftar daftar bilangan bulat | N | yang disebut pon melds dari lawan yang diamati dalam bentuk 34 |
.chow34 | daftar daftar bilangan bulat | N | yang disebut chow melds dari lawan yang diamati dalam bentuk 34 |
.minkan34 | daftar daftar bilangan bulat | N | gabungan minkan yang disebut dari lawan yang diamati dalam bentuk 34 |
.ankan34 | daftar daftar bilangan bulat | N | yang disebut perpaduan ankan dari lawan yang diamati dalam bentuk 34 |
.safe_tiles | daftar bilangan bulat | Y | ubin dalam bentuk 34 yang benar-benar aman bagi agen, yaitu lawan yang diamati tidak dapat menang dengan ubin tersebut |
.nama | rangkaian | Y | nama lawannya |
.tingkat | rangkaian | Y | tingkat lawan |
.kursi | bilangan bulat | Y | ID kursi lawan yang diamati |
.dealer_seat | bilangan bulat | Y | ID kursi dealer |
.is_dealer | boolean | N | apakah lawan yang diamati adalah dealer atau bukan |
.reach_status | boolean | Y | menunjukkan apakah lawan yang diamati telah mengklaim Riichi |
.just_reach() | boolean | N | apakah lawan yang diamati baru saja mengklaim Riichi |
.tmp_rank | bilangan bulat | Y | peringkat lawan yang diamati dalam game saat ini |
.skor | bilangan bulat | Y | skor lawan yang diamati pada pertandingan saat ini |
.is_open_hand | boolean | N | apakah lawan yang diamati sudah melakukan open melds |
.turn_num | bilangan bulat | N | jumlah belokan saat ini |
.player_wind | bilangan bulat | N | pemain angin adalah salah satu jenis yaku |
.round_wind | bilangan bulat | N | angin bulat adalah salah satu jenis yaku |
.bonus_honors | daftar bilangan bulat | Y | semua ubin karakter yang memiliki yaku |
Untuk mengakses informasi tentang meja permainan, seseorang dapat menghubungi self.game_table
Mengakses | Tipe data | Yg mungkin berubah | Deskripsi |
---|---|---|---|
.bot | contoh kelas agen | Y | contoh kelas agen |
.get_player(i) | contoh kelas lawan | Y | instance kelas lawan, i=1,2,3 |
.dealer_seat | bilangan bulat | Y | ID kursi dealer |
.bonus_indikator | daftar bilangan bulat | Y | indikator bonus dalam bentuk 136 |
.round_number | bilangan bulat | Y | angka bulat |
.reach_sticks | bilangan bulat | Y | Berapa banyak tongkat Riichi yang ada di atas meja. Pemain yang menang selanjutnya akan menerima semua poin dari tongkat Riichi tersebut |
.honba_sticks | bilangan bulat | Y | Berapa batang honba yang ada di atas meja. Pemain akan mendapat poin ekstra sesuai tongkat honba jika menang |
.count_ramaining_tiles | bilangan bulat | Y | Jumlah sisa ubin yang belum terungkap |
.terungkap | daftar bilangan bulat | Y | Setiap elemen dalam daftar menunjukkan berapa banyak salinan ubin khusus ini yang telah terungkap (buangan, penggabungan terbuka, indikator bonus, dll.) |
.round_win | bilangan bulat | N | angin bulat adalah salah satu jenis yaku |
.bonus_tiles | daftar bilangan bulat | N | Daftar ubin bonus. Setiap kemunculan ubin bonus di ubin tangan dihitung sebagai yaku |
.last_discard | bilangan bulat | N | Buangan terbaru dari lawan, ubin ini benar-benar aman menurut aturan |
profesor saya Johannes Fürnkranz (Kelompok Teknik Pengetahuan TU Darmstadt)
supervisor saya Tobias Joppen (TU Darmstadt Knowledge Engineering Group)