Kamis, 30 Oktober 2025

Pertemuan 10 : Testing dan Debugging

Testing Sales Item PBO (Pertemuan 10)

Pemrograman Berbasis Objek (PBO)
Nama: Hosea Felix Sanjaya
NRP: 5025241177
Kelas: B
Tahun: 2025


Testing Class Comment di Java

Halo semuanya! 👋
Pada kesempatan kali ini, saya mau membahas tentang pengujian (testing) untuk sebuah class sederhana bernama Comment.
Class ini dirancang untuk merepresentasikan sebuah komentar pengguna, misalnya dalam sistem ulasan (review system) pada aplikasi e-commerce atau forum diskusi.

Tujuan Class

Class Comment memiliki fungsi utama untuk menyimpan informasi berikut:

  • Author (Penulis komentar)
  • Text (Isi komentar)
  • Rating (Penilaian dalam skala 1–5)
  • Votes (Jumlah suara atau dukungan)

Selain menyimpan data, class ini juga mendukung operasi sederhana seperti:

  • upvote() → menambah satu suara positif.
  • downvote() → mengurangi satu suara.

Kode Program Class Comment

/**
 * Write a description of class Comment here.
 *
 * @author Hosea Felix Sanjaya
 * @version 30 Oct 2025
 */
public class Comment {
    private String author;
    private String text;
    private int rating;
    private int votes;
    
    public Comment(String author, String text, int rating) {
        this.author = author;
        this.text = text;
        this.rating = rating;
        this.votes = 0;
    }
    
    public String getAuthor() {
        return author;
    }

    public String getText() {
        return text;
    }

    public int getRating() {
        return rating;
    }

    public int getVoteCount() {
        return votes;
    }
    
    public void upvote() {
        votes++;
    }

    public void downvote() {
        votes--;
    }
    
    public String getFullDetails() {
        return "Author: " + author + "\n" +
               "Rating: " + rating + "/5\n" +
               "Votes: " + votes + "\n" +
               "Comment: " + text;
    }
}

Class Testing: CommentTester

Untuk menguji fungsionalitas class Comment, kita buat class lain bernama CommentTester.
Class ini akan membuat objek Comment, menampilkan detailnya, dan mencoba melakukan voting.

/**
 * Class untuk mengetes Comment class.
 *
 * @author Hose
 * @version 30 Oct 2025
 */
public class CommentTester {
    public static void main(String[] args) {
        // Membuat objek comment
        Comment comment1 = new Comment("Hosea", "Produk ini sangat bagus!", 5);
        
        // Menampilkan detail awal
        System.out.println("=== Detail Awal ===");
        System.out.println(comment1.getFullDetails());
        
        // Melakukan voting
        comment1.upvote();
        comment1.upvote();
        comment1.downvote();
        
        // Menampilkan hasil setelah voting
        System.out.println("\n=== Setelah Voting ===");
        System.out.println(comment1.getFullDetails());
    }
}

Hasil Output

=== Detail Awal ===
Author: Hosea
Rating: 5/5
Votes: 0
Comment: Produk ini sangat bagus!

=== Setelah Voting ===
Author: Hosea
Rating: 5/5
Votes: 1
Comment: Produk ini sangat bagus!

Dokumentasi







Selasa, 21 Oktober 2025

Pertemuan 9 - Implementasi World of Zuul

Analisis Desain Kelas PBO (Pertemuan 9) - Studi Kasus: World of Zuul

Pemrograman Berbasis Objek (PBO)

Nama   : Hosea Felix Sanjaya
NRP     : 5025241177
Kelas  : B
Tahun : 2025


Pendahuluan

Dalam materi perkuliahan Pemrograman Berbasis Objek (PBO) pertemuan ke-9, kita membahas dua konsep fundamental dalam desain perangkat lunak yang berkualitas: Cohesion (Kohesi) dan Coupling (Kopling). Prinsip utamanya adalah untuk selalu mengusahakan "High Cohesion, Loose Coupling".

  • High Cohesion (Kohesi Tinggi): Menandakan bahwa sebuah kelas memiliki satu tanggung jawab yang jelas dan terfokus. Semua metode dan atribut di dalam kelas tersebut bekerja bersama untuk mencapai satu tujuan tunggal.
  • Loose Coupling (Kopling Longgar): Menandakan bahwa antar kelas memiliki tingkat ketergantungan yang rendah. Perubahan pada satu kelas (misalnya, perbaikan internal) sebisa mungkin tidak mengharuskan perubahan pada kelas lain yang menggunakannya.

Untuk memahami penerapan konsep ini, kita akan melakukan analisis terhadap "World of Zuul", sebuah studi kasus game petualangan berbasis teks sederhana yang sangat populer digunakan dalam pengajaran OOP.

Deskripsi Sistem (World of Zuul)

World of Zuul adalah sebuah game petualangan berbasis teks yang sangat sederhana. Pemain dapat "berjalan-jalan" di dalam sebuah lingkungan kampus fiksi dengan mengetikkan perintah teks sederhana.

Tujuan dari game ini (dari sisi akademis) adalah untuk mendemonstrasikan bagaimana sebuah program dapat dipecah menjadi beberapa kelas yang saling berinteraksi, masing-masing dengan tanggung jawabnya sendiri.

Alur Sistem (Game Flow)

  1. Game dimulai dan menampilkan pesan selamat datang serta lokasi awal pemain.
  2. Game mencetak pintu keluar (exits) yang tersedia dari lokasi saat ini.
  3. Game menunggu pemain mengetikkan perintah (misalnya, "go south" atau "help").
  4. Parser akan membaca input dan mengubahnya menjadi objek Command.
  5. Game akan memproses objek Command tersebut:
    • Jika perintah "go", pemain akan dipindahkan ke Room lain (jika ada pintu).
    • Jika perintah "help", game akan menampilkan daftar perintah yang valid.
    • Jika perintah "quit", game akan berakhir.
  6. Loop berlanjut kembali ke langkah 2 sampai pemain mengetik "quit".

Kode Program Lengkap

Sistem ini dibangun dari 5 kelas utama, ditambah 1 kelas `Main` untuk menjalankannya.

1. Kelas Game.java

Ini adalah kelas utama yang menginisialisasi semua bagian game, membuat ruangan, dan menjalankan game loop utama. Kelas ini juga yang memproses perintah dari pengguna.


/**
 * This class is the main class of the "World of Zuul" application. 
 * "World of Zuul" is a very simple, text based adventure game.  Users 
 * can walk around some scenery. That's all. It should really be extended 
 * to make it more interesting!
 *
 * To play this game, create an instance of this class and call the "play"
 * method.
 *
 * This main class creates and initialises all the others: it creates all
 * rooms, creates the parser and starts the game.  It also evaluates and
 * executes the commands that the parser returns.
 *
 * @author  Michael Kolling and David J. Barnes
 * @version 1.0 (February 2002)
 */

class Game 
{
    private Parser parser;
    private Room currentRoom;
        
    /**
     * Create the game and initialise its internal map.
     */
    public Game() 
    {
        createRooms();
        parser = new Parser();
    }

    /**
     * Create all the rooms and link their exits together.
     */
    private void createRooms()
    {
        Room outside, theatre, pub, lab, office;
      
        // create the rooms
        outside = new Room("outside the main entrance of the university");
        theatre = new Room("in a lecture theatre");
        pub = new Room("in the campus pub");
        lab = new Room("in a computing lab");
        office = new Room("in the computing admin office");
        
        // initialise room exits
        outside.setExits(null, theatre, lab, pub);
        theatre.setExits(null, null, null, outside);
        pub.setExits(null, outside, null, null);
        lab.setExits(outside, office, null, null);
        office.setExits(null, null, null, lab);

        currentRoom = outside;  // start game outside
    }

    /**
     * Main play routine.  Loops until end of play.
     */
    public void play() 
    {            
        printWelcome();

        // Enter the main command loop.  Here we repeatedly read commands and
        // execute them until the game is over.
                
        boolean finished = false;
        while (! finished) {
            Command command = parser.getCommand();
            finished = processCommand(command);
        }
        System.out.println("Thank you for playing.  Good bye.");
    }

    /**
     * Print out the opening message for the player.
     */
    private void printWelcome()
    {
        System.out.println();
        System.out.println("Welcome to Adventure!");
        System.out.println("Adventure is a new, incredibly boring adventure game.");
        System.out.println("Type 'help' if you need help.");
        System.out.println();
        System.out.println("You are " + currentRoom.getDescription());
        System.out.print("Exits: ");
        if(currentRoom.northExit != null)
            System.out.print("north ");
        if(currentRoom.eastExit != null)
            System.out.print("east ");
        if(currentRoom.southExit != null)
            System.out.print("south ");
        if(currentRoom.westExit != null)
            System.out.print("west ");
        System.out.println();
    }

    /**
     * Given a command, process (that is: execute) the command.
     * If this command ends the game, true is returned, otherwise false is
     * returned.
     */
    private boolean processCommand(Command command) 
    {
        boolean wantToQuit = false;

        if(command.isUnknown()) {
            System.out.println("I don't know what you mean...");
            return false;
        }

        String commandWord = command.getCommandWord();
        if (commandWord.equals("help"))
            printHelp();
        else if (commandWord.equals("go"))
            goRoom(command);
        else if (commandWord.equals("quit"))
            wantToQuit = quit(command);

        return wantToQuit;
    }

    // implementations of user commands:

    /**
     * Print out some help information.
     * Here we print some stupid, cryptic message and a list of the 
     * command words.
     */
    private void printHelp() 
    {
        System.out.println("You are lost. You are alone. You wander");
        System.out.println("around at the university.");
        System.out.println();
        System.out.println("Your command words are:");
        System.out.println("   go quit help");
    }

    /** * Try to go to one direction. If there is an exit, enter
     * the new room, otherwise print an error message.
     */
    private void goRoom(Command command) 
    {
        if(!command.hasSecondWord()) {
            // if there is no second word, we don't know where to go...
            System.out.println("Go where?");
            return;
        }

        String direction = command.getSecondWord();

        // Try to leave current room.
        Room nextRoom = null;
        if(direction.equals("north"))
            nextRoom = currentRoom.northExit;
        if(direction.equals("east"))
            nextRoom = currentRoom.eastExit;
        if(direction.equals("south"))
            nextRoom = currentRoom.southExit;
        if(direction.equals("west"))
            nextRoom = currentRoom.westExit;

        if (nextRoom == null)
            System.out.println("There is no door!");
        else {
            currentRoom = nextRoom;
            System.out.println("You are " + currentRoom.getDescription());
            System.out.print("Exits: ");
            if(currentRoom.northExit != null)
                System.out.print("north ");
            if(currentRoom.eastExit != null)
                System.out.print("east ");
            if(currentRoom.southExit != null)
                System.out.print("south ");
            if(currentRoom.westExit != null)
                System.out.print("west ");
            System.out.println();
        }
    }

    /** * "Quit" was entered. Check the rest of the command to see
     * whether we really quit the game. Return true, if this command
     * quits the game, false otherwise.
     */
    private boolean quit(Command command) 
    {
        if(command.hasSecondWord()) {
            System.out.println("Quit what?");
            return false;
        }
        else
            return true;  // signal that we want to quit
    }
}

2. Kelas Room.java

Kelas ini merepresentasikan satu lokasi atau ruangan dalam game. Setiap ruangan memiliki deskripsi dan referensi ke ruangan lain melalui pintu keluar (exit).


/**
 * Class Room - a room in an adventure game.
 *
 * This class is the main class of the "World of Zuul"
 * application. 
 * "World of Zuul" is a very simple, text based adventure game.
 *
 * A "Room" represents one location in the scenery of the game.  It is 
 * connected to other rooms via exits.  The exits are labelled north, 
 * east, south, west.  For each direction, the room stores a reference
 * to the neighboring room, or null if there is no exit
 * in that direction.
 *
 * @author  Michael Kolling and David J. Barnes
 * @version 1.0 (February 2002)
 */

class Room 
{
    public String description;
    public Room northExit;
    public Room southExit;
    public Room eastExit;
    public Room westExit;

    /**
     * Create a room described "description". Initially, it has
     * no exits. "description" is something like "a kitchen" or
     * "an open court yard".
     */
    public Room(String description) 
    {
        this.description = description;
    }

    /**
     * Define the exits of this room.  Every direction either leads
     * to another room or is null (no exit there).
     */
    public void setExits(Room north, Room east, Room south, Room west) 
    {
        if(north != null)
            northExit = north;
        if(east != null)
            eastExit = east;
        if(south != null)
            southExit = south;
        if(west != null)
            westExit = west;
    }

    /**
     * Return the description of the room (the one that was defined
     * in the constructor).
     */
    public String getDescription()
    {
        return description;
    }
}

3. Kelas Parser.java

Kelas ini bertanggung jawab membaca input dari pengguna dan mengubahnya menjadi objek Command yang dapat dimengerti oleh game.


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

/**
 * This class is the main class of the "World of Zuul"
 * application. 
 * "World of Zuul" is a very simple, text based adventure game.
 *
 * This parser reads user input and tries to interpret it as an "Adventure"
 * command. Every time it is called it reads a line from the terminal and
 * tries to interpret the line as a two word command. It returns the command
 * as an object of class Command.
 *
 * The parser has a set of known command words. It checks user input against
 * the known commands, and if the input is not one of the known commands, it
 * returns a command object that is marked as an unknown command.
 *
 * @author  Michael Kolling and David J. Barnes
 * @version 1.0 (February 2002)
 */

class Parser 
{

    private CommandWords commands;  // holds all valid command words

    public Parser() 
    {
        commands = new CommandWords();
    }

    public Command getCommand() 
    {
        String inputLine = "";   // will hold the full input line
        String word1;
        String word2;

        System.out.print("> ");     // print prompt

        BufferedReader reader = 
            new BufferedReader(new InputStreamReader(System.in));
        try {
            inputLine = reader.readLine();
        }
        catch(java.io.IOException exc) {
            System.out.println ("There was an error during reading: "
                                + exc.getMessage());
        }

        StringTokenizer tokenizer = new StringTokenizer(inputLine);

        if(tokenizer.hasMoreTokens())
            word1 = tokenizer.nextToken();      // get first word
        else
            word1 = null;
        if(tokenizer.hasMoreTokens())
            word2 = tokenizer.nextToken();      // get second word
        else
            word2 = null;

        // note: we just ignore the rest of the input line.

        // Now check whether this word is known. If so, create a command
        // with it. If not, create a "null" command (for unknown command).

        if(commands.isCommand(word1))
            return new Command(word1, word2);
        else
            return new Command(null, word2);
    }
}

4. Kelas Command.java

Kelas ini adalah kelas data sederhana yang menyimpan informasi tentang perintah yang diketik pengguna. Ini memisahkan kata perintah (kata pertama) dan kata kedua.


/**
 * This class is the main class of the "World of Zuul" application. 
 * "World of Zuul" is a very simple, text based adventure game.
 *
 * This class holds information about a command that was issued by the user.
 * A command currently consists of two strings: a command word and a second
 * word (for example, if the command was "take map", then the two strings
 * are "take" and "map").
 *
 * The way this is used is: Commands are already checked for being valid
 * command words. If the user entered an invalid command (a word that is not
 * known) then the command word is <null>.
 *
 * If the command has only one word, then the second word is <null>.
 *
 * @author  Michael Kolling and David J. Barnes
 * @version 1.0 (February 2002)
 */

class Command
{
    private String commandWord;
    private String secondWord;

    /**
     * Create a command object. First and second word must be supplied, but
     * either one (or both) can be null. The command word should be null to
     * indicate that this was a command that was not recognised by this game.
     */
    public Command(String firstWord, String secondWord)
    {
        commandWord = firstWord;
        this.secondWord = secondWord;
    }

    /**
     * Return the command word (the first word) of this command. If the
     * command was not understood, the result is null.
     */
    public String getCommandWord()
    {
        return commandWord;
    }

    /**
     * Return the second word of this command. Returns null if there was no
     * second word.
     */
    public String getSecondWord()
    {
        return secondWord;
    }

    /**
     * Return true if this command was not understood.
     */
    public boolean isUnknown()
    {
        return (commandWord == null);
    }

    /**
     * Return true if the command has a second word.
     */
    public boolean hasSecondWord()
    {
        return (secondWord != null);
    }
}

5. Kelas CommandWords.java

Kelas ini memiliki satu tanggung jawab: menyimpan dan memvalidasi daftar semua kata perintah yang sah dalam game.


/**
 * This class is the main class of the "World of Zuul"
 * application. 
 * "World of Zuul" is a very simple, text based
 * adventure game.
 *
 * This class holds an enumeration of all command words
 * known to the game.
 * It is used to recognise commands as they are typed
 * in.
 *
 * @author  Michael Kolling and David J. Barnes
 * @version 1.0 (February 2002)
 */

class CommandWords
{
    // a constant array that holds all valid command
    // words
    private static final String validCommands[] = {
        "go", "quit", "help", "look"
    };

    /**
     * Constructor - initialise the command words.
     */
    public CommandWords()
    {
        // nothing to do at the moment...
    }

    /**
     * Check whether a given String is a valid command
     * word. 
     * Return true if it is, false if it isn't.
     */
    public boolean isCommand(String aString)
    {
        for(int i = 0; i < validCommands.length; i++) {
            if(validCommands[i].equals(aString))
                return true;
        }
        // if we get here, the string was not found in
        // the commands
        return false;
    }
}

6. Kelas Main.java (Untuk Menjalankan)

Kelas ini tidak ada di gambar, namun diperlukan untuk membuat objek `Game` dan memulai permainan.


public class Main {
    public static void main(String[] args) {
        // Buat objek Game baru
        Game game = new Game();
        
        // Panggil metode play() untuk memulai permainan
        game.play();
    }
}

Analisis Desain (Kohesi & Kopling)

Sekarang, mari kita evaluasi desain kelas "World of Zuul" menggunakan konsep yang telah kita pelajari.

Analisis Kohesi (Prinsip: High Cohesion)

Kohesi mengukur seberapa fokus sebuah kelas terhadap satu tanggung jawab. Desain yang baik memiliki Kohesi Tinggi.

Contoh Kohesi Tinggi (Desain Baik)

  • Room: Sangat kohesif. Tanggung jawabnya hanya satu: merepresentasikan satu lokasi. Semua data (description, northExit, dll.) dan metode (setExits, getDescription) hanya berfokus pada properti ruangan itu saja.
  • Command: Sangat kohesif. Tanggung jawabnya hanya menyimpan dua kata dari perintah pengguna (commandWord dan secondWord).
  • CommandWords: Sangat kohesif. Tanggung jawab tunggalnya adalah mengetahui dan memvalidasi semua kata perintah yang sah dalam game.
  • Parser: Kohesif. Tanggung jawabnya jelas, yaitu membaca input mentah dari pengguna dan mengubahnya menjadi objek Command.

Contoh Kohesi Rendah (Desain Kurang Baik)

  • Game: Kelas ini adalah contoh utama dari Kohesi Rendah. Perhatikan semua tanggung jawabnya yang berbeda:
    1. Membuat dan menginisialisasi semua ruangan (createRooms).
    2. Menjalankan game loop utama (play).
    3. Memproses setiap jenis perintah (processCommand).
    4. Menjalankan logika spesifik untuk setiap perintah (printHelp, goRoom, quit).

Kelas Game melakukan terlalu banyak hal. Ini membuatnya sulit dipahami, di-debug, dan dirawat. Jika kita ingin menambah 10 perintah baru, kita harus mengubah kelas Game di banyak tempat.

Analisis Kopling (Prinsip: Loose Coupling)

Kopling mengukur seberapa besar ketergantungan satu kelas terhadap kelas lain. Desain yang baik memiliki Kopling Longgar (Loose Coupling).

Contoh Kopling Longgar (Desain Baik)

  • Parser dan Game: Kopling di antara keduanya cukup longgar.
    • Kelas Game hanya perlu memanggil parser.getCommand().
    • Game tidak peduli bagaimana Parser mendapatkan perintah itu (apakah dari terminal, file, atau internet).
    • Parser juga tidak tahu apa-apa tentang Game atau Room. Ia hanya mengembalikan objek Command.
    • Ini adalah desain yang bagus. Kita bisa mengganti seluruh implementasi Parser tanpa merusak kelas Game.

Contoh Kopling Erat (Desain Kurang Baik)

  • Game dan Command: Di dalam metode processCommand, terdapat blok if-else yang besar. Ini adalah kopling yang erat. Jika kita ingin menambah perintah baru (misal, "look" atau "take"), kita harus memodifikasi kode internal kelas Game dengan menambah else if baru. Ini membuat Game sangat bergantung pada setiap detail perintah yang ada.
  • Game dan Room: Ini adalah contoh terburuk dalam kode ini. Kelas Game (dalam goRoom dan printWelcome) mengakses fields dari Room secara langsung:
    nextRoom = currentRoom.northExit;
    if(currentRoom.northExit != null) ...
    Ini terjadi karena kelas Room mendeklarasikan variabelnya sebagai public (public Room northExit;), yang merupakan pelanggaran berat terhadap prinsip Enkapsulasi.

    Ini adalah kopling yang sangat erat. Game bergantung pada struktur internal Room. Jika kita ingin mengubah cara Room menyimpan exit (misalnya, menjadi HashMap), maka kelas Game akan rusak total dan harus ditulis ulang.

Kesimpulan

Studi kasus "World of Zuul" adalah contoh yang sangat baik untuk belajar. Desainnya berhasil memisahkan beberapa tanggung jawab dengan baik (seperti Parser dan Command) yang menunjukkan Kohesi Tinggi dan Kopling Longgar.

Namun, desain ini juga secara sengaja menunjukkan praktik yang buruk (Kohesi Rendah di kelas Game dan Kopling Erat antara Game dan Room) sebagai bahan pelajaran. Langkah selanjutnya dari materi ini biasanya adalah melakukan Refactoring: yaitu memperbaiki struktur kode ini untuk meningkatkan kohesi dan mengurangi kopling, tanpa mengubah fungsionalitas game.

Dokumentasi

Senin, 13 Oktober 2025

Pertemuan 8 - ETS Coffee Machine

Evaluasi Tengah Semester Pemrograman Berbasis Objek (PBO)



Nama  : Hosea Felix sanjaya

NRP    : 5025231177

Kelas  : A

Tahun : 2025


Pendahuluan

Dalam evaluasi tengah semester mata kuliah Pemrograman Berbasis Objek (PBO) ini, saya diminta untuk mengimplementasikan konsep Object-Oriented Programming (OOP) dalam bentuk simulasi Coffee Machine (Mesin Penjual Kopi Otomatis) menggunakan bahasa pemrograman Java.


Soal

Sistem Vending Coffee Machine adalah aplikasi yang mensimulasikan mesin penjual otomatis untuk minuman kopi. Pengguna dapat memilih jenis kopi, ukuran gelas, menambahkan gula atau susu, melakukan pembayaran, dan menerima kopi yang telah disiapkan oleh mesin.
Sistem ini mengelola stok bahan (kopi, gula, susu, air), memproses pembayaran, serta memberikan laporan transaksi dan status mesin.

Alur Sistem (Flow)

Alur kerja Vending Coffee Machine
  • Mesin aktif → menampilkan menu pilihan kopi.
  • Pengguna memilih jenis dan ukuran kopi.
  • Pengguna menambah gula/susu (opsional).
  • Mesin menampilkan total harga.
  • Pengguna melakukan pembayaran.
  • Mesin memverifikasi pembayaran → jika cukup → membuat kopi.
  • Kopi disajikan → sistem mengurangi stok.
  • Transaksi disimpan ke log.
  • Jika stok habis → admin diingatkan untuk refill.

Ketentuan

  • Tentukan fitur yang ada pada mesin.
  • Gambarkan rancangan kelas dan rancangan obyek vending coffee mashin.
  • Buatkan output simulasi vending coffe machine.
  • Implementasikan dalam bentuk aplikasi simulasi vending coffe machine.
  • Buatlah Video Presentasi yang menjelaskan pekerjaanmu kemudian upload di Youtube.
  • Buat Dokumentasi pengerjaan di blog, kemudian isi google form  Link Pengumpulan ETS.

Deskripsi Sistem

Sistem Coffee Machine ini bekerja seperti mesin penjual otomatis yang menyediakan berbagai jenis kopi.
Pengguna dapat:

  • Memasukkan uang.

  • Memilih jenis kopi (20 varian).

  • Menentukan ukuran (Small, Medium, Large).

  • Menambah gula atau susu jika stok tersedia.

  • Memesan lebih dari satu kopi sekaligus.

Program juga mencatat setiap transaksi ke dalam file transaction_log.txt dan menampilkan pesan jika stok habis.


Kode Program Lengkap

Kelas CoffeeMachine

/**
 * Coffee Machine in JAVA.
 *
 * @author Hosea Felix
 * @version 14 Oktober 2025
 */

import java.util.*;
import java.io.*;

public class CoffeeMachine {
    private int balance;
    private int coffeeStock;
    private int milkStock;
    private int sugarStock;

    public CoffeeMachine() {
        this.balance = 0;
        this.coffeeStock = 10;
        this.milkStock = 5;
        this.sugarStock = 5;
    }

    private static class CoffeeItem {
        String name;
        int price;
        CoffeeItem(String name, int price) {
            this.name = name;
            this.price = price;
        }
    }

    private final CoffeeItem[] menu = {
        new CoffeeItem("Americano", 30000),
        new CoffeeItem("Latte", 35000),
        new CoffeeItem("Cappuccino", 35000),
        new CoffeeItem("Espresso", 15000),
        new CoffeeItem("Macchiato", 32000),
        new CoffeeItem("Mocha", 37000),
        new CoffeeItem("Flat White", 33000),
        new CoffeeItem("Affogato", 28000),
        new CoffeeItem("Cold Brew", 25000),
        new CoffeeItem("Caramel Latte", 38000),
        new CoffeeItem("Hazelnut Coffee", 39000),
        new CoffeeItem("Vanilla Latte", 36000),
        new CoffeeItem("Irish Coffee", 40000),
        new CoffeeItem("Turkish Coffee", 42000),
        new CoffeeItem("Coconut Latte", 37000),
        new CoffeeItem("Pumpkin Spice Latte", 41000),
        new CoffeeItem("Matcha Latte", 36000),
        new CoffeeItem("Honey Cappuccino", 38000),
        new CoffeeItem("Toffee Nut Latte", 39000),
        new CoffeeItem("Double Espresso", 28000)
    };

    public void start() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("===== ☕ Welcome to Hosee Coffee Machine ☕ =====");

        while (true) {
            if (coffeeStock <= 0) {
                System.out.println("\n❌ Stok kopi habis! Mesin tutup sementara.");
                System.out.println("Silakan isi ulang stok kopi sebelum beroperasi kembali.");
                break;
            }

            printMenu();
            System.out.print("\nMasukkan uang Anda (Rp): ");
            int money = scanner.nextInt();
            insertMoney(money);

            System.out.print("\nPilih nomor kopi (1-" + menu.length + "): ");
            int coffeeChoice = scanner.nextInt();

            System.out.print("Pilih ukuran (1. Small  2. Medium +5000  3. Large +10000): ");
            int sizeChoice = scanner.nextInt();

            boolean addSugar = false;
            boolean addMilk = false;

            if (sugarStock > 0) {
                System.out.print("Tambah gula? +2000 (y/n): ");
                addSugar = scanner.next().equalsIgnoreCase("y");
            } else {
                System.out.println("⚠️  Stok gula habis! Tidak dapat menambahkan gula.");
            }

            if (milkStock > 0) {
                System.out.print("Tambah susu? +3000 (y/n): ");
                addMilk = scanner.next().equalsIgnoreCase("y");
            } else {
                System.out.println("⚠️  Stok susu habis! Tidak dapat menambahkan susu.");
            }

            System.out.print("Masukkan jumlah pesanan: ");
            int quantity = scanner.nextInt();

            processOrder(coffeeChoice, sizeChoice, addSugar, addMilk, quantity);

            System.out.print("\nApakah ingin memesan lagi? (y/n): ");
            String again = scanner.next();
            if (!again.equalsIgnoreCase("y")) {
                System.out.println("\nTerima kasih telah menggunakan Hosee Coffee Machine!");
                System.out.println("Saldo akhir Anda: Rp " + balance);
                break;
            }
        }
    }

    public void printMenu() {
        System.out.println("\n===== MENU KOPI =====");
        for (int i = 0; i < menu.length; i++) {
            System.out.printf("%2d. %-25s Rp %d\n", (i + 1), menu[i].name, menu[i].price);
        }
        System.out.println("\nStok saat ini → Kopi: " + coffeeStock + ", Susu: " + milkStock + ", Gula: " + sugarStock);
    }

    public void insertMoney(int amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("Saldo Anda: Rp " + balance);
        } else {
            System.out.println("Nominal tidak valid!");
        }
    }

    public void processOrder(int choice, int size, boolean sugar, boolean milk, int quantity) {
        if (choice < 1 || choice > menu.length) {
            System.out.println("❌ Pilihan kopi tidak valid.");
            return;
        }

        if (coffeeStock <= 0) {
            System.out.println("❌ Kopi habis! Mesin tidak bisa melayani pesanan.");
            return;
        }

        if (quantity <= 0) {
            System.out.println("❌ Jumlah pesanan tidak valid.");
            return;
        }

        CoffeeItem item = menu[choice - 1];
        int basePrice = item.price;
        int sizeAdd = (size == 2) ? 5000 : (size == 3) ? 10000 : 0;
        int totalExtra = 0;

        if (quantity > coffeeStock) {
            System.out.println("⚠️  Stok kopi tidak cukup untuk jumlah tersebut. Ulangi pemesanan.");
            return;
        }

        if (sugar && sugarStock < quantity) {
            System.out.println("⚠️  Stok gula tidak cukup. Pesanan dibatalkan.");
            return;
        }
        if (milk && milkStock < quantity) {
            System.out.println("⚠️  Stok susu tidak cukup. Pesanan dibatalkan.");
            return;
        }

        if (sugar) totalExtra += 2000;
        if (milk) totalExtra += 3000;

        int totalPrice = (basePrice + sizeAdd + totalExtra) * quantity;

        System.out.println("\nAnda memesan: " + quantity + " " + item.name + (quantity > 1 ? "s" : ""));
        System.out.println("Total harga: Rp " + totalPrice);
        System.out.println("Saldo Anda: Rp " + balance);

        if (balance >= totalPrice) {
            balance -= totalPrice;
            makeCoffee(item.name, sugar, milk, quantity);
            logTransaction(item.name, totalPrice, quantity);
            System.out.println("💵 Kembalian sementara Anda: Rp " + balance);
        } else {
            System.out.println("❌ Saldo tidak cukup. Transaksi dibatalkan.");
        }
    }

    public void makeCoffee(String name, boolean sugar, boolean milk, int quantity) {
        coffeeStock -= quantity;
        if (sugar) sugarStock -= quantity;
        if (milk) milkStock -= quantity;

        System.out.println("\n☕ Membuat pesanan Anda...");
        for (int i = 1; i <= quantity; i++) {
            System.out.println("Sedang membuat " + name + " ke-" + i + "...");
        }
        if (sugar) System.out.println("Menambahkan gula...");
        if (milk) System.out.println("Menambahkan susu...");
        System.out.println("✅ Pesanan selesai! Selamat menikmati kopi Anda.");

        checkStock();
    }

    public void checkStock() {
        if (coffeeStock <= 0) {
            System.out.println("\n❌ Kopi habis! Mesin tidak bisa melanjutkan penjualan.");
        } else if (coffeeStock <= 3 || milkStock <= 2 || sugarStock <= 2) {
            System.out.println("\n⚠️  Peringatan: Stok hampir habis!");
            System.out.println("Stok kopi: " + coffeeStock + ", susu: " + milkStock + ", gula: " + sugarStock);
        }
    }

    public void logTransaction(String coffeeName, int totalPrice, int quantity) {
        try (FileWriter writer = new FileWriter("transaction_log.txt", true)) {
            writer.write("[" + new Date() + "] " + quantity + "x " + coffeeName + " - Rp " + totalPrice + "\n");
        } catch (IOException e) {
            System.out.println("Gagal menulis log: " + e.getMessage());
        }
    }
}



Kode Main (Untuk Menjalankan Program)

Kelas Main

/**
 * The main engine.
 *
 * @author Hosea Felix Sanjaya
 * @version 14 Oktober 2025
 */
public class Main {
    public static void main(String[] args) {
        CoffeeMachine machine = new CoffeeMachine();
        machine.start();
    }
}


Penjelasan Fitur Utama

Fitur Deskripsi
Enkapsulasi Atribut balance, coffeeStock, milkStock, dan sugarStock dibuat private agar hanya bisa diakses lewat method.
Menu Array Menggunakan CoffeeItem (inner class) agar menu mudah diperluas.
Validasi stok Program memeriksa stok sebelum memproses pesanan.
Kondimen dinamis Hanya menampilkan opsi tambah gula/susu jika stok masih ada.
Transaksi log Semua pembelian dicatat ke file transaction_log.txt.
Interaktif Program berbasis teks interaktif seperti vending machine nyata.

Gambar Rancangan Kelas







Output Program









Kasus Jika Pesan Melebihi Stok Awal

Senin, 06 Oktober 2025

Pertemuan 7 - Support System

Tugas Pemrograman Java – Technical Support System

Nama: Hosea Felix Sanjaya
Kelas: PBO - A
NRP: 5025241177

Berikut adalah implementasi lengkap dari program Technical Support System dalam bahasa Java yang terdiri dari tiga file: SupportSystem.java, Responder.java, dan InputReader.java.


SupportSystem.java


import java.io.IOException;

public class SupportSystem {
    private InputReader reader;
    private Responder responder;

    /**
     * Creates a technical support system.
     */
    public SupportSystem() {
        reader = new InputReader();
        responder = new Responder();
    }

    /**
     * Start the technical support system. This will print a
     * welcome message and enter into a dialog with the user,
     * until the user ends the dialog.
     */
    public void start() {
        boolean finished = false;

        printWelcome();

        while (!finished) {
            String input = reader.getInput();

            if (input != null && input.startsWith("bye")) {
                finished = true;
            } else {
                String response = responder.generateResponse();
                System.out.println(response);
            }
        }

        printGoodbye();
    }

    /**
     * Print a welcome message to the screen.
     */
    private void printWelcome() {
        System.out.println();
        System.out.println("Welcome to the DodgySoft Technical Support System.");
        System.out.println();
        System.out.println("Please tell us about your problem.");
        System.out.println();
        System.out.println("We will assist you with any problem you might have.");
        System.out.println();
        System.out.println("Please type 'bye' to exit our system.");
    }

    /**
     * Print a good-bye message to the screen.
     */
    private void printGoodbye() {
        System.out.println("Nice talking to you. Bye...");
    }

    // Simple main to run the support system
    public static void main(String[] args) throws IOException {
        SupportSystem sys = new SupportSystem();
        sys.start();
    }
}

Responder.java


public class Responder {

    /**
     * Construct a Responder - nothing to do
     */
    public Responder() {
    }

    /**
     * Generate a response.
     *
     * @return A string that should be displayed as the response
     */
    public String generateResponse() {
        return "That sounds interesting. Tell me more...";
    }
}

InputReader.java


import java.util.Scanner;
public class InputReader {
    private final Scanner scanner;

    public InputReader() {
        scanner = new Scanner(System.in);
    }

    /**
     * Read a line of input from the user.
     * @return the input line (trimmed), or null if EOF
     */
    public String getInput() {
        if (scanner.hasNextLine()) {
            return scanner.nextLine().trim();
        } else {
            return null;
        }
    }
}

Penjelasan Singkat Program

  • SupportSystem.java adalah kelas utama yang menjalankan sistem dukungan teknis.
  • Responder.java menghasilkan tanggapan otomatis untuk setiap input dari pengguna.
  • InputReader.java digunakan untuk membaca input teks dari pengguna.

Pada saat program dijalankan, pengguna akan melihat pesan sambutan dan dapat mengetik masalah mereka. Ketik bye untuk keluar dari sistem.


© 2025 – Hosea Felix Sanjaya | Project: Technical Support System


Dokumentasi


Tampilan Program Saat Dijalankan


Penerapannya di Sistem FRS

Berikut adalah implementasi lengkap dari program FRS Academic Support System dalam bahasa Java yang berfungsi membantu mahasiswa dalam menyelesaikan berbagai permasalahan saat pengisian FRS seperti kelas penuh, jadwal bentrok, atau login gagal.


AcademicSupport.java


import java.util.*;
import java.util.concurrent.TimeUnit;

public class AcademicSupport {
    private Map> responses;
    private Random random;

    public AcademicSupport() {
        responses = new HashMap<>();
        random = new Random();

        responses.put("kelas penuh", Arrays.asList(
                "Silakan konfirmasi ke TU untuk membuka kelas tambahan.",
                "Hubungi bagian akademik agar kelas tersebut bisa ditambah kuotanya."
        ));
        responses.put("salah ambil kelas", Arrays.asList(
                "Drop kelas yang salah dan pilih kelas yang sesuai.",
                "Segera ubah pilihan mata kuliah sebelum periode FRS berakhir."
        ));
        responses.put("login gagal", Arrays.asList(
                "Pastikan username dan password benar, atau reset password di DPTSI.",
                "Coba login melalui perangkat lain, bisa jadi browser Anda bermasalah."
        ));
        responses.put("gagal ambil kelas", Arrays.asList(
                "SKS tidak mencukupi atau prasyarat belum terpenuhi.",
                "Coba periksa apakah Anda sudah lulus mata kuliah prasyaratnya."
        ));
        responses.put("jadwal bentrok", Arrays.asList(
                "Pilih kelas dengan jadwal berbeda atau konsultasi dengan dosen wali.",
                "Anda bisa mengganti kelas lain yang tidak bertabrakan."
        ));
        responses.put("gagal akses website", Arrays.asList(
                "Coba lagi beberapa saat. Jika tetap gagal, hubungi DPTSI.",
                "Pastikan koneksi internet stabil dan website sedang tidak maintenance."
        ));
        responses.put("pilihan tidak muncul", Arrays.asList(
                "Pastikan periode pengisian FRS sudah dibuka.",
                "Hubungi TU jika data semester Anda belum terupdate."
        ));
        responses.put("captcha salah", Arrays.asList(
                "Perhatikan huruf besar kecil. Refresh halaman jika captcha tidak muncul.",
                "Gunakan browser lain jika captcha tidak terbaca."
        ));
        responses.put("frs belum disetujui", Arrays.asList(
                "Hubungi dosen wali untuk menyetujui FRS Anda.",
                "Pastikan dosen wali sudah menyetujui FRS sebelum submit."
        ));
        responses.put("frs ditutup", Arrays.asList(
                "Periode FRS telah berakhir. Hubungi dosen wali untuk bantuan.",
                "Silakan ajukan permohonan perpanjangan ke bagian akademik."
        ));
        responses.put("web lag", Arrays.asList(
                "Coba refresh halaman, bisa jadi koneksi internet lambat.",
                "Tutup tab lain untuk mengurangi beban jaringan."
        ));
    }

    public String getResponse(String userInput) {
        String lowerInput = userInput.toLowerCase();

        for (String key : responses.keySet()) {
            if (lowerInput.contains(key)) {
                List replyList = responses.get(key);
                return replyList.get(random.nextInt(replyList.size()));
            }
        }

        String[] generic = {
            "Bisa dijelaskan lebih detail permasalahannya?",
            "Saya belum paham, bisa dijelaskan ulang?",
            "Tolong jelaskan masalah Anda dengan lebih spesifik."
        };
        return generic[random.nextInt(generic.length)];
    }

    private void delayResponse() {
        try {
            TimeUnit.MILLISECONDS.sleep(400 + random.nextInt(400));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    public static void main(String[] args) {
        AcademicSupport as = new AcademicSupport();
        Scanner scanner = new Scanner(System.in);

        System.out.println("=== Sistem Bantuan Akademik / FRS ===");
        System.out.println("Ketik kata kunci seperti 'kelas penuh', 'frs ditutup', atau 'login gagal'.");
        System.out.println("Ketik 'exit' untuk keluar.\n");

        while (true) {
            System.out.print("Problem: ");
            String input = scanner.nextLine();

            if (input.equalsIgnoreCase("exit")) {
                System.out.println("\nTerima kasih telah menggunakan layanan ini. Semoga membantu!");
                break;
            }

            as.delayResponse();
            String response = as.getResponse(input);
            System.out.println("→ " + response + "\n");
        }

        scanner.close();
    }
}

Penjelasan Fungsionalitas FRS

  • Program ini meniru chatbot akademik yang membantu mahasiswa ketika menghadapi kendala saat pengisian FRS.
  • Masalah yang dikenali mencakup kelas penuh, login gagal, jadwal bentrok, FRS belum disetujui, dan lain-lain.
  • Mahasiswa cukup mengetik permasalahan, dan sistem akan memberikan solusi otomatis sesuai konteks.
  • Respon dihasilkan secara acak dari kumpulan saran yang relevan agar terasa lebih alami.
  • Ketik exit untuk mengakhiri sesi.

© 2025 – Hosea Felix Sanjaya | Project: FRS Academic Support System


Rabu, 01 Oktober 2025

Pertemuan 6 - Grouping Object

Project Java: Sistem Bioskop Sederhana

Project Java: Sistem Bioskop Sederhana

Nama: Hosea Felix Sanjaya
Kelas: PBO - A
NRP: 5025241177

Deskripsi Project

Sistem ini memodelkan sebuah bioskop yang memiliki beberapa studio, dan setiap studio memutar beberapa film. Kita akan menggunakan empat class utama:

  • Film → objek film dengan judul dan durasi
  • Studio → ruangan di bioskop yang memutar beberapa film
  • Bioskop → kumpulan studio dalam satu gedung
  • Main → class utama untuk menjalankan program

Struktur Project

BioskopProject/
 ├── Film.java
 ├── Studio.java
 ├── Bioskop.java
 └── Main.java

Kode Program

🔹 Film.java

public class Film {
    private String title;
    private int duration; // dalam menit

    public Film(String title, int duration) {
        this.title = title;
        this.duration = duration;
    }

    public String getTitle() { return title; }
    public int getDuration() { return duration; }

    @Override
    public String toString() {
        return title + " (" + duration + " menit)";
    }
}

🔹 Studio.java

import java.util.*;

public class Studio {
    private String studioName;
    private List<Film> films = new ArrayList<>();

    public Studio(String studioName) {
        this.studioName = studioName;
    }

    public void addFilm(Film f) {
        films.add(f);
    }

    public void showStudioInfo() {
        System.out.println("Studio: " + studioName);
        for (Film f : films) {
            System.out.println(" - " + f);
        }
        System.out.println();
    }
}

🔹 Bioskop.java

import java.util.*;

public class Bioskop {
    private String cinemaName;
    private List<Studio> studios = new ArrayList<>();

    public Bioskop(String cinemaName) {
        this.cinemaName = cinemaName;
    }

    public void addStudio(Studio s) {
        studios.add(s);
    }

    public void showBioskopInfo() {
        System.out.println("=== " + cinemaName + " ===\\n");
        for (Studio s : studios) {
            s.showStudioInfo();
        }
    }
}

🔹 Main.java

public class Main {
    public static void main(String[] args) {
        // Buat film
        Film f1 = new Film("Avengers: Endgame", 181);
        Film f2 = new Film("Spider-Man: No Way Home", 148);
        Film f3 = new Film("The Batman", 176);
        Film f4 = new Film("Interstellar", 169);

        // Buat studio
        Studio s1 = new Studio("Studio 1");
        s1.addFilm(f1);
        s1.addFilm(f2);

        Studio s2 = new Studio("Studio 2");
        s2.addFilm(f3);
        s2.addFilm(f4);

        // Buat bioskop
        Bioskop cgv = new Bioskop("CGV - Mall Kota");
        cgv.addStudio(s1);
        cgv.addStudio(s2);

        // Tampilkan informasi
        cgv.showBioskopInfo();
    }
}

Contoh Output

=== CGV - Mall Kota ===

Studio: Studio 1
 - Avengers: Endgame (181 menit)
 - Spider-Man: No Way Home (148 menit)

Studio: Studio 2
 - The Batman (176 menit)
 - Interstellar (169 menit)

Pertemuan 15 : Aplikasi CRUD JAVA

Pertemuan 15 - Java CRUD Database Tanggal: 9 Desember 2025 Nama: Hosea Felix Sanjaya NRP: 5025241177 a. Setup & Persiapan Envi...