"""Sesi 12 — Functions / Modular Programming | Kode Pendamping Lengkap
SMAS St. John · Ekskul CSSE (Python)

Cara pakai:
  1. Simpan file ini, buka di VS Code
  2. Tekan Run ▶ (atau ketik di terminal: python kode.py)
  3. Baca output di terminal — lalu baca komentar di dalamnya:
     setiap BAGIAN sesuai urutan slide deck Sesi 12

File ini mengikuti alur deck:
  BAGIAN 1 = fungsi = mesin mini: def + panggil (slide 04)
  BAGIAN 2 = parameter & argument      (slide 05)
  BAGIAN 3 = return — hasil keluar mesin (slide 06)
  BAGIAN 4 = return vs print           (slide 07)
  BAGIAN 5 = tugas 1: mesin geometri   (slide 08)
  BAGIAN 6 = parameter default & modular (slide 09)
  BAGIAN 7 = tugas 2 + challenge: tiga fungsi satu program (slide 10-12)
  BAGIAN 8 = jebakan NameError, None, missing arguments (slide 13)
"""

# ============================================================
# BAGIAN 1 — fungsi = mesin mini: def + panggil (slide 04)
# ============================================================
# def = MERAKIT mesin (belum jalan).
# Panggilan nama() = MENYALAKAN mesin.

def sapa(nama):
    pesan = "Hai, " + nama + "!"
    return pesan             # hasil keluar mesin

print(sapa("Budi"))          # Hai, Budi!
print(sapa("Ani"))           # Hai, Ani! — mesin sama, buah beda

# Nama fungsi pakai snake_case deskriptif: hitung_luas(), bukan f().
# JEBAKAN: def sapa: tanpa tanda kurung param — untuk sekarang mesin
# kita selalu punya parameter; nanti BAGIAN 6 ada default-nya.

# ============================================================
# BAGIAN 2 — parameter & argument (slide 05)
# ============================================================
# PARAMETER = kotak masukan berlabel, ditulis di definisi.
# ARGUMENT  = nilai beneran yang masuk kotak, ditulis di panggilan.

def luas_persegi_panjang(panjang, lebar):
    return panjang * lebar

print(luas_persegi_panjang(8, 5))   # 40 — 8 masuk panjang, 5 masuk lebar
print(luas_persegi_panjang(7, 2))   # 14 — mesin yang sama, argument beda

# Trik: "mesin ini butuh apa untuk bekerja?" — itulah parameternya.

# ============================================================
# BAGIAN 3 — return: hasil keluar mesin (slide 06)
# ============================================================
# Hasil return bisa DISIMPAN ke variabel dan DIHITUNG LAGI.

def luas_persegi(sisi):
    return sisi * sisi

hasil = luas_persegi(5)     # hasil = 25 — ditangkap & disimpan
print(hasil)                # 25
print(hasil * 2)            # 50 — bisa dipakai lagi, ini intinya!

# Selesai return, mesin berhenti — baris di bawahnya tidak dieksekusi.

# ============================================================
# BAGIAN 4 — return vs print (slide 07) — JANGAN dikacaukan!
# ============================================================
# Keduanya jalan beneran — jalankan ini dan lihat bedanya:

def kali_return(a, b):
    return a * b            # menyerahkan hasil

def kali_print(a, b):
    print(a * b)            # cuma menampilkan di layar

hasil_a = kali_return(3, 4)
print("versi return :", hasil_a)         # versi return : 12
print("dihitung lagi:", hasil_a + 1)     # dihitung lagi: 13 — hidup!

hasil_b = kali_print(3, 4)   # layar mencetak 12 (dari dalam mesin)...
print("versi print :", hasil_b)          # versi print : None — kosong!

# print = barista menunjukkan kopi: kelihatan, tidak bisa diminum.
# return = barista menyerahkan kopi ke tanganmu: bisa disimpan & dihitung.

# ============================================================
# BAGIAN 5 — Tugas 1: mesin geometri — luas & keliling (slide 08)
# ============================================================

def luas_persegi_panjang(panjang, lebar):
    return panjang * lebar

def keliling_persegi_panjang(panjang, lebar):
    return 2 * (panjang + lebar)

# Panggil sekali...
print("Luas:", luas_persegi_panjang(8, 5))         # Luas: 40
print("Keliling:", keliling_persegi_panjang(8, 5)) # Keliling: 26

# ...lalu panggil LAGI tanpa menulis ulang rumus — bukti reusable:
print("Luas 7x2:", luas_persegi_panjang(7, 2))     # Luas 7x2: 14

# ============================================================
# BAGIAN 6 — parameter default & modular (slide 09)
# ============================================================
# Default = nilai cadangan: kotak yang tidak diisi tetap bikin mesin jalan.

def sapa(nama="teman"):
    return "Hai, " + nama + "!"

print(sapa("Budi"))    # Hai, Budi!  — kotak diisi, default ditimpa
print(sapa())          # Hai, teman! — kotak kosong, pakai cadangan

# Modular = 1 fungsi 1 tanggung jawab. luas() cuma hitung luas,
# keliling() cuma keliling — program besar dirakit dari mesin kecil.

# ============================================================
# BAGIAN 7 — tugas 2 + challenge: tiga fungsi satu program
#            (slide 10-12)
# ============================================================
# TUGAS PENILAIAN sesi ini: 3 fungsi (luas, keliling, konversi)
# didefinisikan di ATAS, lalu dipanggil semua di BAWAH.

def konversi_suhu(celsius):
    return celsius * 9 / 5 + 32

def cek_genap(angka):
    return angka % 2 == 0    # % = sisa bagi; sisa 0 = habis dibagi 2

def status_nilai(nilai):
    return "Lulus" if nilai >= 75 else "Remedial"

# --- rakit semuanya dalam satu program ---
print("Luas 8x5 :", luas_persegi_panjang(8, 5))              # 40
print("Keliling 8x5 :", keliling_persegi_panjang(8, 5))      # 26
print("32 C =", konversi_suhu(32), "F")                      # 32 C = 89.6 F
print("0 C =", konversi_suhu(0), "F")                        # 0 C = 32.0 F
print("7 genap?", cek_genap(7), "| 8 genap?", cek_genap(8))  # False | True

# cek_genap return BOOLEAN — langsung sah dipakai di if:
if cek_genap(10):
    print("10 boleh dibagi jadi 2 tim")    # 10 boleh dibagi jadi 2 tim

# REUSE — mesin dipanggil ulang di loop atas list Sesi 11:
nilai = [85, 92, 68]
for angka in nilai:
    print(angka, status_nilai(angka))      # 85 Lulus → 92 Lulus → 68 Remedial

# ============================================================
# BAGIAN 8 — jebakan: NameError, None, missing args (slide 13)
# ============================================================
# Ketiga jebakan ini TIDAK di-run — baca, pahami, lalu cegah.

# JEBAKAN 1 — NameError: dipanggil sebelum didefinisikan
# print(luas(8, 5))      # NameError: name 'luas' is not defined
# def luas(p, l):
#     return p * l
# Python membaca file DARI ATAS — mesin belum dirakit saat dipanggil.
# Obat: def dulu di atas, panggil belakangan di bawah.

# JEBAKAN 2 — lupa return: hasil jadi None
# def luas(p, l):
#     print(p * l)       # cuma tampil di layar
# hasil = luas(8, 5)     # 40 tampil... TAPI hasil = None
# print(hasil + 1)       # TypeError! None + angka tidak bisa di +
# Obat: ganti print jadi return di dalam mesin.

# JEBAKAN 3 — kotak masukan kosong
# luas()   # TypeError: missing 2 required positional arguments: 'p', 'l'
# Blender dinyalakan tanpa buah. Jumlah argument = jumlah parameter,
# atau beri default di parameter terakhir: def luas(p=1, l=1).

# ============================================================
# Case kumulatif — rekap pola nilai dengan mesin (bekal Sesi 13)
# ============================================================
# Alat Sesi 11 (list) + hari ini (fungsi) dirakit jadi satu:

rekap = [70, 80, 90]
for nilai_ in rekap:
    print("Nilai", nilai_, ":", "*" * (nilai_ // 10 - 6),
          status_nilai(nilai_))
# Nilai 70 : * Remedial
# Nilai 80 : ** Lulus
# Nilai 90 : *** Lulus
