Modul 6 - Attachment
Modul 6 - Attachment
0
JULI , 2022
DISUSUN OLEH :
Andi Shafira Dyah K.
Mutaqhin Dean
DIAUDIT OLEH
Fera Putri Ayu L., S.Kom., M.T.
PERSIAPAN MATERI
Kegiatan pada modul ini merupakan perpaduan materi yang telah dipelajari pada modul
modul sebelumnya.
TUJUAN PRAKTIKUM
1. Mahasiswa mampu mengimplementasikan pemrograman fungsional pada studi kasus
logika pemrograman.
2. Mahasiswa mampu mengimplementasikan pemrograman fungsional pada masalah
gamification sederhana.
PERSIAPAN SOFTWARE/APLIKASI
● Komputer/Laptop
● Sistem operasi Windows/Linux/Mac/Android
MATERI POKOK
Pada pemrograman fungsional, modul juga dapat diakses melalalui google collab agar lebih
interaktif :
Modul 6
1|LAB-IT UMM
Modul 6 Pemrograman Fungsional
Functional programming on gamification case studies.
↳ 9 cells hidden
Fungsi Rekursi
Banyak upaya untuk membuat sebuah kode menjadi fungsional, diantaranya adalah
mengurangi penggunaan iterasi dan beralih pada fungsi rekursi, menghapus redudancy
kode serta memaksimalkan penggunaan berbagai macam metode yang sudah kita
pelajari di modul modul sebelumnya.
Tujuan dari pemrograman fungsional adalah untuk meringkas kode seefektif dan
seefisien mungkin. Pemrograman fungsional melakukan pemanggilan fungsi yang dapat
memberikan hasil yang sama secara berturut-turut berdasarkan teori fungsi matematika.
Recursion merupakan elemen yang sangat penting dalam pemrograman fungsional. Dasar
dari rekursif adalah self-reference, yaitu fungsi yang memanggil dirinya sendiri. Berbeda
dengan loop for dan while, rekursi bukanlah iterasi. Coba perhatikan contoh berikut!
def faktorial(x):
return x * faktorial(x-1) #memanggil fungsi faktorial untuk diulangi dengan x-1
print(faktorial(4))
#RecursionError: maximum recursion depth exceeded
---------------------------------------------------------------------------
RecursionError Traceback (most recent call last)
<ipython-input-14-23b0bc055fcc> in <module>()
1 def faktorial(x):
2 return x * faktorial(x-1) #memanggil fungsi faktorial untuk diulangi
dengan x-1
----> 3 print(faktorial(4))
1 frames
... last 1 frames repeated, from the frame below ...
<ipython-input-14-23b0bc055fcc> in faktorial(x)
1 def faktorial(x):
----> 2 return x * faktorial(x-1) #memanggil fungsi faktorial untuk diulangi
dengan x-1
3 print(faktorial(4))
2|LAB-IT UMM
RecursionError: maximum recursion depth exceeded
Iya lah error, kan belum dikasih base case, hal ini menyebabkan loop tak terbatas
seperti perulangan "while" berikut ini(coba kalian run):
def faktorialWhile(n):
result = 1
current_number = 0
while (True):
result *= n-current_number
current_number += 1
return result
print(faktorialWhile(4))
Nungguin lama kan ya, dan hasilnya ga keluar-keluar, karena dia lagi looping forever.
Dan program itu ga akan berhenti kalau ga kalian stop, dan lama kelamaan dia akan
menghabiskan memory kalian, bahkan bisa bikin hang. Itulah bedanya iterasi dengan
rekursif. Iterasi akan terus berjalan, sedangkan rekursif tidak akan dijalankan jika tidak
ditemukan base case yang dapat menghentikan looping self-reference nya.
T-tapi, base case itu apa?
- 1)!
sehingga
4! = 4 x 3!
3! = 3 x 2!
2! = 2 x 1!
1! = 1 Nahh ini nih yang disebut base case. Coba perhatikan contoh berikut
untuk implementasinya:
def faktorial(x):
if x == 1: #base case
return 1
else:
return x * faktorial(x-1) #operasi perkalian dengan incremental rekursi
print(faktorial(4))
3|LAB-IT UMM
24
Okee, udah mashok khan? Sekarang coba bandingkan kode rekursif perhitungan
faktorial tersebut dengan kode berikut!
def faktorialWhile(n):
result = 1 #base case
while (n > 0):
result *= n #operasi perkalian
n -= 1 #increment
return result
faktorialWhile(4)
24
Sama sama menghitung nilai fakorial kok. Tapi coba perhatikan efisiensi dari kode
tersebut, agak boros ya kalau pake iterasi :(
Loop vs Rekursi
• Rekursi tidak membutuhkan kondisi yang harus dipenuhi sebelum dapat dijalankan.
• Rekursi memiliki batasan untuk eksekusinya. Ini terutama karena fungsi disimpan
di Stack Memory, yang memiliki ukuran maksimum. Fungsi rekursif akan terus
memanggil dirinya sendiri, mendorong nilai dan instance baru dari fungsi ke stack,
yang pada akhirnya dapat menyebabkan kesalahan. Jadi hati hati ya pakenya
• Sebagai perbandingan, loop disimpan dalam memori dinamis, di mana variabel
dapat dibuat tanpa batas
• Eksekusi fungsi rekursif relatif lebih lambat daripada loop
• Rekursi umumnya lebih mudah dibaca daripada loop
• Rekursi lebih mahal, dari segi komputasi, dibandingkan dengan loop, tetapi
dapat dipercepat dengan memoization
def pangkatFor(x,y):
result = 1
for n in range(y):
result = result*x
return result
4|LAB-IT UMM
print("%d dipangkatkan %d = %d" % (x,y,pangkatFor(x,y)))
Masukan Nilai X : 3
Masukan Nilai Y : 2
3 dipangkatkan 2 = 9
def pangkatRecursion(x,y):
if y == 0:
return 1
else:
return x * pangkatRecursion(x,y-1) #rekursinya di sinii,
#fungsi pangkatRecursion dipanggil oleh fungsinya sendiri dengan parameter(x,y-
1) #Mengembalikan nilai x dikali dengan x sebanyak n hingga nilai y sama dengan
0
Masukan Nilai X : 3
Masukan Nilai Y : 2
3 dipangkatkan 2 = 9
#fungsi Hitung BMI dari data list yang berisikan berat badan dalam kg dan tinggi
badan def bmi_calc(data):
weight_kg = data[0]
height_m = data[1]
bmi = int(weight_kg / height_m**2)
return bmi
bmi_subject1 = bmi_calc(subject1)
print("bmi {} = {}".format('subject1', bmi_subject1))
bmi_subject2 = bmi_calc(subject2)
print("bmi {} = {}".format('subject2', bmi_subject2))
5|LAB-IT UMM
bmi_subject3 = bmi_calc(subject3)
print("bmi {} = {}".format('subject3', bmi_subject3))
bmi_subject4 = bmi_calc(subject4)
print("bmi {} = {}".format('subject4', bmi_subject4))
bmi_subject5 = bmi_calc(subject5)
print("bmi {} = {}".format('subject5', bmi_subject5))
bmi subject1 = 30
bmi subject2 = 29
bmi subject3 = 29
bmi subject4 = 24
bmi subject5 = 28
huekk boross. Kita banyak mengulang kode statement yang sama persis, cuma beda
isian variabel saja. Harusnya bisa disederhanakan lagi. Masih ingat caranya? cara ini
sudah pernah dibahas di modul 3 dan 5 lho... Yap, statement yang sama cukup kita
tulis satu kali dalam fungsi, dan statement yang berbeda akan kita jadikan parameter.
Seperti ini implementasinya...
#fungsi Hitung BMI dari data list yang berisikan berat badan dalam kg dan tinggi badan
def bmi_calc(data):
return int(data[0] / data[1] ** 2)
cetak_bmi(1, bmi_calc(subject_1))
cetak_bmi(2, bmi_calc(subject_2))
cetak_bmi(3, bmi_calc(subject_3))
cetak_bmi(4, bmi_calc(subject_4))
cetak_bmi(5, bmi_calc(subject_5))
bmi subject1 = 30
bmi subject2 = 29
bmi subject3 = 29
bmi subject4 = 24
bmi subject5 = 28
Hikk tapi masih ga enak dipandang ya, masih ada perulangan kode statement yang
sama... beda di angka subjek nya aja, apa masih bisa disederhankan lagi? mari kita
coba perbaiki sekali lagi bagian yang berulangnya...
6|LAB-IT UMM
# 1. kita satukan data subjek dengan memanfaatkan koleksi data (tipe sequence)
# Subject data = [weight_kg, height_m]
subjects =[[80, 1.62], # subject1
[69, 1.53], # subject2
[80, 1.66], # subject3
[80, 1.79], # subject4
[72, 1.60]] # subject5
bmi subject1 = 30
bmi subject2 = 29
bmi subject3 = 29
bmi subject4 = 24
bmi subject5 = 28
Ok, sampai sini sudah paham kan yang dimaksud eliminasi redudancy code?
eitt, tapi belum sampe situ.. kode yang barusan masih belum fungsional. Kenapa?
Karena dalam pemrograman fungsional, iterasi pada data koleksi tidak lagi
menggunakan perulangan for, melainkan menggunakan fungsi seperti map(), filter(),
rekursi, reduce(), dan lainnya. Lalu bagaimana merubah looping for kita itu menjadi
menggunakan fungsi?
Mari kita coba buat menjadi kode yang fungsional, perhatikan kode berikut :D
# 1. Kita gunakan fungsi map untuk memetakan data berat dan tinggi subjects menjadi
dat bmi_subjects = map(lambda subject : bmi_calc(subject), subjects)
list_bmi = list(bmi_subjects) #casting data map menjadi list
print(list_bmi) #agar bisa di print
cetak_bmi(list_bmi)
Eeh, kok masih ada looping for nya. Kita ganti pakai rekursif yuk...
7|LAB- IT UMM
#fungsi rekursif untuk mencetak dataList dengan index i
def cetak_bmi_rekursi(dataList, i):
lenList = len(dataList)
if i == lenList: # base case saat index i mencapai dataList terakhir (berdasarkan le
return # return None --> tidak mencetak apapun
else:
print("bmi subject{} = {}".format(i+1, dataList[i])) #kode yang sama persis
seperti return cetak_bmi_rekursi(dataList, i+1) #rekursi untuk dataList ke-i+1
cetak_bmi_rekursi(list_bmi, 0)
bmi subject1 = 30
bmi subject2 = 29
bmi subject3 = 29
bmi subject4 = 24
bmi subject5 = 28
Jadi lebih banyak kode yah, tapi itulah fungsi yang sesuai dengan paradigma fungsional.
Dimana fungsi adalah suatu expresi yang akan mengembalikan (return) nilai. Sedangkan
fungsi cetak_bmi() sebelumnya itu hanya sebuah prosedur untuk mencetak dengan iterasi.
Fungsi tanpa return nilai kita sebut sebagai prosedur, dan identik dengan paradigma
prosedural. Jadi fungsi di pemrograman fungsional harus me return sesuatu ya gaes...
Berikut cara lain agar fungsi cetak_bmi() yang prosedural bisa menjadi fungsional dengan
menambahkan inner function dan return didalamnya. Cekidot
8|LAB- IT UMM
bmi subject4 = 24
bmi subject5 = 28
Nah, seperti itulah pemrograman fungsional. Semoga kalian semakin paham ya...
Mari kita review lagi tentang apa itu paradigma fungsional:
Paradigma fungsional adalah prinsip yang menjadi landasan pemrograman yang
berbasiskan pada fungsi Matematika. Jadi setiap kode kita akan dijalankan layaknya
ekspresi matematika, baik itu fungsi, variabel dan semuanya di anggap sebagi ekspresi
yang selalu memberikan nilai/hasil.
KEGIATAN PERCOBAAN
Dengan diberikan dictionary allheroes, magic, attack, dan spell berikut ini,
• Check Hero, check hero digunakan untuk melihat hero dan spell yang kita pilih.
• Buy Item, buy item digunakan untuk membeli item yang tersedia dalam
dictionary magic atau attack. Item magic HANYA bisa dibeli bagi hero
yang mempunyai role sebagai Mage, sedangkan item Attack HANYA
9|LAB-IT UMM
bisa dibeli bagi hero yang mempunyai role sebagai Assassin. Item disini
fungsinya untuk menambahkan demage dari hero.
• Fight Lord, fight lord digunakan untuk melawan lord. HP dari lord
adalah 1000. User bisa menggunakan DMG hero ATAU DMG spell
untuk melawan lord hingga HP lord = 0
• Exit, exit digunakan untuk keluar dari game.
1. Pada function buy item, pastikan jika gold hero < 250, maka user tidak dapat
membeli item lagi.
2. HP lord tidak boleh di bawah 0.
def chooseHero():
print("Select 1 Hero you want to play: ")
selectedhero = {}
for i in range(len(allheroes)):
print("Id : {}".format(i))
print("Detail : {}".format(allheroes[i]))
inputs = input("silahkan masukkan pilihan Id: ")
try:
selectedhero.update(allheroes[int(inputs)])
return selectedhero
except:
return "Wrong Input!"
def chooseSpell(hero):
selectedhero = hero
print("\n{} - DMG {}\n".format(selectedhero["Hero"],selectedhero["DMG"]))
for i in range(len(spell)):
print("Id: {} : {} - DMG {}".format(i,spell[i]["Name"],
spell[i]["DMG"])) inputs = input("Pilih Id spell yang akan dipakai? ")
selectedhero["Spell"] = spell[int(inputs)] print("\n{} - DMG {} - Spell
{}\n".
format(selectedhero["Hero"],selectedhero["DMG"],selectedhero["Spell"]))
return selectedhero
def buyItem(hero):
selectedhero = hero
print("\n{} - DMG {} - Gold {}\n".
format(selectedhero["Hero"],selectedhero["DMG"],selectedhero["Gold"]))
if selectedhero["Role"] == "Mage":
for i in range(len(magic)):
print("Id: {} : {} - DMG {} - Price {}".
format(i, magic[i]["Name"], magic[i]["DMG"], magic[i]["Price"]))
inputs = input("silahkan masukkan pilihan Id: ")
try:
if selectedhero["Gold"] < magic[int(inputs)]["Price"]:
print("Gold not enough")
return selectedhero
10 | L A B - I T U M M
else:
selectedhero["DMG"] += magic[int(inputs)]["DMG"]
selectedhero["Gold"] -= magic[int(inputs)]["Price"]
print("\nBUYING SUCCESS")
print("\n{} - DMG {} - Gold {}\n".
format(selectedhero["Hero"],selectedhero["DMG"],selectedhero["Gold"]))
except:
return "Wrong Input!"
elif selectedhero["Role"] == "Assassin":
for i in range(len(attack)):
print("Id: {} : {} - DMG {} - Price {}".
format(i, attack[i]["Name"], attack[i]["DMG"], attack[i]["Price"]))
inputs = input("silahkan masukkan pilihan Id: ")
try:
if selectedhero["Gold"] < attack[int(inputs)]["Price"]:
print("Gold not enough")
return selectedhero
else:
selectedhero["DMG"] += attack[int(inputs)]["DMG"]
selectedhero["Gold"] -= attack[int(inputs)]["Price"]
print("\nBUYING SUCCESS")
print("\n{} - DMG {} - Gold {}".
format(selectedhero["Hero"],selectedhero["DMG"],selectedhero["Gold"]))
except:
return "Wrong Input!"
if selectedhero["Gold"] < 250:
return selectedhero
else:
inputt = input("Ingin beli lagi? (y/n)")
if inputt == "y" or inputt == "Y":
buyItem(selectedhero)
return selectedhero
else:
return selectedhero
def fightLord(hero):
lord = 1000
selectedhero = hero
spell = selectedhero["Spell"]
print("Fight Begin\n")
print("Lord - HP: {}\n".format(lord))
while lord > 0:
print("0 || {} - DMG {}".format(selectedhero["Hero"], selectedhero["DMG"]))
print("1 || {} - DMG {}".format(spell["Name"], spell["DMG"]))
fight = input("Select 0 to fight with hero DMG or 1 to fight with Spell DMG: ")
if fight == "0":
lord -= selectedhero["DMG"]
11 | L A B - I T U M M
elif fight == "1":
lord -= spell["DMG"]
else:
print("Wrong Input!")
if lord > 0:
print("\nLord - HP: {}\n".format(lord))
else:
lord = 0
print("\nLord - HP: {}\n".format(lord))
print("Challange Success\n")
def start():
print("Welcome to mini Mobile Legends Game\n\n")
hero = chooseHero()
selectedherospell = chooseSpell(hero)
flag = True
while flag:
print("Select the activity you want to do:")
print("1. Check Hero")
print("2. Buy Item")
print("3. Fight Lord")
print("4. Exit")
inputs = input("Choose the number :) ")
if inputs == "1":
print("{} - {} - DMG {} - Spell {}".
format(selectedherospell["Hero"], selectedherospell["Role"],
selectedherospell["DMG"], selectedherospell["Spell"]))
elif inputs == "2":
selectedherospell = buyItem(selectedherospell)
elif inputs == "3":
fightLord(selectedherospell)
elif inputs == "4":
print("Thank you for playing this game")
flag = False
else:
return "Wrong Input"
#jalankan program
start()
Setelah di-run berjalan dengan normal ya... Namun coba perhatikan source codenya.
Meski game berjalan dengan baik, tapi source code diatas tidak menggunakan paradigma
fungsional. Mari kita buktikan:
12 | L A B - I T U M M
#hapus dan ubah salah satu nama variabel yang ada del allheroes
myheroes = [{"Hero" : "Kagura", "Role" : "Mage", "DMG" : 350, "Gold" : 1000},
{"Hero" : "Yve", "Role" : "Mage", "DMG" : 250, "Gold" : 1000},
{"Hero" : "Lancelot", "Role" : "Assassin", "DMG" : 200, "Gold" : 1000},
{"Hero" : "Hayabusa", "Role" : "Assassin", "DMG" : 300, "Gold" : 1000},
{"Hero" : "Natalia", "Role" : "Assassin", "DMG" : 150, "Gold" : 1000},
{"Hero" : "Cecilion", "Role" : "Mage", "DMG" : 200, "Gold" : 1000}]
Game tidak lagi bisa berjalan hanya karena kita ganti nama variabelnya. Hal ini membuktikan
bahwa fungsi yang ada sangat bergantung dengan variabel diluar fungsi. Ketergantungan ini
sangat berlawanan dengan prinsip fungsional, dimana fungsi seharusnya tidak bergantung
pada data diluar fungsi (prinsip pure function). Bagaimana cara memperbaikinya biar jadi
fungsi murni(Fungsi yang hasil keluaranya hanya dipengaruhi oleh parameter yang diberikan)?
Berarti kita harus memberikan parameter yang dibutuhkan oleh fungsi. Seperti ini:
Coba bandingkan dengan fungsi chooseHero() sebelumnya!
13 | L A B - I T U M M
Select 1 Hero you want to play:
Id : 0
Detail : {'Hero': 'Kagura', 'Role': 'Mage', 'DMG': 350, 'Gold': 1000}
Id : 1
Detail : {'Hero': 'Yve', 'Role': 'Mage', 'DMG': 250, 'Gold': 1000}
Id : 2
Detail : {'Hero': 'Lancelot', 'Role': 'Assassin', 'DMG': 200, 'Gold': 1000}
Id : 3
Detail : {'Hero': 'Hayabusa', 'Role': 'Assassin', 'DMG': 300, 'Gold': 1000}
Id : 4
Detail : {'Hero': 'Natalia', 'Role': 'Assassin', 'DMG': 150, 'Gold': 1000}
Id : 5
Detail : {'Hero': 'Cecilion', 'Role': 'Mage', 'DMG': 200, 'Gold': 1000}
silahkan masukkan pilihan Id: 3
Voila, game kembali bisa berjalan. Tapi itu baru salah satu contoh saja ya...
PRAKTIKUM MODUL
Modifikasi kode program Mobile Legends Simple Game agar sesuai kaidah pemrograman
fungsional dengan ketentuan :
1. Nama variabel global ubah menjadi: heroes, sihir, serangan, dan mantra. Dan
untuk nama variabel lokal yang digunakan di dalam fungsi tidak boleh diganti.
2. Nama fungsi ubah menjadi: pilihHero, pilihMantra, beli_item, bertarung, dan main
3. Tambahkan pilihan mulai main atau batal di awal game dijalankan
4. Manfaatkan materi yang sudah dipelajari pada modul modul sebelumnya
semaksimal mungkin agar sesuai kaidah pemrograman fungsional (pure function,
inner function, high order function, rekursif, lambda, eliminasi redudancy kode,
function as expression, dan sebagainya)
5. Lengkapi kode dengan exception handling untuk mengatasi setiap error yang
mungkin terjadi selama permainan berlangsung
6. Jelaskan pada asisten bagian mana saja yang diubah dan jelaskan alasannya
14 | L A B - I T U M M
POINT TAMBAHAN :
1. Daftar menu disimpan dan dicetak dengan memanfaatkan data sequence agar
lebih dinamis untuk menghindari print manual.
INDIKATOR PENILAIAN
3. Mengeliminasi penggunaan kode for yang berulang pada beberapa fungsi dengan
membuat fungsi baru yang fungsional (20)
4. Menjelaskan dengan baik dan benar pada asisten, khususnya tentang materi apa
saja yang telah diimplementasikan untuk mencapai kaidah fungsional (30)
Opsional:
15 | L A B - I T U M M