Minggu, 30 November 2025

Pertemuan 14 : Pong Game

Pertemuan 14 - Pong Game!

Tanggal: 30 November 2025
Nama: Hosea Felix Sanjaya
NRP: 5025241177


a. Visualisasi Alur di BlueJ

Penjelasan Alur

Diagram di atas menunjukkan alur kerja dan hubungan antar kelas dalam program Pong Game:

  • Pong (Controller): Berfungsi sebagai pengendali utama yang mengatur logika permainan, pergerakan bola/paddle, pengecekan tabrakan, dan skor.
  • Ball & Paddle (Model): Merupakan objek permainan. Posisi mereka terus diperbarui oleh kelas Pong berdasarkan logika fisika dan input user.
  • Renderer (View): Bertugas menampilkan seluruh objek permainan (visual) ke layar.
  • Dependensi: Panah menunjukkan bahwa Pong mengontrol Ball dan Paddle, kemudian data posisi dikirim ke Renderer untuk digambar. Pemisahan ini membuat struktur aplikasi lebih modular.

b. Code dan Penjelasan

1. Class Pong.java

Berperan sebagai pusat pengendali permainan (Game Controller).


import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.Timer;

public class Pong implements ActionListener, KeyListener
{
    public static Pong pong;
    public int width = 700, height = 700;
    public Renderer renderer;
    public Paddle player1;
    public Paddle player2;
    public Ball ball;
    public boolean bot = false, selectingDifficulty;
    public boolean w, s, up, down;
    public int gameStatus = 0, scoreLimit = 7, playerWon; //0 = Menu, 1 = Paused, 2 = Playing, 3 = Over
    public int botDifficulty, botMoves, botCooldown = 0;
    public Random random;
    public JFrame jframe;

    public Pong()
    {
        Timer timer = new Timer(20, this);
        random = new Random();
        jframe = new JFrame("Pong");
        renderer = new Renderer();

        jframe.setSize(width + 15, height + 35);
        jframe.setVisible(true);
        jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jframe.add(renderer);
        jframe.addKeyListener(this);

        timer.start();
    }

    public void start()
    {
        gameStatus = 2;
        player1 = new Paddle(this, 1);
        player2 = new Paddle(this, 2);
        ball = new Ball(this);
    }

    public void update()
    {
        if (player1.score >= scoreLimit) { playerWon = 1; gameStatus = 3; }
        if (player2.score >= scoreLimit) { gameStatus = 3; playerWon = 2; }

        if (w) { player1.move(true); }
        if (s) { player1.move(false); }

        if (!bot)
        {
            if (up) { player2.move(true); }
            if (down) { player2.move(false); }
        }
        else
        {
            if (botCooldown > 0) {
                botCooldown--;
                if (botCooldown == 0) { botMoves = 0; }
            }

            if (botMoves < 10)
            {
                if (player2.y + player2.height / 2 < ball.y) { player2.move(false); botMoves++; }
                if (player2.y + player2.height / 2 > ball.y) { player2.move(true); botMoves++; }
                
                if (botDifficulty == 0) botCooldown = 20;
                if (botDifficulty == 1) botCooldown = 15;
                if (botDifficulty == 2) botCooldown = 10;
            }
        }
        ball.update(player1, player2);
    }

    public void render(Graphics2D g)
    {
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, width, height);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        if (gameStatus == 0)
        {
            g.setColor(Color.WHITE);
            g.setFont(new Font("Arial", 1, 50));
            g.drawString("PONG", width / 2 - 75, 50);

            if (!selectingDifficulty)
            {
                g.setFont(new Font("Arial", 1, 30));
                g.drawString("Press Space to Play", width / 2 - 150, height / 2 - 25);
                g.drawString("Press Shift to Play with Bot", width / 2 - 200, height / 2 + 25);
                g.drawString("<< Score Limit: " + scoreLimit + " >>", width / 2 - 150, height / 2 + 75);
            }
        }

        if (selectingDifficulty)
        {
            String string = botDifficulty == 0 ? "Easy" : (botDifficulty == 1 ? "Medium" : "Hard");
            g.setFont(new Font("Arial", 1, 30));
            g.drawString("<< Bot Difficulty: " + string + " >>", width / 2 - 180, height / 2 - 25);
            g.drawString("Press Space to Play", width / 2 - 150, height / 2 + 25);
        }

        if (gameStatus == 1)
        {
            g.setColor(Color.WHITE);
            g.setFont(new Font("Arial", 1, 50));
            g.drawString("PAUSED", width / 2 - 103, height / 2 - 25);
        }

        if (gameStatus == 1 || gameStatus == 2)
        {
            g.setColor(Color.WHITE);
            g.setStroke(new BasicStroke(5f));
            g.drawLine(width / 2, 0, width / 2, height);
            g.setStroke(new BasicStroke(2f));
            g.drawOval(width / 2 - 150, height / 2 - 150, 300, 300);
            g.setFont(new Font("Arial", 1, 50));
            g.drawString(String.valueOf(player1.score), width / 2 - 90, 50);
            g.drawString(String.valueOf(player2.score), width / 2 + 65, 50);
            player1.render(g);
            player2.render(g);
            ball.render(g);
        }

        if (gameStatus == 3)
        {
            g.setColor(Color.WHITE);
            g.setFont(new Font("Arial", 1, 50));
            g.drawString("PONG", width / 2 - 75, 50);
            if (bot && playerWon == 2) { g.drawString("The Bot Wins!", width / 2 - 170, 200); }
            else { g.drawString("Player " + playerWon + " Wins!", width / 2 - 165, 200); }
            g.setFont(new Font("Arial", 1, 30));
            g.drawString("Press Space to Play Again", width / 2 - 185, height / 2 - 25);
            g.drawString("Press ESC for Menu", width / 2 - 140, height / 2 + 25);
        }
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        if (gameStatus == 2) { update(); }
        renderer.repaint();
    }

    public static void main(String[] args) { pong = new Pong(); }

    @Override
    public void keyPressed(KeyEvent e)
    {
        int id = e.getKeyCode();
        if (id == KeyEvent.VK_W) w = true;
        else if (id == KeyEvent.VK_S) s = true;
        else if (id == KeyEvent.VK_UP) up = true;
        else if (id == KeyEvent.VK_DOWN) down = true;
        else if (id == KeyEvent.VK_RIGHT) {
            if (selectingDifficulty) { if (botDifficulty < 2) botDifficulty++; else botDifficulty = 0; }
            else if (gameStatus == 0) scoreLimit++;
        }
        else if (id == KeyEvent.VK_LEFT) {
            if (selectingDifficulty) { if (botDifficulty > 0) botDifficulty--; else botDifficulty = 2; }
            else if (gameStatus == 0 && scoreLimit > 1) scoreLimit--;
        }
        else if (id == KeyEvent.VK_ESCAPE && (gameStatus == 2 || gameStatus == 3)) gameStatus = 0;
        else if (id == KeyEvent.VK_SHIFT && gameStatus == 0) { bot = true; selectingDifficulty = true; }
        else if (id == KeyEvent.VK_SPACE) {
            if (gameStatus == 0 || gameStatus == 3) {
                if (!selectingDifficulty) bot = false; else selectingDifficulty = false;
                start();
            }
            else if (gameStatus == 1) gameStatus = 2;
            else if (gameStatus == 2) gameStatus = 1;
        }
    }

    @Override
    public void keyReleased(KeyEvent e)
    {
        int id = e.getKeyCode();
        if (id == KeyEvent.VK_W) w = false;
        else if (id == KeyEvent.VK_S) s = false;
        else if (id == KeyEvent.VK_UP) up = false;
        else if (id == KeyEvent.VK_DOWN) down = false;
    }

    @Override
    public void keyTyped(KeyEvent e) { }
}

Penjelasan Singkat

  • Inisialisasi: Membuat JFrame, Timer (game loop 20ms), dan Renderer.
  • Method update(): Menangani logika inti seperti pergerakan paddle (manual & bot), fisika bola, dan kondisi menang/kalah.
  • Method render(): Menggambar UI menu, skor, garis lapangan, dan memanggil fungsi render objek lain.
  • Input Handling: Menggunakan KeyListener untuk mendeteksi input keyboard (W/S, Arrow Keys, Space, Shift).

2. Class Ball.java

Menangani logika fisik bola, pergerakan, dan pantulan.


import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

public class Ball
{
    public int x, y, width = 25, height = 25;
    public int motionX, motionY;
    public Random random;
    private Pong pong;
    public int amountOfHits;

    public Ball(Pong pong)
    {
        this.pong = pong;
        this.random = new Random();
        spawn();
    }

    public void update(Paddle paddle1, Paddle paddle2)
    {
        int speed = 5;
        this.x += motionX * speed;
        this.y += motionY * speed;

        if (this.y + height - motionY > pong.height || this.y + motionY < 0)
        {
            if (this.motionY < 0) {
                this.y = 0;
                this.motionY = random.nextInt(4);
                if (motionY == 0) motionY = 1;
            } else {
                this.motionY = -random.nextInt(4);
                this.y = pong.height - height;
                if (motionY == 0) motionY = -1;
            }
        }

        if (checkCollision(paddle1) == 1) {
            this.motionX = 1 + (amountOfHits / 5);
            this.motionY = -2 + random.nextInt(4);
            if (motionY == 0) motionY = 1;
            amountOfHits++;
        }
        else if (checkCollision(paddle2) == 1) {
            this.motionX = -1 - (amountOfHits / 5);
            this.motionY = -2 + random.nextInt(4);
            if (motionY == 0) motionY = 1;
            amountOfHits++;
        }

        if (checkCollision(paddle1) == 2) { paddle2.score++; spawn(); }
        else if (checkCollision(paddle2) == 2) { paddle1.score++; spawn(); }
    }

    public void spawn()
    {
        this.amountOfHits = 0;
        this.x = pong.width / 2 - this.width / 2;
        this.y = pong.height / 2 - this.height / 2;
        this.motionY = -2 + random.nextInt(4);
        if (motionY == 0) motionY = 1;
        if (random.nextBoolean()) motionX = 1; else motionX = -1;
    }

    public int checkCollision(Paddle paddle)
    {
        if (this.x < paddle.x + paddle.width && this.x + width > paddle.x && this.y < paddle.y + paddle.height && this.y + height > paddle.y)
        {
            return 1; //bounce
        }
        else if ((paddle.x > x && paddle.paddleNumber == 1) || (paddle.x < x - width && paddle.paddleNumber == 2))
        {
            return 2; //score
        }
        return 0; //nothing
    }

    public void render(Graphics g)
    {
        g.setColor(Color.WHITE);
        g.fillOval(x, y, width, height);
    }
}

Penjelasan Singkat

  • Fisika: Mengatur posisi (x,y) dan arah gerak (motionX, motionY).
  • Pantulan: Bola memantul jika mengenai batas atas/bawah layar atau mengenai paddle.
  • Skoring: Jika bola melewati paddle, skor lawan bertambah dan posisi bola di-reset (spawn).

3. Class Paddle.java dan Renderer.java

Mengatur objek pemain dan proses penggambaran ke layar.


// PADDLE CLASS
import java.awt.Color;
import java.awt.Graphics;

public class Paddle
{
    public int paddleNumber;
    public int x, y, width = 50, height = 250;
    public int score;

    public Paddle(Pong pong, int paddleNumber)
    {
        this.paddleNumber = paddleNumber;
        if (paddleNumber == 1) this.x = 0;
        if (paddleNumber == 2) this.x = pong.width - width;
        this.y = pong.height / 2 - this.height / 2;
    }

    public void render(Graphics g)
    {
        g.setColor(Color.WHITE);
        g.fillRect(x, y, width, height);
    }

    public void move(boolean up)
    {
        int speed = 15;
        if (up) {
            if (y - speed > 0) y -= speed; else y = 0;
        } else {
            if (y + height + speed < Pong.pong.height) y += speed; else y = Pong.pong.height - height;
        }
    }
}

// RENDERER CLASS
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;

public class Renderer extends JPanel
{
    private static final long serialVersionUID = 1L;

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Pong.pong.render((Graphics2D) g);
    }
}

Penjelasan Singkat

  • Paddle: Merepresentasikan pemain kiri (1) atau kanan (2). Method move() membatasi agar paddle tidak keluar layar.
  • Renderer: Kelas turunan JPanel yang memanggil method render utama dari kelas Pong setiap kali layar perlu digambar ulang (repaint).

c. Dokumentasi Output

Tampilan Awal Permainan (Menu)

Tampilan Permainan Selama Berlangsung

Tampilan Saat Salah Satu Pemain Menang


Kesimpulan

  • Aplikasi Pong ini menerapkan konsep Object Oriented Programming (OOP) dengan memisahkan logika permainan (Pong), objek (Ball, Paddle), dan tampilan (Renderer).
  • Penggunaan Timer memungkinkan terciptanya game loop yang konsisten untuk memperbarui logika fisika dan animasi.
  • Interaksi pengguna ditangani melalui KeyListener, memberikan respons real-time untuk pergerakan paddle.

Senin, 24 November 2025

Pertemuan 13 : Pemrograman GUI

Pertemuan 13 – Pemrograman GUI

Tanggal: 17 November 2025
Nama: Hosea Felix Sanjaya
NRP: 5025241177



1. Aplikasi User Login ("LoginFrame")

Kode Program

 import javax.swing.; import java.awt.; import java.awt.event.*;

public class LoginFrame extends JFrame implements ActionListener { private JTextField userField; private JPasswordField passField; private JButton loginButton;

public LoginFrame() {
    setTitle("Login");
    setSize(300, 150);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLayout(new GridLayout(3, 2));

    // Komponen Input Username
    add(new JLabel("Username:"));
    userField = new JTextField();
    add(userField);

    // Komponen Input Password
    add(new JLabel("Password:"));
    passField = new JPasswordField();
    add(passField);

    // Tombol Login
    loginButton = new JButton("Login");
    loginButton.addActionListener(this);
    add(new JLabel()); // Placeholder kosong untuk grid
    add(loginButton);

    setLocationRelativeTo(null); // Posisi di tengah layar
    setVisible(true);
}

@Override
public void actionPerformed(ActionEvent e) {
    String username = userField.getText();
    String password = new String(passField.getPassword());

    // Validasi sederhana
    if (username.equals("admin") && password.equals("12345")) {
        JOptionPane.showMessageDialog(this, "Login berhasil!");
    } else {
        JOptionPane.showMessageDialog(this, "Username atau password salah!");
    }
}

public static void main(String[] args) {
    new LoginFrame();
}
} 

Penjelasan Singkat

  • extends JFrame → Kelas ini berfungsi sebagai jendela utama aplikasi.
  • implements ActionListener → Digunakan agar kelas dapat merespons aksi (klik tombol) pengguna.
  • GridLayout(3, 2) → Mengatur tata letak komponen menjadi 3 baris dan 2 kolom agar rapi.
  • JPasswordField → Komponen input khusus password (teks disembunyikan).
  • actionPerformed() → Method ini memvalidasi apakah username adalah "admin" dan password "12345".

Dokumentasi

Login and Password

Login Berhasil

Login Gagal


2. Aplikasi Image Viewer

Kode Program

 import javax.swing.; import java.awt.; import java.awt.event.*; import java.io.File;

public class ImageViewer extends JFrame implements ActionListener { private JLabel imageLabel; private JButton openButton;

public ImageViewer() {
    setTitle("Image Viewer");
    setSize(500, 500);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLayout(new BorderLayout());

    // Area untuk menampilkan gambar (Tengah)
    imageLabel = new JLabel("", SwingConstants.CENTER);
    add(imageLabel, BorderLayout.CENTER);

    // Tombol untuk membuka file (Bawah)
    openButton = new JButton("Open Image");
    openButton.addActionListener(this);
    add(openButton, BorderLayout.SOUTH);

    setLocationRelativeTo(null);
    setVisible(true);
}

@Override
public void actionPerformed(ActionEvent e) {
    JFileChooser fileChooser = new JFileChooser();
    int option = fileChooser.showOpenDialog(this);

    if(option == JFileChooser.APPROVE_OPTION) {
        File file = fileChooser.getSelectedFile();
        ImageIcon imageIcon = new ImageIcon(file.getAbsolutePath());
        imageLabel.setIcon(imageIcon);
    }
}

public static void main(String[] args) {
    new ImageViewer();
}
} 

Penjelasan Singkat

  • BorderLayout → Membagi tampilan menjadi 5 area (Center, North, South, East, West). Gambar diletakkan di Center dan tombol di South.
  • JFileChooser → Membuka dialog jendela sistem operasi untuk memilih file gambar dari komputer.
  • ImageIcon → Mengubah file gambar yang dipilih menjadi ikon yang bisa ditampilkan pada JLabel.
  • Event-Driven → Gambar hanya akan muncul setelah pengguna menekan tombol dan memilih file (aksi memicu perubahan).

Kesimpulan

  • Java Swing menyediakan komponen GUI (seperti JFrame, JButton, JTextField) untuk membuat aplikasi desktop interaktif.
  • Interface ActionListener sangat penting untuk menangani interaksi pengguna (Event Handling).
  • Penggunaan Layout Manager (seperti GridLayout dan BorderLayout) membantu menyusun komponen secara terstruktur.

Image Viewer

Jumat, 14 November 2025

Pertemuan 12 : Abstract Class

Pertemuan 12 – Abstract Class

Tanggal: 10 November 2025
Nama: Hosea Felix Sanjaya
NRP: 5025241177


1. Contoh Abstrak Class: “Makhluk Hidup”

Kode Program


public abstract class MakhlukHidup {
    
    protected String nama;
    protected String jenisMakhluk;
    
    public MakhlukHidup(String nama, String jenisMakhluk) {
        this.nama = nama;
        this.jenisMakhluk = jenisMakhluk;
    }
    
    public void bernapas() {
        System.out.println(this.nama + " (" + this.jenisMakhluk + ") sedang bernapas.");
    }
    
    public abstract void bergerak();
    public abstract void berkembangBiak();
    
    public String getNama() {
        return nama;
    }
    public String getJenisMakhluk() {
        return jenisMakhluk;
    }
}




public class Manusia extends MakhlukHidup {
    
    public Manusia(String nama) {
        super(nama, "Manusia");
    }

    @Override
    public void bergerak() {
        System.out.println(this.nama + " bergerak dengan berjalan atau berlari.");
    }

    @Override
    public void berkembangBiak() {
        System.out.println(this.nama + " berkembang biak dengan melahirkan.");
    }
    
    public void berpikir() {
        System.out.println(this.nama + " sedang menggunakan akal untuk berpikir.");
    }
}




public class Hewan extends MakhlukHidup {
    
    private String caraGerak;
    
    public Hewan(String nama, String caraGerak) {
        super(nama, "Hewan");
        this.caraGerak = caraGerak;
    }

    @Override
    public void bergerak() {
        System.out.println(this.nama + " bergerak dengan cara " + this.caraGerak + ".");
    }

    @Override
    public void berkembangBiak() {
        System.out.println(this.nama + " berkembang biak dengan bertelur atau melahirkan.");
    }
}




public class Tumbuhan extends MakhlukHidup {
    
    public Tumbuhan(String nama) {
        super(nama, "Tumbuhan");
    }

    @Override
    public void bergerak() {
        System.out.println(this.nama + " bergerak secara pasif (tumbuh mengikuti cahaya/air).");
    }

    @Override
    public void berkembangBiak() {
        System.out.println(this.nama + " berkembang biak dengan biji atau tunas.");
    }
    
    public void berfotosintesis() {
        System.out.println(this.nama + " sedang melakukan fotosintesis.");
    }
}




public class Main {
    public static void main(String[] args) {
        System.out.println("--- DEMO ABSTRACT CLASS DAN INHERITANCE ---");
        
        Manusia andi = new Manusia("Andi");
        System.out.println("\n** Objek 1: " + andi.getNama() + " **");
        andi.bernapas();         
        andi.bergerak();         
        andi.berkembangBiak();   
        andi.berpikir();         
        
        Hewan kucing = new Hewan("Kucing", "merayap dan melompat");
        System.out.println("\n** Objek 2: " + kucing.getNama() + " **");
        kucing.bernapas();
        kucing.bergerak();
        kucing.berkembangBiak();
        
        Tumbuhan mawar = new Tumbuhan("Mawar");
        System.out.println("\n** Objek 3: " + mawar.getNama() + " **");
        mawar.bernapas();
        mawar.bergerak();
        mawar.berkembangBiak();
        mawar.berfotosintesis(); 

        System.out.println("\n--- DEMO POLIMORFISME ---");
        MakhlukHidup[] daftarMakhluk = new MakhlukHidup[3];
        daftarMakhluk[0] = andi;
        daftarMakhluk[1] = kucing;
        daftarMakhluk[2] = mawar;

        for (MakhlukHidup m : daftarMakhluk) {
            System.out.print(m.getNama() + " bertindak: ");
            m.bergerak();
        }
    }
}

Penjelasan Singkat

  • abstract class MakhlukHidup → berisi metode abstrak bernapas() yang wajib diimplementasikan kelas turunannya.
  • Class Manusia, Hewan, Tumbuhan → masing-masing memberikan implementasi berbeda.
  • Class Main → menggunakan polimorfisme untuk memanggil metode bernapas() pada objek berbeda.

2. Class Abstrak “Animal” + Program Simulasi Hewan

Kode Program


import java.util.List;
import java.util.Random;

public abstract class Animal {
    protected int age;
    protected boolean alive;
    protected Field field;
    protected Location location;
    protected static final Random rand = new Random();

    // Konstruktor
    public Animal(boolean randomAge, Field field, Location location) {
        this.alive = true;
        this.field = field;
        setLocation(location);

        if (randomAge) {
            this.age = rand.nextInt(getMaxAge());
        } else {
            this.age = 0;
        }
    }

    // Getter dan utilitas umum
    public int getAge() { return age; }
    public boolean isAlive() { return alive; }

    public void setDead() {
        alive = false;
        if (location != null) {
            field.clear(location);
            location = null;
            field = null;
        }
    }

    public Location getLocation() { return location; }

    public void setLocation(Location newLocation) {
        if (location != null) {
            field.clear(location);
        }
        location = newLocation;
        field.place(this, newLocation);
    }

    // Umur dan kelahiran
    protected void incrementAge() {
        age++;
        if (age > getMaxAge()) {
            setDead();
        }
    }

    protected void giveBirth(List newAnimals) {
        List free = field.allFreeAdjacentLocations(location);
        int births = breed();

        for (int b = 0; b < births && free.size() > 0; b++) {
            Location loc = free.remove(0);
            Animal young = createOffspring(false, field, loc);
            newAnimals.add(young);
        }
    }

    protected int breed() {
        int births = 0;
        if (canBreed() && rand.nextDouble() <= getBreedingProbability()) {
            births = rand.nextInt(getMaxLitterSize()) + 1;
        }
        return births;
    }

    public boolean canBreed() {
        return age >= getBreedingAge();
    }

    // Method abstrak — diimplementasi oleh subclass
    public abstract void act(List newAnimals);
    protected abstract int getBreedingAge();
    protected abstract int getMaxAge();
    protected abstract double getBreedingProbability();
    protected abstract int getMaxLitterSize();
    protected abstract Animal createOffspring(boolean randomAge, Field field, Location location);
}




import java.util.List;

public class Rabbit extends Animal {
    private static final int BREEDING_AGE = 5;
    private static final int MAX_AGE = 50;
    private static final double BREEDING_PROBABILITY = 0.15;
    private static final int MAX_LITTER_SIZE = 5;

    public Rabbit(boolean randomAge, Field field, Location location) {
        super(randomAge, field, location);
    }

    @Override
    public void act(List newRabbits) {
        incrementAge();
        if (isAlive()) {
            giveBirth(newRabbits);
            Location newLocation = field.freeAdjacentLocation(location);
            if (newLocation != null) {
                setLocation(newLocation);
            } else {
                setDead();
            }
        }
    }

    @Override
    protected int getBreedingAge() { return BREEDING_AGE; }

    @Override
    protected int getMaxAge() { return MAX_AGE; }

    @Override
    protected double getBreedingProbability() { return BREEDING_PROBABILITY; }

    @Override
    protected int getMaxLitterSize() { return MAX_LITTER_SIZE; }

    @Override
    protected Animal createOffspring(boolean randomAge, Field field, Location location) {
        return new Rabbit(randomAge, field, location);
    }
}




import java.util.List;
import java.util.Iterator;

public class Fox extends Animal {
    private static final int RABBIT_ENERGY_VALUE = 10;
    private static final int BREEDING_AGE = 10;
    private static final int MAX_AGE = 70;
    private static final double BREEDING_PROBABILITY = 0.15;
    private static final int MAX_LITTER_SIZE = 3;
    private static final int INITIAL_ENERGY = 20;

    private int energyLevel;

    public Fox(boolean randomAge, Field field, Location location) {
        super(randomAge, field, location);
        energyLevel = INITIAL_ENERGY;
    }

    @Override
    public void act(List newFoxes) {
        incrementAge();
        incrementHunger();

        if (isAlive()) {
            giveBirth(newFoxes);
            Location newLocation = findFood();

            if (newLocation == null) {
                newLocation = field.freeAdjacentLocation(location);
            }

            if (newLocation != null) {
                setLocation(newLocation);
            } else {
                setDead();
            }
        }
    }

    private void incrementHunger() {
        energyLevel--;
        if (energyLevel <= 0) {
            setDead();
        }
    }

    private Location findFood() {
        List adjacent = field.adjacentLocations(location);
        for (Location where : adjacent) {
            Object animal = field.getObjectAt(where);
            if (animal instanceof Rabbit) {
                Rabbit rabbit = (Rabbit) animal;
                if (rabbit.isAlive()) {
                    rabbit.setDead();
                    energyLevel += RABBIT_ENERGY_VALUE;
                    return where;
                }
            }
        }
        return null;
    }

    @Override
    protected int getBreedingAge() { return BREEDING_AGE; }

    @Override
    protected int getMaxAge() { return MAX_AGE; }

    @Override
    protected double getBreedingProbability() { return BREEDING_PROBABILITY; }

    @Override
    protected int getMaxLitterSize() { return MAX_LITTER_SIZE; }

    @Override
    protected Animal createOffspring(boolean randomAge, Field field, Location location) {
        return new Fox(randomAge, field, location);
    }
}




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

public class Field {
    private Object[][] field;

    public Field(int depth, int width) {
        field = new Object[depth][width];
    }

    public void clear(Location location) {
        field[location.getRow()][location.getCol()] = null;
    }

    public void place(Object object, Location location) {
        field[location.getRow()][location.getCol()] = object;
    }

    public Object getObjectAt(Location location) {
        if (location.getRow() >= 0 && location.getRow() < getRow() &&
            location.getCol() >= 0 && location.getCol() < getCol()) {
            return field[location.getRow()][location.getCol()];
        }
        return null;
    }

    public List adjacentLocations(Location location) {
        List locations = new ArrayList<>();

        int row = location.getRow();
        int col = location.getCol();

        if (row > 0) locations.add(new Location(row - 1, col));
        if (row < getRow() - 1) locations.add(new Location(row + 1, col));
        if (col > 0) locations.add(new Location(row, col - 1));
        if (col < getCol() - 1) locations.add(new Location(row, col + 1));

        return locations;
    }

    public List allFreeAdjacentLocations(Location location) {
        List free = new ArrayList<>();
        for (Location loc : adjacentLocations(location)) {
            if (getObjectAt(loc) == null) free.add(loc);
        }
        return free;
    }

    public Location freeAdjacentLocation(Location location) {
        List free = allFreeAdjacentLocations(location);
        return free.isEmpty() ? null : free.get(0);
    }

    public int getRow() { return field.length; }
    public int getCol() { return field[0].length; }

    public void clearAll() {
        for (int i = 0; i < field.length; i++) {
            for (int j = 0; j < field[i].length; j++) {
                field[i][j] = null;
            }
        }
    }
}




import java.util.*;

public class Simulator {
    private Field field;
    private List animals;
    private int step;
    private SimulatorView view;

    private static final int DEFAULT_ROW = 10;
    private static final int DEFAULT_COL = 10;

    public Simulator(int depth, int width) {
        if (width <= 0 || depth <= 0) {
            depth = DEFAULT_ROW;
            width = DEFAULT_COL;
        }

        animals = new ArrayList<>();
        field = new Field(depth, width);
        view = new SimulatorView(depth, width);
        view.setSymbol(Rabbit.class, 'R');
        view.setSymbol(Fox.class, 'F');

        populate();
    }

    public void simulate(int steps) {
        for (int i = 0; i < steps; i++) {
            simulateOneStep();
        }
    }

    private void simulateOneStep() {
        step++;
        List newAnimals = new ArrayList<>();

        for (Iterator it = animals.iterator(); it.hasNext();) {
            Animal animal = it.next();
            animal.act(newAnimals);
            if (!animal.isAlive()) it.remove();
        }

        animals.addAll(newAnimals);
        view.show(step, field);
    }

    private void populate() {
        field.clearAll();
        Random rand = new Random();
        double foxProb = 0.2;
        double rabbitProb = 0.3;

        for (int row = 0; row < field.getRow(); row++) {
            for (int col = 0; col < field.getCol(); col++) {
                Location loc = new Location(row, col);
                if (rand.nextDouble() <= foxProb) {
                    Fox fox = new Fox(false, field, loc);
                    animals.add(fox);
                    field.place(fox, loc);
                } else if (rand.nextDouble() <= rabbitProb) {
                    Rabbit rabbit = new Rabbit(true, field, loc);
                    animals.add(rabbit);
                    field.place(rabbit, loc);
                }
            }
        }
    }
}




public class Location {
    private int row;
    private int col;

    public Location(int row, int col) {
        this.row = row;
        this.col = col;
    }

    public int getRow() { return row; }
    public int getCol() { return col; }
}




import java.util.HashMap;
import java.util.Map;

public class SimulatorView {
    private int row;
    private int col;
    private Map, Character> symbols;

    public SimulatorView(int row, int col) {
        this.row = row;
        this.col = col;
        this.symbols = new HashMap<>();
    }

    public void setSymbol(Class /*isi ini dengan "< ? >" tanpa spasi, di mode html error soalnya*/ animal, char symbol) {
        symbols.put(animal, symbol);
    }

    public void show(int step, Field field) {
        System.out.println("Simulation step " + step + ": ");
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                Object animal = field.getObjectAt(new Location(i, j));
                if (animal == null) {
                    System.out.print(". ");
                } else {
                    Character symbol = symbols.get(animal.getClass());
                    System.out.print((symbol != null ? symbol : '?') + " ");
                }
            }
            System.out.println();
        }
        System.out.println();
    }
}




public class Main {
    public static void main(String[] args) {
        Simulator simulator = new Simulator(10, 10);
        simulator.simulate(5);  // simulasi 5 langkah
    }
}


Penjelasan Singkat

  • Abstract class Animal → memiliki atribut dasar dan metode abstrak move() & eat().
  • Rabbit → melompat dan makan rumput.
  • Fox → berlari cepat dan berburu kelinci.
  • Simulation → menunjukkan penerapan polimorfisme dengan array objek.

Kesimpulan

  • Abstract class digunakan sebagai kerangka dasar bagi subclass.
  • Polimorfisme memungkinkan pemanggilan metode yang berbeda melalui referensi yang sama.
  • Contoh di atas memperlihatkan penerapan OOP dalam kehidupan nyata.

Kamis, 06 November 2025

Pertemuan 11 : Inheritance pada Rental kendaraan

Testing Inheritance PBO - Pertemuan 11

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


Penerapan Inheritance pada Sistem Rental Kendaraan

Halo semuanya! 👋
Pada pertemuan kali ini, saya akan membahas tentang penerapan konsep inheritance dalam Java dengan studi kasus sistem rental kendaraan.
Konsep ini memperlihatkan bagaimana kelas induk dapat mewariskan atribut dan metode umum ke beberapa kelas turunan seperti Mobil, Motor, dan Sepeda. Selain itu, juga ditambahkan kelas Penyewa dan MainApp sebagai pengelola interaksi pengguna.

Tujuan

Tujuan dari program ini adalah untuk memahami konsep pewarisan (inheritance) serta penerapannya dalam pembuatan sistem sederhana berbasis OOP menggunakan Java. Setiap jenis kendaraan akan mewarisi atribut dasar dari kelas Kendaraan, dan memiliki perilaku khusus masing-masing.

Kode Program

1 Class Kendaraan

public class Kendaraan {
    private String merk;
    private String model;
    private int tahunProduksi;

    public Kendaraan(String merk, String model, int tahunProduksi) {
        this.merk = merk;
        this.model = model;
        this.tahunProduksi = tahunProduksi;
    }

    public String getMerk() {
        return merk;
    }

    public String getModel() {
        return model;
    }

    public int getTahunProduksi() {
        return tahunProduksi;
    }

    public String getInfo() {
        return merk + " " + model + " (" + tahunProduksi + ")";
    }
}

2 Class Mobil

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;
    }

    @Override
    public String getInfo() {
        return "Mobil: " + super.getInfo() + ", Roda: " + jumlahRoda;
    }
}

3 Class Motor

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;
    }

    @Override
    public String getInfo() {
        return "Motor: " + super.getInfo() + ", Roda: " + jumlahRoda;
    }
}

4 Class Sepeda

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;
    }

    @Override
    public String getInfo() {
        return "Sepeda: " + super.getInfo() + ", Jenis: " + jenisSepeda;
    }
}

5 Class Penyewa

public class Penyewa {
    private String nama;
    private Kendaraan kendaraanDisewa;

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

    public String getNama() {
        return nama;
    }

    public Kendaraan getKendaraanDisewa() {
        return kendaraanDisewa;
    }

    public String getInfo() {
        return "Nama: " + nama + "\nKendaraan: " + kendaraanDisewa.getInfo();
    }
}

6 Class MainApp

import java.util.ArrayList;
import java.util.Scanner;

public class MainApp {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        // Daftar kendaraan tersedia
        ArrayList daftarKendaraan = new ArrayList();
        daftarKendaraan.add(new Mobil("Toyota", "Avanza", 2020, 4));
        daftarKendaraan.add(new Motor("Honda", "Beat", 2022, 2));
        daftarKendaraan.add(new Sepeda("Polygon", "Helios", 2021, "Balap"));
        daftarKendaraan.add(new Mobil("Daihatsu", "Xenia", 2019, 4));
        daftarKendaraan.add(new Sepeda("BMX", "Street 3000", 2018, "BMX"));
        daftarKendaraan.add(new Motor("Yamaha", "NMax", 2023, 2));
        daftarKendaraan.add(new Mobil("Honda", "Civic", 2018, 4));
        daftarKendaraan.add(new Sepeda("United", "Trifold", 2020, "Lipat"));
        daftarKendaraan.add(new Motor("Suzuki", "Satria FU", 2017, 2));
        daftarKendaraan.add(new Mobil("Mitsubishi", "Pajero Sport", 2021, 4));

        // Daftar penyewa
        ArrayList daftarPenyewa = new ArrayList();
        daftarPenyewa.add(new Penyewa("Andi", daftarKendaraan.get(0)));
        daftarPenyewa.add(new Penyewa("Budi", daftarKendaraan.get(2)));
        daftarPenyewa.add(new Penyewa("Citra", daftarKendaraan.get(1)));

        int pilihan;

        do {
            System.out.println("\n===== MENU RENTAL KENDARAAN =====");
            System.out.println("1. Tampilkan daftar kendaraan");
            System.out.println("2. Tampilkan daftar penyewa");
            System.out.println("3. Tambah penyewa baru");
            System.out.println("4. Hapus penyewa");
            System.out.println("5. Keluar");
            System.out.print("Pilih menu: ");
            pilihan = input.nextInt();
            input.nextLine(); 
            
            switch(pilihan) {
                case 1:
                    System.out.println("\n=== DAFTAR KENDARAAN TERSEDIA ===");
                    int index = 1;
                    for (Kendaraan k : daftarKendaraan) {
                        System.out.println(index + ". " + k.getInfo());
                        index++;
                    }
                    break;

                case 2:
                    System.out.println("\n=== DAFTAR PENYEWA ===");
                    if (daftarPenyewa.isEmpty()) {
                        System.out.println("Belum ada penyewa.");
                    } else {
                        for (Penyewa p : daftarPenyewa) {
                            System.out.println(p.getInfo());
                            System.out.println("---------------------");
                        }
                    }
                    break;

                case 3:
                    System.out.println("\nTambahkan Penyewa Baru");
                    System.out.print("Nama penyewa: ");
                    String nama = input.nextLine();

                    System.out.println("\nPilih kendaraan yang ingin disewa:");
                    for (int i = 0; i < daftarKendaraan.size(); i++) {
                        System.out.println((i + 1) + ". " + daftarKendaraan.get(i).getInfo());
                    }
                    System.out.print("Masukkan nomor kendaraan: ");
                    int pilihKendaraan = input.nextInt();
                    input.nextLine();

                    if (pilihKendaraan < 1 || pilihKendaraan > daftarKendaraan.size()) {
                        System.out.println("Pilihan tidak valid!");
                    } else {
                        Kendaraan dipilih = daftarKendaraan.get(pilihKendaraan - 1);
                        daftarPenyewa.add(new Penyewa(nama, dipilih));
                        System.out.println("Penyewa berhasil ditambahkan!");
                    }
                    break;

                case 4:
                    System.out.println("\nMasukkan nama penyewa yang akan dihapus: ");
                    String hapusNama = input.nextLine();
                    
                    boolean ditemukan = false;
                    for (int i = 0; i < daftarPenyewa.size(); i++) {
                        if (daftarPenyewa.get(i).getNama().equalsIgnoreCase(hapusNama)) {
                            daftarPenyewa.remove(i);
                            System.out.println("Penyewa berhasil dihapus!");
                            ditemukan = true;
                            break;
                        }
                    }
                    if (!ditemukan) {
                        System.out.println("Penyewa tidak ditemukan.");
                    }
                    break;

                case 5:
                    System.out.println("Terima kasih telah menggunakan sistem rental!");
                    break;

                default:
                    System.out.println("Pilihan tidak valid!");
            }
        } while(pilihan != 5);

        input.close();
    }
}

📸 Dokumentasi

Pertemuan 15 : Aplikasi CRUD JAVA

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