Senin, 01 Desember 2025

PBO A - Pertemuan 11 - Penerapan Inheritance pada Sistem Rental Kendaraan

 Nama    : Erlangga Rizqi Dwi Raswanto

NRP      : 5025241179

Kelas     : PBO A


Penerapan Inheritance pada Sistem Rental Kendaraan berbasis Java



  1. Menerapkan konsep inheritance (pewarisan) dalam Java dengan membuat satu kelas induk Kendaraan dan beberapa kelas turunan (Mobil, Motor, Sepeda).

  2. Menunjukkan bagaimana enkapsulasi digunakan untuk melindungi data (atribut dibuat private / protected, akses lewat getter/setter).

  3. Menunjukkan contoh polimorfisme lewat pemanggilan method yang sama (getInfo(), hitungBiaya()) pada objek-objek Kendaraan yang berbeda jenis.

  4. Mengembangkan contoh sederhana menjadi aplikasi kecil yang bisa:

    • menyimpan daftar kendaraan,

    • mencatat penyewa dan transaksi rental,

    • menampilkan kendaraan yang masih tersedia dan daftar transaksi.


2.  Konsep OOP yang Dipakai

  1. Inheritance (pewarisan)

    • Mobil, Motor, Sepeda mewarisi atribut umum dari Kendaraan.

    • Semua jenis kendaraan punya merk, model, tahunProduksi, dan status tersedia.

  2. Enkapsulasi

    • Atribut dibuat private / protected.

    • Akses data melalui method getter dan setter.

  3. Polimorfisme

    • List kendaraan bertipe List<Kendaraan>, tapi isinya bisa Mobil, Motor, atau Sepeda.

    • Saat dipanggil kendaraan.getInfo() atau kendaraan.hitungBiaya(...), yang dipanggil adalah versi method dari kelas turunan masing-masing (dynamic dispatch).

  4. Abstraksi

    • Kendaraan dibuat abstract: tidak dibuat objeknya langsung.

    • Method getInfo() dan hitungBiaya() dibuat abstrak → wajib dioverride di subclass.


3. Implementasi Kelas

3.1. Kendaraan.java

Peran:

  • Menyimpan atribut umum semua kendaraan: merk, model, tahunProduksi, tersedia.

  • Memberi kontrak method abstrak getInfo() dan hitungBiaya().

  • Menyediakan method isTersedia() dan setTersedia() untuk menandai apakah kendaraan masih bisa disewa atau tidak.

/**
 * Kelas induk abstrak untuk semua jenis kendaraan
 */
public abstract class Kendaraan {
    private String merk;
    private String model;
    private int tahunProduksi;
    private boolean tersedia;

    public Kendaraan(String merk, String model, int tahunProduksi) {
        this.merk = merk;
        this.model = model;
        this.tahunProduksi = tahunProduksi;
        this.tersedia = true; // default: masih tersedia untuk disewa
    }

    public String getMerk() {
        return merk;
    }

    public String getModel() {
        return model;
    }

    public int getTahunProduksi() {
        return tahunProduksi;
    }

    public boolean isTersedia() {
        return tersedia;
    }

    public void setTersedia(boolean tersedia) {
        this.tersedia = tersedia;
    }

    /**
     * Info dasar kendaraan: merk, model, tahun produksi.
     * Dipakai oleh subclass untuk menyusun info lengkap.
     */
    protected String getInfoDasar() {
        return merk + " " + model + " (" + tahunProduksi + ")";
    }

    /**
     * Harus dioverride oleh setiap subclass untuk menampilkan info lengkap.
     */
    public abstract String getInfo();

    /**
     * Menghitung biaya sewa berdasarkan lama hari.
     * Implementasi spesifik ada di masing-masing subclass.
     */
    public abstract double hitungBiaya(int lamaHari);
}

3.2. Mobil.java

Peran:

  • Turunan Kendaraan yang mewakili mobil.

  • Menambahkan atribut jumlahRoda.

  • Menentukan cara menampilkan info dan menghitung biaya sewa khusus mobil.

/**
 * Kelas Mobil sebagai turunan dari Kendaraan
 */
public class Mobil extends Kendaraan {
    private int jumlahRoda;

    public Mobil(String merk, String model, int tahunProduksi, int jumlahRoda) {
        super(merk, model, tahunProduksi);
        this.jumlahRoda = jumlahRoda;
    }

    public int getJumlahRoda() {
        return jumlahRoda;
    }

    @Override
    public String getInfo() {
        return "Mobil  : " + getInfoDasar() + ", jumlah roda: " + jumlahRoda;
    }

    @Override
    public double hitungBiaya(int lamaHari) {
        // contoh: tarif mobil Rp350.000 per hari
        double tarifPerHari = 350_000;
        return tarifPerHari * lamaHari;
    }
}

3.3. Motor.java

Peran:

  • Turunan Kendaraan yang mewakili motor.

  • Juga memakai jumlahRoda, biasanya 2.

  • Biaya sewa berbeda dari mobil.

/**
 * Kelas Motor sebagai turunan dari Kendaraan
 */
public class Motor extends Kendaraan {
    private int jumlahRoda;

    public Motor(String merk, String model, int tahunProduksi, int jumlahRoda) {
        super(merk, model, tahunProduksi);
        this.jumlahRoda = jumlahRoda;
    }

    public int getJumlahRoda() {
        return jumlahRoda;
    }

    @Override
    public String getInfo() {
        return "Motor  : " + getInfoDasar() + ", jumlah roda: " + jumlahRoda;
    }

    @Override
    public double hitungBiaya(int lamaHari) {
        // contoh: tarif motor Rp100.000 per hari
        double tarifPerHari = 100_000;
        return tarifPerHari * lamaHari;
    }
}

3.4. Sepeda.java

Peran:

  • Turunan Kendaraan yang mewakili sepeda.

  • Menambahkan atribut jenisSepeda (misalnya: Gunung, Balap, BMX, Lipat).

  • Biaya sewanya lebih murah.

/**
 * Kelas Sepeda sebagai turunan dari Kendaraan
 */
public class Sepeda extends Kendaraan {
    private String jenisSepeda;

    public Sepeda(String merk, String model, int tahunProduksi, String jenisSepeda) {
        super(merk, model, tahunProduksi);
        this.jenisSepeda = jenisSepeda;
    }

    public String getJenisSepeda() {
        return jenisSepeda;
    }

    @Override
    public String getInfo() {
        return "Sepeda : " + getInfoDasar() + ", jenis: " + jenisSepeda;
    }

    @Override
    public double hitungBiaya(int lamaHari) {
        // contoh: tarif sepeda Rp50.000 per hari
        double tarifPerHari = 50_000;
        return tarifPerHari * lamaHari;
    }
}

3.5. Penyewa.java

Peran:

  • Menyimpan data orang yang menyewa kendaraan.

  • Di sini disimpan nama dan noIdentitas (misal: NIK, KTP, SIM, atau ID lain).

/**
 * Menyimpan data penyewa kendaraan
 */
public class Penyewa {
    private String nama;
    private String noIdentitas;

    public Penyewa(String nama, String noIdentitas) {
        this.nama = nama;
        this.noIdentitas = noIdentitas;
    }

    public String getNama() {
        return nama;
    }

    public String getNoIdentitas() {
        return noIdentitas;
    }

    public String getInfo() {
        return nama + " (ID: " + noIdentitas + ")";
    }
}

3.6. Rental.java

Peran:

  • Menghubungkan satu Penyewa dengan satu Kendaraan.

  • Menyimpan lama sewa (hari) dan total biaya sewa.

  • Saat objek Rental dibuat, status kendaraan otomatis diubah jadi tidak tersedia.

/**
 * Mewakili satu transaksi rental kendaraan
 */
public class Rental {
    private Penyewa penyewa;
    private Kendaraan kendaraan;
    private int lamaHari;
    private double totalBiaya;

    public Rental(Penyewa penyewa, Kendaraan kendaraan, int lamaHari) {
        this.penyewa = penyewa;
        this.kendaraan = kendaraan;
        this.lamaHari = lamaHari;

        // saat dirental, kendaraan tidak lagi tersedia
        this.kendaraan.setTersedia(false);

        // hitung total biaya sewa menggunakan polimorfisme
        this.totalBiaya = kendaraan.hitungBiaya(lamaHari);
    }

    public Penyewa getPenyewa() {
        return penyewa;
    }

    public Kendaraan getKendaraan() {
        return kendaraan;
    }

    public int getLamaHari() {
        return lamaHari;
    }

    public double getTotalBiaya() {
        return totalBiaya;
    }

    public String getInfo() {
        String biayaFormatted = String.format("Rp %,.0f", totalBiaya);
        return "Penyewa : " + penyewa.getInfo() +
               "\nKendaraan: " + kendaraan.getInfo() +
               "\nLama sewa: " + lamaHari + " hari" +
               "\nTotal    : " + biayaFormatted;
    }
}

3.7. RentalApp.java (Main)

Peran:

  • Menjadi titik masuk program (main).

  • Membuat daftar kendaraan (mobil, motor, sepeda).

  • Membuat beberapa penyewa dan transaksi rental.

  • Menampilkan:

    • daftar kendaraan yang masih tersedia,

    • daftar transaksi rental yang sedang berjalan.

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

/**
 * Kelas utama untuk menjalankan aplikasi rental kendaraan
 */
public class RentalApp {

    public static void main(String[] args) {
        // 1. Membuat daftar kendaraan
        List<Kendaraan> daftarKendaraan = new ArrayList<>();
        daftarKendaraan.add(new Mobil("Toyota", "Avanza", 2022, 4));
        daftarKendaraan.add(new Motor("Honda", "Vario", 2021, 2));
        daftarKendaraan.add(new Sepeda("Polygon", "Xtrada", 2020, "Gunung"));
        daftarKendaraan.add(new Mobil("Suzuki", "Ertiga", 2019, 4));
        daftarKendaraan.add(new Sepeda("United", "Miami", 2023, "BMX"));
        daftarKendaraan.add(new Motor("Yamaha", "NMax", 2022, 2));

        // 2. Daftar rental (transaksi)
        List<Rental> daftarRental = new ArrayList<>();

        // 3. Membuat beberapa penyewa
        Penyewa p1 = new Penyewa("Budi", "KTP001");
        Penyewa p2 = new Penyewa("Siti", "KTP002");
        Penyewa p3 = new Penyewa("Andi", "KTP003");

        // 4. Contoh transaksi:
        //    Budi sewa Avanza 2 hari, Siti sewa Sepeda Gunung 3 hari, Andi sewa Motor NMax 1 hari
        Rental r1 = new Rental(p1, daftarKendaraan.get(0), 2); // Avanza
        Rental r2 = new Rental(p2, daftarKendaraan.get(2), 3); // Sepeda Gunung
        Rental r3 = new Rental(p3, daftarKendaraan.get(5), 1); // NMax

        daftarRental.add(r1);
        daftarRental.add(r2);
        daftarRental.add(r3);

        // 5. Tampilkan daftar kendaraan yang masih tersedia
        System.out.println("=== Daftar Kendaraan Tersedia ===");
        for (Kendaraan k : daftarKendaraan) {
            if (k.isTersedia()) {
                System.out.println("- " + k.getInfo());
            }
        }

        System.out.println();

        // 6. Tampilkan daftar penyewa dan kendaraan yang disewa
        System.out.println("=== Daftar Transaksi Rental ===");
        for (Rental r : daftarRental) {
            System.out.println(r.getInfo());
            System.out.println("--------------------------------");
        }
    }
}

4. Contoh Output Program

Kurang lebih output di console akan seperti ini:


Terlihat bahwa:

  • Kendaraan yang sudah disewa tidak muncul lagi di daftar tersedia, karena setTersedia(false) dipanggil saat Rental dibuat.

  • Method yang dipanggil sama (getInfo() dan hitungBiaya()), tapi hasilnya berbeda tergantung jenis kendaraan → contoh polimorfisme.

PBO A - Pertemuan 9 - Game World of Zuul

Nama    : Erlangga Rizqi Dwi Raswanto

NRP      : 5025241179

Kelas     : PBO A

Halo, di pertemuan ini saya membuat sebuah game petualangan bernama Game World of Zuul




Dalam project ini terdapat 5 kelas utama, yaitu:

  1. CommandWords
    Menyimpan semua kata perintah (command) yang valid dalam game, misalnya: go, help, quit, look.
    Kelas ini menggunakan array String untuk menampung daftar perintah, dan menyediakan method untuk mengecek apakah sebuah kata termasuk perintah yang valid.

  2. Parser
    Kelas yang bertugas membaca input dari user lewat terminal, memecah input menjadi kata-kata, lalu mengubahnya menjadi objek Command.
    Parser akan mengecek apakah kata pertama termasuk perintah yang dikenal di CommandWords. Jika tidak, command tersebut dianggap tidak dikenal (unknown).

  3. Command
    Objek Command merepresentasikan satu perintah yang diketik user.
    Sebuah perintah terdiri dari:

    • kata pertama (command utama, misalnya: go)

    • kata kedua (argumen, misalnya: north)
      Kelas ini punya method untuk:

    • mengecek apakah command valid atau tidak,

    • mengambil kata pertama,

    • mengambil kata kedua (jika ada).

  4. Room
    Objek Room merepresentasikan lokasi di dalam game.
    Setiap ruangan punya:

    • deskripsi (misalnya "in a lecture theater")

    • pintu keluar (exit) ke arah north, east, south, west yang bisa mengarah ke ruangan lain.

  5. Game
    Ini adalah kelas utama yang menjalankan game.
    Tugasnya:

    • Membuat semua ruangan dan menghubungkan pintu keluarnya.

    • Membuat objek Parser.

    • Menyimpan lokasi ruangan saat ini (currentRoom).

    • Menjalankan game loop (menerima command dari user dan mengeksekusinya).

    • Mengimplementasikan perintah-perintah seperti go, help, dan quit.


Gambaran Cara Kerja Program

Secara umum alur game-nya seperti ini:

  1. Program dijalankan → objek Game dibuat.

  2. Konstruktor Game:

    • memanggil createRooms() untuk membuat ruangan dan menghubungkannya,

    • membuat objek Parser.

  3. User memulai permainan dengan memanggil method play().

  4. Di dalam play(), program:

    • menampilkan pesan sambutan (printWelcome()),

    • masuk ke loop utama:

      • mengambil command dari Parser,

      • memproses command dengan processCommand(),

      • jika user mengetik quit, loop berhenti.

  5. Program berakhir dengan menampilkan pesan perpisahan.

Source Code Game:


Source Code Room:


Source Code Parser:


Source Code Command:

Source Code CommandWords:


Cara Mengimplementasikan dan Menjalankan

Berikut langkah-langkah

  1. Buat objek Game:

    • Klik kanan pada kelas Game → pilih new Game() → beri nama objek, misal game1.

  2. Jalankan game:

    • Klik kanan pada objek game1 → pilih method void play().

  3. Di jendela terminal, masukkan perintah seperti:

    • help

    • go east

    • go south

    • quit


Output :


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...