diff --git a/README.md b/README.md index be6e1e7..cb91217 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,64 @@ > Tugas Besar - IF1210 Dasar Pemrograman 2024 # About +Pada tugas besar Dasar Pemrograman IF1210 2024 ini kami membuat program sebuah permainan bertipe turn-based berdasarkan cerita Purry the Platypus, atau dikenal juga dengan Agent P, yang ingin menyelamatkan kota Danville dari Dr. Asep Spakbor. Karena monster-monster yang dimiliki Dr. Asep Spakbor terlalu kuat, maka Agent P membutuhkan bantuan Agent O.W.C.A. (para player) untuk mencari dan melatih para monster yang kuat di hutan terpencil yang diyakini menjadi tempat tinggal banyak monster-monster kuat. Adapun program dapat di-run melalui file main.py pada terminal. # Contributors +- Abu Dzar Al-Ghifari (16523058) +- Muhammad Refino Ramadhan (19623028) +- Darren Mansyl (19623168) +- Favian Rafi Laftiyanto (19623238) +- Mahesa Satria Prayata (19623278) # Features +Sesuai dengan background cerita di atas, program dapat diurai menjadi fungsional-fungsional sebagai berikut, +1. Fungsi-fungsi penyimpanan akun dan data dan fungsi RNG, +> F00 - Random Number Generator, untuk menghasilkan bilangan acak menggunakan algoritma Linear Congruential Generator (LCG). +> F01 - Register, untuk memasukkan username dan password dari akun yang akan digunakan untuk memulai permainan. Username hanya dapat mengandung alfabet A-Z, a-z, underscore “_”, strip “-”, dan angka 0-9. Bila username belum terdaftar, maka akun diharuskan untuk memilih 1 monster starter, 0 O.W.C.A. coin, dan terdaftar sebagai agent. +> F02 - Login, untuk login ke akun yang sudah didaftar sebelumnya. +> F03 - Logout, untuk keluar dari akun yang sedang digunakan. +> F04 - Menu dan Help, untuk mengingatkan dan menuntun pengguna dan mengingatkan untuk melakukan validasi input dalam bentuk footnote. +> F05 - Monster, file yang menyimpan data monster dengan format “monster.csv”. File tersebut berisi statistik monster berupa, +Type, nama dari monster yang bersifat unik. +> ATK Power, Kekuatan serangan setiap monster. Ketika monster melakukan serangan, nilai kekuatan serangannya diambil secara acak dengan rentang ±30% dari ATK Power. Contoh untuk ATK Power = 500, rentang nilai serangannya adalah 350 - 850. +> DEF Power, Kekuatan pertahanan setiap monster dari serangan. DEF digunakan sebagai faktor pengali untuk mengurangi serangan musuh. Rentang nilainya adalah 0 - 50. Contoh untuk DEF Power = 50, maka monster dapat menurunkan serangan musuh sebesar 50%. +> HP, jumlah darah yang dimiliki para monster +> F06 - Potion, untuk membantu player dalam battle. Berikut adalah jenis-jenis potion serta efeknya, +> Healing Potion, Mengisi darah sebanyak 25% dari Base HP. Pastikan HP tidak melebihi dari maksimal HP. +> Resilience Potion, Meningkatkan DEF Power sebanyak 5% dari DEF Power. +> Strength Potion, Meningkatkan ATK Power sebanyak 5% dari ATK Power. +> ATK Power, DEF Power, dan HP mengikuti level Monster dari player, Masing-masing potion hanya dapat digunakan sekali dalam 1 battle dan efeknya hanya berlaku hingga battle itu selesai. +> F14 - Load, untuk masuk kembali ke akun yang sudah terdaftar. +> F15 - Save, untuk menyimpan progress akun ke dalam folder yang ditentukan. +> F16 - Exit, untuk keluar dari program. Ada juga fitur untuk save terlebih dahulu sebelum melakukan exit. +2. Fungsi-fungsi yang dapat diakses oleh agent, +> F07 - Inventory, berupa file untuk menyimpan item yang dimiliki oleh player seperti potion, monster, dan monster ball. Terdapat format file yang berbeda untuk item (item_inventory.csv) dan monster (monster_inventory.csv). +> F08 - Battle, fitur utama dalam game ini untuk melawan monster-monster liar yang dipilih secara random. berikut adalah mekanismenya, +Muncul monster (musuh) secara random (RNG) database Monster; Agent memilih monster (agent) yang ingin dipertarungkan. +> Setiap putaran Agent memiliki pilihan untuk “Attack”, “Use Potion”, atau “Quit”; Monster (musuh) hanya bisa “Attack”. +> Kondisi kemenangan adalah saat nyawa monster (musuh) habis; Agent mendapatkan OC (OC yang diterima random (RNG), misal 5-30). +> Kondisi kekalahan adalah saat nyawa monster (agent) habis; Agent keluar dari pertempuran, nyawa monster yang dipertarungkan kembali penuh (tidak hilang dari inventory). +> F09 - Arena, fitur latihan agar player dapat terbiasa dengan mekanisme battle. Mekanismenya sama seperti fitur battle. Player akan mendapatkan hadiah setara dengan jumlah stage yang berhasil dilewati. (OC = O.W.C.A. Coin) +Stage 1: 50 OC +Stage 2: 100 OC +Stage 3: 150 OC +Stage 4: 200 OC +stage 5: 250 OC +> F10 - Shop & Currency, tempat player membeli monster dan potion tambahan. Terdapat format file khusus item (item_shop.csv) dan monster (monster_shop.csv). +> F11 - Laboratory, fitur untuk meng-upgrade level monster yang dimiliki oleh player. Untuk melakukan upgrade diperlukan OC. Berikut adalah harganya, +Level 1 - 2: 100, +Level 2 - 3: 200, +Level 3 - 4: 400, +Level 4 - 5: 700 +Fungsi-fungsi yang dapat diakses oleh admin, +> F12 - Shop Management, untuk mengubah dan menghapus item dalam shop +> F13 - Monster Management, untuk menampilkan seluruh monster dalam program dan menambah monster ke program. -# How to Run \ No newline at end of file +# How to Run +Program dapat di-run dengan cara membuka terminal pada file "main.py" kemudian mengetik "python main.py data1" pada terminal. *Note: data1 bisa diubah menjadi data yang lain yang tersedia pada folder data. +Setelah memulai program, user dapat menggunakan fitur "Help" untuk melihat fitur apa saja yang dapat dilakukan. +Sebelum login, terdapat 4 fitur yang dapat dilakukan: login, register, save, dan exit. +Setelah register dan/atau login, terdapat 7 fitur yang dapat dilakukan, yaitu: battle, arena, shop, inventory, laboratory, jackpot, dan logout. +Ada pula fitur khusus yang hanya bisa diakses oleh user dengan role "Admin" (tidak ada cara untuk register sebagai "Admin", yaitu: monster management, shop management, dan logout. + +Selamat bermain! ^-^ diff --git a/blank.py b/blank.py new file mode 100644 index 0000000..e69de29 diff --git a/data/data1/item_inventory.csv b/data/data1/item_inventory.csv new file mode 100644 index 0000000..82b2573 --- /dev/null +++ b/data/data1/item_inventory.csv @@ -0,0 +1,13 @@ +userid;type;quantity +1;Healing Potion;2 +1;Resilience Potion;3 +1;Strength Potion;2 +1;Monster Ball;2 +3;Healing Potion;2 +3;Resilience Potion;1 +3;Strength Potion;4 +3;Monster Ball;1 +2;Healing Potion;2 +2;Resilience Potion;2 +2;Strength Potion;9 +2;Monster Ball;5 \ No newline at end of file diff --git a/data/data1/item_shop.csv b/data/data1/item_shop.csv new file mode 100644 index 0000000..7e08cd5 --- /dev/null +++ b/data/data1/item_shop.csv @@ -0,0 +1,5 @@ +type;stock;price +Healing Potion;5;25 +Resilience Potion;5;30 +Strength Potion;5;40 +Monster Ball;5;100 \ No newline at end of file diff --git a/data/data1/monster.csv b/data/data1/monster.csv new file mode 100644 index 0000000..86babdf --- /dev/null +++ b/data/data1/monster.csv @@ -0,0 +1,16 @@ +id;type;atk_power;def_power;hp +1;Godzilla;70;32;540 +2;Mimic;45;28;600 +3;Makima;135;5;250 +4;Jalangkung;3700;12;650 +5;gigidi;54;19;420 +6;Gorlock;22;20;700 +7;Bunny;65;24;550 +8;Roga;88;8;222 +9;Molded;66;24;440 +10;Mohg;50;20;600 +11;Malenia;55;30;500 +12;Kraken;20;35;570 +13;Mothra;57;21;520 +14;Parkinson;44;31;470 +15;Ifrit;90;5;330 \ No newline at end of file diff --git a/data/data1/monster_inventory.csv b/data/data1/monster_inventory.csv new file mode 100644 index 0000000..fa699c0 --- /dev/null +++ b/data/data1/monster_inventory.csv @@ -0,0 +1,8 @@ +id;monster;level +1;Mimic;1 +1;Makima;2 +1;Jalangkung;3 +2;Makima;1 +2;Mimic;1 +3;Jalangkung;2 +3;Mimic;1 \ No newline at end of file diff --git a/data/data1/monster_shop.csv b/data/data1/monster_shop.csv new file mode 100644 index 0000000..41ee368 --- /dev/null +++ b/data/data1/monster_shop.csv @@ -0,0 +1,4 @@ +monster_id;stock;price +1;6;800 +2;13;300 +3;2;750 \ No newline at end of file diff --git a/data/data1/user.csv b/data/data1/user.csv new file mode 100644 index 0000000..6f16e9b --- /dev/null +++ b/data/data1/user.csv @@ -0,0 +1,8 @@ +id;username;password;role;coin +1;bagas;12345;agent;100000000000 +2;bagus;12345;agent;100 +3;bages;12345;agent;100 +4;bagos;12345;agent;100 +5;bagis;12345;agent;100 +6;june;12345;admin;9999 +7;juni;12345;admin;9999 \ No newline at end of file diff --git a/data/data2/item_inventory.csv b/data/data2/item_inventory.csv new file mode 100644 index 0000000..82b2573 --- /dev/null +++ b/data/data2/item_inventory.csv @@ -0,0 +1,13 @@ +userid;type;quantity +1;Healing Potion;2 +1;Resilience Potion;3 +1;Strength Potion;2 +1;Monster Ball;2 +3;Healing Potion;2 +3;Resilience Potion;1 +3;Strength Potion;4 +3;Monster Ball;1 +2;Healing Potion;2 +2;Resilience Potion;2 +2;Strength Potion;9 +2;Monster Ball;5 \ No newline at end of file diff --git a/data/data2/item_shop.csv b/data/data2/item_shop.csv new file mode 100644 index 0000000..7e08cd5 --- /dev/null +++ b/data/data2/item_shop.csv @@ -0,0 +1,5 @@ +type;stock;price +Healing Potion;5;25 +Resilience Potion;5;30 +Strength Potion;5;40 +Monster Ball;5;100 \ No newline at end of file diff --git a/data/data2/monster.csv b/data/data2/monster.csv new file mode 100644 index 0000000..2afb49b --- /dev/null +++ b/data/data2/monster.csv @@ -0,0 +1,17 @@ +id;type;atk_power;def_power;hp +1;Godzilla;70;32;540 +2;Mimic;45;28;600 +3;Makima;135;5;250 +4;Jalangkung;37;12;650 +5;gigidi;54;19;420 +6;Gorlock;22;20;700 +7;Bunny;65;24;550 +8;Roga;88;8;222 +9;Molded;66;24;440 +10;Mohg;50;20;600 +11;Malenia;55;30;500 +12;Kraken;20;35;570 +13;Mothra;57;21;520 +14;Parkinson;44;31;470 +15;Ifrit;90;5;330 +16;kanaguri;1000;50;1000 \ No newline at end of file diff --git a/data/data2/monster_inventory.csv b/data/data2/monster_inventory.csv new file mode 100644 index 0000000..a96177d --- /dev/null +++ b/data/data2/monster_inventory.csv @@ -0,0 +1,10 @@ +id;monster;level +1;Mimic;1 +1;Makima;2 +1;Jalangkung;3 +2;Makima;1 +2;Mimic;1 +3;Jalangkung;2 +3;Mimic;1 +1;kanaguri;1 +1;Godzilla;1 \ No newline at end of file diff --git a/data/data2/monster_shop.csv b/data/data2/monster_shop.csv new file mode 100644 index 0000000..bc44c3e --- /dev/null +++ b/data/data2/monster_shop.csv @@ -0,0 +1,5 @@ +monster_id;stock;price +1;5;800 +2;13;300 +3;2;750 +16;110;111 \ No newline at end of file diff --git a/data/data2/user.csv b/data/data2/user.csv new file mode 100644 index 0000000..8f3e7b3 --- /dev/null +++ b/data/data2/user.csv @@ -0,0 +1,8 @@ +id;username;password;role;coin +1;bagas;12345;agent;99999999089 +2;bagus;12345;agent;100 +3;bages;12345;agent;100 +4;bagos;12345;agent;100 +5;bagis;12345;agent;100 +6;june;12345;admin;9999 +7;juni;12345;admin;9999 \ No newline at end of file diff --git a/data/data3/item_inventory.csv b/data/data3/item_inventory.csv new file mode 100644 index 0000000..6b9013e --- /dev/null +++ b/data/data3/item_inventory.csv @@ -0,0 +1,16 @@ +userid;type;quantity +1;Healing Potion;2 +1;Resilience Potion;3 +1;Strength Potion;2 +1;Monster Ball;2 +3;Healing Potion;2 +3;Resilience Potion;1 +3;Strength Potion;4 +3;Monster Ball;1 +2;Healing Potion;2 +2;Resilience Potion;2 +2;Strength Potion;9 +2;Monster Ball;5 +8;healingpotion;0 +8;respotion;0 +8;strenghpotion;0 \ No newline at end of file diff --git a/data/data3/item_shop.csv b/data/data3/item_shop.csv new file mode 100644 index 0000000..7e08cd5 --- /dev/null +++ b/data/data3/item_shop.csv @@ -0,0 +1,5 @@ +type;stock;price +Healing Potion;5;25 +Resilience Potion;5;30 +Strength Potion;5;40 +Monster Ball;5;100 \ No newline at end of file diff --git a/data/data3/monster.csv b/data/data3/monster.csv new file mode 100644 index 0000000..86babdf --- /dev/null +++ b/data/data3/monster.csv @@ -0,0 +1,16 @@ +id;type;atk_power;def_power;hp +1;Godzilla;70;32;540 +2;Mimic;45;28;600 +3;Makima;135;5;250 +4;Jalangkung;3700;12;650 +5;gigidi;54;19;420 +6;Gorlock;22;20;700 +7;Bunny;65;24;550 +8;Roga;88;8;222 +9;Molded;66;24;440 +10;Mohg;50;20;600 +11;Malenia;55;30;500 +12;Kraken;20;35;570 +13;Mothra;57;21;520 +14;Parkinson;44;31;470 +15;Ifrit;90;5;330 \ No newline at end of file diff --git a/data/data3/monster_inventory.csv b/data/data3/monster_inventory.csv new file mode 100644 index 0000000..86ccaab --- /dev/null +++ b/data/data3/monster_inventory.csv @@ -0,0 +1,9 @@ +id;monster;level +1;Mimic;1 +1;Makima;2 +1;Jalangkung;3 +2;Makima;1 +2;Mimic;1 +3;Jalangkung;2 +3;Mimic;1 +8;Godzilla;1 \ No newline at end of file diff --git a/data/data3/monster_shop.csv b/data/data3/monster_shop.csv new file mode 100644 index 0000000..41ee368 --- /dev/null +++ b/data/data3/monster_shop.csv @@ -0,0 +1,4 @@ +monster_id;stock;price +1;6;800 +2;13;300 +3;2;750 \ No newline at end of file diff --git a/data/data3/user.csv b/data/data3/user.csv new file mode 100644 index 0000000..bb27a11 --- /dev/null +++ b/data/data3/user.csv @@ -0,0 +1,9 @@ +id;username;password;role;coin +1;bagas;12345;agent;100000000000 +2;bagus;12345;agent;100 +3;bages;12345;agent;100 +4;bagos;12345;agent;100 +5;bagis;12345;agent;100 +6;june;12345;admin;9999 +7;juni;12345;admin;9999 +8;bagas123-_;ekif;agent;0 \ No newline at end of file diff --git a/data/data4/item_inventory.csv b/data/data4/item_inventory.csv new file mode 100644 index 0000000..82b2573 --- /dev/null +++ b/data/data4/item_inventory.csv @@ -0,0 +1,13 @@ +userid;type;quantity +1;Healing Potion;2 +1;Resilience Potion;3 +1;Strength Potion;2 +1;Monster Ball;2 +3;Healing Potion;2 +3;Resilience Potion;1 +3;Strength Potion;4 +3;Monster Ball;1 +2;Healing Potion;2 +2;Resilience Potion;2 +2;Strength Potion;9 +2;Monster Ball;5 \ No newline at end of file diff --git a/data/data4/item_shop.csv b/data/data4/item_shop.csv new file mode 100644 index 0000000..7e08cd5 --- /dev/null +++ b/data/data4/item_shop.csv @@ -0,0 +1,5 @@ +type;stock;price +Healing Potion;5;25 +Resilience Potion;5;30 +Strength Potion;5;40 +Monster Ball;5;100 \ No newline at end of file diff --git a/data/data4/monster.csv b/data/data4/monster.csv new file mode 100644 index 0000000..2de3d0a --- /dev/null +++ b/data/data4/monster.csv @@ -0,0 +1,17 @@ +id;type;atk_power;def_power;hp +1;Godzilla;70;32;540 +2;Mimic;45;28;600 +3;Makima;135;5;250 +4;Jalangkung;3700;12;650 +5;gigidi;54;19;420 +6;Gorlock;22;20;700 +7;Bunny;65;24;550 +8;Roga;88;8;222 +9;Molded;66;24;440 +10;Mohg;50;20;600 +11;Malenia;55;30;500 +12;Kraken;20;35;570 +13;Mothra;57;21;520 +14;Parkinson;44;31;470 +15;Ifrit;90;5;330 +16;ohio;100;10;10 \ No newline at end of file diff --git a/data/data4/monster_inventory.csv b/data/data4/monster_inventory.csv new file mode 100644 index 0000000..f38ffeb --- /dev/null +++ b/data/data4/monster_inventory.csv @@ -0,0 +1,8 @@ +id;monster;level +1;Mimic;5 +1;Makima;2 +1;Jalangkung;3 +2;Makima;1 +2;Mimic;1 +3;Jalangkung;2 +3;Mimic;1 \ No newline at end of file diff --git a/data/data4/monster_shop.csv b/data/data4/monster_shop.csv new file mode 100644 index 0000000..e920ed1 --- /dev/null +++ b/data/data4/monster_shop.csv @@ -0,0 +1,3 @@ +monster_id;stock;price +1;6;800 +3;2;750 \ No newline at end of file diff --git a/data/data4/user.csv b/data/data4/user.csv new file mode 100644 index 0000000..9a132df --- /dev/null +++ b/data/data4/user.csv @@ -0,0 +1,8 @@ +id;username;password;role;coin +1;bagas;12345;agent;99999993760 +2;bagus;12345;agent;100 +3;bages;12345;agent;100 +4;bagos;12345;agent;100 +5;bagis;12345;agent;100 +6;june;12345;admin;9999 +7;juni;12345;admin;9999 \ No newline at end of file diff --git a/doc/IF1210_LaporanTB_K08-B.pdf b/doc/IF1210_LaporanTB_K08-B.pdf new file mode 100644 index 0000000..8590d32 Binary files /dev/null and b/doc/IF1210_LaporanTB_K08-B.pdf differ diff --git a/doc/MoM Asistensi 1.pdf b/doc/MoM Asistensi 1.pdf new file mode 100644 index 0000000..f36875b Binary files /dev/null and b/doc/MoM Asistensi 1.pdf differ diff --git a/doc/MoM Asistensi 2.pdf b/doc/MoM Asistensi 2.pdf new file mode 100644 index 0000000..dcbb03e Binary files /dev/null and b/doc/MoM Asistensi 2.pdf differ diff --git a/main.py b/main.py index e69de29..2464fd7 100644 --- a/main.py +++ b/main.py @@ -0,0 +1,119 @@ +from src.load import * +from src.battle import * +from src.arena import* +from src.RandomNumberGenerator import * +from src.inventory import * +from src.shopCurrency import * +from src.help import * +from src.laboratory import * +from src.jackpot import * +import time +from src.exit import * +from src.monsterManagement import * +from src.readwritecsv import * + +data=load() +if data != [] : + userData = data[0] + inventoryData = data[1] + monsterData = data[2] + monsInvData = data[3] + itemShopData = data[4] + monsShopData = data[5] + loginStatus = False + while True : + print("Ketik 'Help' untuk mendapatkan petunjuk dari Almighty God") + command = input("---> ") + if command.lower() == "login" : + while True : + userInv, yourMonsInv, role, coin = login(userData, inventoryData, monsInvData) + if userInv != 0 and role != 0 and coin !=0 and yourMonsInv !=0 : + loginStatus = True + break + elif command.lower() == 'register' : + userInv, yourMonsInv, role, coin = register(userData, inventoryData, monsInvData, monsterData) + loginStatus = True + elif command.lower() == "help" : + help(loginStatus, "belumlogin") + elif command.lower() == 'save' : + save(inventoryData, monsterData, userData, monsShopData, itemShopData, monsInvData) + elif command.lower()=='exit' : + exit(userData, monsInvData, itemShopData, monsterData, monsShopData, inventoryData) + break + else : + print(f"command '{command}' tidak ada.") + if loginStatus == True : + if role.lower() == 'agent': + while True : + id = int(userInv[0][0]) + print("Ketik 'Help' untuk mendapatkan petunjuk dari Almighty God") + command = input("---> ") + if command.lower() == 'battle' : + randomNumber = RNG(1, len(monsterData)) + time.sleep(2/10) + randomLevel = RNG(1,5) + confirm = battlerule() + if confirm.lower() == "n" : + continue + opening(monsterData, randomNumber) + chosen = choose(yourMonsInv) + battleCoin,damageTaken,damageDealt = battle(monsterData, monsInvData, yourMonsInv, userInv, chosen, randomNumber, randomLevel, 'battle') + coin += battleCoin + userData[id][4] = str(coin) + elif command.lower() == 'arena' : + arenaCoin = arena(monsterData, monsInvData, yourMonsInv, userInv) + coin += arenaCoin + userData[id][4] = str(coin) + elif command.lower() == 'inventory' : + inventory(userInv, yourMonsInv, monsterData, role, coin) + elif command.lower() == 'logout' : + while True : + confirm = input("Apakah anda yakin untuk logout?(Y/N)--> ") + if confirm.lower() == "y" : + print("Logout berhasil") + loginStatus = False + break + elif confirm.lower() == 'n' : + break + else : + print("Masukkan input yang benar") + if loginStatus == False : + break + elif command.lower() == 'shop' : + coin = shopOpen(role, itemShopData, coin, userInv, monsterData, monsShopData, yourMonsInv, monsInvData) + userData[id][4] = str(coin) + elif command.lower() == 'help' : + help(loginStatus, role) + elif command.lower() == 'laboratory' : + coin = laboratory(yourMonsInv, coin, role) + userData[id][4] = str(coin) + elif command.lower() == 'jackpot' : + coin = jackpot(id, coin, monsInvData, yourMonsInv) + userData[id][4] = str(coin) + else : + print(f"command '{command}' tidak ada.") + elif role == 'admin' : + while True : + print("Ketik 'Help' untuk mendapatkan petunjuk dari Almighty God") + command = input("--->") + if command.lower() == 'help': + help(loginStatus, role) + elif command.lower() == 'shop': + monsShopData, itemShopData = shopmanagement(itemShopData, monsShopData, monsterData) + elif command.lower() == 'logout' : + while True : + confirm = input("Apakah anda yakin untuk logout?(Y/N)--> ") + if confirm.lower() == "y" : + print("Logout berhasil") + loginStatus = False + break + elif confirm.lower() == 'n' : + break + else : + print("Masukkan input yang benar") + if loginStatus == False : + break + elif command.lower() == 'monster' : + monsterManagement(monsterData) + else : + print(f"command '{command}' tidak ada.") \ No newline at end of file diff --git a/ok.py b/ok.py new file mode 100644 index 0000000..4bc00ca --- /dev/null +++ b/ok.py @@ -0,0 +1,19 @@ +def is_valid_string(input_string): + for char in input_string: + ascii_value = ord(char) + # Check if the character is a letter, number, hyphen, or underscore + valid = ( + (65 <= ascii_value <= 90) or # A-Z + (97 <= ascii_value <= 122) or # a-z + (48 <= ascii_value <= 57) or # 0-9 + ascii_value == 45 or # hyphen (-) + ascii_value == 95 # underscore (_) + ) + # If any character is not valid, return False + if valid == False: + return False + return True + +# Example usage: +print(is_valid_string("---___#")) + diff --git a/src/RandomNumberGenerator.py b/src/RandomNumberGenerator.py new file mode 100644 index 0000000..60a3b44 --- /dev/null +++ b/src/RandomNumberGenerator.py @@ -0,0 +1,27 @@ +import os +import time + +# Fungsi untuk membuat sebuah nomor acak +def LCG(a, c, m): + seed = int(os.getpid()*123 + time.time()*45) + x2 = (a * seed + c) % m # Rumus Dasar LCG + return x2 +# Seed ditentukan menggunakan process id dan time agar selalu bervariasi +# *123, *45 hanya untuk menambah kerandoman + +# Fungsi untuk memastikan bahwa nomor acak yang didapat berada pada range yang ditentukan +def GenerateNumber(x2,num_range): + a = 48271 + c = 0 + m = 2**31 - 1 + # Nilai-nilai diatas diapakai dalam C++11 dalam fungsi minstd_rand + x2 = (a * x2 + c) % m + return int((x2 / (m - 1)) * (num_range[1] - num_range[0]) + num_range[0]) +# Dapet formula dari yt :) + +# Fungsi yang digunakan untuk mensimplifikasi sehingga hanya perlu menyertakan batas-batasnnya +def RNG(x,y): + a = 48271 + c = 0 + m = 2**31 - 1 + return GenerateNumber(LCG(a,c,m),[x,y]) \ No newline at end of file diff --git a/src/arena.py b/src/arena.py new file mode 100644 index 0000000..0d81d48 --- /dev/null +++ b/src/arena.py @@ -0,0 +1,90 @@ +from src.battle import * +from src.RandomNumberGenerator import * +def arenaart() : + print(f''' + T~~ + /" + T~~ |'| T~~ + T~~ | T~ WWWW| + | /"\ | | |/\T~~ + /"\ WWW /"\ |' |WW| + WWWWW/\| / \|'/\|/" + | /__\/]WWW[\/__\WWWW + |" WWWW'|I_I|'WWWW' | + | |' |/ - \|' |' | + |' | |LI=H=LI|' | | + | |' | |[_]| | |' | + | | |_|###|_| | | + '---'--'-/___\-'--'---' ''') + +def arenarule() : + arenaart() + print(""" +======================WELCOME TO THE ARENA====================== +ARENA MEKANISM : + 1. THERE WILL BE A TOTAL OF 5 STAGES IN THE ARENA, EACH STAGE YOU WILL BE BATTLING + A RANDOMLY SELECTED MONSTER + 2. YOUR ENEMY LEVEL WILL BE EQUAL TO THE STAGE NUMBER YOUR CURRENTLY ON + 3. DEFEATING EACH STAGE WILL GAVE YOU A REWARD, THE HIGHER THE STAGE, THE + THE GREATER THE REWARD + 4. IF YOU LOSE ONCE, THE ARENA WILL BE OVER + 5. IF YOU WIN ALL THE WAY, YOU WILL GET A BONUS REWARD + 6. POTIONS EFFECT ONLY LAST TILL THE END OF EACH STAGE + 7. MONSTER BALL IS PROHIBITED IN THE ARENA """) + while True : + confirm = input("PROCEED?(Y/N)--->") + if confirm.lower() =='y' : + return confirm + elif confirm.lower() =='n' : + return confirm + else : + print("BE CLEAR") + +def arena(monsterdata,monsterinventory,yourmonsterdata,userinventory) : + #deklarasi variabel + reward = [30,45,60,75,90] #coins gain from defeating each stage + coins=0 + totaldamageTaken = 0 + totaldamageDealt = 0 + confirm = arenarule() + if confirm.lower()=="n" : #jika tidak jadi + print("SEE U ANOTHER DAY") + else : + chosen = choose(yourmonsterdata) #fungsi untuk memilih monster dari pilihan monsterinventory + stage = 1 + for i in range(5) : #pemanggilan fungsi battle sebanyak maksimum 5 kali + random_number = RNG(1,len(monsterdata)) + enemylevel = i+1 #level monster musuh sesuai nomor stage + print(f"--------->>>STAGE {i+1}<<<---------") + opening(monsterdata,random_number) + coin,damageTaken,damageDealt = battle(monsterdata,monsterinventory,yourmonsterdata,userinventory,chosen,random_number,enemylevel,'arena') + totaldamageTaken += damageTaken + totaldamageDealt += damageDealt + + if coin==0 : #coin==0 di arena hanya terjadi saat monster kita kalah + print("ARENA IS OVER, TRY AGAIN") + break + else : #monster kita menang + stage += 1 + print("STAGE CLEARED") + print() + if stage != 6 : + print("PREPARING NEXT STAGE") + + for i in range(1,stage) : + coins += reward[i-1] + + if stage==6 : #jika berhasil sampai ke stage terakhir dan menang akan mendapatkan bonus 50 coin + print("CONGRATULATION YOU MADE IT ALL THE WAY!!!!") + print("HERE A BONUS 50 COINS FOR YOU!!!") + coins += 50 + + #STATISTIK ARENA + print("==========================================") + print("STATISTICS FROM THE ARENA :") + print(f"NUMBER OF STAGE : {stage-1}") + print(f"TOTAL COIN GAINED FROM THE ARENA : {coins}") + print(f"TOTAL DAMAGE TAKEN : {totaldamageTaken}") + print(f"TOTAL DAMAGE DEALT : {totaldamageDealt}") + print("==========================================") + return coins \ No newline at end of file diff --git a/src/battle.py b/src/battle.py new file mode 100644 index 0000000..ab59317 --- /dev/null +++ b/src/battle.py @@ -0,0 +1,267 @@ +#import module yang dibutuhkan +from src.potion import * +from src.RandomNumberGenerator import * +from src.monsterball import * +import time + +def battleart() : #fungsi tampilan awal + print(''' + |\ /) + /\_\\__ (_// +| `>\-` _._ //`) + \ /` \\ _.-`:::`-._ // + ` \|` ::: `|/ + | ::: | + |.....:::.....| + |:::::::::::::| + | ::: | + \ ::: / + \ ::: / + `-. ::: .-' + //`:::`\\ + // ' \\ + |/ \\''') + +def battlerule() : + battleart() + print(""" +BATTLE MEKANISM : + 1. YOU WILL FIGHT A RANDOMLY SELECTED MONSTER WITH A RANDOMLY SELECTED LEVEL + 2. IT IS TURN BASE 1V1 SYSTEM WITH THE YOU(THE PLAYER) ALWAYS MAKE THE FIRST MOVE + 3. IN EACH OF YOUR MOVE, YOU WILL BE GIVEN 4 CHOICES : ATTACK,USE POTION,USE MONSTERBALL OR QUIT + 4. THE ENEMY CAN ONLY ATTACK + 5. IF THE ENEMY HEALTH IS DOWN TO 0, YOU WIN THE BATTLE AND RANDOM AMOUNT OF GOLD + 6. IF YOUR MONSTER HEALTH IS DOWN TO ZERO, YOU WILL LOSE AND GET 0 GOLD + 7. YOU CAN ONLY USE EACH POTION ONCE AND THE EFFECT ONLY LAST TILL THE BATTLE ENDS + 8. FAILING TO CACTH THE ENEMY MONSTER WITH THE MONSTERBALL DOES NOT SKIP THEIR TURN + 9. IF YOU QUIT MID BATTLE, YOU WILL GET 0 GOLD +""") + while True : + confirm = input("PROCEED?(Y/N)--->") + if confirm.lower() =='y' : + return confirm + elif confirm.lower() =='n' : + return confirm + else : + print("BE CLEAR") + +#fungsi untuk memilih monster yg ingin dipakai untuk battle +def choose(yourmonsterdata) : + while True : + print("=======PLEASE CHOOSE A MONSTER=======") + x=0 + for i in yourmonsterdata : #menampilkan seluruh monster yg player punya + print(f"{x+1}. {(i[1]).upper()}") + x+=1 + chosen = input("(1/2/3/dst)--->") #input monster yg ingin dipilih + k=0 + for i in range(1,len(yourmonsterdata)+1) : + if str(i)==chosen : + k=1 + break #jika monster yg dipilih ada dalam pilihan + if k==1 : break + else : + print(f'pilihan ke-{chosen} tidak tersedia') #jika tidak ada dalam pilihan + return int(chosen) + + +#fungsi untuk menampilkan monster yg akan dilawan +def opening(monsterdata,random_number) : + name = monsterdata[random_number][1] + print(f'''============================================= +>>>>>>>>>{name.upper()} HAS ARRIVED !!!<<<<<<<<< +=============================================''' + ) + +def battle(monsterdata,monsterinventory,yourmonsterdata,userinventory,chosen,random_number,random_level,type) : + file1 = monsterdata + + used_pot=[0,0,0] #potion hanya bisa digunakan sekali + + level=yourmonsterdata[chosen-1][2] #level monster anda + name=yourmonsterdata[chosen-1][1] #nama monster anda + + #PROGRAM UTAMA ========================================================== + print(f'{name.upper()} READY TO HELP') + + indeks=0 + for i in file1 : #mencari indeks monster kita di file monster.csv + if i[1]==name : + break + indeks+=1 + + #deklarasi stat variabel + originalhealth = int(int(file1[indeks][4]) + (int(level)-1)*(10/100)*int(file1[indeks][4])) + yourattack = int(int(file1[indeks][2]) + (int(level)-1)*(10/100)*int(file1[indeks][2])) + yourdefense = int(int(file1[indeks][3]) + (int(level)-1)*(10/100)*int(file1[indeks][3])) + yourhealth = int(int(file1[indeks][4]) + (int(level)-1)*(10/100)*int(file1[indeks][4])) + enemyhealth = int(int(file1[random_number][4]) + (random_level-1)*(10/100)*int(file1[random_number][4])) + enemyattack = int(int(file1[random_number][2]) + (random_level-1)*(10/100)*int(file1[random_number][2])) + enemydefense = int(int(file1[random_number][3]) + (random_level-1)*(10/100)*int(file1[random_number][3])) + + damagetaken=0 + damagedealt=0 + turn=1 + while True : + #menampilkan stat kedua monster saat battle + print(f">>>>>>>>>>>>>>>>>TURN {turn}<<<<<<<<<<<<<<<<<<<<") + print("=============================================") + print(f"ENEMY : {file1[random_number][1].upper()}") + print(f"HEALTH : {enemyhealth}") + print(f"ATTACK : {enemyattack}") + print(f"DEFENSE : {enemydefense}") + print(f"LEVEL : {random_level}") + print("=============================================") + print(f"YOUR MONSTER : {name.upper()}") + print(f"HEALTH : {yourhealth}") + print(f"ATTACK : {yourattack}") + print(f"DEFENSE : {yourdefense}") + print(f"LEVEL : {level}") + print("=============================================") + #menampilkan action yg bisa dilakukan + print("CHOOSE AN ACTION :") + print("1. ATTACK") + print("2. DRINK POTION") + if type=='battle' : #jika mode battle terdapat option tambahan yaitu monsterball + print("3. MONSTER BALL ") + print("4. QUIT") + elif type=='arena' : + print("3. QUIT") #jika mode arena tidak ada option monsterball + print("=====================") + action = (input("choose an action(1/2/3/4)--->")) + if action=='1' : + #ACTION ATTACK + damagerng = RNG(70,130) + time.sleep(1/10) + damage = yourattack*(damagerng/100) + if enemyhealth >= (damage-(enemydefense/100)*damage) : #menghitung damagedealt jika enemy belom mati + damagedealt += (int(damage-(enemydefense/100)*damage)+1) + else : #jika enemy mati maka damagedealt hanya ditambah sebesar sisa darah enemy sebelum mati + damagedealt += enemyhealth + enemyhealth -= (damage-(enemydefense/100)*damage) + enemyhealth = int(enemyhealth) + #MENAMPILKAN MEKANISME DAMAGE SERANGAN + print("=============================================") + print(">>>>>>>>>>>>>>>YOU ATTACKED !!!<<<<<<<<<<<<<<") + if damagerng < 100 : + print(f"ATTACK DAMAGE : {damage} ({damagerng-100}%)") + else : + print(f"ATTACK DAMAGE : {damage} (+{damagerng-100}%)") + print(f"REDUCED DAMAGE : {(enemydefense/100)*damage} ({enemydefense}%)") + print(f"TOTAL DAMAGE : {(damage-(enemydefense/100)*damage)}") + if enemyhealth > 0 : #JIKA MONSTER BELOM MATI + print(f"ENEMY MONSTER HEALTH IS DOWN TO : {enemyhealth}") + else : + print(f"ENEMY MONSTER HEALTH IS DOWN TO : {0}") + elif action=='2' : + #ACTION POTION + while True : + print("=======CHOOSE A POTION !=======") + print("1. STRENGHT") + print(f" you have : {jumlahPot(userinventory)[0]}") + print("2. RESILIENSE") + print(f" you have : {jumlahPot(userinventory)[1]}") + print("3. HEAL") + print(f" you have : {jumlahPot(userinventory)[2]}") + print("4. CANCEL") + potionchoice = (input("(1/2/3/4)--->")) + #validasi input + for i in range(1,5) : + if potionchoice==str(i) : #jika input==1/2/3/4 + break + else : + print(f"Opsi {potionchoice} tidak ada") #jika input lainnya + continue + #newstat adalah stat baru baik untuk atk/def/hp setelah memakai potion + newstat = potion(jumlahPot(userinventory),indexPot(userinventory),used_pot,userinventory,yourattack,yourdefense,yourhealth,originalhealth,name,int(potionchoice)) + if potionchoice =='1' : #ATK potion + if newstat==0 : #newstat ==0 hanya terjadi jika potion tidak bisa digunakan + continue + else : + yourattack = int(newstat) + break + elif potionchoice =='2' : #DEF potion + if newstat==0 : + continue + else : + yourdefense = int(newstat) + break + elif potionchoice =='3' : #Heal potion + if newstat==0 : + continue + else : + yourhealth = int(newstat) + break + elif potionchoice =='4' : #Cancel + break + if potionchoice == '4' : + continue + elif action=='3' : + if type =='battle' : #Jika mode battle action 3 adalah monster ball + success = monsterball(random_number,random_level,userinventory,monsterdata,monsterinventory,yourmonsterdata) + if success==1 : + print(f"{file1[random_number][1].upper()} IS ADDED TO YOUR INVENTORY") + return 0,damagetaken,damagedealt + elif success ==2 : #Jika gagal + continue + elif type =='arena': #Jika mode arena action 3 adalah quit + print('=============================================') + print('YOU LEFT THE BATTLE FIELD') + print('=============================================') + coin = 0 + return coin,damagetaken,damagedealt + elif action=='4' : + if type=='arena' : #TIDAK ADA OPSI 4 DI ARENA + print("OPTION 4 IS NOT AVAILABLE") + continue + elif type=='battle' : #OPSI 4 DIBATTLE ADALAH QUIT + print('=============================================') + print('YOU LEFT THE BATTLE FIELD') + print('=============================================') + coin = 0 + return coin,damagetaken,damagedealt + else : + print(f"OPTION {action} IS NOT AVAILABLE") + continue + + #Jika musuh darahnya sudah habis + if enemyhealth <= 0 : + print("=============================================") + print("YOU DEFEATED YOUR ENEMY") + print("WELL DONE") + coin = RNG(1,100) + if type.lower() == 'battle' : + print(f"YOU GOT {coin} COINS") + print("=============================================") + return coin,damagetaken,damagedealt + + #Jika musuh masih hidup, musuh menyerang balik + damagemusuhrng = RNG(70,130) + damagemusuh=enemyattack*(damagemusuhrng/100) + print(f">>>>>>>>>>>>>{file1[random_number][1]} ATTACK BACK !!!<<<<<<<<<<<<") + if yourhealth >= (damagemusuh - (yourdefense/100)*damagemusuh) : + damagetaken += int(damagemusuh - (yourdefense/100)*damagemusuh) +1 #Jika monster kita masih hidup setelah serangan + else : + damagetaken += yourhealth #jika monster kita mati setelah serangan + yourhealth -= (damagemusuh - (yourdefense/100)*damagemusuh) + yourhealth = int(yourhealth) + #MENAMPILKAN MEKANISMA DAMAGE SERANGAN + if damagemusuhrng < 100 : + print(f"ATTACK DAMAGE : {damagemusuh} ({damagemusuhrng-100}%)") + else : + print(f"ATTACK DAMAGE : {damagemusuh} (+{damagemusuhrng-100}%)") + print(f"REDUCED DAMAGE : {(yourdefense/100)*damagemusuh} ({yourdefense}%)") + print(f"TOTAL DAMAGE : {(damagemusuh - (yourdefense/100)*damagemusuh)}") + if yourhealth >0 : #jika monster kita masih hidup + print(f"{name} HEALTH IS DOWN TO : {yourhealth}") + else : + print(f"{name} HEALTH IS DOWN TO : {0}") + + #jika darah monster kita habis + if yourhealth <= 0 : + print("=============================================") + print("YOU ARE DEAD") + print("DONT GIVE UP") + print("=============================================") + return 0,damagetaken,damagedealt + turn+=1 \ No newline at end of file diff --git a/src/csvParser.py b/src/csvParser.py new file mode 100644 index 0000000..593351a --- /dev/null +++ b/src/csvParser.py @@ -0,0 +1,63 @@ +import sys +sys.path.append("C:\if1210-2024-tubes-k08-b\data") + +def splitSemicolon(text): # Fungsi mirip .split() namun untuk string dengan pemisah semicolon saja + separated = [] + word = '' + + for char in (text): + if char == '\n' : # jika "\n" (newline), pengecekan berhenti (agar newline tidak masuk ke array) + break + elif char != ';': + word += char # jika bukan ";", huruf akan digabung satu persatu menjadi sebuah kata + else: # char == ";" + separated.append(word) # jika ";", maka kata yang telah terbentuk akan dimasukkan dalam array + word = '' # kemudian kata akan dikosongkan kembali (semicolon dilewat) + + separated.append(word) # Untuk kata setelah semicolon terakhir + + return separated + +def csvRead(path): # Fungsi membaca file .csv baris per baris + csvOpen = open(path,'r') # Membuka file .csv + cleanData = [] + + for row in csvOpen: # Membaca setiap baris + cleanData.append(splitSemicolon(row)) # Memisahkan kalimat dari semicolon + + csvOpen.close() # Menutup file + return cleanData + + + +def splitSemicolonInt(text): + separated = [] + word = '' + for char in (text): + if char == '\n' : + break + elif char != ';': + word += char + else: + if word.isdigit(): + word = int(word) + separated.append(word) + word = '' + if word.isdigit(): + word = int(word) + separated.append(word) + return separated + +def csvReadInt(path): + csvOpen = open(path,'r') + cleanData = [] + for row in csvOpen: + cleanData.append(splitSemicolonInt(row)) + csvOpen.close() + return cleanData + +def csvWriteAll(path,newList): # Fungsi mengupdate csv lama dengan data-data list terbaru + with open(path,'w') as csvWrite: + for rows in newList: + csvWrite.write(''.join(rows)) + return \ No newline at end of file diff --git a/src/exit.py b/src/exit.py new file mode 100644 index 0000000..44db483 --- /dev/null +++ b/src/exit.py @@ -0,0 +1,10 @@ +from src.load import save +def exit(user,monsterinventory,itemshop,monster,monstershop,iteminventory): + confirmExit = input(("Apakah Anda mau melakukan penyimpanan file yang sudah diubah (y/n) :")) + while confirmExit.lower() != "y" and confirmExit.lower() != "n": + confirmExit = input(("Masukkan y/n saja :")) + if confirmExit.lower() == "y": + save(iteminventory,monster,user,monstershop,itemshop,monsterinventory) + print("Program berhasil disave dan ditutup!") + elif confirmExit.lower() == "n" : + print("Program berhasil ditutup!") diff --git a/src/help.py b/src/help.py new file mode 100644 index 0000000..e0665c0 --- /dev/null +++ b/src/help.py @@ -0,0 +1,76 @@ +def godServant() : + print(""" + .---. + / ,-- + .--. ( (^_^) ) .--. + ,' \ (.-`-'(_) / `. + / `-/ \ `. \-' +: (_,' . / (.\_ ") \ . `._) : +| `-'(_,\ \ / /._)`-' | +| . `.\,O,'.' . : | +| . : ! /\_ /\ ! . ! | +| ! |-'-| : ""T"" : |-'-| | | +| |-' `-'| H |`-' `-| | +`-' | H .:| `-' + | . H !|| + | : H :!| + | ! H !|| + | | H ||| + | | H ||| + /_,'V.L|. +""") + +def help(status,role) : #jika pengguna belum login, status akan menjadi false dan mengeluarkan beberapa command umum + #command umum + godServant() + if status == False : + print("List commands you can call :") + print("1. Login") + print(" Login ke akun admin/agent") + print("2. Register") + print(" Membuat akun agent baru") + print("3. Save") + print(" Menyimpan semua perubahan dalam sebuah folder") + print("4. Exit") + print(" Keluar dari program") + print() + print("Footnote :") + print("1. Anda belum login silahkan login terlebih dahulu atau melaukan register") + print("2. Pastikan input yang anda masukkan sudah tepat atau sesuai perintah program") + print("3. Jangan lupa untuk save program sebelum exit") + else : #jika pengguna sudah login, tampilkan daftar perintah berdasarkan role pengguna + if role == 'agent' : #jika pengguna adalah agent + #command yang dapat dilakukan oleh agent + print("List commands you can call :") + print("1. Battle") + print(" 1v1 dengan monster random") + print("2. Arena") + print(" Tempat pelatihan monster anda") + print("3. Shop") + print(" Tempat jual beli potion dan monster") + print("4. Inventory") + print(" Cek semua item dan monster anda") + print("5. Laboratory") + print(" Tempat untuk meng-upgrade monster anda") + print("6. Jackpot") + print(" Tempat untuk menguji keberuntungan anda") + print("7. Logout") + print(" Keluar dari akun anda") + print() + print("Footnote :") + print("1. Pastikan input yang dimasukkan sesuai dengan perintah program") + print("2. Jangan lupa untuk save program setelah logout") + if role == 'admin' : #jika pengguna adalah admin + #command yang dapat dilakukan oleh admin + print("List commands you can call :") + print("1. Shop") + print(" Manage shop") + print("2. Monster") + print(" Manage monster") + print("3. Logout") + print(" Keluar dari akun anda") + print() + print("Footnote :") + print("1. Pastikan input yang dimasukkan sesuai dengan perintah program") + print("2. Jangan lupa untuk save program setelah logout") + \ No newline at end of file diff --git a/src/inventory.py b/src/inventory.py new file mode 100644 index 0000000..1895ea4 --- /dev/null +++ b/src/inventory.py @@ -0,0 +1,70 @@ +def inventory(userInventory, yourMonsData, monsterData, role, coin) : + print(f'jumlah OWCA coin anda saat ini : {coin}') + while True : + check = input('Silakan pilih jenis item yang ingin diketahui Anda (Monster/Item/Back): ') + if check.lower() == 'item' : + number = 1 + itemArray = [] + for i in userInventory: + itemArray.append(i[1]) + print(f'{number}. {i[1]}') + number += 1 + + while True : + itemNumber = input('Masukkan nomor item untuk menampilkan detail item (1/2/3/Back): ') + inputNum = True # validasi input selain 1/2/3/dst/back + for char in itemNumber: + if ord(char) < ord('0') or ord(char) > ord('9'): + inputNum = False + + if inputNum != False : + if itemNumber.lower() != 'back' : + if int(itemNumber) > len(itemArray) : + print('Nomor item tersebut tidak tersedia') # validasi input nomor item yang salah + else : + itemNumber = int(itemNumber) + print(f'Type: {itemArray[itemNumber-1]}') + print(f'Quantity: {userInventory[itemNumber-1][2]}') + elif itemNumber.lower() == 'back' : + break + else : + print('Masukkan input yang benar') # validasi input itemNumber yang salah + + elif check.lower() == 'monster' : + number = 1 + for i in yourMonsData : + print(f"{number}. {i[1]}") + number += 1 + + while True : + monsNumber = input('Masukkan nomor monster untuk menampilkan detail monster (1/2/dst/Back): ') + inputNum = True + for char in monsNumber: + if ord(char) < ord('0') or ord(char) > ord('9'): + inputNum = False + + if inputNum != False : + if monsNumber.lower() != 'back': + if int(monsNumber) > len(yourMonsData) or int(monsNumber) < 1: + print('Nomor monster tersebut tidak tersedia') + else : + monsNumber = int(monsNumber) + monsLevel = int(yourMonsData[monsNumber-1][2]) + for i in monsterData : + if i[1] == yourMonsData[monsNumber-1][1] : + print(f'Nama : {i[1]}') + print(f'ATK Power : {int(i[2])+(monsLevel-1)*(5/100)*(int(i[2]))}') + print(f'DEF Power : {int(i[3])+(monsLevel-1)*(5/100)*(int(i[3]))}') + print(f'HP : {int(i[4])+(monsLevel-1)*(5/100)*(int(i[4]))}') + print(f'Level : {monsLevel}') + elif monsNumber.lower() == 'back' : + break + else : + print('Masukkan input yang benar') + + elif check.lower() == 'back' : + print("Sampai jumpa lagi !!") + break + + else : + print("Mohon berikan input yang benar") \ No newline at end of file diff --git a/src/jackpot.py b/src/jackpot.py new file mode 100644 index 0000000..2d171dc --- /dev/null +++ b/src/jackpot.py @@ -0,0 +1,79 @@ +import time +from src.RandomNumberGenerator import RNG + +# fungsi prob untuk menghasilkan kemungkinan muncul masing-masing item +def prob(RNG): + if 1 <= RNG <= 40: + return 0 + elif 41 <= RNG <= 65: + return 1 + elif 66 <= RNG <= 80: + return 2 + elif 81 <= RNG <= 95: + return 3 + elif 96 <= RNG <= 100: + return 4 + +# fungsi gacha untuk mengimplementasi probabilitas acak untuk mendapat reward +def gacha(id, coin, monsInv, yourMonsInv): + icon = ['TOPI', 'PEDANG', 'BAJU', 'CELANA', 'JAM'] + iconValue = [60, 80, 120, 170, 300] # menunjukkan value masing-masing icon sesuai dengan index array icon secara berurut + RNG1 = RNG(1, 100) # memberi range RNG masing-masing item + time.sleep(0.2) # men-delay waktu karena RNG yang digunakan berdasar time + RNG2 = RNG(1, 100) + time.sleep(0.1) + RNG3 = RNG(1, 100) + + indexItem1 = prob(RNG1) + indexItem2 = prob(RNG2) + indexItem3 = prob(RNG3) + totalcoin = iconValue[indexItem1] + iconValue[indexItem2] + iconValue[indexItem3] + print("==========================") + print(f"{icon[indexItem1]} | {icon[indexItem2]} | {icon[indexItem3]}") + print("==========================") + + if indexItem1 == indexItem2 and indexItem2 == indexItem3: + print('JACKPOT!! ANDA MENDAPATKAN GORLOCK THE DESTROYER! DESTROY EVERYTHING!') + if any(item[1] == "Gorlock" for item in monsInv): + print('GORLOCK SUDAH ANDA MILIKI, GORLOCK AKAN DIUBAH KE O.W.C.A Coin sebanyak 2000 Coin') + coin += 2000 + else: + monsInv.append([str(id),"Gorlock",'1']) # append Gorlock ke list monsterInventory + yourMonsInv.append([str(id),"Gorlock",'1']) # append Gorlock ke list yourMonsterInventory + else: + print(f"ANDA TIDAK DAPAT JACKPOT, TAPI ANDA DAPAT {totalcoin} COIN !!!") + coin += totalcoin + return coin + +# fungsi jackpot untuk menjalankan program jackpot +def jackpot(id, coin, monsInv , yourMonsInv): + coin = int(coin) + print("SELAMAT DATANG DI JACKPOT 888!!!") + print("ANDA DAPAT MENDAPATKAN GORLOCK THE DESTROYER DENGAN HARGA 500 COIN") + print(f"COIN ANDA SAAT INI SEJUMLAH {coin} ") + print("APAKAH ANDA INGIN MENCOBA KEBERUNTUNGAN ANDA???") + + while True: + inp = input("(Y/N)----->").lower() + if inp == 'y': + confirm = input("APAKAH ANDA YAKIN? (Y/N) :").lower() + if confirm == 'y': + if coin >= 500: + coin = gacha(id, coin, monsInv, yourMonsInv) + coin -= 500 + print(f'COIN ANDA TERSISA {coin} ') + print("APAKAH ANDA INGIN MELANJUTKAN??", end=" ") + else: + print("YAH COIN ANDA TIDAK CUKUP") + print("SILAKAN COBA JACKPOT DI WAKTU LAIN") + break + elif confirm == 'n': + print("Sampai bertemu lagi :)") + return coin + else: + print("Masukkan input yang benar") + elif inp == 'n': + print("Sampai bertemu lagi :)") + return coin + else: + print("Masukkan input yang benar") \ No newline at end of file diff --git a/src/laboratory.py b/src/laboratory.py new file mode 100644 index 0000000..1e184ac --- /dev/null +++ b/src/laboratory.py @@ -0,0 +1,99 @@ +def laboratory(yourMonsData, coin, role): + if role != 'admin' : + arrayHarga = [100, 200, 400, 700] # list harga untuk meng-upgrade level monster + + while True: + print(f"JUMLAH COIN ANDA : {coin}") + print('============ MONSTER LIST ============') + number = 1 + for i in yourMonsData : + print(f"{number}. {i[1]} LEVEL: {i[2]}") + number += 1 + + print('============ UPGRADE PRICE ============') + for i in range (1,5): + print(f'{i}. Level {i} --> Level {i+1}: {arrayHarga[i-1]}') + + pilihMons = input('Pilih monster yang ingin di-upgrade (1/2/dst/Back): ') + inputMons = True # validasi input selain 1/2/3/dst/back + for char in str(pilihMons) : + if ord(char) < ord('0') or ord(char) > ord('9'): + inputMons = False + + if pilihMons.lower() == 'back' : # input = back + print("Sampai bertemu lagi !") + break + + if int(pilihMons) > len(yourMonsData) or int(pilihMons) < 1 : # input > jumlah monster atau input < 1 + inputMons = False + + if inputMons != False : + inputMonsNum = True # validasi input selain 1/2/3/dst/back + for char in str(pilihMons) : + if ord(char) < ord('0') or ord(char) > ord('9'): + inputMonsNum = False + + if inputMonsNum != False : + pilihMons = int(pilihMons) + while True: + if yourMonsData[pilihMons-1][2] != '5': + monsUpgrade = input('Silakan pilih ke level berapa kah Anda ingin meng-upgrade monster Anda (1/2/dst/Back): ') + + inputMonsUp = True # validasi input selain 1/2/3/dst/back + for char in str(monsUpgrade) : + if ord(char) < ord('0') or ord(char) > ord('9'): + inputMonsUp = False + + if inputMonsUp != False : + if monsUpgrade <= yourMonsData[pilihMons-1][2] : # validasi input upgrade level <= level saat ini + print("Masa mau upgrade ke level yg sama/lebih rendah sih.. Itu mah downgrade kak") + + elif int(monsUpgrade) > 5 : + print('Upgrade cuman sampai level 5 kakak, level di atas 5 itu level kesulitan tubes daspro') + + else : + monsUpgrade = int(monsUpgrade) + harga = 0 + for i in range (int(yourMonsData[pilihMons-1][2]), monsUpgrade): # total harga upgrade + harga += arrayHarga[i-1] + + print(f'{yourMonsData[pilihMons-1][1]} akan di-upgrade ke level {monsUpgrade}') + print(f'Harga untuk meng-upgrade {yourMonsData[pilihMons-1][1]} adalah {harga}') + + while True : + lanjut = input('Lanjutkan upgrade (Y/N): ') # konfirmasi upgrade + if lanjut.lower() == 'y': + if coin >= harga : + yourMonsData[pilihMons-1][2] = str(monsUpgrade) + coin -= harga + print(f'Selamat! {yourMonsData[pilihMons-1][1]} berhasil di-upgrade ke level {monsUpgrade}!') + print(f'Coin Anda tersisa {coin}') + break + else : + print('Maaf! Anda tidak memiliki Coin yang cukup') + break + elif lanjut.lower() == 'n' : + break + else : + print("Masukkan input yang benar") + print() + + elif monsUpgrade.lower() == 'back' : + break + else : + print("Masukkan input level yang benar") + print() + else : # jika level sudah max + print('Maaf! Monster yang Anda pilih sudah memiliki level maksimum. Silakan pilih monster lain') + break + elif inputMonsNum == 'back': + break + else: + print('Masukkan input yang benar') + else : + print("Masukkan nomor monster yang benar") + print() + else : + print('Maaf! Anda tidak memiliki akses sebagai admin') + + return coin \ No newline at end of file diff --git a/src/load.py b/src/load.py new file mode 100644 index 0000000..ecd54fa --- /dev/null +++ b/src/load.py @@ -0,0 +1,146 @@ +from src.readwritecsv import * +import os +import argparse +def load() : + parser = argparse.ArgumentParser(add_help=False,usage='%(prog)s ') + parser.add_argument("nama_folder",nargs="?",type=str,default="") + args = parser.parse_args() + path = "data/"+args.nama_folder # Perlu ditambah "save/" karena parent foldernya "save" + if(path == "data/"): # jika args.nama_folder kosong + print("Tidak ada nama folder yang diberikan!\n") + parser.print_usage() + return [] + elif(os.path.exists(path)): # jika folder ditemukan + print("Loading...") + print("Selamat datang") + user = read_csv(path+"/user.csv") + inventory = read_csv(path+"/item_inventory.csv") + monster = read_csv(path+"/monster.csv") + monsterinventory = read_csv(path+"/monster_inventory.csv") + itemshop=read_csv(path+"/item_shop.csv") + monstershop=read_csv(path+"/monster_shop.csv") + return [user,inventory,monster,monsterinventory,itemshop,monstershop] #return semua variabel utama + else: # folder tidak ditemukan + print(f"Folder \"{path}\" tidak ditemukan.") + return [] + +def login(user,inventory,monsterinventory) : #fungsi untuk login + username = input("username: ") #input username + password = input("password: ") #input password + for i in user : + if i[1] == username : #pemeriksaan apakah username sesuai + if i[2] == password : #pemeriksaan apakah password sesuai + if i[3] == 'agent' : #jika pengguna adalah agent + player_inventory = [] + monster_inventory =[] + print("Login berhasil") + for j in inventory : #pengumpulan inventaris barang pengguna + if j[0]==i[0] : + player_inventory.append(j) + for j in monsterinventory : #pengumpulan inventaris monster pengguna + if j[0]==i[0] : + monster_inventory.append(j) + return player_inventory,monster_inventory,i[3],int(i[4]) #mengembalikan data inventaris (barang dan monster) dan role + break + elif i[3] == 'admin' : #jika pengguna adalah admin + print("Login berhasil") + return 1,1,i[3],1 + else : + print("password salah") #jika password salah + return 0,0,0,0 + break + else : + print("username tidak ditemukan") #jika username tidak sesuai + return 0,0,0,0 + +def register(user,inventory,monsterinventory,monster) : #fungsi untuk register + while True : + usernamebaru = input("Masukkan Username :") #meminta input username baru dari pengguna + status = False + for char in usernamebaru: + ascii_value = ord(char) + # Check if the character is a letter, number, hyphen, or underscore + valid = ( + (65 <= ascii_value <= 90) or # A-Z + (97 <= ascii_value <= 122) or # a-z + (48 <= ascii_value <= 57) or # 0-9 + ascii_value == 45 or # strip (-) + ascii_value == 95 # underscore (_) + ) + # If any character is not valid, return False + if valid == False: + print("Username hanya boleh mengandung huruf,angka,strip dan underscore") + break + else : + status = True + if status == False : + continue + for i in user : + if i[1]== usernamebaru : #jika username sudah terpakai + print("Username sudah terpakai") + status = False + break + else : + status = True + if status == False : + continue + break + passwordbaru = input("Masukkan password :") #meminta input password baru dari pengguna + #menampilkan pilihan monster untuk pengguna + print('PILIH MONSTER PERTAMA ANDA :') + for i in range(3) : + print(f"{i+1}. {monster[i+1][1]}") + idpilihan = input("--->") #meminta pengguna untuk memilih monster pertama + idbaru = len(user) #menentukan id baru untuk pengguna + monsterinventory.append([str(idbaru),monster[int(idpilihan)][1],'1']) #menambahkan monster yang telah dipilih kelam monster inventory + user.append([str(idbaru),usernamebaru,passwordbaru,'agent','0']) #menambahkan pengguna baru ke daftar pengguna + #menambahkan item awal ke inventory pengguna baru + inventory.append([str(idbaru),'healingpotion','0']) + inventory.append([str(idbaru),'respotion','0']) + inventory.append([str(idbaru),'strenghpotion','0']) + + player_inventory = [] + monster_inventory =[] + print("SELAMAT DATANG AGENT BARU") + #mengumpulkan inventaris barang milik pengguna baru + for j in inventory : + if j[0]==str(idbaru) : + player_inventory.append(j) + #mengumpulkan inventaris monster milik pengguna baru + for j in monsterinventory : + if j[0]==str(idbaru) : + monster_inventory.append(j) + return player_inventory,monster_inventory,'agent',0 #mengembalikan data inventaris (barang dan monster) dan role + + + +def write(path,data) : + # Writing data to the CSV file + with open(path, 'w') as file: + for row in data: + file.write(','.join(map(str, row)) + '\n') + + print(f"CSV file '{path}' has been created successfully.") + +def save(inventory,monster,user,monstershop,itemshop,monsterinventory) : + # ALGORITMA + path = "data/" + input("Masukkan nama folder: ") #path folder tujuan + print("Saving...") + if (os.path.exists(path)) : #jika folder sudah ada + write_csv(path+"/item_inventory.csv",inventory) + write_csv(path+"/user.csv",user) + write_csv(path+"/monster.csv",monster) + write_csv(path+"/monster_shop.csv",monstershop) + write_csv(path+"/item_shop.csv",itemshop) + write_csv(path+"/monster_inventory.csv",monsterinventory) + print(f"Berhasil melakukan Save pada folder {path}") + else : #jika folder belum ada + os.mkdir(path) + write_csv(path+"/item_inventory.csv",inventory) + write_csv(path+"/user.csv",user) + write_csv(path+"/monster.csv",monster) + write_csv(path+"/monster_shop.csv",monstershop) + write_csv(path+"/item_shop.csv",itemshop) + write_csv(path+"/monster_inventory.csv",monsterinventory) + print(f"Membuat folder baru {path}") + print(f"Berhasil melakukan Save pada folder {path}") diff --git a/src/monsterManagement.py b/src/monsterManagement.py new file mode 100644 index 0000000..3093268 --- /dev/null +++ b/src/monsterManagement.py @@ -0,0 +1,211 @@ +# FUNGSI UNTUK PENAMBAHAN MONSTER +# Fungsi - fungsi proses untuk mengecek validasi input data monster +def cekint(input): + # Check if the input is empty, it's not an integer + if input == '': + return False + # Convert input to string if it is not already + input = str(input) + # Check for a negative sign at the beginning + if input[0] == '-': + if len(input) == 1: + return False # Only a '-' is not an integer + input = input[1:] # Remove the negative sign for further check + # Check if all characters are digits + for char in input: + if ord(char) < ord('0') or ord(char) > ord('9'): + return False + return True + +def checkType(type,listMonster): + while True: + monsterExist = False # asumsi awal, nama yang diinput tidak sama dengan nama pada database. + for i in range(1, len(listMonster)): # 1 sebagai parameter karena listMonster[0] merupakan judul, len(listMonster) sebagai parameter akhir karena database monster bisa berubah seiring game berjalan. + if listMonster[i][1] == type: # apabila nama monster yang diinput ada yang sama dengan nama monster yang ada di database + print("Nama sudah terdaftar. Coba lagi!") + type = str(input("Masukkan Type Monster : ")) + monsterExist = True # bila nama monster yang diinput ada yang sama dengan nama monster yang ada di database, maka menjadi True. + if monsterExist == False : # Terjadi apabila nama monster yang diinput berhasil pengecekan + break + return type + +def checkAttack(attack): + while True: + if cekint(attack): # bila keseluruhan attack berupa angka + attack = int(attack) # ubah menjadi integer agar dapat dioperasikan + if attack < 0 : + print("Masa attack mines yg bener aje") + attack = str(input("Masukkan attack power : ")) + continue + break + + else : # terdapat character yang bukan angka + print("Masukkan bukan bertipe integer, coba lagi!") + attack = str(input("Masukkan attack power : ")) # input berupa string karena untuk pengecekan isdigit() + return attack + +def checkDefense(defense): + while True: + if cekint(defense): # defense berupa angka secara keseluruhan + defense = int(defense) # diubah menjadi integer agar dapat dioperasikan + if 0 <= defense <= 50 : # nilai sudah sesuai ketentuan + break + else : # defense > 0 dan defense > 50, belum sesuai + print("Masukkan harus bernilai 0-50") + defense = str(input("Masukkan DEF power (0-50) : ")) + else : # defense tidak merupakan angka secara keseluruhan + print("Masukkan bukan bertipe integer, coba lagi!") + defense = str(input("Masukkan DEF power (0-50) : ")) + return defense + +def checkHp(hp): + while True: + if cekint(hp): # keseluruhan hp berupa angka + hp = int(hp) # ubah menjadi integer agar dapat dioperasikan + if hp < 0 : + print("masa hp mines yang bener aje") + hp = str(input("Masukkan hp : ")) + continue + break + else : # terdapat character yang bukan angka pada hp + print("Masukkan bukan bertipe integer, coba lagi!") + hp = str(input("Masukkan hp : ")) # input berupa string karena untuk pengecekan isdigit() perlu tipe data string + return hp + +# FUNGSI SIMPLIFIKASI +# Fungsi-fungsi dibawah berisi input awal data monster baru dari user +def newType(listMonster): + type = str(input("Masukkan Type Monster : ")) + return checkType(type,listMonster) + +def newAttack(): + attack = str(input("Masukkan attack power : ")) + return checkAttack(attack) + +def newDefense(): + defense = str(input("Masukkan DEF power (0-50) : ")) + return checkDefense(defense) + +def newHp(): + hp = str(input("Masukkan hp : ")) + return checkHp(hp) + +# FUNGSI CHECK Y/N +def checkUserInput(listMonster,userInput, nType, nAttack , nDefense, nHp): + while True: + if userInput.lower() == "y" : + # disini masukkan file ke csv dulu karena bila append terlebih dahulu len(listMonster) id akan tidak sesuai pada file monster.csv + listMonster.append([str(len(listMonster)), nType, str(nAttack), str(nDefense), str(nHp)]) + print("Monster berhasil ditambahkan") + break + elif userInput.lower() == "n" : + print("Monster gagal ditambahkan") + break + else : # Input bukan Y/N + print("input tidak valid, hanya menerima input Y/N") + userInput = str(input("(Y/N): ")) + +def validUserInput(listMonster,userInput, nType, nAttack, nDefense, nHp): + userInput = str(input("Apakah mau tambahkan monster? (Y/N): ")) + checkUserInput(listMonster,userInput, nType, nAttack, nDefense, nHp) + +# FUNGSI PENAMBAHAN MONSTER BARU SECARA KESELURUHAN +def newMonster(listMonster): + nType = newType(listMonster) + nAttack = newAttack() + nDefense = newDefense() + nHp = newHp() + userInput = "" + validUserInput(listMonster,userInput, nType, nAttack, nDefense, nHp) + +# FUNGSI PENCETAKAN TABEL RAPIH +# Fungsi mengubah elemen integer pada list dari data csv menjadi string karena nanti akan digunakan fungsi len() +def changeInt(listMonster): + for i in range(1,len(listMonster)): + for j in range(5): + if j != 1 : # karena j == 1 berupa type monster yang berupa string + listMonster[i][j] = str(listMonster[i][j]) + return listMonster + +# Fungsi mencari elemen terbesar dalam 1 kolom +# elemen terbesar tiap kolom akan disimpan pada array largestElement, posisi bersamaan dengan kolom +def findLargestElement(largestElement,listMonster): + for i in range(len(largestElement)): + for j in range(len(listMonster)): + if largestElement[i] < len(listMonster[j][i]): + largestElement[i] = len(listMonster[j][i]) + return largestElement + +# Fungsi mengganti header dari file csv yang kurang rapih +def changeHeader(newHeader, listMonster): + for i in range(5): + listMonster[0][i] = newHeader[i] + return + +# Fungsi print tabel database monster +def printTabel (listMonster, largestElement): + for i in range(len(listMonster)): + # Print judul terlebih dahulu + print(listMonster[i][0], end="") + for j in range(abs(largestElement[0]-(len(listMonster[i][0])))): + print(" ", end="") + print(" |", end="") + + # Print type monster + print(" ", listMonster[i][1], end="") + for j in range(abs(largestElement[1]-(len(listMonster[i][1])))): + print(" ", end="") + print(" |", end="") + + # Print ATK Power + print(" ", listMonster[i][2], end="") + for j in range(abs(largestElement[2]-(len(listMonster[i][2])))): + print(" ", end="") + print(" |", end="") + + # Print DEF Power + print(" ", listMonster[i][3], end="") + for j in range(abs(largestElement[3]-(len(listMonster[i][3])))): + print(" ", end="") + print(" |", end="") + + # Print HP + print(" ", listMonster[i][4], end="") + for j in range(abs(largestElement[4]-(len(listMonster[i][4])))): + print(" ", end="") + print(" |", end="") + + # Enter agar program lanjut print baris ke-2 dan seterusnya + print("") + return + +# Fungsi akhir pencetakan tabel +def tabelMonster(listMonster): + largestElement = [-1, -1, -1, -1, -1] + newHeader = ["ID", "Type", "ATK Power", "DEF Power", "HP"] + changeInt(listMonster) + findLargestElement(largestElement,listMonster) + changeHeader(newHeader, listMonster) + printTabel(listMonster, largestElement) + return + +# FUNGSI AKHIR MONSTER MANAGEMENT +def monsterManagement(listMonster): + while True : + print(""" +SELAMAT DATANG DI DATABASE PARA MONSTER !!! +1. Tampilkan Semua Monster +2. Tambah Monster Baru +( Ketik nomor untuk aksi yang diinginkan, ketik 0 untuk keluar ) + """) + aksiUser = str(input("Pilih Aksi: ")) + if aksiUser == "1" : + tabelMonster(listMonster) + str(input("Ketik apapun untuk balik ke menu: ")) + elif aksiUser == "2" : + newMonster(listMonster) + elif aksiUser == "0" : + print("Teirma kasih telah mengunjungi database monster") + break + else : + print("Input tidak valid, input yang diterima hanya 0/1/2") \ No newline at end of file diff --git a/src/monster_art.csv b/src/monster_art.csv new file mode 100644 index 0000000..58bf5f0 --- /dev/null +++ b/src/monster_art.csv @@ -0,0 +1,291 @@ +1. Godzilla +⠀⠀⠀⠀⣾⠀⠀⠀⣠⣴⣶⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⢀⣀⣤⣴⣧⡀⠀⠿⠿⣿⣿⣿⣿⡄⣠⡄⠀⠀⠀⠀⠀⢠⡶⠀⠀⠀⠀⠀⠀⠀ +⠈⠉⣤⣿⣍⠛⠆⠀⠈⠙⠻⠿⣿⣿⣌⢁⣤⣶⣤⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀ +⢀⢐⡿⠿⢿⣿⣿⣿⣿⣿⣿⣶⣶⢻⣿⣆⠻⣿⠛⠀⠀⢿⣷⡀⠀⠀⠀⠀⠀⠀ +⠉⠟⠀⠀⠀⠀⠀⠉⠉⠛⣛⣛⣣⣿⣿⣿⣧⡰⣿⣿⡆⠈⠻⣿⣶⣀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣷⡘⢫⣤⣄⠀⠙⢿⣿⣷⣄⡀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⠿⠿⢿⣿⣿⣿⣌⠿⠟⠀⠀⠀⠙⢿⣿⣷⡄ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⢟⣵⣿⣿⣿⣎⣿⣿⣿⣦⡸⣿⠂⠀⠀⠈⣿⣿⣷ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⡿⣡⣿⣿⣿⣿⣷⣄⡀⠀⣀⣼⣿⣿⡇ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⠫⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⠁⢀⣮⣝⡻⠿⢿⣿⣿⣿⣿⡿⠿⠟⠋⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⣠⣶⣿⣿⣿⠘⠛⠛⠛⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + +2. Mimic +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠿⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⡿⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⣀⣀⣤⣤⠀⣉⠑⠀⠠⣤⣤⣤⣤⣤⠀⠀⠚⢉⠀⡀⠀⠀⠀ +⠀⠀⣠⣴⣶⣶⠆⢀⣈⡉⠛⠀⠉⠀⠓⠒⠙⠛⠛⠛⠃⠒⠒⠀⠉⠠⠿⠦⠀⠀ +⠀⣸⣿⣿⡿⠋⣠⡿⠋⠀⢸⣿⠏⢸⣿⣿⠁⢻⣿⠃⠈⢿⡿⠀⣶⣶⠀⣶⡤⠀ +⠀⣿⣿⠟⢁⣼⠟⡁⢾⣧⠀⠋⠀⠈⢿⠇⠀⠀⠃⠀⠀⠘⠁⠀⢸⡟⠀⠙⠁⠀ +⠀⠸⠋⣠⡿⠃⣴⡇⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠁⠀⠀⠀⠀ +⠀⠀⢰⡟⠀⢀⠀⠉⡀⠀⠀⠀⠀⠀⣰⠀⠀⠀⠀⠀⠀⠀⠀⠀⣆⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠰⣿⡄⣴⣇⠀⣰⣇⠀⣰⣿⡇⠀⣴⡄⠀⢰⣆⠀⢰⣿⡄⢠⣷⡀⠀ +⠀⠀⠀⣶⣶⣤⣤⣍⡉⢀⣉⠙⠀⠛⠛⠓⠐⠛⠓⠀⠛⠛⠂⠚⠛⠁⣈⣉⠁⠀ +⠀⠀⠀⣿⣿⣿⣿⣿⠁⣼⣿⣿⣿⣿⣿⡇⢸⣿⠟⣿⡇⢸⣿⣿⣿⣿⣿⣿⠀⠀ +⠀⠀⠀⠸⣿⣿⣿⣿⠀⣿⣿⣿⣿⣿⣿⡇⢸⣿⠄⣿⡇⢸⣿⣿⣿⣿⣿⣿⠀⠀ +⠀⠀⠀⠄⠹⣿⡿⠋⠀⠙⢿⣿⣿⣿⣿⡇⢸⣿⣤⣿⡇⢸⣿⣿⣿⣿⣿⠟⠀⠀ +⠀⠀⠀⠀⠀⠉⠀⠺⠀⣧⡈⢻⣿⣿⣿⣷⣶⣶⣶⣶⣶⣾⣿⣿⣿⡿⠃⣰⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠁⠀⠀⠀⠀ + +3. Makima +⠀⠀⠀⠀⢀⠎⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢂⠨⡆⠀⠀⠹⣧⠀⣀⣀⠀⠀⠀ +⠀⠀⠀⢀⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣆⠘⡌⡄⣷⢀⠀⠀⣌⠇⠀⠀⠀⠀⠀ +⠀⠀⠀⠘⠀⠀⠀⢀⠀⠀⢀⣤⣾⢀⢹⡟⣧⣷⣧⢿⠀⢥⣀⢬⣻⡀⠀⠀⠀⠀ +⠀⠀⠀⠀⡀⠀⢠⣯⠀⣀⡾⣿⢿⡿⢺⣏⣽⣛⣷⣸⣴⣌⢗⠲⣽⡇⠀⠀⠀⠀ +⠀⠀⠀⢰⣇⢰⣿⣧⣼⣿⣳⢋⡟⠀⣾⠟⣿⣯⣼⠋⡏⡿⣔⡔⢻⣿⠀⠀⠀⠀ +⠀⠀⠀⢸⣿⣾⣿⣿⣏⣿⣿⡦⠀⠀⠈⠐⠊⠁⢸⠂⡇⠇⢈⡓⣜⠏⠀⠀⠀⠀ +⠀⠀⠀⣀⣿⡇⣻⣏⠟⠛⣿⣏⡄⠀⠀⠀⠀⠀⢸⠨⡇⠀⠀⣴⡟⠀⢀⠀⠀⠀ +⣄⠀⢿⠀⢹⣧⣿⠏⢆⠉⠉⠀⢇⣀⠂⠀⠀⠀⢸⠀⡇⠀⠀⣿⠯⠟⠛⠓⠀⠀ +⠀⠑⠨⢦⠀⡇⣿⠀⠀⠢⡀⠀⠀⠈⢀⣀⠀⠀⢸⣦⣇⠂⠀⢠⣄⡐⠲⠆⠀⠀ +⠀⠀⠀⠀⠀⢀⡿⡆⠀⡄⠎⠂⢄⠀⠉⠁⠀⠀⢸⣿⡇⠀⠀⠘⡐⠙⣄⡀⡀⠀ +⠀⠀⠀⠀⠀⢸⠁⠇⠀⡇⠐⠊⠰⣹⡖⡤⡄⠤⢺⡿⡇⠀⡠⠈⠀⠀⠈⠢⡍⠛ +⠀⠀⠀⠀⠀⢸⢠⠀⠀⠃⠀⠣⡀⣻⣿⠁⢡⠀⢸⡇⠗⠊⠀⠀⠀⠀⠀⣰⡇⠑ +⠀⠀⠀⠀⠀⠀⡘⠀⠀⡇⠀⠀⢰⣵⠇⠀⠙⠢⣼⣽⣢⠀⠀⠀⠀⢀⠼⠁⡇⠀ +⠀⠀⠀⠀⠀⠀⣷⡇⠀⠀⣀⠔⠊⡜⠀⢀⣼⣿⣿⣿⣿⠗⡄⠀⡀⡡⠁⠀⠀⠀ +⠀⠀⠀⠠⠀⠀⣿⣧⡀⠊⢠⠎⡘⢸⢀⡊⣽⣿⣿⣿⣏⠄⡚⠚⠚⠃⠀⠀⠀⠀ + +4. Jalangkung +⠀⠀⠀⠀⠀⢀⣀⠖⠀⠉⠉⡀⠦⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⢀⣾⠇⠁⠰⠀⠁⢄⢈⡨⠄⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⢸⢾⠀⠂⢈⠈⠠⠁⣅⡼⢤⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⢿⡗⢶⣶⠆⢡⡊⠛⠱⠌⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠈⠺⡆⡤⢊⠩⢀⡀⠊⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠁⠁⢻⢧⣀⣀⢀⢠⣄⣄⢒⠰⡲⠆ +⠀⠀⠀⠀⠀⠀⢀⡀⡀⢤⢭⣾⡮⠃⡘⠛⠊⠊⠀⠂⠂⠀ +⠀⣀⣤⠀⠀⡇⠇⠃⠃⢀⠁⢛⣍⠀⠀⠀⠀⠀⠀⢀⠈⠀ +⠛⠙⢚⠀⠘⠀⡄⠀⠀⠀⠑⠈⣿⠀⠀⠗⠀⠁⠑⠀⠈⡀ +⠀⠀⠈⢇⠀⠀⠃⠂⠄⠊⡀⠀⣿⡇⠄⠀⠀⠃⠀⠀⠀⠁ +⠀⠀⠀⠨⠀⠁⠐⢀⢂⠒⠁⠀⠸⣿⠐⠀⠀⠀⢃⠀⢀⠀ +⠀⠀⠀⠀⢓⠀⠀⠁⠀⠂⠀⠀⢀⣄⢀⡀⡠⠐⠠⠁⠍⠈ +⠀⠀⠀⠀⠀⠂⡤⠄⠀⠳⢁⡘⠐⣟⡇⠀⠈⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠐⠀⠐⠀⠀⠀⠀⠀⠛⢞⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢓⠀⠀⠀⠀⠀⠀⠀ + +5. gigidi +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣿⣿⣷⣿⣶⣦⣄⣀⣀⣠⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠏⠙⠛⠛⠛⠉⠙⠿⡿⣿⣿⣶⣄⡀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠔⠛⠒⠢⡄⠀⠀⠀⠀⠀⠠⣄⠈⠙⢿⣿⣆⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⠆⠀⠀⠀⢹⠀⠀⡤⠒⠒⠲⣄⠱⠀⠀⠹⣿⣆ +⠀⠀⠀⠀⠀⠀⠀⣀⠴⠊⠁⠈⠦⢄⣀⡤⠃⠀⢸⠶⠀⠀⠀⢸⠆⠀⣀⣴⣿⡿ +⠀⠀⠀⠀⢀⡴⠊⠁⠀⠀⠀⠀⢀⡠⠞⠁⢀⣀⠈⠣⢤⣠⠤⠊⠀⠀⣿⣿⡟⠃ +⠀⠀⢀⡔⠁⠀⠀⠀⠀⢀⠖⠊⠉⠀⠀⠀⠀⣸⠂⠀⠀⠀⠀⠀⠀⠀⠫⡯⠀⠀ +⠀⣠⠋⠀⠀⠀⠀⠀⢴⠂⠑⠦⠤⠤⠤⠴⠚⠁⠀⠀⠀⠀⠀⠀⠀⠀⢹⡅⠀⠀ +⢰⠃⠀⠀⠀⠀⠀⠀⠀⠙⢲⠤⢤⣤⣀⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠈⡇⠀⠀ +⡎⠀⠀⠀⠀⠀⠀⠀⠀⠀⣨⠶⣦⣤⣄⣀⣀⣀⣀⣈⠆⠀⠀⠀⠀⠀⠀⡇⠀⠀ +⢇⠀⠀⠀⠀⠀⠀⠀⠀⠘⠦⡀⠀⠉⠛⢿⣛⡿⣻⠟⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀ +⠘⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⢸⠁⠀⠀ +⠀⠈⢦⡀⠀⠀⠀⠀⠠⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠎⠀⠀⠀ +⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠈⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠔⠁⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠙⠦⢤⣤⠭⠶⢄⡀⠀⠀⠀⠀⠀⠀⠀⢀⡤⠚⠁⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠲⢤⣀⣠⠤⠔⠊⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀ + +6. Gorlock +⣿⣷⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢼⠰⡇⢾⡇⢽⢺⣷⡄⢸⣷⣤⣽⣷⠻⣿⣶⣞⠿⢿⣿⣶⡤⢦⣶⠶⣶⣶⣴⢦⠙⠥⣷⣄⣉⣡⣴⣷⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⢰⣿⣷⣸⣿⣿⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣆⡹⠤⠶⢖⣹⣿⣿⣿⡿⢿⣿⠛⡄⢩⣦⣼⣯⣿⣾⣿⣧⣛⣚⡟⠙⣛⣷⡟⣿⣾⣿⣿⣿⠿⠿⢿⠉⢋⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠄⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⣿⣿⣿⣿⣿⣿⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⢗⣯⣭⡭⡙⣅⠹⡇⠄⢻⠀⣇⡼⠋⠈⠉⠙⠻⣿⣿⣿⣿⣿⣿⣿⣿⣷⣽⣿⣿⣔⠁⠴⠂⣈⡃⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠄⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢽⣿⣿⣿⣿⣿⡿⣾⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡏⢸⠁⣶⡄⡷⢸⣆⠀⢸⣆⣠⠏⠀⠀⠀⠀⠀⠀⠀⠉⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⡘⠛⣁⣦⣤⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⣿⣿⣿ +⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣷⡈⠦⣩⡴⢖⣹⣿⣶⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣿⣿⣿⣷⣿⣿⣿⣿⣿⣿⠿⢿⡟⠛⠉⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⣿⣿⣿⣿⣿⣿⣿⣿⣭⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣽⣯⣿⣿⣿⣿⣿⣿⣿⣿⣭⣿⣿⣿⣿ +⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣶⢖⣺⣭⣙⢻⠉⢿⢀⡙⢲⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣿⣿⣿⣿⣿⣿⣿⣿⣥⡴⠄⢡⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠇⡞⢡⣤⢸⡆⣷⠈⠉⠛⢿⣿⡄⢀⣴⣻⣿⣟⣛⠛⠒⠀⠀⠀⠹⣿⣿⣿⣿⣿⣿⣿⣿⡶⠚⢩⣆⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣇⠱⣌⣩⡬⢖⡏⠀⠀⠀⣀⠄⠀⠈⠉⠉⠛⠻⠿⠿⠦⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣿⠿⠟⢻⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⣿⣭⣯⣿⣿⣽⣿⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣽⣿⣿⣿⣯⣿⣿⣽⣿ +⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣷⡶⢶⣒⣛⡃⠀⠀⡔⠁⢀⣠⣀⣨⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡜⡄⢰⣿⣿⣿⣿⣿⣿⣿⡗⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⢱⠏⣩⣅⣇⣤⣤⣴⢶⣬⢥⣁⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣧⢀⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⠈⡦⠽⣫⡵⣾⣽⣻⣧⢨⠭⠭⠉⠓⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⡿⢿⠟⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣭⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣽⣿⣿⣿ +⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡿⠛⠑⠛⠲⡌⢳⣿⣷⡿⣿⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⢣⠀⣶⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣽⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⢟⡡⠂⠡⢈⢈⣴⣼⣷⣭⣿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡞⠁⠀⠚⠃⢸⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⠛⣷⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⡿⣷⣄⠁⣖⣦⣿⣿⣿⢿⣿⡵⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣰⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠉⠻⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣇⣯⢸⡇⠲⠤⡀⠀⠀⠀⠀⠀⢿⣭⣟⣻⣿⣿⣿⡟⠉⣠⡾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠂⣌⣲⣿⣿⣿⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣿⡇⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣿⡾⣸⠁⠀⠀⠈⠂⠀⠀⠀⠀⠈⢻⠽⠿⠚⠉⢙⣻⣾⠛⠁⠀⠀⠀⠀⠀⠀⠀⠠⠄⣐⣢⣵⣾⣿⡿⣻⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⡇⠀⠀⠀⠀⠀⣀⣸⢛⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⣿⣿⣿⣿⣿ +⣿⣿⣧⠃⠀⠀⠀⠀⠈⠋⠀⠀⠀⡞⠁⠀⠀⢀⡔⡿⢻⣿⣾⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣽⣿⢳⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣨⡤⠴⢶⣛⣯⢷⣞⣯⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⠢⠤⣤⣮⣾⠥⢺⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠔⢩⣿⣷⡈⠗⣿⣿⣾⣿⣿⣿⣿⣿⣿⡿⣇⠀⠀⠀⠀⠀⠀⠀⢀⣀⡤⠔⠊⠀⠀⠉⢣⡀⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣽⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠋⣽⠋⠠⣾⣿⡿⡟⠀⠀⠀⠀⠄⠀⠀⠀⠀⠀⢀⣾⣿⣿⣧⠠⣿⣿⣿⣿⡿⣿⣿⣿⣿⣧⡟⠀⠀⠀⠀⢀⣤⣴⠚⠉⠁⠀⠀⠀⠀⣀⣨⣷⣞⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⢃⡼⠃⠀⠀⣿⣿⣇⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢿⣿⣿⣿⣦⣿⣷⢻⣿⣿⣭⣿⣿⣿⡟⠁⠀⠀⠀⢰⣿⣟⣻⣷⣄⣀⣤⣶⣾⣿⣿⣿⣿⣿⣿⣿⣟⣩⣍⣛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠁⣾⠁⠀⠀⠀⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣿⣿⣿⢻⣿⡿⣿⣿⣿⣟⣿⡏⡇⠀⠀⠀⠀⠘⣿⣶⣯⣽⣾⣿⣿⣿⣿⠿⠿⠟⢛⣿⠇⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣽⣯⣿⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⣿⣿⣿⣽⣿⣿⣿ +⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠀⠈⣧⡀⠀⠀⠀⣿⣿⢻⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣘⣿⣿⣿⣿⣿⣿⣿⣷⡇⠀⠀⠀⠀⠀⠈⢻⢧⠿⠟⠛⠉⠹⣿⣆⣀⣰⣿⠋⠀⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⣿⣿⣿ +⡇⠀⠀⠀⠀⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⣦⣀⣰⣿⣿⣿⠀⢀⡀⢀⡀⠀⠀⠀⠀⠀⠀⣀⡴⢿⣿⣿⣿⣷⡺⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⢠⡇⠀⠀⠀⠀⠀⠀⠈⣿⣿⡏⢀⠀⠀⠀⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣀⣀⣤⣠⣔⣈⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢉⣿⣿⣿⣿⣭⠥⠤⠤⣍⣓⣦⣤⣤⣴⠞⠋⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠈⠣⣀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡧⢄⡀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣽⣿⣿⣿ +⡏⢁⡠⢀⣞⣦⣉⠿⣦⣀⠀⡸⣆⠀⣀⡤⠖⠒⠉⣿⣿⣿⣿⡉⠻⠟⣛⣻⡿⠊⠙⠫⠄⡀⠀⠀⠀⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠈⠉⠒⠒⠒⠒⠶⣿⣿⣿⣿⡗⠊⠀⠀⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⡧⡟⣿⠿⣿⠉⣻⡆⢏⣻⣿⣿⣿⡟⠁⠀⠀⠀⠀⢿⣿⣿⡟⠙⠛⠛⠋⠉⠀⠀⠀⠀⠀⠈⠑⠢⢀⡘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣏⢷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⢿⠇⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣷⢳⣧⠐⣋⣴⠟⠁⠀⢎⢺⣿⡟⠀⠀⠀⠀⠀⠀⢸⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠌⢧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣹⣸⡁⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣧⣉⣻⣟⠁⠀⠀⠀⢎⣲⣿⠁⠀⠀⠀⠀⠀⠀⢸⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡎⡜⡹⣆⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⢿⣿⠇⠀⠀⠀⢠⣿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⠁⠀⠀⠀⠉⠁⢢⠀⠀⢺⢳⣇⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⡜⡳⢯⣷⣤⣻⣄⠀⠀⠀⢐⣿⡿⢸⡿⠀⠀⣀⡀⢿⣿⡿⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⠀⠀⠀⠀⠀⢰⡇⠀⠐⢂⣻⣿⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡿⣿⣿⣿⣿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣬⣓⢏⣾⡿⠁⠉⠛⠶⣦⣾⣿⣿⣟⣧⠐⠀⠂⠄⣿⣿⡇⢸⣿⣿⣿⣿⣿⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⡀⠀⣤⢤⣄⠀⠤⠤⠴⠶⣾⣿⡄⠀⠀⠀⠀⠀⠀⢸⣿⣿⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣷⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢉⢻⣿⣿⣎⣖⡇⠀⠀⠀⠀⠀⣿⣿⣿⡿⢿⣦⣬⣴⣾⣿⣿⠇⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⡇⠀⢺⣶⣞⣻⠓⠾⢭⣛⣿⣿⣷⡀⠀⠀⠀⠀⠀⢸⣿⣿⣚⢔⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣽⣧⠈⠢⡘⣿⣿⣿⠀⠀⠀⠀⠀⠀⣿⣿⣿⡇⢹⡇⠐⣺⣿⣿⣿⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⠇⢹⡶⠽⣿⡿⠀⠀⠀⠀⠈⠉⠛⠻⠦⡀⠀⠀⠀⣾⣿⣿⣿⡾⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⡿⣿⣿⣿⣿⣿⣿⣿⣷⡻⢦⣁⣱⣿⣿⡟⠀⠀⠀⠀⣴⡿⣿⣿⣿⣀⣄⣿⣜⣿⣿⣿⣇⡞⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⠆⠈⠚⠓⢦⡏⠀⠀⠀⠀⠀⠀⠀⢀⣠⣬⣷⣶⣶⣿⣿⣿⣿⣿⣿⣟⣦⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠙⢿⣿⣿⣿⣿⣿⣿⣷⡬⡙⣿⣿⣿⡇⠀⠀⠀⠈⢿⣇⣿⣿⣿⠛⡉⣿⣿⣿⠿⠛⢉⠂⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⣿⣿⡹⢯⡿⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣿⡇⠀⢸⣿⣿⣿⣿⣿⣿⡞⢿⢿⣿⣿⣿⡁⠀⣠⡄⠀⠈⢻⣿⣿⣿⣼⣷⡿⣿⡁⡀⠀⠀⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠻⠿⢿⣿⣷⣿⣿⣿⣿⣿⣿⠿⠿⠛⡉⢁⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⣿⣾⣿⣿⣿⣿⣻⣿⠰⣉⣞⣿⣿⡟⠴⣾⣟⣻⡷⢤⡒⢻⣿⣿⠉⢉⡀⠘⣷⠻⣧⠀⠀⣿⣿⣿⣿⣿⣿⣻⣿⣿⣿⣿⣿⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ + +7. Bunny + ,\ + \\\,_ + \` ,\ + __,.-" =__) + ." ) + ,_/ , \/\_ + \_| )_-\ \_-` + `-----` `--` + +8. Roga +⠀⠀⠀⠀⠀⢀⠀⠠⠄⡀⠀⠀⠀⠀⠀⠀⠀⠠⢀⢀⣨⣅⣒⡠⡀⠀⠀⠀⠀ +⠀⠀⠀⠠⣢⣴⣶⣶⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣿⣿⣿⣿⢶⣄⡀⠀⠀ +⠀⢀⣪⣾⣿⣿⣿⡋⠀⠀⣀⠀⠀⠀⠀⢸⣠⣤⡄⠀⠘⣿⣿⣿⡄⠹⢎⠄⠀ +⠀⢲⣿⣿⣿⠟⠁⠁⠀⠀⣿⠀⠀⠀⠀⢸⠀⢟⠃⠀⠀⢹⣿⣿⣯⠀⠀⢋⡄ +⠈⣿⡿⠛⠁⠀⠘⠀⠀⠀⢀⠀⣔⠀⠀⢸⣆⠘⢶⠀⠀⢸⣿⣿⣿⠀⠀⣀⢠ +⢸⣟⠀⠀⠀⠀⠀⢂⠀⣀⣙⣵⣻⡇⠀⣼⣿⣗⣉⣀⢀⣾⣿⣿⠟⡂⠅⠒⠁ +⠑⠀⠨⠅⣂⠄⡀⢀⠢⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠙⠻⠏⠃⠁⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠈⠁⡀⠀⠈⢻⣿⣿⣿⣿⣿⣿⣿⡟⠁⠀⢁⠀⠀⠀⠀⠀⠀⠀ +⡤⠀⠀⠀⠀⠀⠀⠡⡀⠀⣸⣿⣿⣿⣿⣿⣿⣿⠀⠀⢀⠄⠀⢸⣿⣿⣿⣿⣿ +⠀⠀⠀⠀⠀⠀⠀⠀⠈⡨⠋⠙⢟⠛⠿⠿⡿⠏⠁⡮⡀⠀⠀⠘⠛⠛⠛⠛⣻ +⠀⠀⠀⠀⠀⠀⠀⠀⡐⠀⠀⠀⣾⣧⢀⡰⠀⢰⣿⣿⣷⠀⠀⠀⠀⠀⠀⠱⣿ +⠀⠀⠀⠀⠀⠀⠀⠀⠇⠀⠀⠀⣿⣿⢿⣇⠀⣸⣿⣿⣿⠂⠀⠀⠀⠀⠀⠀⠀ +⣀⣀⣀⡀⠀⠀⠀⠀⠐⢄⣠⣴⡿⢋⠀⡈⠦⣿⣿⣿⠏⠀⠀⠤⣄⣤⣤⠄⠀ + +⣿⣿⣿⡿⠟⣉⣉⡉⠻⠿⠟⠋⠉⠉⠉⠉⠙⠛⢿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣿⠋⣴⣾⣿⣿⡿⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⠦⣭⣙⢿⣿⣿⣿⣿⣿ +⣿⠃⣼⣿⣿⣿⣿⠁⠀⠀⠀⠀⢠⡤⠤⡀⠀⠀⠀⠀⠈⢽⣿⣿⣿⢿⣿⣿⣿ +⣿⢰⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠑⠏⠀⠀⠀⠠⠀⠀⠼⣿⣿⣿⣷⣿⣿⣿ +⣿⢸⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⡩⢼⠡⠀⠀⢹⡛⠿⠿⢟⣵⣿ +⣿⠠⢙⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣬⣭⣿⣯⡄⠀⢸⣿⣶⣶⠿⣷⢿ +⣿⣷⣄⠉⢿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠛⠛⡇⢀⡾⠋⠀⠀⠀⠀⢹ +⣿⣿⣿⣿⣦⣍⣛⠷⣠⡀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠤⡇⣸⠚⠠⡀⠀⠀⢀⣼ +⣿⣿⣿⣿⡿⠿⠛⠉⠡⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣸⣴⣾⣿⣿ +⣿⣿⠟⠁⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣶⣶⣾⣿⣿⣿⣿⣿⣿ +⣿⡏⠀⠀⠀⠀⢤⣶⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣇⢀⣤⡆⣠⣿⣿⡧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣿⣿⣿⣿ +⣿⣿⣿⣿⣿⣿⣿⣿⡇⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿ + +9. Molded +⠀⠀⠀⠀⠀⣠⣶⣷⣦⡀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⢠⣿⣿⣿⣿⡟⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀ +⠀⠀⠀⣠⣾⣿⣿⣿⣿⣷⣦⡀⠀⠀⠀ +⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀ +⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀ +⢸⣿⣿⡇⣾⣿⣿⣿⣿⣿⡟⠻⣿⣿⡀ +⢸⣿⣿⡇⢻⣿⣿⣿⣿⣿⣿⠀⢹⣿⡇ +⠘⣿⡿⠀⢸⣿⣿⣿⣿⣿⣿⠀⢠⣿⡇ +⢸⣿⣿⠀⣾⣿⣿⣿⣿⣿⣿⠀⢀⣿⡇ +⠈⢿⣿⡀⣿⣿⣿⣿⣿⣿⡏⠀⠈⠀⡇ +⠀⢸⣿⣿⢿⣿⣿⣿⣿⣿⠇⠀⠀⠀⠀ +⠀⠸⣿⡇⣼⣿⣿⢹⣿⣿⠀⠀⠀⠀⠀ +⠀⠀⣷⢳⢻⣿⣿⣸⣿⣿⠀⠀⠀⠀⠀ +⠀⠀⠸⠀⠈⣿⡇⣿⣿⣿⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⣿⣷⠙⠛⢿⣷⣦⠀⠀⠀ +⠀⠀⠀⠀⠀⠿⡿⠷⠀⠀⠈⠁⠀⠀⠀ + +10. Mohg +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠂⠰⡀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠒⡂⣒⠤⡀⠀⠀⠀⡠⢒⢙⠍⢒⢴⣅⠀⡠⣄⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⣦⠂⢭⡲⡇⡡⣻⣣⣀⡴⣑⣣⣐⠵⢪⣦⡥⣦⡳⠽⠀⠀⠀⠀⠀ +⠀⡠⡸⠿⡮⡰⣟⣨⣂⣸⣊⡭⣶⡊⠈⡖⣾⡘⢻⣑⢧⡧⣹⢥⡃⠀⠀⠀⠀ +⠀⢃⢲⣊⣹⣴⣙⣬⢿⢗⢻⠮⠀⠓⡚⠎⣶⠜⠻⢳⡯⡾⣯⣁⡆⠀⠀⠀⠀ +⠀⠀⠈⣃⢝⢫⠎⢿⣱⣋⣟⢫⢲⡂⣻⣻⢷⣫⡳⠼⡿⢯⢑⡏⠀⠀⠀⠰⠀ +⠀⠀⠀⠈⠊⠎⣒⣼⠎⣷⡓⢎⡿⡼⢞⣧⣩⣆⡏⠶⢿⠼⠉⠀⠀⠀⠀⠀⠀ +⠳⠀⠀⠀⠀⠀⠉⡛⠯⡑⡷⡿⡑⣓⡞⢭⣴⠇⣀⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⢀⠤⡦⠪⢉⡛⢖⠂⣩⠉⠑⢐⠮⡶⢖⠓⠃⠫⢶⠄⡀⠀⠀⠀⠀⠀⠀ +⢀⠐⣊⢀⢠⠜⣐⢊⠁⠈⠀⠀⠈⠚⠑⢩⡫⠀⠀⠀⠀⣁⣱⠃⣂⠀⠀⠀⠀ +⠀⡇⡠⠊⢀⠌⢆⢌⠂⣀⠀⠀⢀⡐⠺⢮⠣⠄⡐⠠⢠⡀⢩⡄⡸⣆⡀⠀⠀ +⠤⠨⠜⠕⠀⠇⠀⢑⠸⢌⠥⢸⣆⠀⠀⠘⢚⡀⠀⠙⡄⣐⣀⠄⠩⠀⠃⠀⡀ +⠢⠠⠀⠀⢂⢁⠂⣂⠡⡒⠌⠍⢨⠒⠈⠙⡹⡋⠑⢆⠚⣂⡅⠉⣀⢈⠄⠀⠀ +⠀⡀⢢⠒⡘⠉⢔⠬⠝⡮⠢⠢⠊⢳⠂⡤⡺⠄⣀⠸⠁⠷⡀⡃⠒⠁⠢⠘⠄ +⠀⠠⢸⠀⠀⠀⠀⠸⠂⣈⣠⠌⢠⣀⠀⡈⡇⠀⢨⢨⠗⠙⢔⢄⠀⡁⣧⡸⠃ +⢀⠔⠁⠀⠀⠀⠀⠘⡭⠀⠙⡀⢫⠉⠡⢙⢫⠌⢡⢫⠀⠀⠀⠑⢥⠉⠀⢀⠄ +⠁⠀⠀⠀⠀⠀⢠⢌⡱⢦⣄⠠⠀⡀⠀⠘⠁⢀⢃⠪⡄⠀⠀⠀⠈⡖⠦⣁⠀ +⠀⠀⠀⠀⠀⠰⣚⣬⡢⡠⠀⠠⠀⠗⣀⡶⡰⡡⢲⠟⡀⠀⠀⠀⠀⠁⠛⠁⠀ +⠀⠀⠀⠀⠀⣆⠁⡒⢿⠊⣰⣆⠧⠀⡘⠂⠁⠀⠵⡫⠈⠆⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⢐⢠⢂⠔⡁⡈⠀⢂⠙⠄⡀⠀⠀⠒⢀⠕⡡⠀⡄⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⢀⡫⢂⡂⡑⠐⡆⢹⠀⠓⠀⠀⠁⠀⠈⠀⠄⠀⠀⢐⡀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⣑⣁⠊⡰⠂⠠⠈⣢⢬⡄⠰⡠⠤⠤⠀⠁⣘⠔⠮⢀⠀⠀⠀⠀⠀ +⠀⠀⠀⢨⣦⡊⠈⡀⠀⠀⠀⡦⢒⢼⠄⠀⠀⠀⠀⡜⢀⡐⢢⢈⠀⠀⠀⠀⠀ +⠀⠀⠀⠈⠀⠊⢑⠔⡠⠀⢀⡀⠡⡁⡀⠀⠀⠀⠊⢀⡢⠵⠅⠊⠀⠀⠀⠀⠀ +⠀⠀⠀⢠⠀⠀⣷⠒⠈⢢⡈⣇⠨⠂⢌⡐⡒⠀⠠⠔⠀⢌⠌⣀⠀⠀⠀⠀⠀ +⠀⠀⠀⠈⣛⠀⠁⠀⠀⠠⡃⡟⠀⠐⠐⡁⡁⠑⠀⠀⢠⠃⠐⠀⠀⠀⠀⠀⠀ + +11. Malenia +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠔⠒⠀⠒⢠⡀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠋⠀⣀⠤⠤⠽⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠁⢠⠞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⡆⠀⢙⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⡄ +⠀⠀⠀⠀⠀⠀⠀⢀⠖⠁⠀⠀⠀⠉⠢⢄⠀⠀⠀⠀⠀⠀⡗⠃⢰ +⠀⠀⠀⢀⡢⠀⡰⠁⣀⡀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠇⠀⢸ +⢀⠆⢰⣦⡀⢰⠁⣾⣿⣿⠀⠀⠀⠀⠀⠀⠀⠈⢢⣀⡀⠜⠀⢠⠃ +⠈⠈⠈⢿⣿⣼⡀⠉⠉⠁⠀⠀⢀⣀⣀⠀⠀⠀⠀⠀⢀⡠⠔⠁⠀ +⠀⠀⠀⠈⢿⣿⣷⣄⠀⠀⠀⠀⣿⣿⣿⠀⠀⡠⠊⠉⠁⠀⠀⠀⠀ +⠀⠀⠀⠀⢸⣿⡏⣷⠛⠢⣀⡀⠙⠛⣁⠤⠊⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⢀⣏⣿⠇⢸⠀⠈⡇⢹⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⢸⣻⣿⡇⠘⡇⠀⢣⢸⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⢀⣿⣾⣿⣷⡀⢹⠀⢸⢸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⢠⡿⠟⣿⣿⣿⣷⣄⣣⡠⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠁⠀⠀⠛⢿⣿⢿⣿⡟⢷⣽⠧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + +12. Kraken +⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣴⣶⣤⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⣠⡤⣤⣄⣾⣿⣿⣿⣿⣿⣿⣷⣠⣀⣄⡀⠀⠀⠀⠀ +⠀⠀⠀⠀⠙⠀⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣬⡿⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⢀⣼⠟⢿⣿⣿⣿⣿⣿⣿⡿⠘⣷⣄⠀⠀⠀⠀⠀ +⣰⠛⠛⣿⢠⣿⠋⠀⠀⢹⠻⣿⣿⡿⢻⠁⠀⠈⢿⣦⠀⠀⠀⠀ +⢈⣵⡾⠋⣿⣯⠀⠀⢀⣼⣷⣿⣿⣶⣷⡀⠀⠀⢸⣿⣀⣀⠀⠀ +⢾⣿⣀⠀⠘⠻⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⠿⣿⡁⠀⠀⠀ +⠈⠙⠛⠿⠿⠿⢿⣿⡿⣿⣿⡿⢿⣿⣿⣿⣷⣄⠀⠘⢷⣆⠀⠀ +⠀⠀⠀⠀⠀⢠⣿⠏⠀⣿⡏⠀⣼⣿⠛⢿⣿⣿⣆⠀⠀⣿⡇⡀ +⠀⠀⠀⠀⢀⣾⡟⠀⠀⣿⣇⠀⢿⣿⡀⠈⣿⡌⠻⠷⠾⠿⣻⠁ +⠀⠀⣠⣶⠟⠫⣤⠀⠀⢸⣿⠀⣸⣿⢇⡤⢼⣧⠀⠀⠀⢀⣿⠀ +⠀⣾⡏⠀⡀⣠⡟⠀⠀⢀⣿⣾⠟⠁⣿⡄⠀⠻⣷⣤⣤⡾⠋⠀ +⠀⠙⠷⠾⠁⠻⣧⣀⣤⣾⣿⠋⠀⠀⢸⣧⠀⠀⠀⠉⠁⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠈⠉⠉⠹⣿⣄⠀⠀⣸⡿⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠛⠿⠟⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀ + +13. Mothra +⠈⠱⣶⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⢾⣿⣿⣷⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⣼⣏⢭⡛⢿⣿⠲⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣤⠴⠂ +⠀⢠⣿⣷⢵⢶⡾⠇⢹⣷⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⢞⡿⣟⣻⠋⠀⠀ +⠀⣸⡟⠈⢠⠀⣳⠂⡞⢣⡼⡶⡀⠀⠀⠀⠀⠀⣀⡴⣻⠋⣻⢶⣾⢏⠀⠀⠀ +⠀⠘⣿⣶⣾⣛⠛⠀⣶⣟⢞⡸⠸⡆⣰⣶⢆⡾⢃⡇⠇⠞⠃⠀⢻⡇⠀⠀⠀ +⠀⠀⠘⠻⠿⠿⠖⠐⠛⡻⢇⢦⣾⡷⢅⣯⣟⣼⢾⣃⣀⣶⣿⡔⠞⠁⠀⠀⠀ +⠀⠀⠀⠀⠀⡀⡤⣆⡡⢴⣲⣚⡏⣟⣭⡻⣽⣰⢦⡀⠉⠉⠉⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⢠⣷⣿⣵⣫⣾⡿⠣⡝⢽⡎⣱⡞⣞⣻⣾⡆⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠘⠽⢿⠿⠿⠟⠁⠀⠅⣿⠁⠻⣿⣿⣿⠿⡇⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠂⠀⠀⠀⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⡄ + +14. Parkinson +⠀⢀⣴⡾⢿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠈⢻⣧⡀⠙⣿⡆⠀⠀⡐⠉⠢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⣼⠟⣡⣾⠟⠁⠀⠀⢃⠀⠀⠇⠀⠀⢀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⣼⡏⣼⠋⠀⠀⠀⢀⣀⡈⢢⡔⠀⣠⠞⠉⠙⢿⣷⡀⠀⠀⠀⠀⠀⠀⠀ +⢠⣿⠀⢿⣦⣤⣤⣶⡟⣿⣿⣿⣿⣾⣅⠀⠀⠀⢸⣿⠃⠀⠀⠀⠀⠀⠀⠀ +⠘⣿⣆⠈⠙⠛⠛⠋⣸⣿⣿⣿⣿⣿⣿⠀⠀⠀⣸⡏⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠙⠿⣧⠀⠀⢀⣼⣿⣿⣿⣿⣿⣿⣿⠀⠀⢠⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠙⡇⠀⣿⣿⢻⣿⣿⣿⣿⣿⣿⠀⢀⣾⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⡇⠀⣿⣏⢸⣿⣿⣿⣿⣿⣿⠀⣸⡏⠀⠀⠀⠀⢀⣠⣴⣦⡄⠀ +⠀⠀⠛⠚⠀⠀⢿⣿⠈⢹⣿⣿⣿⣿⡇⠀⣿⡇⠀⠀⢀⣴⡿⠋⢉⣿⡿⠀ +⠀⠀⠀⠀⠀⠀⠘⣿⡄⠈⣿⣿⣿⣿⡇⠀⣿⣿⣦⣶⡿⠋⣠⣴⠟⠋⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⢻⣇⠀⣿⣿⣿⣿⣇⠀⠘⠛⠛⢉⣴⣾⣯⣤⣤⣄⠀⠀ +⠀⠀⠀⠀⠀⢸⠀⠈⣿⡀⣿⣿⣿⢻⣿⡀⠀⣠⣾⣿⣿⡿⠋⠉⠙⢿⣧⠀ +⠀⠀⠀⠀⠀⣸⠀⠀⢸⣇⣿⣿⣿⠈⠻⢿⣾⣿⣿⡿⠃⠠⢢⣰⠀⢈⣿⡆ +⠀⠀⠀⠀⡼⠃⠀⠀⠘⣿⢹⣿⡇⠀⢀⣿⣿⡏⢹⠀⠀⢤⠈⠉⠀⣸⣿⠇ +⠀⠀⢀⡾⠁⠀⠀⠀⢠⣿⢸⣿⠃⠀⢸⣿⡿⠀⢸⡄⠀⠈⢷⣶⣾⣿⡿⠀ +⠀⠀⣼⣧⠀⠀⠀⠀⣸⣿⢸⣿⠀⠀⢻⣿⣇⠀⣸⡇⠀⠀⠀⠉⠛⠋⠀⠀ +⠀⠀⣿⣿⣦⣤⣠⣾⣿⡏⠸⣿⡀⠀⠘⣿⣿⣶⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠘⠻⣿⣿⣿⣿⡟⠀⠀⠻⠁⠀⠀⠈⠛⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀ + +15. Ifrit + , ,, , + | || | ,/ _____ \. + \_||_/ ||_/ \_|| + || \_| . . |_/ + || | L | + ,|| |`==='| + |>| ___`> -<'___ + |>|\ / \ + \>| \ / , . . | + || \/ /| . | . | | + ||\ ` / | ___|___ | | ( + (( || `--' | _______ | | )) ( +( )\|| ( )\ | - --- - | -| ( ( \ )) +(\/ || ))/ ( | -- - -- | | )) ) \(( + ( ()||((( ())| | |( (( () ) \ No newline at end of file diff --git a/src/monsterball.py b/src/monsterball.py new file mode 100644 index 0000000..8f0aa5a --- /dev/null +++ b/src/monsterball.py @@ -0,0 +1,54 @@ +from src.RandomNumberGenerator import * + +# Fungsi untuk fitur bonus Monster Ball +def monsterball(monsterid,monsterlevel,userinventory,monsterdata,monsterinventory,yourmonsterdata): + jumlahball = int(userinventory[3][2]) + chance = RNG(1,100) + success = 0 + if jumlahball >= 1 : # Cek apakah player memiliki monster bal; + for i in yourmonsterdata : # Looping untuk cek apakah monster yang ingin ditangkap sudah ada di inventory + if i[1]==monsterdata[monsterid][1] : # bila monster sudah dimiliki player + print("Anda sudah memiliki monster tersebut!") + success= 2 + return success + else : # bila monster tidak dimiliki player + print('WHOOSSHHH YOU THROWED THE MONSTER BALL') + jumlahball -=1 # 1 bola sudah digunakan + userinventory[3][2]=str(jumlahball) + if monsterlevel==1 : # bila monster yang dilawan level 1, maka chance player mendapatkan monster tersebut 75% + if chance>=1 and chance<=75 : + print('SUCCESS!!') + success = 1 + else : + print('THE MONSTER ESCAPED THE BALL!!') + elif monsterlevel==2 : # monster level 2, chance 50% + if chance>=1 and chance<=50 : + print('SUCCESS!!') + success = 1 + else : + print('yaah ga dapet') + elif monsterlevel==3 : # monster level 3, chance 25% + if chance>=1 and chance<=25 : + print('SUCCESS!!') + success = 1 + else : + print('THE MONSTER ESCAPED THE BALL!!') + elif monsterlevel==4 : # monster level 4, chance 10% + if chance>=1 and chance<=10 : + print('SUCCESS!!') + success = 1 + else : + print('THE MONSTER ESCAPED THE BALL!!') + elif monsterlevel==5 : # monster level 5, chance 5% + if chance>=1 and chance<=5 : + print('SUCCESS!!') + success = 1 + else : + print('THE MONSTER ESCAPED THE BALL!!') + else : # Player tidak memiliki monster ball + print('YOU DONT HAVE A MONSTER BALL') + success = 2 + if success==1 : # success = 1 berarti monster success ditangkap dan monster ditambah ke inventory player + yourmonsterdata.append([userinventory[0][0],monsterdata[monsterid][1],str(monsterlevel)]) + monsterinventory.append([userinventory[0][0],monsterdata[monsterid][1],str(monsterlevel)]) + return success diff --git a/src/potion.py b/src/potion.py new file mode 100644 index 0000000..244851f --- /dev/null +++ b/src/potion.py @@ -0,0 +1,101 @@ +# fungsi jumlahPot untuk mengambil data potion yang ada di userInventory +def jumlahPot(userInventory) : + for i in userInventory : + if i[1] == 'Strength Potion' : + jumlahStr = i[2] + break + else : + jumlahStr = 0 + for i in userInventory : + if i[1] == 'Resilience Potion' : + jumlahRes = i[2] + break + else : + jumlahRes = 0 + for i in userInventory : + if i[1] == 'Healing Potion' : + jumlahHeal = i[2] + break + else : + jumlahHeal = 0 + + return [int(jumlahStr), int(jumlahRes), int(jumlahHeal)] + +# fungsi indexPot untuk mengecek index masing-masing tipe potion di userInventory +def indexPot(userInventory) : + indexStr = 0 + indexRes = 0 + indexHeal = 0 + + for i in userInventory : + if i[1] != 'Strength Potion' : # untuk mencari indexStr dengan menambahkan indexStr secara berulang + indexStr += 1 + elif i[1] == 'Strength Potion' : # untuk mendapatkan indexStr dengan menghentikan penambahan indexStr + break + + for i in userInventory : + if i[1] != 'Resilience Potion' : + indexRes += 1 + elif i[1] == 'Resilience Potion' : + break + + for i in userInventory : + if i[1] != 'Healing Potion' : + indexHeal += 1 + elif i[1] == 'Healing Potion' : + break + + return [indexStr, indexRes, indexHeal] + +# fungsi potion untuk meng-return nilai 1 atau 0 untuk diproses di battle.py +def potion(jumlahpot, indexPot, used_Pot_Array, userInventory, attack, defense, HP, max_HP, mons_Name, pilihan): + if pilihan == 1 : + if int(jumlahpot[0]) > 0 : # mengecek ada tidaknya potion strength + if used_Pot_Array[0] == 0 : # mengecek pernah tidaknya potion strength digunakan + used_Pot_Array[0] += 1 + attack *= 105/100 + print(f"Potion STRENGTH telah diminum, {mons_Name} menjadi lebih KUAT!") + jumlahpot[0] -= 1 + userInventory[indexPot[0]][2] = str(int(userInventory[indexPot[0]][2])-1) + return attack # return nilai attack monster setelah menggunakan potion strength + else : + print("Potion STRENGTH hanya bisa digunakan sekali") + return 0 # return 0 untuk mengindikasi potion tidak bisa digunakan + else : + print("Yahh.. Sayangnya Anda tidak memiliki potion STRENGTH") + return 0 + + elif pilihan == 2 : + if int(jumlahpot[1]) > 0 : # mengecek ada tidaknya potion resilience + if used_Pot_Array[1] == 0 : # mengecek pernah tidaknya potion resilience digunakan + used_Pot_Array[1] += 1 + defense *= 110/100 + print(f"Potion RESILIENCE telah diminum, {mons_Name} menjadi lebih SULIT DILUKAI!") + jumlahpot[1] -=1 + userInventory[indexPot[1]][2] = str(int(userInventory[indexPot[1]][2])-1) + return defense # return nilai defense monster setelah menggunakan potion resilience + else : + print("Potion RESILIENCE hanya bisa digunakan sekali") + return 0 + else : + print("Yahh.. Sayangnya Anda tidak memiliki potion RESILIENCE") + return 0 + + elif pilihan==3 : + if int(jumlahpot[2]) > 0 : # mengecek ada tidaknya potion healing + if used_Pot_Array[2] == 0 : # mengecek pernah tidaknya potion healing digunakan + used_Pot_Array[2] += 1 + if HP * 125/100 <= max_HP : # mengecek penggunaan potion melebihi HP maksimum atau tidak + HP *= 125/100 # return nilai HP monster setelah menggunakan potion healing + else : + HP = max_HP + print(f"Potion HEALING telah diminum, HP {mons_Name} telah REGENERASI!") + jumlahpot[2] -= 1 + userInventory[indexPot[2]][2] = str(int(userInventory[indexPot[2]][2])-1) + return HP + else : + print("Potion HEALING hanya bisa digunakan sekali") + return 0 + else : + print("Yahh.. Sayangnya Anda tidak memiliki potion HEALING") + return 0 \ No newline at end of file diff --git a/src/readwritecsv.py b/src/readwritecsv.py new file mode 100644 index 0000000..70dd428 --- /dev/null +++ b/src/readwritecsv.py @@ -0,0 +1,29 @@ +def read_csv(path) : + field = '' + row = [] + data =[] + with open(path) as file : + for char in file.read(): + if char == ';': + row.append(field) + field='' + elif char=="\n" : + row.append(field) + data.append(row) + field='' + row=[] + else : + field += char + row.append(field) + data.append(row) + return data + +def write_csv(filename, data): + with open(filename, 'w') as file: + for row_index, row in enumerate(data): + for item_index, item in enumerate(row): + file.write(item) + if item_index < len(row) - 1: + file.write(';') + if row_index < len(data) - 1: + file.write('\n') \ No newline at end of file diff --git a/src/shopCurrency.py b/src/shopCurrency.py new file mode 100644 index 0000000..564473f --- /dev/null +++ b/src/shopCurrency.py @@ -0,0 +1,419 @@ +from src.monsterManagement import cekint +itemID = ["Type", "Healing Potion", "Resilience Potion", "Strength Potion", "Monster Ball"] + +#TAMPILAN KASIR +def shopInterface(): + print(" ▀▄▀▄▀▄ SHOP ▄▀▄▀▄▀ ▂███████▂ _____ ") + print(" |__∆|___|_∆_|_|_|∆| ██ █ ██ |$___| ") + print(" |___|__∆|___|_|∆|_| ███▀▀▀███ __||_ ") + print(" |∆__|___|∆__|∆|_|_| ███████ /_____\ ") + print(" |___|_∆_|___|_|∆|_| ██████████████ KASIR ██") + print(" =================== ███████████████████████") + return + +def shopOpen(role,potionShop,coin,userinventory,monsterdata,monstershop,yourmonsterdata,monsterinventory): + yourcoin = coin + if role == "agent": #jika role agent + print(" ↤↤↤↤↤ SELAMAT DATANG DI SHOP!!! ↦↦↦↦↦") + print() + shopInterface() #tampilkan kasir + print() + while True: + pilihMenu = input(">>> Pilih aksi (lihat/beli/keluar): ") + if pilihMenu.lower() == "lihat": + lihat_pilih = input(">>> Mau lihat apa? (monster/item): ") + lihatSelesai = False + while lihat_pilih != "monster" and lihat_pilih != "item": + lihat_pilih = input(">>> Pilih antara monster/item: ") #jika input bukan monster/item + if lihat_pilih.lower() == "monster" : + print("ID | Type\t| ATK Power\t| DEF Power\t| HP\t| Stok\t| Harga") + for i in range(1,len(monstershop)): # Menampilkan setiap monster yang tersedia di Shop + idMonsterLihat=int(monstershop[i][0]) + print(f"{monsterdata[idMonsterLihat][0]} | {monsterdata[idMonsterLihat][1]}\t| {monsterdata[idMonsterLihat][2]}\t\t| {monsterdata[idMonsterLihat][3]}\t\t| {monsterdata[idMonsterLihat][4]}\t| {monstershop[i][1]}\t| {monstershop[i][2]}") + elif lihat_pilih.lower() == "item": + print("ID | Type\t\t| Stok\t| Harga") + for i in range(1,len(potionShop)): # Menampilkan setiap potion yang tersedia di Shop + if potionShop[i][0] == "Healing Potion": + idPotion = 1 + elif potionShop[i][0] == "Resilience Potion": + idPotion = 2 + elif potionShop[i][0] == "Strength Potion": + idPotion = 3 + elif potionShop[i][0] == "Monster Ball": + idPotion = 4 + print(f"{idPotion} | {potionShop[i][0]}\t| {potionShop[i][1]}\t| {potionShop[i][2]}") + lihatSelesai == True + elif pilihMenu.lower() == "beli": + print(f"Jumlah O.W.C.A Coin-mu sekarang {yourcoin}.") + print() + beliType = input(">>> Mau beli apa? (monster/item): ") + while beliType.lower() != "monster" and beliType.lower() != "item": + beliType = input(">>> Pilih antara monster/item: ") #jika input bukan monster/item + if beliType.lower() == "monster": + while True: + transactionStatus = 0 + idMonsterBeli = (input(">>> Masukkan id monster: ")) + #validasi input + for i in monstershop : + if idMonsterBeli== i[0] : #jika id monster terdapat dishop + break + else : + print("Id monster tersebut tidak tersedia") #jika id tidak ada dishop + continue + idMonsterBeli = int(idMonsterBeli) + for i in yourmonsterdata : #cek jika monster tersebut sudah dimiliki + if monsterdata[idMonsterBeli][1] == i[1] : + print("Monster sudah dimiliki") + break + else : #jika belum + for i in monstershop : + if i[0]==str(idMonsterBeli) : + if yourcoin >= int(i[2]) : #jika coin cukup untuk membeli + print("monster berhasil ditambahkan") + yourcoin -= int(i[2]) + yourmonsterdata.append([userinventory[0][0],monsterdata[idMonsterBeli][1],'1']) + monsterinventory.append([userinventory[0][0],monsterdata[idMonsterBeli][1],'1']) + monsterShopLocation = 0 + for i in monstershop : #stok berkurang satu (dimasukkan ke list monstershop) + if i[0]==str(idMonsterBeli) : + monstershop[monsterShopLocation][1] = str(int(monstershop[monsterShopLocation][1])-1) + break + monsterShopLocation += 1 + transactionStatus = 1 + break + else : #jika coin tidak cukup + print("Maaf O.W.C.A. Coin-mu kurang.") + break + if transactionStatus == 1 : #jika transaski sukses + break + print() + elif beliType.lower() == "item": + while True : + idPotion = (input(">>> Masukkan id item: ")) + #validasi input id + for i in range(1,5) : + if idPotion == str(i) : #jika idinput == 1/2/3/4 + break + else : + print("Id tersebut tidak tersedia") #jika idinput selain 1/2/3/4 + continue + idPotion=int(idPotion) + while True : + jumlahPotionBeli = (input(">>> Masukkan jumlah: ")) + if cekint(jumlahPotionBeli) : #jika input adalah integer + if int(potionShop[idPotion][1]) >0 : #jika stok tersedia + jumlahPotionBeli=int(jumlahPotionBeli) + if jumlahPotionBeli>int(potionShop[idPotion][1]): + print("Stock tidak cukup") #jika jumlah yg dibeli melebihi stok + else : + if yourcoin >= (jumlahPotionBeli * int(potionShop[idPotion][2])): #jika coinmu cukup + print(f"Berhasil membeli item: {jumlahPotionBeli} {potionShop[idPotion][0]}. Item sudah masuk ke inventory-mu!") + print() + userinventory[idPotion-1][2]=str(int(userinventory[idPotion-1][2])+jumlahPotionBeli) + yourcoin-=(jumlahPotionBeli * int(potionShop[idPotion][2])) + #stok berkurang satu + potionShop[idPotion][1]=str(int(potionShop[idPotion][1])-jumlahPotionBeli) + break + else : #jika coinmu kurang + print("Maaf O.W.C.A Coin-mu kurang.") + break + else : #jika stok habis + print("Stock Potion habis!") + break + else : #jika input bukan integer + print("Tolong masukkan integer yang benar") + break + elif pilihMenu.lower()=="keluar": # pilihMenu == "keluar" + print(f"Sampai bertemu lagi, User!") + return yourcoin + else : + print("Aksi tidak diketahui") + else : + print("anda tidak memiliki akses") +def shopmanagement(potionShop,monstershop,monsterdata) : + print(" ↤↤↤↤ SELAMAT DATANG KEMBALI ADMIN! ↦↦↦↦") + print() + shopInterface() #tampilkan kasir + print() + while True: + pilihMenu = input(">>> Pilih aksi (lihat/tambah/ubah/hapus/keluar): ") + if pilihMenu.lower() == "lihat": + lihat_pilih = input(">>> Mau lihat apa? (monster/item): ") + while lihat_pilih != "monster" and lihat_pilih != "item": + lihat_pilih = input(">>> Pilih antara monster/item: ") #jika input bukan monster/item + if lihat_pilih == "monster": + print("ID | Type\t| ATK Power\t| DEF Power\t| HP\t| Stok\t| Harga") + for i in range(1,len(monstershop)): # Menampilkan setiap monster yang tersedia di Shop + idMonsterLihat=int(monstershop[i][0]) + print(f"{monsterdata[idMonsterLihat][0]} | {monsterdata[idMonsterLihat][1]}\t| {monsterdata[idMonsterLihat][2]}\t\t| {monsterdata[idMonsterLihat][3]}\t\t| {monsterdata[idMonsterLihat][4]}\t| {monstershop[i][1]}\t| {monstershop[i][2]}") + elif lihat_pilih == "item": + print("ID | Type\t\t| Stok\t| Harga") + for i in range(1,len(potionShop)): # Menampilkan setiap potion yang tersedia di Shop + if potionShop[i][0] == "Healing Potion": + idPotion = 1 + elif potionShop[i][0] == "Resilience Potion": + idPotion = 2 + elif potionShop[i][0] == "Strength Potion": + idPotion = 3 + elif potionShop[i][0] == "Monster Ball": + idPotion = 4 + print(f"{idPotion} | {potionShop[i][0]}\t| {potionShop[i][1]}\t| {potionShop[i][2]}") + + elif pilihMenu.lower() == "tambah": + idMonsterShop = [] + for i in range(1,len(monstershop)): + idMonsterShop.append(monstershop[i][0]) #membuat list yg berisi semua id monster yg terdapat dishop + idMonsterData = [] + for i in range(1,len(monsterdata)): + idMonsterData.append(monsterdata[i][0]) #membuat list yg berisi semua id monster yg terdapat dimonster data + tambah_pilih = input("Mau tambah apa? (monster/item): ") + while tambah_pilih != "monster" and tambah_pilih != "item": + tambah_pilih = (input(">>> Pilih antara monster/item: ")) + if tambah_pilih == "monster": + print("ID | Type\t\t| ATK Power\t| DEF Power\t| HP\t|") + for i in range(1,len(monsterdata)): # Menampilkan setiap monster yang tersedia di Shop + if monsterdata[i][0] in idMonsterShop: + continue + else: + idMonsterLihat=int(monsterdata[i][0]) + print(f"{i} | {monsterdata[idMonsterLihat][1]}\t\t| {monsterdata[idMonsterLihat][2]}\t\t| {monsterdata[idMonsterLihat][3]}\t\t| {monsterdata[idMonsterLihat][4]}\t|") + print() + idMonsterTambah = input(">>> Masukkan id monster: ") + #validasi kevalidan id + while idMonsterTambah in idMonsterShop or idMonsterTambah not in idMonsterData: + if idMonsterTambah not in idMonsterData: #jika id tidak ada pada data + print("ID tidak valid! Pilih ID yang terdapat pada tabel!") + idMonsterTambah = (input(">>> Masukkan id monster: ")) + elif idMonsterTambah in idMonsterShop: #jika id sudah ada dishop + print("Monster sudah ada di Shop!") + idMonsterTambah = (input(">>> Masukkan id monster: ")) + stokMonsterTambah = (input(">>> Masukkan stok awal: ")) + while cekint(stokMonsterTambah) == False : #validasi integer + print("masukkan integer yg benar") + stokMonsterTambah = (input("Masukkan stok awal: ")) + hargaMonsterTambah = (input(">>> Masukkan harga: ")) + while cekint(hargaMonsterTambah) == False : #validasi integer + print("masukkan integer yg benar") + hargaMonsterTambah = (input("Masukkan harga : ")) + addMonsterShop = [idMonsterTambah,str(stokMonsterTambah),str(hargaMonsterTambah)] + monstershop.append(addMonsterShop) + print(f"{monsterdata[int(idMonsterTambah)][1]} telah berhasil ditambahkan ke dalam Shop!") + elif tambah_pilih == "item": + if len(potionShop)!=5 : #jika itemshop tidak keisi semua + print("ID | Type") + potionFound = False + countFalse = 0 + for i in range(1,5): + for j in range(1,len(potionShop)): + if itemID[i] in potionShop[j][0]: + potionFound = True + break + else: + potionFound = False + continue + if potionFound == False: + print(f"{i} | {itemID[i]}") #menampilkan seluruh item yg tidak ada dishop + countFalse += 1 + if countFalse == 0: + print("Semua Item sudah tersedia pada Shop!") + print() + else: + while True : + iditemTambah = (input(">>> Masukkan id item (1-4): ")) + #validasi integer + if cekint(iditemTambah) == False : + print("Masukkan integer yang benar") + continue + #validasi jika id<1 atau>4 + if (int(iditemTambah) < 1 or int(iditemTambah) > 4): + print("id tidak valid!") + continue + sudahadadishop = True + #validasi jika id sudah ada dishop + for i in potionShop : + if itemID[int(iditemTambah)]==i[0] : + print("Item sudah terdapat di shop") + break + else : + sudahadadishop =False + if sudahadadishop == True : + continue + break + stokPotionTambah = (input("Masukkan stok awal: ")) + #validasi integer + while cekint(stokPotionTambah) == False : + print("masukkan integer yg benar") + stokPotionTambah = (input("Masukkan stok awal: ")) + hargaPotionTambah = (input("Masukkan harga: ")) + #validasi integer + while cekint(hargaPotionTambah) == False : + print("masukkan integer yg benar") + hargaPotionTambah = (input("Masukkan harga :")) + newPotion = [itemID[int(iditemTambah)],str(stokPotionTambah),str(hargaPotionTambah)] + potionShop.append(newPotion) + print(f"{itemID[int(iditemTambah)]} telah berhasil ditambahkan ke dalam Shop!") + print() + + elif pilihMenu.lower() == "ubah": + ubah_pilih = input("Mau ubah apa? (monster/item): ") + while ubah_pilih != "monster" and ubah_pilih != "item": + ubah_pilih = (input(">>> Pilih antara monster/item: ")) + if ubah_pilih == "monster": + while True : + idMonsterUbah = (input(">>> Masukkan id monster: ")) + #validasi apakah id terdapat dishop + for i in monstershop : + if idMonsterUbah== i[0] : + break + else : + print('ID tersebut tidak tersedia') + continue + stokMonsterBaru = (input(">>> Masukkan stok baru: ")) + #validasi integer + while cekint(stokMonsterBaru)== False and stokMonsterBaru!="" : + print("Masukkan integer yg benar") + stokMonsterBaru = input('Masukkan stok baru:') + hargaMonsterBaru = (input(">>> Masukkan harga baru: ")) + #validasi integer + while cekint(hargaMonsterBaru)== False and hargaMonsterBaru!="" : + print("Masukkan integer yg benar") + hargaMonsterBaru = input('Masukkan stok baru:') + pesanUbah = f"{monsterdata[int(idMonsterUbah)][1]} telah berhasil diubah " + if (stokMonsterBaru != ""): #jika stok berubah + pesanUbah += f"dengan stok baru sejumlah {int(stokMonsterBaru)}" + for i in range(len(monstershop)) : + if monstershop[i][0]==(idMonsterUbah) : + monstershop[i][1]=str(stokMonsterBaru) + if (stokMonsterBaru != "") and (hargaMonsterBaru != ""): + pesanUbah += " dan " + if (hargaMonsterBaru != ""): #jika harga berubah + pesanUbah += f"dengan harga baru {int(hargaMonsterBaru)}" + for i in range(len(monstershop)) : + if monstershop[i][0]==(idMonsterUbah) : + monstershop[i][2]=str(hargaMonsterBaru) + pesanUbah += "!" + print(pesanUbah) + break + elif ubah_pilih == "item": + while True : + iditemUbah = input(">>> Masukkan id item: ") + #validasi integer + if cekint(iditemUbah)==False : + print("Masukkan integer yang benar") + continue + #validasi apakah id <1 atau >4 + if int(iditemUbah) > 4 or int(iditemUbah) < 1 : + print("Id tersebut tidak tersedia") + continue + #validasi apakah id tersebut terdapat dishop atau tidak + for i in potionShop: + if itemID[int(iditemUbah)]==i[0] : + break + else : + print("Id tersebut tidak tersedia") + continue + stokitemBaru = ((input(">>> Masukkan stok baru: "))) + #validasi integer + while cekint(stokitemBaru)== False and stokitemBaru!="": + print("Masukkan integer yg benar") + stokitemBaru = input('Masukkan stok baru:') + hargaitemBaru = ((input(">>> Masukkan harga baru: "))) + #validasi integer + while cekint(hargaitemBaru)== False and hargaitemBaru!="": + print("Masukkan integer yg benar") + hargaitemBaru = input('Masukkan harga baru:') + pesanUbah = f"{itemID[int(iditemUbah)]} telah berhasil diubah " + if (stokitemBaru != ""): #jika stok berubah + for i in range(len(potionShop)) : + if potionShop[i][0] == itemID[int(iditemUbah)] : + potionShop[i][1]=str(stokitemBaru) + pesanUbah += f"dengan stok baru sejumlah {stokitemBaru}" + if (stokitemBaru != "") and (hargaitemBaru != ""): + pesanUbah += " dan " + if (hargaitemBaru != ""): #jika harga berubah + for i in range(len(potionShop)) : + if potionShop[i][0] == itemID[int(iditemUbah)] : + potionShop[i][2]=str(hargaitemBaru) + pesanUbah += f"dengan harga baru {hargaitemBaru}" + pesanUbah += "!" + print(pesanUbah) + break + + elif pilihMenu.lower() == "hapus": + hapusPilih = input(">>> Mau hapus apa? (monster/item): ") + while hapusPilih != "monster" and hapusPilih != "item": + hapusPilih = (input(">>> Pilih antara monster/item: ")) + if hapusPilih.lower() == "monster": + while True : + idMonsterHapus = (input(">>> Masukkan id monster: ")) + #validasi apakah id tersebut terdapat dishop atau tidak + for i in monstershop : + if idMonsterHapus == i[0] : + break + else : + print("Id tersebut tidak tersedia") + continue + idMonsterHapus=int(idMonsterHapus) + while True : + yakinHapus = input(f"Apakah anda yakin ingin menghapus {monsterdata[idMonsterHapus][1]} dari Shop (y/n)? ") + if yakinHapus.lower() == "y": #double check apakah benar ingin dihapus + newMonsterList = [['monster_id','stock','price']] + for i in range(1,len(monstershop)): + if monstershop[i][0] == str(idMonsterHapus): + continue + else: + newMonsterList.append(monstershop[i]) + monstershop = newMonsterList + print(f"{monsterdata[idMonsterHapus][1]} telah berhasil dihapus dari Shop!") + break + elif yakinHapus.lower() =='n': + print("Penghapusan dibatalkan!") + print() + break + else : + print("Masukkan Y/N") + break + elif hapusPilih.lower() == "item": + while True : + iditemHapus = (input(">>> Masukkan id item: ")) + #validasi integer + if cekint(iditemHapus)==False : + print("Masukkan integer yang benar") + continue + #validasi apakah >4 atau <1 + if int(iditemHapus) > 4 or int(iditemHapus) < 1 : + print("Id tersebut tidak tersedia") + continue + #validasi apakah id item terdapat dishop atau tidak + for i in potionShop: + if itemID[int(iditemHapus)]==i[0] : + break + else : + print("Id tersebut tidak tersedia") + continue + while True : + yakinHapus = input(f"Apakah anda yakin ingin menghapus {itemID[int(iditemHapus)]} dari Shop (y/n)? ") + if yakinHapus.lower() == "y": #double cek apakah ingin dihapus + newitemList = [] + for i in range(len(potionShop)): + if potionShop[i][0] == itemID[int(iditemHapus)]: + continue + else: + newitemList.append(potionShop[i]) + potionShop = newitemList + print(f"{itemID[int(iditemHapus)]} telah berhasil dihapus dari Shop!") + print() + break + elif yakinHapus.lower() =='n': + print("Penghapusan dibatalkan!") + print() + break + else : + print("masukkan (Y/N)") + break + + elif pilihMenu.lower() == 'keluar': # pilihMenu == "keluar" + print("Sampai bertemu lagi Admin!") + return monstershop,potionShop + else : #jika aksi bukan tambah hapus ubah lihat dan keluar + print("aski tidak diketahui") \ No newline at end of file