Senin, 13 Oktober 2025

PBO A - Pertemuan 8 - Evaluasi Tengah Semester

 Nama    : Erlangga Rizqi Dwi Raswanto

NRP      : 5025241179

Kelas     : PBO A

Soal Evaluasi Tengah Semester

Demo              https://youtu.be/ucMWWojthF8

Link Github    https://github.com/erlanggardr/ETS_PBO_5025241179


Mengimplementasikan Vending Coffee Machine 


Adapun fitur-fitur yang ada didalam program ini adalah :

  • Menu Kopi dengan harga dasar ukuran S
  • Pemilihan Ukuran Gelas, terdapat 3 pilihan yaitu S/M/L (Small/Medium/Large)
    • Multiplier harga per ukuran (M=1.2, L=1.4)
    • Multiplier penggunaan resource per ukuran (M=1.1, L=1.4)
  • Pemilihan addon
    • Gula : gratis
    • Susu : +Rp2000
  • Pembayaran & Kembalian
  • Manajemen stok & Peringatan Refill saat mau habis
  • Menu Admin:
    • Laporan stok 
    • Log Transaksi dengan keterangan tanggal/jam, id transaksi, nama produk, total harga, beserta keterangan kembalian jika ada

Diagram pada BlueJ



Rancangan Kelas :

 Coffee  
  ├─ name:String  
  ├─ price:int  
  └─ +getName():String, +getPrice():int  
   
 Size  
  ├─ SMALL=1, MEDIUM=2, LARGE=3  
  ├─ +sizeCup(int):String  
  ├─ +multiplierPrice(int):double  // S=1.0, M=1.2, L=1.4  
  └─ +multiplierResource(int):double// S=1.0, M=1.1, L=1.2  
   
 Inventory  
  ├─ coffeeGram:int, waterML:int, sugarGram:int, milkML:int  
  ├─ BASE_COFFEE=5g, BASE_WATER=150ml, MILK_PER_CUP=50ml, SUGAR_PER_CUP=10g  
  ├─ +enoughFor(addSugar, addMilk, size):boolean  
  ├─ +lackingMessage(addSugar, addMilk, size):String  
  ├─ +consume(addSugar, addMilk, size):void  
  ├─ +quickRefill():void  
  ├─ +lowStockWarning():String  
  └─ +toString():String  
   
 Transaction  
  ├─ id:int, time:String (yyyy-MM-dd HH:mm:ss)  
  ├─ coffeeName:String, size:int, sugar:boolean, milk:boolean  
  ├─ total:int, paid:int, change:int  
  └─ +toString():String  
   
 CoffeeMachine (program utama)  
  ├─ menu: Coffee[]  
  ├─ inv: Inventory  
  ├─ log: ArrayList<Transaction>  
  ├─ +main(String[]):void  
  ├─ +showMenu():void  
  ├─ +showReport():void  
  ├─ +readInt(Scanner,String):int  
  └─ +readYesNo(Scanner,String):boolean  
   

Rancangan objek :

 CoffeeMachine  
  ├─ menu[4] → Coffee("Espresso",13000), ("Americano",10000),  
  │       ("Cappuccino",15000), ("Latte",18000)  
  ├─ inv → Inventory(coffeeGram=300, waterML=2000, sugarGram=100, milkML=500)  
  └─ log → [] 

Penjelasan masing-masing class/file :



Coffee.java



Kelas Coffee merepresentasikan satu item menu kopi. Kelas ini hanya menyimpan dua informasi: name (nama kopi) dan price.

Atribut:

  • name: String  - nama kopi yang ditampilkan di menu dan dicetak pada transaksi.

  • price: int  - harga dasar  (ukuran Small).

Konstruktor:

  • Menerima name dan price lalu menyimpannya ke field. 

Metode:

  • getName() -  mengembalikan nama kopi.

  • getPrice()  -  mengembalikan harga dasar.


Size.java


Kelas Size menyediakan konstanta untuk ukuran cup (SMALL=1, MEDIUM=2, LARGE=3) dan fungsi bantu untuk:

  • menampilkan label ukuran S/M/L,

  • mengembalikan multiplier harga (untuk menghitung total rupiah),

  • mengembalikan multiplier resource (untuk menghitung pemakaian bahan).

Konstanta:

  • SMALL=1, MEDIUM=2, LARGE=3 

Fungsi Bantu:

  • sizeCup(int s)"S", "M", atau "L" sesuai kode ukuran. Jika kode tidak cocok, mengembalikan "Not Valid".

  • multiplierPrice(int s) → pengali harga:

    • M → 1.2 (naik 20%), L → 1.4 (naik 40%), S → 1.0 (tidak berubah).

  • multiplierResource(int s) → pengali pemakaian bahan (kopi & air):

    • M → 1.1 (naik 10%), L → 1.4 (naik 40%), S → 1.0.


Transaction.java



Kelas Transaction merekam satu transaksi yang berhasil: identitas, waktu, pilihan user, dan angka-angka uangnya. Dengan menyimpan jejak transaksi, aplikasi bisa menampilkan laporan di menu admin.

Field:

  • id: int - nomor urut transaksi. 

  • time: Stringtimestamp transaksi dalam format yyyy-MM-dd HH:mm:ss.

  • coffeeName: String - nama kopi yang dibeli.

  • size: int - kode ukuran (1/2/3)

  • sugar: boolean - apakah menambah gula.

  • milk: boolean - apakah menambah susu.

  • total: int - total harga yang dihitung.

  • paid: int - jumlah uang yang dibayarkan pengguna.

  • change: int - kembalian (paid − total).

Konstruktor:

  • Mengisi semua field berdasarkan parameter.

  • Membentuk waktu sekarang dengan LocalDateTime.now() dan memformatnya secara manual menggunakan String.format agar menjadi YYYY-MM-DD HH:MM:SS.

Representasi Teks:

  • toString() menghasilkan satu baris ringkas untuk laporan, misalnya:
    [2025-10-15 10:07:02] #002 Espresso ukuran M + susu. total Rp14000, bayar Rp20000, kembali Rp6000
    Label ukuran didapat dari Size.sizeCup(size)S/M/L. Add-on (gula/susu) hanya dituliskan jika true.

Inventory.java



Kelas Inventory menyimpan stok bahan untuk:

  • Menghitung kebutuhan bahan per 1 gelas berdasarkan ukuran + add-on,

  • Memeriksa apakah stok cukup,

  • Menghasilkan pesan komponen mana yang kurang,

  • Mengurangi stok setelah transaksi sukses,

  • Memberi peringatan stok rendah,

  • Menampilkan ringkasan stok sebagai teks.

Field Stok (state mesin):

  • coffeeGram: int - stok kopi dalam gram.

  • waterML: int  - stok air dalam mililiter.

  • sugarGram: int  - stok gula dalam gram.

  • milkML: int -  stok susu dalam mililiter.

Konstanta konsumsi (ukuran Small):

  • BASE_COFFEE = 5 gram kopi per cup ukuran S.

  • BASE_WATER = 150 ml air per cup ukuran S.

  • MILK_PER_CUP = 50 ml susu jika pengguna pilih susu.

  • SUGAR_PER_CUP = 10 gram gula jika pengguna pilih gula.

Konstruktor:

  • Menerima nilai awal stok untuk keempat bahan. Nilai ini menjadi state awal mesin saat aplikasi mulai.

Perhitungan Kebutuhan Bahan (per 1 gelas):

  • Kopi: ceil(BASE_COFFEE × multiplierResource(size)).

  • Air: ceil(BASE_WATER × multiplierResource(size)).

  • Susu: tetap 50 ml jika dipilih.

  • Gula: tetap 10 g jika dipilih.

Pemeriksaan & Konsumsi:

  • enoughFor(addSugar, addMilk, size)
    Menghitung kebutuhan bahan untuk kombinasi tersebut lalu membandingkan dengan stok. Mengembalikan true jika semua bahan mencukupi.

  • lackingMessage(addSugar, addMilk, size)
    Jika ada yang kurang, membangun string “Stok tidak cukup: …” yang menyebutkan bahan mana saja yang kurang (kopi/air/gula/susu).

  • consume(addSugar, addMilk, size)
    Mengurangi stok sesuai kebutuhan yang telah dihitung. Dipanggil hanya setelah pembayaran cukup (transaksi sukses).

Informasi & Peringatan:

  • lowStockWarning()
    Mengembalikan teks peringatan jika ada bahan di bawah ambang (kopi < 30g, air < 200ml, gula < 20g, susu < 50ml). Jika aman, mengembalikan “Stok aman.”.

  • toString()
    Mengembalikan ringkasan stok: “Stok: Kopi Xg, Air Yml, Gula Zg, Susu Wml”.


CoffeeMachine.java



Kelas CoffeeMachine adalah program utama yaitu: membaca input, menampilkan menu, memanggil perhitungan harga & stok, memverifikasi pembayaran, mengurangi stok, mencatat transaksi, dan menyediakan laporan admin.

Data statis:

  • menu: Coffee[] - daftar item kopi 

  • MILK_PRICE: int - biaya tambahan

  • inven: Inventory - stok awal bahan

  • log: ArrayList<Transaction> - daftar transaksi yang berhasil, untuk laporan.

Metode main :

  1. Membuat Scanner untuk baca input dari konsol.

  2. While loop sebagai representasi mesin yang selalu aktif sampai user keluar:

    • Tampilkan menu dengan showMenu():
      a) nomor 1..N untuk kopi,
      b) 8 untuk Laporan admin,
      c) 0 untuk Keluar.

    • Baca pilihan pengguna dengan readInt(...). Metode ini memaksa input angka non-negatif; jika bukan angka, token dibuang dan diminta ulang.

    • Kondisi khusus pilihan:

      • 0 → ucapkan terima kasih dan break (keluar dari program).

      • 8 → panggil showReport() untuk menampilkan stok & semua transaksi; kemudian continue (kembali ke menu).

    • Validasi pilihan kopi: jika tidak di rentang 1..menu.length, tampilkan error dan kembali ke menu.

    • Ambil kopi terpilih: Coffee pesanan = menu[pilih - 1].

    • Pilih ukuran: tampilkan opsi 1) S 2) M 3) L

    • Pilih add-on: tanya Tambah gula? (y/n) dan Tambah susu? (y/n).

    • Cek stok: panggil inven.enoughFor(addSugar, addMilk, size).

      • Jika tidak cukup, tampilkan inven.lackingMessage(...) (menyebut bahan apa yang kurang), cetak ringkasan stok (inven.toString()) dan peringatan (inven.lowStockWarning()), lalu kembali ke menu.

    • Hitung total:

      • priceMult = Size.multiplierPrice(size)

      • total = round(pesanan.getPrice() × priceMult) + (addMilk ? MILK_PRICE : 0)

    • Pembayaran:

      • Cetak total dan minta Bayar (Rp):.

      • Jika bayar kurang dari total → tolak transaksi (“Kurang Rp …”) dan kembali ke menu.

      • Jika cukup → lanjut.

    • Seduh & konsumsi stok:

      • Cetak “Menyeduh … (S/M/L) + gula/susu …” sebagai feedback proses.

      • Kurangi stok dengan inven.consume(addSugar, addMilk, size).

    • Kembalian & log:

      • Hitung kembalian = bayar − total dan cetak.

      • Buat ID transaksi baru = log.size() + 1.

      • Tambahkan objek Transaction baru ke log (berisi waktu, item, ukuran, add-on, total, bayar, kembalian).

    • Info stok:

      • Cetak inven.lowStockWarning() untuk memberi tau kalau bahan ada yang mulai menipis.

  3. Menutup Scanner saat keluar loop.

Metode helper:

  • showMenu() - Mencetak daftar menu + opsi admin/keluar.

  • showReport() - Mencetak ringkasan stok (inven.toString()), lalu setiap transaksi (t.toString()), atau pesan “Belum ada transaksi.” jika log kosong.

  • readInt(Scanner, String): int -  Membaca input bilangan bulat non-negatif. Jika input bukan angka, menolak dan meminta ulang

  • readYesNo(Scanner, String): boolean - Membaca jawaban "y" atau "n"


Flowchart / Alur Sistem Program



PBO A - Pertemuan 7 - FRS Tech Support System

 Nama    : Erlangga Rizqi Dwi Raswanto

NRP      : 5025241179

Kelas     : PBO A


Pada pertemuan ini, dibuat implementasi support system yang berkaitan dengan FRS. Program bekerja sebagai chatbot sederhana yang membaca keluhan pengguna lalu memberikan saran berbasis kata kunci. Solusi memanfaatkan struktur data Map (LinkedHashMap) untuk pemetaan keyword → respons, List (ArrayList) untuk fallback jawaban generik, serta Random untuk merandom jawaban generik ketika tidak ada kata kunci yang cocok.
Agar pencocokan lebih akurat, sistem menerapkan strategi “prioritas frasa terpanjang”: contoh, frasa “login gagal” akan dipilih lebih dulu dibanding kata tunggal “login”.

Kode FRSSupportApp.java

Tujuan: titik masuk program, menangani loop input, menampilkan bantuan, daftar kata kunci (faq), dan keluar program.

 import java.util.Scanner;  
   
 public class FRSSupportApp  
 {  
   public static void main(String[] args){  
     Scanner sc = new Scanner(System.in);  
     Responder responder = new Responder();  
       
     System.out.println("=== FRS Technical Support (Console) ===");  
     System.out.println("Ketik keluhan Anda (contoh: 'login gagal', 'jadwal bentrok').");  
     System.out.println("Perintah: 'faq' (lihat kata kunci), 'help' (bantuan), 'exit' (keluar).\n");  
       
     while(true){  
       System.out.print("> ");  
         
       if (!sc.hasNextLine()) break;  
         
       String input = sc.nextLine().trim();  
         
       if (input.equalsIgnoreCase("exit")){  
         System.out.println("Terimakasih! Semoga masalah anda terselesaikan!");  
         break;  
       }  
         
       if (input.equalsIgnoreCase("help")){  
         System.out.println("Bantuan: ");  
         System.out.println("Sistem cocokan kata kunci dan beri solusi");  
         System.out.println("Perintah: faq, help, exit.\n");  
         continue;  
       }  
         
       if (input.equalsIgnoreCase("faq")){  
         System.out.println(responder.faq());  
         continue;  
       }  
         
       System.out.println(responder.getResponse(input));  
     }  
       
     sc.close();  
   }  
 }  

Penjelasan singkat:

  • Menampilkan welcome dan daftar perintah (faq, help, exit).

  • Membaca input pengguna baris demi baris.

  • Mengarahkan pemrosesan ke Responder.getResponse(...).

  • faq memanggil Responder.faq() untuk menampilkan kata kunci yang dikenali.


Kode Responder.java

Tujuan: menyimpan basis pengetahuan (kata kunci → jawaban), menyiapkan jawaban generik, dan mengimplementasikan strategi pencocokan.

 import java.util.*;  
   
 public class Responder{  
   private final Map<String, String> responses = new LinkedHashMap();  
   private final List<String> generics     = new ArrayList<>();  
   private final List<String> keysByLength   = new ArrayList<>();  
   private final Random rng          = new Random();  
     
   public Responder() {  
     responses.put("kelas penuh", "Hubungi TU/dosen pengampu untuk pembukaan kelas tambahan atau cari kelas paralel lain.");  
     responses.put("salah ambil kelas", "Drop kelas yang salah dan ambil kelas yang sesuai pada periode revisi.");  
     responses.put("login gagal", "Periksa NRP/password. Jika tetap gagal, reset password via portal DPTSI.");  
     responses.put("gagal ambil kelas", "Cek prasyarat & sisa SKS. Pastikan prasyarat mata kuliah terpenuhi.");  
     responses.put("jadwal bentrok", "Pilih kelas lain dengan jadwal berbeda atau konsultasi ke dosen wali.");  
     responses.put("gagal akses website", "Coba beberapa saat lagi, cek koneksi, nonaktifkan VPN, atau hubungi DPTSI.");  
     responses.put("pilihan tidak muncul", "Pastikan periode FRS sudah dibuka & data semester benar. Jika belum, hubungi TU.");  
     responses.put("captcha salah", "Ketik ulang captcha, refresh halaman, atau coba browser lain.");  
     responses.put("frs belum disetujui", "Hubungi dosen wali untuk persetujuan FRS.");  
     responses.put("frs ditutup", "Periode FRS berakhir. Koordinasikan dengan dosen wali/TU untuk opsi lanjutan.");  
     responses.put("web lag", "Bersihkan cache browser, coba jaringan lain, dan muat ulang halaman.");  
     responses.put("sks", "Cek batas maksimum SKS semester ini di portal & total SKS yang diambil.");  
     responses.put("prasyarat", "Pastikan MK prasyarat telah lulus/terpenuhi sebelum mengambil MK terkait.");  
     responses.put("hapus matkul", "Ubah/drop KRS hanya saat periode revisi. Cek kalender akademik.");  
   
     generics.add("Bisa jelaskan lebih detail kendalanya?");  
     generics.add("Saya belum paham, boleh diulang lebih spesifik?");  
   
     keysByLength.addAll(responses.keySet());  
     keysByLength.sort((a, b) -> Integer.compare(b.length(), a.length()));  
   }  
     
   public String faq(){  
     StringBuilder sb = new StringBuilder("Kata kunci yang dikenali:\n");  
     int i = 1;  
     for (String k : keysByLength) sb.append(i++).append(". ").append(k).append("\n");  
     sb.append("\nContoh: 'Saya login gagal dari tadi malam'.");  
     return sb.toString();  
   }  
     
   public String getResponse(String userInput){  
     if (userInput == null || userInput.trim().isEmpty()){  
       return pickGeneric();  
     }  
       
     String text = normalize(userInput);  
       
     for (String key : keysByLength){  
       if (text.contains(key)){  
         return responses.get(key);  
       }  
     }  
       
     for (String w : text.split("\\s+")){  
       if(responses.containsKey(w)){  
         return responses.get(w);  
       }  
     }  
       
     return pickGeneric();  
   }  
   
   private String pickGeneric(){  
     return generics.get(rng.nextInt(generics.size()));  
   }  
     
   private String normalize(String s){  
     String lower = s.toLowerCase();  
     lower = lower.replaceAll("[^\\p{L}\\p{Nd}\\s]", " ");  
     return lower.replaceAll("\\s+", " ").trim();  
   }  
 }  

Penjelasan singkat:

  • responses (LinkedHashMap) menyimpan keyword → saran. Pemakaian LinkedHashMap mempertahankan urutan penambahan, sehingga daftar pada faq() tampil rapi dan konsisten.

  • generics (ArrayList) berisi jawaban umum jika tidak ada kecocokan.

  • keysByLength menyimpan semua kata kunci yang diurutkan dari yang terpanjang. Ini penting agar frasa seperti “login gagal” tidak kalah oleh kata tunggal “login”.

  • normalize(...) menurunkan huruf, menghapus tanda baca, serta merapikan spasi supaya pencocokan .contains(...) lebih stabil.

  • Alur pencocokan:

    1. Coba cocokkan frasa terpanjang (keysByLength).

    2. Jika gagal, coba cocokkan per-kata.

    3. Jika tetap tidak ada, kembalikan jawaban generik acak (pickGeneric()).


Contoh Penggunaan






Minggu, 05 Oktober 2025

PBO A - Pertemuan 6 - Latihan Grouping Object

 Nama    : Erlangga Rizqi Dwi Raswanto

NRP      : 5025241179

Kelas     : PBO A


Pada pertemuan ini, materi berfokus pada Grouping Objek dan sifat/perilaku objek. Grouping Objek berarti mengelompokkan banyak objek berdasarkan struktur data agar mudah dikelola. Program yang dibuat adalah aplikasi Personal Notebook berbasis terminal yang memungkinkan pengguna:

  • menambah catatan,

  • melihat daftar catatan,

  • mencari catatan,

  • menghapus catatan.

Pengelompokan objek dilakukan dengan ArrayList<Note> di dalam NotebookApp. Setiap catatan direpresentasikan sebagai objek Note (berisi judul dan isi).


Konsep OOP pada aplikasi ini 

  • Kelas sebagai blueprint objek: Note mewakili satu catatan.

  • Sifat (atribut): title, content (bersifat privateenkapsulasi).

  • Perilaku (method): konstruktor, getter, dan toString() pada Note.

  • Grouping objek: ArrayList<Note> pada NotebookApp menyimpan banyak Note.

  • Enkapsulasi: akses atribut Note dibatasi, diakses lewat getter.


Desain Class 

Note.java

 public class Note {  
   private String title;  
   private String content;  
   
   public Note(String title, String content) {  
     this.title = title;  
     this.content = content;  
   }  
   
   public String getTitle() {  
     return title;  
   }  
   public String getContent() {  
     return content;  
   }  
   
   @Override  
   public String toString() {  
     return "Judul: " + title + "\nIsi: " + content;  
   }  
 }  
   
  • Atribut:
private String title;
private String content;
  • Konstruktor: Note(String title, String content) untuk membentuk objek yang valid.
  • Getter: getTitle(), getContent() enkapsulasi.
  • Representasi: toString() menampilkan catatan.

NotebookApp.java

 public class Note {  
   private String title;  
   private String content;  
   
   public Note(String title, String content) {  
     this.title = title;  
     this.content = content;  
   }  
   
   public String getTitle() {  
     return title;  
   }  
   public String getContent() {  
     return content;  
   }  
   
   @Override  
   public String toString() {  
     return "Judul: " + title + "\nIsi: " + content;  
   }  
 }

  • Struktur data: ArrayList<Note> notes = new ArrayList<>();
  • I/O: memakai Scanner dengan validasi input angka menu.
  • Menu & Fitur:
  1. Tambah Catatan
    Meminta judul dan isi, lalu notes.add(new Note(title, content)).

  2. Lihat Semua Catatan
    Menampilkan daftar judul (nomor urut + judul). Bila kosong, diberi pesan.

  3. Cari Catatan
    Pencarian case-insensitive berdasarkan substring judul (contains). Semua kecocokan ditampilkan lengkap via toString().

  4. Hapus Catatan
    Menghapus berdasarkan judul yang sama persis (case-insensitive) memakai removeIf(...)

  5. Keluar
    Mengakhiri program dan menutup Scanner.


Contoh Penggunaan :

Menambah Catatan


Melihat Catatan



Mencari dan menampilkan catatan




Menghapus dan melihat catatan





PBO A - Pertemuan 5 - Konsep dan Sifat Objek

Nama    : Erlangga Rizqi Dwi Raswanto

NRP      : 5025241179

Kelas     : PBO A

1) Pendahuluan

Pada minggu ini dibuat sebuah sistem mini FRS (Formulir Rencana Studi) untuk mendemonstrasikan konsep OOP dengan kode Java sederhana. Fungsi aplikasi :

  • Melihat daftar mata kuliah yang tersedia

  • Mengambil mata kuliah (cek kapasitas & duplikasi)

  • Drop mata kuliah

  • Melihat KRS (daftar MK diambil + total SKS)


2) Empat Pilar OOP (dan bagaimana diterapkan)

  1. Encapsulation (Enkapsulasi)

    • Seluruh atribut pada Dosen, MataKuliah, Mahasiswa bersifat private dan diakses via getter (dan operasi khusus seperti daftar(), batal(), ambil(), drop()).

    • Efeknya: aturan kapasitas, larangan duplikasi, dsb terkendali di dalam kelasnya masing-masing.

  2. Abstraction (Abstraksi)

    • Detail teknis seperti logika naik/turun kapasitas disembunyikan melalui metode daftar()/batal() pada MataKuliah.

    • Kelas Main cukup memanggil API sederhana (mis. m.ambil(mk)), tanpa tahu bagaimana kapasitas dihitung.

  3. Inheritance (Pewarisan)

    • Program ini tidak memakai pewarisan eksplisit (selain turunan implisit dari Object).

    • Jika diperlukan, sangat mudah menambahkan superkelas Orang (punya nama) lalu Dosen & Mahasiswa mewarisinya.

  4. Polymorphism (Polimorfisme)

    • Method overriding pada toString() (di Dosen, MataKuliah). Saat objek dicetak, Java memilih implementasi toString milik objek aktual (polimorfisme berbasis Object).


3) Diagram Kelas (UML)

classDiagram
class Dosen {
  - nama : String
  - nip  : String
  + Dosen(nama:String, nip:String)
  + getNama() String
  + getNip() String
  + toString() String
}

class MataKuliah {
  - kode : String
  - nama : String
  - sks : int
  - kapasitas : int
  - terisi : int
  - jadwal : String
  - dosen : Dosen
  + MataKuliah(kode,nama,sks,kapasitas,jadwal,dosen)
  + getKode() String
  + getNama() String
  + getSks() int
  + getJadwal() String
  + getDosen() Dosen
  + isPenuh() boolean
  + daftar() boolean
  + batal() boolean
  + toString() String
}

class Mahasiswa {
  - nama : String
  - nrp  : String
  - krs : List<MataKuliah>
  + Mahasiswa(nama:String, nrp:String)
  + getNama() String
  + getNrp() String
  + getKRS() List<MataKuliah>
  + ambil(MataKuliah) boolean
  + drop(MataKuliah) boolean
  + totalSks() int
}

class Main {
  + main(String[]) void
  - tampilKatalog(List<MataKuliah>) void
  - cetakKRS(Mahasiswa) void
  - bacaInt() int
  - valid(int, List<?>) boolean
}

Dosen <.. MataKuliah : dosen pengampu
Mahasiswa "1" --> "*" MataKuliah : mengambil

4) Rincian Kelas & Metode

A. Dosen

  • Atribut: nama, nip (keduanya final)

  • Metode kunci: toString() untuk menampilkan dosen rapi di konsol.

  • Peran: metadata pengampu MK (tanpa logika bisnis).

B. MataKuliah

  • Atribut: kode, nama, sks, kapasitas, terisi, jadwal, dosen.

  • Metode bisnis:

    • isPenuh()true jika terisi >= kapasitas

    • daftar() → tambah 1 kursi jika belum penuh

    • batal() → kurangi 1 kursi jika ada yang terdaftar

  • Tujuan: menjaga aturan kapasitas dan format tampilan.

C. Mahasiswa

  • Atribut: nama, nrp, krs (list MK yang diambil)

  • Metode bisnis:

    • ambil(mk) → gagal jika sudah diambil atau kapasitas penuh

    • drop(mk) → gagal jika MK belum ada di KRS

    • totalSks() → jumlahkan sks semua MK di krs

  • Tujuan: menjaga aturan duplikasi di sisi mahasiswa.

D. Main

    • Inisialisasi data contoh (Dosen, daftar MataKuliah)

    • Input 1 mahasiswa

    • Menu: daftar MK / ambil / drop / lihat KRS

    • Utilitas: tampilKatalog, cetakKRS, bacaInt, valid


5) Alur Operasi (Ringkas)

sequenceDiagram
participant U as User
participant Main
participant Mhs as Mahasiswa
participant MK as MataKuliah

U->>Main: Pilih (1) Lihat daftar MK
Main->>Main: tampilKatalog(katalog)

U->>Main: Pilih (2) Ambil MK (nomor i)
Main->>MK: katalog.get(i)
Main->>Mhs: ambil(MK)
Mhs->>MK: daftar() (cek kapasitas)
MK-->>Mhs: true/false
Mhs-->>Main: true/false (tambah ke KRS jika true)
Main-->>U: Berhasil/Gagal

U->>Main: Pilih (3) Drop MK (nomor j di KRS)
Main->>Mhs: drop(MK_j)
Mhs->>MK: batal() (kurangi terisi)
MK-->>Mhs: true/false
Mhs-->>Main: true/false
Main-->>U: Berhasil/Gagal

U->>Main: Pilih (4) Lihat KRS
Main->>Mhs: getKRS(), totalSks()
Main-->>U: Daftar MK + total SKS

6) Source Code

Dosen.java
public class Dosen {
private final String nama;
private final String nip;


public Dosen(String nama, String nip) {
this.nama = nama;
this.nip = nip;
}


public String getNama() { return nama; }
public String getNip() { return nip; }


@Override
public String toString() {
return nama + " (NIP: " + nip + ")";
}
}

Mahasiswa.java

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class Mahasiswa {
private String nama;
private String nrp;
private List<MataKuliah> krs = new ArrayList<>();


public Mahasiswa(String nama, String nrp) {
this.nama = nama;
this.nrp = nrp;
}


public String getNama() { return nama; }
public String getNrp() { return nrp; }
public List<MataKuliah> getKRS() { return Collections.unmodifiableList(krs); }


public boolean ambil(MataKuliah mk) {
if (krs.contains(mk)) return false; // sudah diambil
if (mk.daftar()) {
krs.add(mk);
return true;
}
return false; // penuh
}


public boolean drop(MataKuliah mk) {
if (!krs.contains(mk)) return false;
if (mk.batal()) {
krs.remove(mk);
return true;
}
return false;
}


public int totalSks() {
int sum = 0;
for (MataKuliah mk : krs) sum += mk.getSks();
return sum;
}
}

MataKuliah.java

public class MataKuliah {
private String kode;
private String nama;
private int sks;
private int kapasitas;
private int terisi = 0;
private String jadwal; // contoh: "Senin 10:00-11:50"
private Dosen dosen;


public MataKuliah(String kode, String nama, int sks, int kapasitas, String jadwal, Dosen dosen) {
this.kode = kode;
this.nama = nama;
this.sks = sks;
this.kapasitas = kapasitas;
this.jadwal = jadwal;
this.dosen = dosen;
}


public String getKode() { return kode; }
public String getNama() { return nama; }
public int getSks() { return sks; }
public String getJadwal() { return jadwal; }
public Dosen getDosen() { return dosen; }


public boolean isPenuh() { return terisi >= kapasitas; }


/** Coba daftar satu kursi. true jika berhasil */
public boolean daftar() {
if (isPenuh()) return false;
terisi++;
return true;
}


/** Batalkan satu kursi. true jika berhasil */
public boolean batal() {
if (terisi <= 0) return false;
terisi--;
return true;
}


@Override
public String toString() {
String d = (dosen == null ? "-" : dosen.getNama());
return String.format("%s - %s (%d SKS) | %s | %d/%d | Dosen: %s",
kode, nama, sks, jadwal, terisi, kapasitas, d);
}
}
Main.java
import java.util.*;

public class Main {
    private static final Scanner sc = new Scanner(System.in);

    public static void main(String[] args) {
        // Data contoh dosen
        Dosen d1 = new Dosen("Fajar Baskoro", "19700001");
        Dosen d2 = new Dosen("Victor Hariadi", "19700002");

        // Input satu mahasiswa
        System.out.print("Nama mahasiswa : ");
        String nama = sc.nextLine();
        System.out.print("NRP mahasiswa  : ");
        String nrp = sc.nextLine();
        Mahasiswa m = new Mahasiswa(nama, nrp);

        // Katalog MK minimal
        List<MataKuliah> katalog = new ArrayList<>();
        katalog.add(new MataKuliah("IF101", "PBO",          3, 2, "Senin 10:00-11:50",  d1));
        katalog.add(new MataKuliah("IF102", "Teori Graf",   3, 3, "Selasa 08:00-09:40", d2));
        katalog.add(new MataKuliah("IF103", "Struktur Data",3, 1, "Kamis 10:00-11:50",  d2));

        int pilih;
        do {
            System.out.println("\n==== MENU FRS (Sederhana) ====");
            System.out.println("Login: " + m.getNama() + " (" + m.getNrp() + ")");
            System.out.println("1. Lihat daftar mata kuliah");
            System.out.println("2. Ambil mata kuliah");
            System.out.println("3. Drop mata kuliah");
            System.out.println("4. Lihat KRS");
            System.out.println("0. Keluar");
            System.out.print("Pilih: ");
            pilih = bacaInt();

            switch (pilih) {
                case 1:
                    tampilKatalog(katalog);
                    break;

                case 2:
                    tampilKatalog(katalog);
                    System.out.print("Pilih nomor MK: ");
                    int ambil = bacaInt() - 1;
                    if (valid(ambil, katalog)) {
                        boolean ok = m.ambil(katalog.get(ambil));
                        System.out.println(ok ? "Berhasil ambil." : "Gagal (penuh/duplikat).");
                    }
                    break;

                case 3:
                    List<MataKuliah> list = new ArrayList<>(m.getKRS());
                    if (list.isEmpty()) { System.out.println("KRS kosong."); break; }
                    for (int i = 0; i < list.size(); i++) {
                        System.out.println((i+1) + ". " + list.get(i));
                    }
                    System.out.print("Pilih nomor MK untuk di-drop: ");
                    int drop = bacaInt() - 1;
                    if (valid(drop, list)) {
                        boolean ok = m.drop(list.get(drop));
                        System.out.println(ok ? "Berhasil drop." : "Gagal drop.");
                    }
                    break;

                case 4:
                    cetakKRS(m);
                    break;

                case 0:
                    System.out.println("Selesai.");
                    break;

                default:
                    System.out.println("Menu tidak valid.");
            }
        } while (pilih != 0);
    }

    private static void tampilKatalog(List<MataKuliah> katalog) {
        System.out.println("\nDaftar Mata Kuliah:");
        for (int i = 0; i < katalog.size(); i++) {
            System.out.println((i + 1) + ". " + katalog.get(i));
        }
    }

    private static void cetakKRS(Mahasiswa m) {
        List<MataKuliah> list = new ArrayList<>(m.getKRS());
        if (list.isEmpty()) { System.out.println("KRS kosong."); return; }
        System.out.println("\nKRS Saat Ini:");
        int total = 0;
        for (MataKuliah mk : list) {
            System.out.println("- " + mk.getNama() + " (" + mk.getSks() + " SKS)");
            total += mk.getSks();
        }
        System.out.println("Total SKS: " + total);
    }

    private static int bacaInt() {
        while (true) {
            try {
                return Integer.parseInt(sc.nextLine().trim());
            } catch (Exception e) {
                System.out.print("Masukkan angka: ");
            }
        }
    }

    private static boolean valid(int idx, List<?> list) {
        if (idx < 0 || idx >= list.size()) {
            System.out.println("Nomor tidak valid.");
            return false;
        }
        return true;
    }
}



7) Contoh Penggunaan


Login dan melihat daftar kuliah



Mengambil kelas kuliah



Melihat KRS



Drop KRS



PBO A - Pertemuan 15 - Pong!

Nama : Erlangga Rizqi Dwi Raswanto NRP : 5025241179 Kelas : PBO A 1. Pendahuluan Pada pertemuan 15, kita mempraktikkan pembuatan game...