Thursday, December 25, 2025

Pertemuan 13 | Abstract Class

 Nama     : Naufal Daffa Alfa Zain

 Nrp         : 5025241066

 Kelas      : Pemrograman Web A2

Pada pertemuan ke‑13 kami mendapat dua tugas. Tugas pertama adalah membuat abstraksi makhluk hidup lewat kelas dasar MakhlukHidup beserta turunan manusia, hewan, dan tumbuhan untuk menunjukkan bagaimana metode abstrak dipaksa diimplementasikan. Kami juga menambahkan perilaku umum seperti tumbuh() dan tampilkanInformasi() sehingga setiap turunan bisa memanfaatkan logika bersama sambil tetap menyuntikkan ciri khasnya.



Source Code :

DemoMakhluk.Java
package id.rabbitandfox.makhluk;

public class DemoMakhluk {

    public static void main(String[] args) {
        Manusia manusia = new Manusia("Riyan", "pengembang perangkat lunak");
        Hewan hewan = new Hewan("Kelinci", "herbivora");
        Tumbuhan tumbuhan = new Tumbuhan("Anggrek", "monokotil");

        tampilkan(manusia);
        manusia.bekerja();

        tampilkan(hewan);
        hewan.makan();

        tampilkan(tumbuhan);
        tumbuhan.fotosintesis();
    }

    private static void tampilkan(MakhlukHidup makhluk) {
        makhluk.tumbuh();
        makhluk.tampilkanInformasi();
        System.out.println("------------------------------------");
    }
}

MakhlukHidup.Java
package id.rabbitandfox.makhluk;

public abstract class MakhlukHidup {
    private final String nama;

    protected MakhlukHidup(String nama) {
        if (nama == null || nama.isBlank()) {
            throw new IllegalArgumentException("Nama makhluk hidup wajib diisi.");
        }
        this.nama = nama;
    }

    public String getNama() {
        return nama;
    }
    public abstract String bernapasDengan();
    public abstract String berkembangBiakMelalui();
    public void tumbuh() {
        System.out.printf("%s mengalami pertumbuhan secara bertahap.%n", nama);
    }

    public void tampilkanInformasi() {
        System.out.printf(
                "%s bernapas dengan %s dan berkembang biak melalui %s.%n",
                nama,
                bernapasDengan(),
                berkembangBiakMelalui()
        );
    }
}

Hewan.Java
package id.rabbitandfox.makhluk;

public class Hewan extends MakhlukHidup {
    private final String jenisMakanan;

    public Hewan(String nama, String jenisMakanan) {
        super(nama);
        this.jenisMakanan = jenisMakanan;
    }

    @Override
    public String bernapasDengan() {
        return "paru-paru atau insang tergantung spesies";
    }

    @Override
    public String berkembangBiakMelalui() {
        return "bertelur atau melahirkan sesuai jenis hewan";
    }

    public void makan() {
        System.out.printf("%s termasuk hewan %s.%n", getNama(), jenisMakanan);
    }
}

Manusia.Java

package id.rabbitandfox.makhluk;

public class Manusia extends MakhlukHidup {
    private final String profesi;

    public Manusia(String nama, String profesi) {
        super(nama);
        this.profesi = profesi;
    }

    @Override
    public String bernapasDengan() {
        return "paru-paru";
    }

    @Override
    public String berkembangBiakMelalui() {
        return "melahirkan (vivipar)";
    }

    public void bekerja() {
        System.out.printf("%s bekerja sebagai %s.%n", getNama(), profesi);
    }
}

Tumbuhan.Java

package id.rabbitandfox.makhluk;

public class Tumbuhan extends MakhlukHidup {
    private final String jenisBatang;

    public Tumbuhan(String nama, String jenisBatang) {
        super(nama);
        this.jenisBatang = jenisBatang;
    }

    @Override
    public String bernapasDengan() {
        return "stomata dan lentisel";
    }

    @Override
    public String berkembangBiakMelalui() {
        return "penyerbukan dan pembuahan";
    }

    public void fotosintesis() {
        System.out.printf("%s dengan batang %s melakukan fotosintesis.%n", getNama(), jenisBatang);
    }
}


Tugas kedua adalah membangun simulasi game Rabbit and Fox berbasis BlueJ dengan memanfaatkan abstraksi MakhlukGame. Saya menyiapkan GameBoard sebagai papan, menambahkan perilaku kelinci menghindar dan rubah mengejar, lalu menjalankan semuanya melalui GameRunner untuk memantau sisa populasi setiap putaran.



Source Code:

GameRunner.Java
public class GameRunner {

    public static void main(String[] args) throws InterruptedException {
        GameBoard papan = new GameBoard(10, 10);

        papan.tambahMakhluk(new Rabbit("Rabbit-1", new Position(2, 2)));
        papan.tambahMakhluk(new Rabbit("Rabbit-2", new Position(7, 4)));
        papan.tambahMakhluk(new Rabbit("Rabbit-3", new Position(4, 8)));
        papan.tambahMakhluk(new Fox("Fox-1", new Position(0, 0)));
        papan.tambahMakhluk(new Fox("Fox-2", new Position(9, 9)));

        int putaranMaks = 30;
        for (int putaran = 1; putaran <= putaranMaks; putaran++) {
            System.out.println("Putaran " + putaran);
            papan.tampilkanPapan();
            papan.jalankanPutaran();
            System.out.printf("Sisa kelinci: %d | Sisa rubah: %d%n",
                    papan.hitungMakhluk(Rabbit.class),
                    papan.hitungMakhluk(Fox.class));
            System.out.println("----------------------------------");
            if (papan.hitungMakhluk(Rabbit.class) == 0) {
                System.out.println("Semua kelinci telah tertangkap!");
                break;
            }
            Thread.sleep(300);
        }

        System.out.println("Simulasi selesai.");
    }
}


GameBoard.Java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Random;

public class GameBoard {
    private final int rows;
    private final int cols;
    private final List<MakhlukGame> daftarMakhluk = new ArrayList<>();
    private final Random random = new Random();

    public GameBoard(int rows, int cols) {
        if (rows <= 0 || cols <= 0) {
            throw new IllegalArgumentException("Ukuran papan harus lebih besar dari nol");
        }
        this.rows = rows;
        this.cols = cols;
    }

    public void tambahMakhluk(MakhlukGame makhluk) {
        if (!posisiDiDalam(makhluk.getPosisi())) {
            throw new IllegalArgumentException("Posisi makhluk berada di luar papan");
        }
        if (!kosong(makhluk.getPosisi())) {
            throw new IllegalArgumentException("Petak sudah terisi makhluk lain");
        }
        daftarMakhluk.add(makhluk);
    }

    public void hapusMakhluk(MakhlukGame makhluk) {
        daftarMakhluk.remove(makhluk);
    }

    public void pindahkanMakhluk(MakhlukGame makhluk, Position posisiBaru) {
        if (!posisiDiDalam(posisiBaru)) {
            return;
        }
        makhluk.pindahKe(posisiBaru);
    }

    public boolean posisiDiDalam(Position posisi) {
        int r = posisi.getRow();
        int c = posisi.getCol();
        return r >= 0 && r < rows && c >= 0 && c < cols;
    }

    public boolean kosong(Position posisi) {
        return getMakhlukPada(posisi) == null;
    }

    public MakhlukGame getMakhlukPada(Position posisi) {
        for (MakhlukGame makhluk : daftarMakhluk) {
            if (makhluk.getPosisi().equals(posisi)) {
                return makhluk;
            }
        }
        return null;
    }

    public List<MakhlukGame> getMakhluk() {
        return Collections.unmodifiableList(daftarMakhluk);
    }

    public List<Position> tetangga(Position posisi) {
        List<Position> hasil = new ArrayList<>();
        for (int dr = -1; dr <= 1; dr++) {
            for (int dc = -1; dc <= 1; dc++) {
                if (dr == 0 && dc == 0) {
                    continue;
                }
                Position kandidat = new Position(posisi.getRow() + dr, posisi.getCol() + dc);
                if (posisiDiDalam(kandidat)) {
                    hasil.add(kandidat);
                }
            }
        }
        return hasil;
    }

    public List<Position> tetanggaKosong(Position posisi) {
        List<Position> kosong = new ArrayList<>();
        for (Position kandidat : tetangga(posisi)) {
            if (kosong(kandidat)) {
                kosong.add(kandidat);
            }
        }
        return kosong;
    }

    public Optional<MakhlukGame> cariTerdekat(Class<? extends MakhlukGame> tipe, Position dari) {
        MakhlukGame kandidat = null;
        int jarakTerdekat = Integer.MAX_VALUE;
        for (MakhlukGame makhluk : daftarMakhluk) {
            if (tipe.isInstance(makhluk)) {
                int jarak = dari.manhattanDistance(makhluk.getPosisi());
                if (jarak < jarakTerdekat) {
                    jarakTerdekat = jarak;
                    kandidat = makhluk;
                }
            }
        }
        return Optional.ofNullable(kandidat);
    }

    public void jalankanPutaran() {
        List<MakhlukGame> iterasi = new ArrayList<>(daftarMakhluk);
        Collections.shuffle(iterasi, random);
        for (MakhlukGame makhluk : iterasi) {
            if (daftarMakhluk.contains(makhluk)) {
                makhluk.lakukanLangkah(this);
            }
        }
    }

    public void tampilkanPapan() {
        char[][] grid = new char[rows][cols];
        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < cols; c++) {
                grid[r][c] = '.';
            }
        }
        for (MakhlukGame makhluk : daftarMakhluk) {
            Position pos = makhluk.getPosisi();
            grid[pos.getRow()][pos.getCol()] = makhluk.getSimbol();
        }
        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < cols; c++) {
                System.out.print(grid[r][c] + " ");
            }
            System.out.println();
        }
    }

    public Random getRandom() {
        return random;
    }

    public int hitungMakhluk(Class<? extends MakhlukGame> tipe) {
        int total = 0;
        for (MakhlukGame makhluk : daftarMakhluk) {
            if (tipe.isInstance(makhluk)) {
                total++;
            }
        }
        return total;
    }
}


MakhlukGame.Java

public abstract class MakhlukGame {
    private final String nama;
    private final char simbol;
    private Position posisi;

    protected MakhlukGame(String nama, Position posisi, char simbol) {
        if (nama == null || nama.isBlank()) {
            throw new IllegalArgumentException("Nama makhluk tidak boleh kosong");
        }
        if (posisi == null) {
            throw new IllegalArgumentException("Posisi awal wajib ada");
        }
        this.nama = nama;
        this.posisi = posisi;
        this.simbol = simbol;
    }

    public String getNama() {
        return nama;
    }

    public Position getPosisi() {
        return posisi;
    }

    public char getSimbol() {
        return simbol;
    }

    protected void pindahKe(Position posisiBaru) {
        this.posisi = posisiBaru;
    }

    public abstract void lakukanLangkah(GameBoard papan);
}

Position.Java

public final class Position {
    private final int row;
    private final int col;

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

    public int getRow() {
        return row;
    }

    public int getCol() {
        return col;
    }

    public int manhattanDistance(Position other) {
        return Math.abs(row - other.row) + Math.abs(col - other.col);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof Position)) {
            return false;
        }
        Position other = (Position) obj;
        return row == other.row && col == other.col;
    }

    @Override
    public int hashCode() {
        return 31 * row + col;
    }

    @Override
    public String toString() {
        return "(" + row + "," + col + ")";
    }
}

Rabbit.Java

import java.util.List;
import java.util.Optional;

public class Rabbit extends MakhlukGame {

    public Rabbit(String nama, Position posisi) {
        super(nama, posisi, 'R');
    }

    @Override
    public void lakukanLangkah(GameBoard papan) {
        List<Position> kandidat = papan.tetanggaKosong(getPosisi());
        if (kandidat.isEmpty()) {
            return;
        }

        Optional<MakhlukGame> fox = papan.cariTerdekat(Fox.class, getPosisi());
        if (fox.isPresent()) {
            Position posisiFox = fox.get().getPosisi();
            int jarakSaatIni = getPosisi().manhattanDistance(posisiFox);
            Position terbaik = null;
            int jarakTerbaik = jarakSaatIni;

            for (Position posisiBaru : kandidat) {
                int jarak = posisiBaru.manhattanDistance(posisiFox);
                if (jarak > jarakTerbaik) {
                    jarakTerbaik = jarak;
                    terbaik = posisiBaru;
                }
            }

            if (terbaik != null) {
                papan.pindahkanMakhluk(this, terbaik);
                return;
            }
        }

        Position acak = kandidat.get(papan.getRandom().nextInt(kandidat.size()));
        papan.pindahkanMakhluk(this, acak);
    }
}

Fox.Java

import java.util.Collections;
import java.util.List;
import java.util.Optional;

public class Fox extends MakhlukGame {

    public Fox(String nama, Position posisi) {
        super(nama, posisi, 'F');
    }

    @Override
    public void lakukanLangkah(GameBoard papan) {
        Position tujuan = cariTujuan(papan);
        if (tujuan == null) {
            return;
        }

        MakhlukGame penghuni = papan.getMakhlukPada(tujuan);
        if (penghuni instanceof Rabbit) {
            papan.hapusMakhluk(penghuni);
            System.out.println(getNama() + " memakan " + penghuni.getNama());
        } else if (penghuni instanceof Fox) {
            return; // tidak menabrak rubah lain
        }

        papan.pindahkanMakhluk(this, tujuan);
    }

    private Position cariTujuan(GameBoard papan) {
        Optional<MakhlukGame> target = papan.cariTerdekat(Rabbit.class, getPosisi());
        if (target.isPresent()) {
            Position posisiTarget = target.get().getPosisi();
            int deltaRow = Integer.compare(posisiTarget.getRow(), getPosisi().getRow());
            int deltaCol = Integer.compare(posisiTarget.getCol(), getPosisi().getCol());
            Position maju = new Position(getPosisi().getRow() + deltaRow, getPosisi().getCol() + deltaCol);
            if (papan.posisiDiDalam(maju)) {
                MakhlukGame penghuni = papan.getMakhlukPada(maju);
                if (penghuni == null || penghuni instanceof Rabbit) {
                    return maju;
                }
            }
        }

        List<Position> tetangga = papan.tetangga(getPosisi());
        Collections.shuffle(tetangga, papan.getRandom());
        for (Position kandidat : tetangga) {
            MakhlukGame penghuni = papan.getMakhlukPada(kandidat);
            if (penghuni == null || penghuni instanceof Rabbit) {
                return kandidat;
            }
        }
        return null;
    }
}

Pertemuan 13 | Abstract Class

 Nama     : Naufal Daffa Alfa Zain  Nrp         : 5025241066  Kelas      : Pemrograman Web A2 Pada pertemuan ke‑13 kami mendapat dua tugas. ...