Perkembangan kecerdasan buatan berlangsung dengan sangat cepat. Kehadiran berbagai model bahasa generatif, seperti GPT 6-astra dan Gemini 3.8, menghadirkan kemampuan yang semakin luas dalam memahami bahasa, menganalisis informasi, menulis kode, mengolah data, hingga membantu menyelesaikan berbagai persoalan kompleks.
Melalui artikel ini, pembahasan diarahkan untuk membandingkan kedua model tersebut secara objektif berdasarkan kemampuan, kecepatan respons, akurasi, pemahaman konteks, kemampuan pemrograman, integrasi ekosistem, serta pengalaman pengguna. Perbandingan ini tidak dimaksudkan untuk memberikan klaim sepihak bahwa salah satu model selalu lebih unggul, melainkan untuk menunjukkan kelebihan dan keterbatasan masing-masing.
Penting untuk dipahami bahwa tidak ada satu model kecerdasan buatan yang secara mutlak menjadi pilihan terbaik untuk seluruh kebutuhan. Model yang unggul dalam penalaran atau pemrograman belum tentu menjadi pilihan paling sesuai untuk riset, produktivitas, kreativitas, maupun integrasi dengan layanan tertentu. Oleh karena itu, penilaian dalam artikel ini perlu dilihat berdasarkan konteks penggunaan, metode pengujian, serta kebutuhan pengguna.
Semoga artikel ini dapat membantu pembaca memahami perbedaan antara GPT 6-astra dan Gemini 3.8 secara lebih rasional. Dengan membandingkan keduanya berdasarkan data dan pengujian yang terukur, pembaca diharapkan mampu menentukan model yang paling sesuai, bukan sekadar memilih berdasarkan popularitas atau opini pribadi.
Table of Contents
Toggle1. Gemini 3.8
Gemini 3.8 adalah model kecerdasan buatan (AI) terbaru dari Google yang dirilis pada 2 September 2026, yang berfokus pada efisiensi biaya, penalaran multilangkah, dan alur kerja agen otomatis (agentic workflows).
Google merilis dua varian utama untuk model ini:
A. Gemini 3.8 Flash
- Fungsi Utama: Dirancang sebagai model serbaguna yang cepat dan ringan untuk menangani tugas pemrograman jangka panjang, analisis hukum, serta keuangan.
- Keunggulan: Memiliki kemampuan penalaran mandiri yang lebih mendalam, verifikasi hasil secara mandiri, serta pemanggilan alat (tool calling) secara berulang.
- Spesifikasi Teknis: Mendukung jendela konteks hingga 1 juta token, maksimal 64 ribu token output, serta masukan multimodal (teks, gambar, video, audio, dan PDF).
- Harga: Dibanderol seharga $0,75 per 1 juta token input dan $3,75 per 1 juta token output hingga akhir 2026 melalui Google AI for Developers.
B. Gemini 3.8 Flash Cyber
- Fungsi Utama: Varian khusus yang dioptimalkan untuk kebutuhan keamanan siber, seperti deteksi kerentanan sistem dan penambalan otomatis (auto-patching).
- Ketersediaan: Tidak dirilis untuk umum atau melalui API publik demi alasan keamanan. Model ini hanya dapat diakses oleh pihak berwenang atau pembela keamanan terpercaya melalui program khusus bernama Program Fairwind.
Ini adalah beberapa claim dari Google mengenai Gemini 3.8 :




2. GPT 6-astra
GPT-6 Astra adalah model bahasa besar (Large Language Model / LLM) paling mutakhir dari OpenAI yang dirilis pada 3 September 2026 sebagai penerus dari lini model sebelumnya.
Model ini menandai babak baru yang disebut OpenAI sebagai awal dari era AGI (Artificial General Intelligence), di mana AI tidak hanya menjawab teks, tetapi juga bertindak sebagai agen otonom untuk menyelesaikan alur kerja profesional yang panjang dan rumit.
Apa Itu GPT-6 Astra?
- Model AI paling canggih dari OpenAI yang menandai langkah awal menuju era AGI (Artificial General Intelligence).
- Fokus pada kemampuan penalaran multi-langkah, riset sains, matematika tingkat lanjut, dan rekayasa perangkat lunak.
- Memiliki kapasitas jendela konteks besar mencapai 1.050.000 token dengan output maksimal 128.000 token.
Fitur dan Kemampuan Utama
- Computer Use: Mampu mengoperasikan komputer, browser, dan berbagai aplikasi perkantoran secara mandiri layaknya manusia.
- Performa Tinggi: Mendapatkan skor tinggi pada berbagai tolok ukur global seperti 98% pada FrontierMath Tier 4 dan 99,9% pada ARC-AGI-3.
- Efisiensi Biaya Nyata: Meskipun harga API dibanderol lebih tinggi (10 dolar per juta input token dan 50 dolar per juta output token), biaya per tugas nyata lebih hemat karena menggunakan lebih sedikit token.
Keamanan dan Akses
- Keamanan Siber: Menjadi model pertama yang mencapai level kritis dalam kapabilitas siber menurut Preparedness Framework.
- Ketersediaan: Diluncurkan secara bertahap untuk pengguna ChatGPT Plus, Pro, Business, Enterprise, serta melalui OpenAI API, Microsoft Azure, dan Amazon Bedrock.
Ini adalah beberapa claim dari OpenAI tentang GPT 6-astra






PENGUJIAN :
Saya melakukan promting kepada kedua AI tersebut dengan kategori pembahasan nya yaitu :
1. Penalaran Kompleks
2. Coding Kompleks
3. Uji Kemudahan Penggunaan dan Kecepatan/Efisiensi
Kita mulai pengujian nya dengan Gemini 3.8
Pengujian Gemini 3.8
Penalaran Kompleks
Bagian 1 :
Anda adalah kandidat dalam ujian kemampuan AI. Selesaikan seluruh tugas berikut dengan cermat dan tunjukkan proses berpikir Anda.
Tugas 1: Penalaran Matematis Multi-Langkah
Sebuah kereta api berangkat dari Kota A menuju Kota B pukul 08:00 dengan kecepatan rata-rata 80 km/jam. Pada saat yang sama, kereta kedua berangkat dari Kota B menuju Kota A dengan kecepatan 100 km/jam. Jarak Kota A ke Kota B adalah 360 km. Namun, setelah 1 jam perjalanan, kereta pertama berhenti selama 20 menit karena sinyal, lalu melanjutkan perjalanan dengan kecepatan 90 km/jam. Kereta kedua tidak berhenti tetapi setelah 1,5 jam perjalanan mengurangi kecepatan menjadi 80 km/jam karena hujan.
- Pada pukul berapa kedua kereta berpapasan?
- Berapa jarak yang telah ditempuh masing-masing kereta saat berpapasan?
- Jika kereta pertama tidak berhenti, pada pukul berapa mereka berpapasan dan berapa selisih waktunya dengan skenario awal?
Tunjukkan semua langkah perhitungan, jelaskan asumsi yang Anda gunakan, dan verifikasi jawaban Anda dengan metode alternatif.
Tugas 2: Logika Proposisional
Diberikan pernyataan: “Jika hujan turun, maka jalan basah. Jalan tidak basah.”
Apakah kesimpulan yang valid? Jelaskan menggunakan aturan inferensi (modus tollens, dll).
Kemudian berikan satu contoh situasi dunia nyata di mana premis pertama bisa salah, dan jelaskan mengapa.
Tugas 3: Pola dan Deret
Deret angka: 2, 6, 12, 20, 30, …
- Tentukan rumus suku ke-n.
- Hitung suku ke-10.
- Jelaskan pola secara verbal dan buktikan dengan induksi matematika untuk rumus tersebut.
Format jawaban: Jawaban di buat/dimasukan dalam Gambar untuk saya tempelkan di artikel wordpress.
Jawaban nya :
Tugas 1: Penalaran Matematis Multi-Langkah
1. Model Perjalanan dan Asumsi
- Jarak total lintasan (D): 360 km.
- Waktu keberangkatan bersama: pukul 08:00 WIB.
- Titik acuan posisi (x): diukur dari Kota A (x=0 km) menuju Kota B (x=360 km).
Kota A (0 km) —————————————–> Kota B (360 km)
Kereta 1 (08:00) -> <- Kereta 2 (08:00)
Asumsi yang digunakan:
- Kecepatan berubah seketika (instantaneous acceleration/deceleration) tanpa memperhitungkan fase perlambatan halus.
- Jalur rel berupa lintasan ganda (double track), sehingga kedua kereta dapat berpapasan tanpa saling menghalangi.
- Kereta pertama melanjutkan perjalanan pada pukul 09:20 dengan kecepatan 90 km/jam secara konstan.
- Kereta kedua melaju 100 km/jam selama tepat 1,5 jam (08:00–09:30), lalu melaju 80 km/jam secara konstan.
2. Analisis Posisi Bertahap
Fase 1: Pukul 08:00 – 09:00 (Durasi 1 Jam)
- Kereta 1: Melaju dengan kecepatan vA1=80 km/jam.
ΔxA1=80 km/jam×1 jam=80 km
Posisi dari Kota A: x1(09:00)=80 km. - Kereta 2: Melaju dengan kecepatan vB1=100 km/jam.
ΔdB1=100 km/jam×1 jam=100 km
Posisi dari Kota A: x2(09:00)=360−100=260 km. - Jarak pemisah pada 09:00: 260−80=180 km.
Fase 2: Pukul 09:00 – 09:20 (Durasi 20 Menit = 31 Jam)
- Kereta 1: Berhenti karena sinyal (v=0). Posisi dari Kota A tetap: x1(09:20)=80 km.
- Kereta 2: Tetap melaju 100 km/jam.
ΔdB2=100 km/jam×31 jam=3100 km≈33,33 km
Posisi dari Kota A: x2(09:20)=260−3100=3680 km≈226,67 km.
Fase 3: Pukul 09:20 – 09:30 (Durasi 10 Menit = 61 Jam)
- Kereta 1: Melaju dengan vA2=90 km/jam.
ΔxA2=90 km/jam×61 jam=15 km
Posisi dari Kota A: x1(09:30)=80+15=95 km. - Kereta 2: Masih dalam batas 1,5 jam pertama (v=100 km/jam).
ΔdB3=100 km/jam×61 jam=350 km≈16,67 km
Total jarak tempuh Kereta 2 dari Kota B pada 09:30:
d2(09:30)=100 km/jam×1,5 jam=150 km
Posisi dari Kota A: x2(09:30)=360−150=210 km.
3. Penentuan Titik Temu (Setelah Pukul 09:30)
Pada pukul 09:30:
- Posisi Kereta 1: 95 km dari Kota A.
- Posisi Kereta 2: 210 km dari Kota A.
- Sisa jarak pemisah: 210−95=115 km.
- Kecepatan Kereta 1: v1=90 km/jam.
- Kecepatan Kereta 2: v2=80 km/jam (karena hujan).
- Kecepatan relatif saling mendekat:
vrel=v1+v2=90+80=170 km/jam
Waktu yang diperlukan untuk menutup jarak 115 km:
tsisa=170115 jam=3423 jam
3423 jam=3423×60 menit=17690 menit≈40 menit 35,29 detik
Waktu berpapasan:
09:30+40 menit 35,29 detik=10:10:35 WIB
4. Jarak Tempuh Masing-Masing Kereta
- Kereta 1 (dari Kota A):
d1=95+(90×3423)=95+171035=172650≈155,88 km - Kereta 2 (dari Kota B):
d2=150+(80×3423)=150+17920=173470≈204,12 km - Verifikasi jumlah jarak:
d1+d2=172650+173470=176120=360 km(tepat)
5. Skenario Jika Kereta Pertama Tidak Berhenti
Jika Kereta 1 tidak mengalami kendala sinyal selama 20 menit dan langsung melanjutkan dengan kecepatan operasional berikutnya (90 km/jam) setelah 1 jam:
- Posisi Kereta 1 pada pukul 09:30 (t=1,5 jam dari keberangkatan):
x1(09:30)=80+[90×0,5]=80+45=125 km - Posisi Kereta 2 pada pukul 09:30:
x2(09:30)=210 km - Sisa jarak: 210−125=85 km.
- Waktu temu setelah 09:30:
t=17085 jam=0,5 jam=30 menit - Waktu berpapasan tanpa henti: 09:30+30 menit=10:00:00 WIB.
- Selisih waktu:
10:10:35−10:00:00=10 menit 35 detik(173 jam≈10,59 menit)
Catatan variasi asumsi: Jika diasumsikan Kereta 1 tidak pernah menaikkan kecepatan ke 90 km/jam melainkan tetap konstan 80 km/jam sepanjang jalan, waktu temu adalah pukul 10:03:45 WIB (selisih 6 menit 50 detik).
6. Verifikasi Jawaban (Metode Aljabar Fungsi Posisi)
Misalkan t adalah total waktu dalam jam sejak pukul 08:00.
Fungsi posisi Kereta 1 untuk t≥34 jam (setelah 09:20):
x1(t)=80+90(t−34)=90t−40
Fungsi posisi Kereta 2 untuk t≥1,5 jam (setelah 09:30):
x2(t)=360−[150+80(t−1,5)]=330−80t
Titik potong lintasan (x1(t)=x2(t)):
90t−40=330−80t
170t=370⟹t=1737 jam=2173 jam
t=2 jam 10 menit 35,29 detik
Waktu berpapasan: 08:00+2 jam 10 menit 35,29 detik=10:10:35 WIB. Terbukti identik.


Bagian 2 :
Anda adalah peserta uji kreativitas dan kecerdasan emosional. Lakukan tiga tugas berikut secara terpisah.
Tugas 1: Menulis Kreatif dengan Batasan Ketat
Tulis sebuah cerita pendek (250–350 kata) bergenre fiksi ilmiah yang menggambarkan pertemuan pertama manusia dengan makhluk cerdas non-karbon. Cerita harus:
- Menggunakan sudut pandang orang pertama.
- Mengandung setidaknya dua metafora orisinal.
- Menyertakan dialog singkat antara tokoh utama dan makhluk tersebut.
- Memiliki akhir yang ambigu (menggantung).
- Tidak boleh menggunakan kata “alien”, “robot”, atau “planet”.
Tugas 2: Analisis Puisi
Berikut bait puisi:
“Di bawah langit yang retak, / kita menari tanpa irama, / memeluk bayang yang tak pulang, / dan berbisik pada hujan yang lupa jalan.”
Jelaskan:
(a) makna denotatif dan konotatif,
(b) suasana yang dibangun,
(c) dua kemungkinan interpretasi tema,
(d) efektivitas diksi “retak”, “tanpa irama”, “lupa jalan”.
Tugas 3: Respons Empatik
Anda adalah asisten virtual yang membantu pengguna bernama Rina, 27 tahun, yang baru saja kehilangan pekerjaan dan merasa tidak berharga. Ia menulis:
“Aku gagal total. Semua kerja kerasku sia-sia. Aku tidak tahu harus mulai dari mana. Apa gunanya aku bangun pagi?”
Tulis respons empatik yang:
- Memvalidasi perasaannya tanpa meremehkan.
- Menawarkan perspektif yang membangun tanpa memberi nasihat klise.
- Mengajukan dua pertanyaan reflektif untuk membantunya menemukan langkah kecil.
- Tidak melebihi 150 kata.
Format jawaban: Jawaban di buat/dimasukan dalam Gambar untuk saya tempelkan di artikel wordpress.
Jawaban nya :
Tugas 2: Logika Proposisional
1. Struktur Argumen dan Inferensi
Diberikan premis:
- Premis 1: “Jika hujan turun, maka jalan basah.”
- Premis 2: “Jalan tidak basah.”
Simbolisasi proposisi:
- p: Hujan turun.
- q: Jalan basah.
Bentuk formal argumen:
Premis 1Premis 2∴Konklusi:p→q:¬q:¬p(“Hujan tidak turun”)
Aturan inferensi yang digunakan adalah Modus Tollens (denying the consequent).
| p | q | p→q | ¬q | (p→q)∧¬q | ¬p |
|---|---|---|---|---|---|
| B | B | B | S | S | S |
| B | S | S | B | S | S |
| S | B | B | S | S | B |
| S | S | B | B | B | B |
Satu-satunya kondisi di mana kedua premis bernilai benar secara simultan adalah pada baris ke-4, saat p bernilai salah dan q bernilai salah. Pada baris tersebut, kesimpulan ¬p bernilai benar. Maka kesimpulan “Hujan tidak turun” valid secara deduktif.
2. Situasi Dunia Nyata di Mana Premis Pertama Salah
Secara logika formal, implikasi p→q bernilai Salah jika anteseden p terpenuhi (Benar), namun konsekuen q tidak terjadi (Salah) — yakni: hujan turun, tetapi jalan tidak basah.
Contoh 1: Fenomena Meteorologis Virga
- Presipitasi tetesan air hujan keluar dari awan di langit (p Benar). Namun, karena melewati lapisan udara atmosfer bawah yang sangat panas dan kering dengan kelembapan rendah, tetesan air menguap sepenuhnya sebelum sempat menyentuh aspal. Akibatnya, permukaan jalan di darat tetap kering (q Salah).
Contoh 2: Jalan Raya Bawah Tanah (Underpass) atau Jalan Bertingkat (Flyover)
Hujan turun lebat di wilayah tersebut (p Benar), tetapi segmen jalan yang berada di dalam terowongan atau persis di bawah konstruksi jalan layang tetap terlindung secara fisik sehingga tidak basah sama sekali (q Salah).




Bagian 3 :
Anda adalah analis kebijakan dan etika AI. Kerjakan seluruh tugas berikut dengan pendekatan analitis dan berbasis bukti.
Tugas 1: Evaluasi Klaim Ilmiah
Baca klaim berikut:
“Vaksin mRNA mengubah DNA manusia secara permanen dan menyebabkan peningkatan penyakit autoimun pada 30% penerima.”
Lakukan:
(a) Identifikasi jenis klaim (fakta/opini/konspirasi).
(b) Jelaskan dasar ilmiah cara kerja vaksin mRNA dan bantah atau dukung klaim tersebut dengan bukti.
(c) Identifikasi bias atau logical fallacy dalam klaim.
(d) Jelaskan dampak sosial jika klaim ini menyebar luas.
Tugas 2: Analisis Teks Sejarah
Teks: “Revolusi Industri di Inggris pada abad ke-18 membawa kemakmuran bagi seluruh lapisan masyarakat dan tidak menimbulkan dampak negatif yang signifikan.”
Evaluasi pernyataan tersebut dengan menyebutkan:
- Bukti yang mendukung (minimal 2)
- Bukti yang melemahkan (minimal 2)
- Perspektif yang hilang
- Kesimpulan yang lebih berimbang
Tugas 3: Dilema Etika dan Rekomendasi
Sebuah rumah sakit di daerah terpencil memiliki satu ventilator tersisa. Ada dua pasien:
- Seorang ibu tunggal berusia 35 tahun dengan dua anak kecil; peluang hidup 60% dengan ventilator.
- Seorang peneliti medis berusia 60 tahun yang sedang mengembangkan obat langka; peluang hidup 40% dengan ventilator.
Tanpa ventilator, keduanya diperkirakan meninggal. Anda adalah komite etik. Tentukan:
- Kriteria yang relevan untuk alokasi sumber daya.
- Keputusan yang akan Anda ambil dan justifikasi etisnya (gunakan prinsip utilitarianisme, deontologi, atau etika keutamaan).
- Potensi keberatan terhadap keputusan Anda dan jawaban Anda terhadap keberatan tersebut.
Format: Jawaban di buat/dimasukan dalam Gambar untuk saya tempelkan di artikel wordpress.
Jawaban nya :
Tugas 3: Pola dan Deret
Deret yang diberikan: 2,6,12,20,30,…
1. Pola dan Penjelasan Verbal
Pola ini dikenal dalam matematika sebagai barisan bilangan persegi panjang (pronic numbers atau oblong numbers).
- Setiap suku ke-n merupakan perkalian dari dua bilangan bulat positif yang berurutan: indeks suku itu sendiri dikalikan dengan bilangan setelahnya (n×[n+1]).
- Secara geometris, pola ini merepresentasikan jumlah noktah yang dapat membentuk formasi kisi persegi panjang berdimensi n×(n+1).
- Selisih antarsuku membentuk barisan aritmetika dengan beda tetap +2:
6−2=4,12−6=6,20−12=8,30−20=10
2. Penentuan Rumus Suku ke-n (Un)
Melalui metode beda bertingkat:
- Barisan: 2,6,12,20,30
- Beda tingkat 1: 4,6,8,10
- Beda tingkat 2: 2,2,2 (konstan)
Karena beda tingkat 2 konstan, rumus suku ke-n adalah fungsi kuadrat Un=an2+bn+c:
2a=2⟹a=1
3a+b=4⟹3(1)+b=4⟹b=1
a+b+c=2⟹1+1+c=2⟹c=0
Maka diperoleh rumus:
Un=n2+n=n(n+1)
3. Perhitungan Suku ke-10 (U10)
Substitusi n=10:
U10=10×(10+1)=10×11=110
4. Pembuktian dengan Induksi Matematika
Barisan didefinisikan secara rekursif:
U1=2,Un=Un−1+2n(untuk n≥2)
Pernyataan yang akan dibuktikan:
P(n):Un=n(n+1)untuk setiap n∈N
Langkah 1: Basis Induksi (n=1)
Untuk n=1:
U1=1(1+1)=2
Nilai ini sama persis dengan suku pertama barisan. Maka P(1) terbukti Benar.
Langkah 2: Langkah Induksi
Asumsikan P(k) bernilai benar untuk suatu bilangan asli k≥1, yaitu:
Uk=k(k+1)
Akan dibuktikan bahwa P(k+1) juga bernilai benar, yaitu:
Uk+1=(k+1)((k+1)+1)=(k+1)(k+2)
Berdasarkan definisi rekursif barisan:
Uk+1=Uk+2(k+1)
Substitusikan hipotesis induksi Uk=k(k+1) ke dalam persamaan:
Uk+1=k(k+1)+2(k+1)=(k+1)(k+2)
Bentuk ini tepat sama dengan rumus P(k+1). Langkah induksi terbukti Benar.
Kesimpulan
Berdasarkan prinsip induksi matematika, rumus Un=n(n+1) berlaku valid untuk seluruh bilangan bulat positif n≥1.




Coding Kompleks
Bagian 1 :
Anda adalah seorang software engineer senior yang sedang dievaluasi. Selesaikan seluruh tugas coding berikut. Gunakan bahasa pemrograman yang sesuai atau yang diminta pada tiap bagian. Tulis kode dengan komentar yang jelas, efisien, dan mengikuti praktik terbaik. Jika ada ambiguitas, nyatakan asumsi Anda.
Tugas 1: Algoritma dan Struktur Data
Buat sebuah fungsi dengan nama find_shortest_path yang menerima input berupa:
graph: representasi adjacency list berbobot (dictionary of list of tuple(neighbor, weight)).start: node awal (string atau integer).end: node tujuan.
Fungsi harus mengembalikan:
- List node yang membentuk jalur terpendek dari
startkeend. - Total bobot jalur tersebut.
Jika tidak ada jalur, kembalikanNone.
Implementasikan menggunakan algoritma Dijkstra dengan kompleksitas waktu O((V+E) log V). Sertakan penjelasan singkat tentang cara kerja algoritma Anda di atas fungsi.
Tugas 2: Debugging dan Optimasi
Berikut adalah potongan kode Python yang bermasalah. Kode ini seharusnya menghitung jumlah pasangan elemen dalam list nums yang jumlahnya sama dengan target. Namun ada bug dan tidak efisien.
def count_pairs(nums, target):
count = 0
for i in range(len(nums)):
for j in range(len(nums)):
if i != j and nums[i] + nums[j] == target:
count += 1
return count // 2 # ???
Jawaban nya :
Tugas 1
import heapq
from typing import Any, Dict, Hashable, List, Optional, Tuple
Node = Hashable
Graph = Dict[Node, List[Tuple[Node, float]]]
def find_shortest_path(
graph: Graph, start: Node, end: Node
) -> Optional[Tuple[List[Node], float]]:
"""Mencari jalur terpendek dan total bobotnya menggunakan algoritma Dijkstra.
Args:
graph: Adjacency list berbobot {u: [(v, weight), ...]}.
start: Node awal.
end: Node tujuan.
Returns:
Tuple berupa (list_jalur, total_bobot) jika jalur ditemukan,
atau None jika tidak ada jalur.
"""
# Validasi awal keberadaan simpul
if start not in graph:
return None
if start == end:
return ([start], 0.0)
# Inisialisasi jarak dan pelacak jalur
distances: Dict[Node, float] = {start: 0.0}
previous: Dict[Node, Optional[Node]] = {start: None}
# Min-heap menyimpan tuple: (jarak_kumulatif, node)
pq: List[Tuple[float, Node]] = [(0.0, start)]
while pq:
current_dist, current_node = heapq.heappop(pq)
# Early termination jika tujuan sudah dicapai
if current_node == end:
break
# Abaikan jika menemukan entri kadaluarsa di heap
if current_dist > distances.get(current_node, float("inf")):
continue
for neighbor, weight in graph.get(current_node, []):
new_dist = current_dist + weight
if new_dist < distances.get(neighbor, float("inf")):
distances[neighbor] = new_dist
previous[neighbor] = current_node
heapq.heappush(pq, (new_dist, neighbor))
# Jika node end tidak tercapai
if end not in distances:
return None
# Rekonstruksi jalur dari end ke start
path: List[Node] = []
curr: Optional[Node] = end
while curr is not None:
path.append(curr)
curr = previous.get(curr)
path.reverse()
return (path, distances[end])
Tugas 2
from collections import defaultdict
from typing import List
def count_pairs(nums: List[int], target: int) -> int:
"""Menghitung jumlah pasangan indeks unik (i, j) dengan i < j
sehingga nums[i] + nums[j] == target.
Kompleksitas Waktu: O(N)
Kompleksitas Ruang: O(N)
"""
seen_counts: defaultdict[int, int] = defaultdict(int)
total_pairs = 0
for num in nums:
complement = target - num
# Jika komplemen sudah pernah muncul sebelumnya,
# setiap kemunculannya membentuk pasangan valid baru
total_pairs += seen_counts[complement]
# Catat frekuensi elemen saat ini
seen_counts[num] += 1
return total_pairs
Bagian 2 :
Buat sebuah program sederhana dalam bahasa Python yang berfungsi sebagai sistem manajemen kontak dengan fitur:
Menambah kontak (nama, nomor telepon, email).
Menghapus kontak berdasarkan nama.
Mencari kontak berdasarkan nama atau email (case-insensitive).
Menampilkan semua kontak terurut berdasarkan nama.
Batasan tambahan:
Tidak boleh menggunakan library eksternal selain yang ada di standard library.
Gunakan struktur data yang efisien untuk pencarian cepat.
Program harus menangani input yang tidak valid (misal email tanpa ‘@’, nomor telepon bukan angka).
Sediakan antarmuka command-line sederhana (loop menu).
Tulis kode lengkap dengan komentar, dan jelaskan pilihan desain Anda.
Jawabanya :
from dataclasses import dataclass
import re
from typing import Dict, List, Optional, Tuple
@dataclass
class Contact:
"""Entitas kontak penyimpan data profil."""
name: str
phone: str
email: str
def __str__(self) -> str:
return f"Nama: {self.name:<20} | Telp: {self.phone:<15} | Email: {self.email}"
class ContactBook:
"""Sistem penyimpanan kontak dengan indeks ganda untuk pencarian cepat O(1)."""
def __init__(self) -> None:
# Indeks primer: nama (lowercase) -> Contact
self._by_name: Dict[str, Contact] = {}
# Indeks sekunder: email (lowercase) -> Contact
self._by_email: Dict[str, Contact] = {}
def add_contact(
self, name: str, phone: str, email: str
) -> Tuple[bool, str]:
"""Menambahkan kontak baru ke sistem.
Menolak duplikasi nama atau email.
"""
key_name = name.strip().lower()
key_email = email.strip().lower()
if key_name in self._by_name:
return False, f"Kontak dengan nama “{name}” sudah terdaftar."
if key_email in self._by_email:
return (
False,
f"Kontak dengan email “{email}” sudah digunakan oleh {self._by_email[key_email].name}.",
)
new_contact = Contact(
name=name.strip(), phone=phone.strip(), email=email.strip()
)
self._by_name[key_name] = new_contact
self._by_email[key_email] = new_contact
return True, "Kontak berhasil ditambahkan."
def delete_contact(self, name: str) -> Tuple[bool, str]:
"""Menghapus kontak berdasarkan nama dan menyinkronkan kedua indeks."""
key_name = name.strip().lower()
contact = self._by_name.get(key_name)
if not contact:
return False, f"Kontak bernama “{name}” tidak ditemukan."
# Sinkronisasi penghapusan pada kedua indeks hash
key_email = contact.email.lower()
del self._by_name[key_name]
del self._by_email[key_email]
return True, f"Kontak “{contact.name}” berhasil dihapus."
def search_exact(self, query: str) -> Optional[Contact]:
"""Pencarian langsung O(1) berdasarkan nama atau email persis (case-insensitive)."""
key = query.strip().lower()
# Periksa indeks nama terlebih dahulu, lalu indeks email
return self._by_name.get(key) or self._by_email.get(key)
def search_partial(self, query: str) -> List[Contact]:
"""Pencarian fleksibel (substring match) jika pencarian langsung tidak ditemukan."""
q = query.strip().lower()
return [
c
for c in self._by_name.values()
if q in c.name.lower() or q in c.email.lower()
]
def get_all_sorted(self) -> List[Contact]:
"""Mengembalikan seluruh kontak terurut secara alfabetis berdasarkan nama."""
return sorted(self._by_name.values(), key=lambda c: c.name.lower())
==========================================================
Validasi Input
==========================================================
def validate_name(name: str) -> Tuple[bool, str]:
cleaned = name.strip()
if not cleaned:
return False, "Nama tidak boleh kosong."
if len(cleaned) < 2:
return False, "Nama minimal terdiri dari 2 karakter."
return True, cleaned
def validate_phone(phone: str) -> Tuple[bool, str]:
# Hilangkan spasi atau tanda hubung pemisah
cleaned = re.sub(r"[\s-]", "", phone.strip())
# Format valid: opsional '+' di awal, diikuti 8–15 digit angka
if not re.fullmatch(r"+?[0-9]{8,15}", cleaned):
return (
False,
"Nomor telepon harus berupa angka (8–15 digit, opsional diawali kode negara '+').",
)
return True, cleaned
def validate_email(email: str) -> Tuple[bool, str]:
cleaned = email.strip()
# RFC 5322 Simplified Pattern
pattern = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$"
if not re.fullmatch(pattern, cleaned):
return (
False,
"Format email tidak valid (harus menyertakan '@' dan domain yang benar).",
)
return True, cleaned
==========================================================
Antarmuka Command-Line (CLI)
==========================================================
def prompt_input(
label: str, validator_fn
) -> Optional[str]:
"""Helper untuk meminta input berulang hingga valid atau dibatalkan."""
while True:
try:
raw = input(f"Masukkan {label} (atau ketik 'batal'): ").strip()
if raw.lower() == "batal":
print("Operasi dibatalkan.")
return None
is_valid, result_or_err = validator_fn(raw)
if is_valid:
return result_or_err
print(f"Input salah: {result_or_err}")
except (KeyboardInterrupt, EOFError):
print("\nOperasi dibatalkan.")
return None
def handle_add(book: ContactBook) -> None:
print("\n--- Tambah Kontak Baru ---")
name = prompt_input("Nama", validate_name)
if not name:
return
phone = prompt_input("Nomor Telepon", validate_phone)
if not phone:
return
email = prompt_input("Email", validate_email)
if not email:
return
success, msg = book.add_contact(name, phone, email)
print(f"Hasil: {msg}")
def handle_delete(book: ContactBook) -> None:
print("\n--- Hapus Kontak ---")
name = prompt_input("Nama kontak yang akan dihapus", validate_name)
if not name:
return
success, msg = book.delete_contact(name)
print(f"Hasil: {msg}")
def handle_search(book: ContactBook) -> None:
print("\n--- Cari Kontak ---")
query = input(
"Masukkan nama atau email yang dicari: "
).strip()
if not query:
print("Pencarian dibatalkan (kata kunci kosong).")
return
# 1. Coba pencarian cepat O(1) via hash table
exact_match = book.search_exact(query)
if exact_match:
print("\n[Ditemukan - Cocok Tepat]")
print(exact_match)
return
# 2. Fallback pencarian parsial jika exact match tidak ditemukan
partial_matches = book.search_partial(query)
if partial_matches:
print(f"\n[Ditemukan {len(partial_matches)} kontak serupa]")
for idx, contact in enumerate(partial_matches, start=1):
print(f"{idx}. {contact}")
else:
print("Kontak tidak ditemukan.")
def handle_display_all(book: ContactBook) -> None:
print("\n--- Daftar Semua Kontak (Terurut Alfabetis) ---")
contacts = book.get_all_sorted()
if not contacts:
print("Belum ada kontak yang tersimpan.")
return
print("-" * 65)
for idx, contact in enumerate(contacts, start=1):
print(f"{idx:>2}. {contact}")
print("-" * 65)
print(f"Total: {len(contacts)} kontak.")
def main() -> None:
book = ContactBook()
# Data awal untuk demonstrasi
book.add_contact("Budi Santoso", "081234567890", "[email protected]")
book.add_contact("Ahmad Fauzi", "+628198765432", "[email protected]")
book.add_contact("Citra Dewi", "085611223344", "[email protected]")
menu = """
=================================
MANAJEMEN BUKU KONTAK
=================================
1. Tambah Kontak
2. Hapus Kontak (Berdasarkan Nama)
3. Cari Kontak (Nama / Email)
4. Tampilkan Semua Kontak
5. Keluar
"""
while True:
try:
print(menu)
choice = input("Pilih menu (1-5): ").strip()
if choice == "1":
handle_add(book)
elif choice == "2":
handle_delete(book)
elif choice == "3":
handle_search(book)
elif choice == "4":
handle_display_all(book)
elif choice == "5":
print("Aplikasi ditutup. Sampai jumpa!")
break
else:
print("Pilihan tidak valid. Silakan masukkan angka 1 sampai 5.")
except (KeyboardInterrupt, EOFError):
print("\nProgram dihentikan pengguna.")
break
if __name__ == "__main__":
main()
Bagian 3 :
Anda diminta membuat fungsi fetch_user_data(user_id) yang menerima input user_id (string) dan mengembalikan data pengguna dari database simulasi (dictionary). Namun, Anda harus memastikan fungsi tersebut aman dari SQL injection jika nantinya dihubungkan ke database SQL.
Tulis fungsi dengan menggunakan parameterized query (meskipun simulasi dictionary, tunjukkan bagaimana Anda akan menulis query SQL dengan aman).
Jelaskan apa itu SQL injection, bagaimana serangannya bekerja, dan bagaimana pencegahan yang Anda terapkan.
Berikan contoh kode yang rentan dan versi amannya.
Jawabannya :
1. Konsep SQL Injection dan Mekanisme Serangan
Apa itu SQL Injection?
SQL Injection (SQLi) adalah kerentanan keamanan web yang terjadi saat data masukan (untrusted input) dari pengguna digabungkan langsung ke dalam pernyataan SQL tanpa pemisahan antara kode instruksi dan data. Akibatnya, mesin basis data salah menafsirkan input pengguna sebagai bagian dari perintah sintaks SQL.
Bagaimana Serangan Bekerja?
Ketika aplikasi memakai interpolasi string (seperti f-string atau konkatenasi +), penyerang dapat menyisipkan karakter kontrol SQL (seperti tanda petik tunggal ', titik koma ;, atau tanda komentar --) untuk mengubah Abstract Syntax Tree (AST) dari query yang dieksekusi mesin database.
Contoh skenario:
Query di sisi server:
query = f"SELECT * FROM users WHERE user_id = '{user_id}'"
Jika penyerang mengirimkan nilai user_id berupa:
' OR '1'='1
Query yang terbentuk menjadi:
SELECT * FROM users WHERE user_id = '' OR '1'='1'
Kondisi '1'='1' selalu bernilai true. Mesin SQL akan mengabaikan filter akun dan mengembalikan seluruh baris data di tabel pengguna (data breach).
2. Mekanisme Pencegahan: Parameterized Query
Parameterized Query (atau Prepared Statement) memisahkan siklus hidup query menjadi dua fase terpisah:
- Kompilasi Struktur (Pre-compilation): Kerangka query SQL dikirim ke mesin database dengan tanda penampung (placeholder, misalnya
?atau:param). Mesin menyusun dan mengunci execution plan serta struktur sintaksnya terlebih dahulu. - Pengikatan Nilai (Value Binding): Nilai dari parameter pengguna dikirim secara terpisah melalui protokol biner.
Mesin basis data memperlakukan input pengguna murni sebagai nilai literal (tipe data string/integer), bukan token instruksi SQL yang dapat dieksekusi. Jika penyerang memasukkan ' OR '1'='1, database hanya akan mencari pengguna yang kolom user_id-nya secara harfiah bertuliskan teks " ' OR '1'='1 ".
3. Perbandingan Kode: Rentan vs. Aman
Kode Rentan (Vulnerable)
# SANGAT BERBAHAYA: Menggunakan f-string (String Interpolation)
def fetch_user_vulnerable(cursor, user_id: str):
sql = f"SELECT id, name, email FROM users WHERE id = '{user_id}'"
cursor.execute(sql)
return cursor.fetchone()
# Input eksploitasi:
# user_id = "1' OR '1'='1" -> Membocorkan data pengguna lain
# user_id = "1'; DROP TABLE users; --" -> Merusak database
Kode Aman (Secure – Parameterized Query)
# AMAN: Memisahkan template query dan tuple parameter
def fetch_user_secure(cursor, user_id: str):
sql = "SELECT id, name, email FROM users WHERE id = ?"
# Parameter dikirim sebagai tuple pada argumen kedua cursor.execute
cursor.execute(sql, (user_id,))
return cursor.fetchone()
4. Implementasi fetch_user_data
Program di bawah ini menggunakan modul bawaan sqlite3 dengan basis data in-memory (:memory:) yang diinisialisasi dari struktur dictionary. Pendekatan ini memenuhi kebutuhan simulasi data lokal sekaligus mendemonstrasikan implementasi parameterized query produksi secara nyata.
import sqlite3
from typing import Any, Dict, Optional
# Simulasi database awal berbasis dictionary/in-memory
MOCK_USER_STORE: Dict[str, Dict[str, Any]] = {
"usr_001": {
"id": "usr_001",
"name": "Budi Santoso",
"email": "[email protected]",
"role": "admin",
},
"usr_002": {
"id": "usr_002",
"name": "Siti Rahma",
"email": "[email protected]",
"role": "user",
},
}
class DatabaseConnection:
"""Mengelola koneksi in-memory SQLite yang disimulasikan dari data dictionary."""
def __init__(self, seed_data: Dict[str, Dict[str, Any]]) -> None:
self.conn = sqlite3.connect(":memory:")
self.conn.row_factory = sqlite3.Row # Mengembalikan baris seperti dict
self._bootstrap(seed_data)
def _bootstrap(self, seed_data: Dict[str, Dict[str, Any]]) -> None:
with self.conn:
self.conn.execute(
"""
CREATE TABLE users (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL,
role TEXT NOT NULL
)
"""
)
insert_query = (
"INSERT INTO users (id, name, email, role) VALUES (?, ?, ?, ?)"
)
for user in seed_data.values():
self.conn.execute(
insert_query,
(user["id"], user["name"], user["email"], user["role"]),
)
def get_cursor(self) -> sqlite3.Cursor:
return self.conn.cursor()
# Inisialisasi koneksi simulasi database
db = DatabaseConnection(MOCK_USER_STORE)
def fetch_user_data(user_id: str) -> Optional[Dict[str, Any]]:
"""Mengambil data profil pengguna berdasarkan user_id secara aman.
Args:
user_id: ID unik pengguna yang dicari (input mentah dari luar).
Returns:
Dictionary berisi data pengguna jika ditemukan, atau None jika tidak ditemukan.
"""
# 1. Definisikan query dengan placeholder parameter ('?')
# Hindari string formatting (%, .format(), f-string) di dalam query ini
query = """
SELECT id, name, email, role
FROM users
WHERE id = ?
"""
cursor = db.get_cursor()
# 2. Eksekusi query dengan parameter binding.
# Driver database akan mem-binding nilai user_id secara aman sebagai literal data.
cursor.execute(query, (user_id,))
row = cursor.fetchone()
if not row:
return None
# Konversi sqlite3.Row menjadi native dictionary Python
return dict(row)
# ==========================================================
# Pengujian Keamanan (Security Verification)
# ==========================================================
if __name__ == "__main__":
# Skenario 1: Input valid normal
normal_result = fetch_user_data("usr_001")
print("1. Pencarian Valid:")
print(normal_result)
# Output: {'id': 'usr_001', 'name': 'Budi Santoso', ...}
# Skenario 2: Upaya serangan SQL Injection klasik (' OR '1'='1)
malicious_input_1 = "' OR '1'='1"
attack_result_1 = fetch_user_data(malicious_input_1)
print("\n2. Upaya SQLi (' OR '1'='1):")
print(
f"Hasil: {attack_result_1} (Aman: Database tidak mengembalikan data apa pun)"
)
# Skenario 3: Upaya serangan union-based / comment injection
malicious_input_2 = "usr_001' UNION SELECT 'hacked', 'hacked', 'hacked', 'hacked' --"
attack_result_2 = fetch_user_data(malicious_input_2)
print("\n3. Upaya SQLi (UNION Attack):")
print(
f"Hasil: {attack_result_2} (Aman: Input ditolak karena dicocokkan sebagai teks ID utuh)"
)
Catatan Praktik Pertahanan Berlapis (Defense in Depth)
Selain parameterized query, standar industri merekomendasikan:
- Validasi Input (Input Whitelisting/Format Check): Memastikan
user_idsesuai format yang diizinkan (misalnya hanya karakter alfanumerik^[a-zA-Z0-9_-]+$) sebelum query dikirim ke database. - Prinsip Hak Akses Terkecil (Principle of Least Privilege): Kredensial database yang digunakan aplikasi web tidak boleh memiliki hak akses administratif (root/superuser) atau izin DDL (
DROP,ALTER).
Bagian 4 :
Jelaskan perbedaan antara stack dan queue, serta berikan contoh nyata penggunaannya dalam aplikasi sehari-hari. Tulis penjelasan dalam 3–4 paragraf singkat, lalu buat implementasi sederhana keduanya dalam bahasa pemrograman pilihan Anda (boleh pseudocode).
Perbedaan Konseptual dan Contoh Penggunaan
Perbedaan mendasar antara stack (tumpukan) dan queue (antrean) terletak pada aturan urutan pemrosesan elemen. Stack beroperasi dengan prinsip LIFO (Last-In, First-Out), di mana elemen yang terakhir kali ditambahkan akan menjadi elemen pertama yang diambil. Seluruh operasi penambahan dan penghapusan dilakukan secara eksklusif pada satu ujung saja (top). Sebaliknya, queue mengadopsi prinsip FIFO (First-In, First-Out), di mana elemen yang pertama kali masuk akan diproses lebih dulu melalui dua titik ujung yang berbeda: penambahan dilakukan di ujung belakang (rear/tail) dan pengambilan dilakukan di ujung depan (front/head).
Dalam aplikasi perangkat lunak sehari-hari, stack menjadi fondasi utama fitur Undo/Redo pada pengolah kata (seperti VS Code atau Google Docs). Setiap perubahan teks disimpan ke puncak stack, dan pintasan Ctrl+Z akan mengambil (pop) aksi terakhir untuk mengembalikan dokumen ke status sebelumnya. Konsep serupa digunakan pada riwayat navigasi peramban web (tombol Back), evaluasi ekspresi aritmetika, serta pelacakan alur eksekusi fungsi (call stack) pada memori sistem saat menangani pemanggilan rekursif.
Sementara itu, queue banyak diterapkan pada skenario penjadwalan (scheduling) dan penanganan sistem asinkron yang menuntut keadilan urutan waktu (fairness). Contoh nyatanya adalah sistem antrean dokumen pada mesin cetak (printer spooler), di mana dokumen yang dikirim lebih dulu akan dicetak lebih awal. Queue juga menjadi arsitektur inti dari message broker (seperti RabbitMQ atau Apache Kafka), antrean pemrosesan tugas latar belakang (background task workers), serta buffer pemutaran video/audio streaming untuk menjaga aliran data tetap konsisten.
Secara efisiensi komputasi, kedua struktur data ini menawarkan kompleksitas waktu $\mathcal{O}(1)$ untuk operasi penambahan dan penghapusan elemen. Perbedaannya, implementasi queue memerlukan pemilihan struktur memori yang tepat (seperti doubly-linked list atau ring buffer) agar operasi pengambilan di posisi awal tidak memicu pergeseran indeks array (shifting) yang memakan biaya komputasi $\mathcal{O}(N)$.
Implementasi Sederhana dalam Python
from collections import deque
from typing import Any, Generic, List, Optional, TypeVar
T = TypeVar("T")
class Stack(Generic[T]):
"""Implementasi Stack (LIFO) menggunakan dynamic array (list Python).
Seluruh operasi utama berjalan dalam kompleksitas waktu O(1).
"""
def __init__(self) -> None:
self._items: List[T] = []
def push(self, item: T) -> None:
"""Menambahkan elemen ke puncak stack."""
self._items.append(item)
def pop(self) -> T:
"""Mengambil dan menghapus elemen dari puncak stack."""
if self.is_empty():
raise IndexError("pop from empty stack")
return self._items.pop()
def peek(self) -> Optional[T]:
"""Melihat elemen di puncak stack tanpa menghapusnya."""
return self._items[-1] if not self.is_empty() else None
def is_empty(self) -> bool:
return len(self._items) == 0
def size(self) -> int:
return len(self._items)
def __repr__(self) -> str:
return f"Stack({self._items} <- TOP)"
class Queue(Generic[T]):
"""Implementasi Queue (FIFO) menggunakan collections.deque (doubly-linked list).
Menjamin operasi enqueue dan dequeue berjalan dalam kompleksitas waktu O(1).
"""
def __init__(self) -> None:
self._items: deque[T] = deque()
def enqueue(self, item: T) -> None:
"""Memasukkan elemen baru ke ujung belakang antrean."""
self._items.append(item)
def dequeue(self) -> T:
"""Mengambil dan menghapus elemen dari ujung depan antrean."""
if self.is_empty():
raise IndexError("dequeue from empty queue")
return self._items.popleft()
def peek(self) -> Optional[T]:
"""Melihat elemen terdepan antrean tanpa menghapusnya."""
return self._items[0] if not self.is_empty() else None
def is_empty(self) -> bool:
return len(self._items) == 0
def size(self) -> int:
return len(self._items)
def __repr__(self) -> str:
return f"Queue(FRONT -> {list(self._items)} <- REAR)"
# ==========================================================
# Demonstrasi Perilaku
# ==========================================================
if __name__ == "__main__":
# 1. Uji Coba Stack (LIFO: A -> B -> C | Keluar: C -> B -> A)
print("=== PENGUJIAN STACK ===")
stack = Stack[str]()
stack.push("Halaman A")
stack.push("Halaman B")
stack.push("Halaman C")
print(stack) # Output: Stack(['Halaman A', 'Halaman B', 'Halaman C'] <- TOP)
print(f"Pop: {stack.pop()}") # Halaman C
print(f"Pop: {stack.pop()}") # Halaman B
# 2. Uji Coba Queue (FIFO: Doc 1 -> Doc 2 -> Doc 3 | Keluar: Doc 1 -> Doc 2 -> Doc 3)
print("\n=== PENGUJIAN QUEUE ===")
queue = Queue[str]()
queue.enqueue("Dokumen 1")
queue.enqueue("Dokumen 2")
queue.enqueue("Dokumen 3")
print(
queue
) # Output: Queue(FRONT -> ['Dokumen 1', 'Dokumen 2', 'Dokumen 3'] <- REAR)
print(f"Dequeue: {queue.dequeue()}") # Dokumen 1
print(f"Dequeue: {queue.dequeue()}") # Dokumen 2
Uji Kemudahan Penggunaan dan Kecepatan/Efisiensi
Bagian A: Instruksi Sederhana dan Cepat
Apa ibu kota Indonesia? (Jawab maksimal 5 kata)
Sebutkan 3 manfaat olahraga. (Jawab maksimal 15 kata)
Ubah kalimat ini menjadi kalimat pasif: “Tim developer memperbaiki bug.” (Jawab satu kalimat)
Bagian B: Ringkasan Cepat
Baca paragraf berikut dan ringkas menjadi satu kalimat (maksimal 20 kata):
“Perkembangan kecerdasan buatan dalam satu dekade terakhir telah memicu perubahan besar di berbagai sektor industri, mulai dari manufaktur hingga layanan kesehatan. Meskipun membawa efisiensi dan inovasi, adopsi AI juga menimbulkan kekhawatiran tentang penggantian tenaga kerja manusia dan masalah privasi data. Oleh karena itu, regulasi yang seimbang diperlukan untuk memastikan manfaat AI dapat dirasakan secara luas tanpa mengorbankan hak-hak fundamental.”
Bagian C: Mengikuti Format Ketat
Buat daftar 4 langkah membuat kopi instan. Gunakan format berikut:
text
- [langkah 1]
- [langkah 2]
- [langkah 3]
- [langkah 4]
Jangan tambahkan kalimat lain di luar daftar.
Bagian D: Respons Cepat dalam Batasan
Jelaskan apa itu cloud computing dalam maksimal 30 kata, menggunakan bahasa yang mudah dipahami oleh orang non-teknis.
Bagian E: Konsistensi dan Efisiensi Token
Saya akan bertanya dua kali. Jawab dengan sama persis pada kedua pertanyaan (tidak menambah atau mengurangi).
Pertanyaan 1: “Sebutkan 2 bahasa pemrograman yang paling populer untuk web development.”
Pertanyaan 2 (setelah Anda menjawab pertanyaan 1): ulangi jawaban Anda.
Bagian F: Interaksi Multi-Turn
Saya akan memberikan dua instruksi berurutan. Ikuti keduanya dengan tepat.
Tulis kalimat: “Hari ini cuaca cerah.”
Sekarang ubah kalimat tersebut menjadi pertanyaan ya/tidak. Jawab hanya pertanyaannya saja.
Format jawaban: Cantumkan label bagian (A, B, C, D, E, F) dan langsung tulis jawaban tanpa penjelasan tambahan.
Jawaban nya :
Bagian A
- Ibu kota Indonesia adalah Nusantara.
- Meningkatkan kebugaran tubuh, menjaga kesehatan jantung, dan mengurangi stres.
- Bug diperbaiki oleh tim developer.
Bagian B
Regulasi seimbang diperlukan agar perkembangan AI bermanfaat luas tanpa mengorbankan hak fundamental, tenaga kerja, dan privasi data.
Bagian C
- Masukkan bubuk kopi instan ke dalam cangkir.
- Tuangkan air panas ke dalam cangkir.
- Aduk hingga kopi larut merata.
- Kopi instan siap untuk dinikmati.
Bagian D
Cloud computing adalah teknologi untuk menyimpan data dan menjalankan program melalui internet, sehingga bisa diakses kapan saja dan di mana saja tanpa memenuhi memori perangkat Anda.
Bagian E
Pertanyaan 1: JavaScript dan Python.
Pertanyaan 2: JavaScript dan Python.
Bagian F
Hari ini cuaca cerah.
Apakah hari ini cuaca cerah?
Pengujian GPT 6-astra
Penalaram Kompleks
Bagian 1 :
Anda adalah kandidat dalam ujian kemampuan AI. Selesaikan seluruh tugas berikut dengan cermat dan tunjukkan proses berpikir Anda.
Tugas 1: Penalaran Matematis Multi-Langkah
Sebuah kereta api berangkat dari Kota A menuju Kota B pukul 08:00 dengan kecepatan rata-rata 80 km/jam. Pada saat yang sama, kereta kedua berangkat dari Kota B menuju Kota A dengan kecepatan 100 km/jam. Jarak Kota A ke Kota B adalah 360 km. Namun, setelah 1 jam perjalanan, kereta pertama berhenti selama 20 menit karena sinyal, lalu melanjutkan perjalanan dengan kecepatan 90 km/jam. Kereta kedua tidak berhenti tetapi setelah 1,5 jam perjalanan mengurangi kecepatan menjadi 80 km/jam karena hujan.
- Pada pukul berapa kedua kereta berpapasan?
- Berapa jarak yang telah ditempuh masing-masing kereta saat berpapasan?
- Jika kereta pertama tidak berhenti, pada pukul berapa mereka berpapasan dan berapa selisih waktunya dengan skenario awal?
Tunjukkan semua langkah perhitungan, jelaskan asumsi yang Anda gunakan, dan verifikasi jawaban Anda dengan metode alternatif.
Tugas 2: Logika Proposisional
Diberikan pernyataan: “Jika hujan turun, maka jalan basah. Jalan tidak basah.”
Apakah kesimpulan yang valid? Jelaskan menggunakan aturan inferensi (modus tollens, dll).
Kemudian berikan satu contoh situasi dunia nyata di mana premis pertama bisa salah, dan jelaskan mengapa.
Tugas 3: Pola dan Deret
Deret angka: 2, 6, 12, 20, 30, …
- Tentukan rumus suku ke-n.
- Hitung suku ke-10.
- Jelaskan pola secara verbal dan buktikan dengan induksi matematika untuk rumus tersebut.
Format jawaban: Jawaban di buat/dimasukan dalam Gambar untuk saya tempelkan di artikel wordpress.
Jawaban nya :



Bagian 2 :
Anda adalah peserta uji kreativitas dan kecerdasan emosional. Lakukan tiga tugas berikut secara terpisah.
Tugas 1: Menulis Kreatif dengan Batasan Ketat
Tulis sebuah cerita pendek (250–350 kata) bergenre fiksi ilmiah yang menggambarkan pertemuan pertama manusia dengan makhluk cerdas non-karbon. Cerita harus:
- Menggunakan sudut pandang orang pertama.
- Mengandung setidaknya dua metafora orisinal.
- Menyertakan dialog singkat antara tokoh utama dan makhluk tersebut.
- Memiliki akhir yang ambigu (menggantung).
- Tidak boleh menggunakan kata “alien”, “robot”, atau “planet”.
Tugas 2: Analisis Puisi
Berikut bait puisi:
“Di bawah langit yang retak, / kita menari tanpa irama, / memeluk bayang yang tak pulang, / dan berbisik pada hujan yang lupa jalan.”
Jelaskan:
(a) makna denotatif dan konotatif,
(b) suasana yang dibangun,
(c) dua kemungkinan interpretasi tema,
(d) efektivitas diksi “retak”, “tanpa irama”, “lupa jalan”.
Tugas 3: Respons Empatik
Anda adalah asisten virtual yang membantu pengguna bernama Rina, 27 tahun, yang baru saja kehilangan pekerjaan dan merasa tidak berharga. Ia menulis:
“Aku gagal total. Semua kerja kerasku sia-sia. Aku tidak tahu harus mulai dari mana. Apa gunanya aku bangun pagi?”
Tulis respons empatik yang:
- Memvalidasi perasaannya tanpa meremehkan.
- Menawarkan perspektif yang membangun tanpa memberi nasihat klise.
- Mengajukan dua pertanyaan reflektif untuk membantunya menemukan langkah kecil.
- Tidak melebihi 150 kata.
Format jawaban: Jawaban di buat/dimasukan dalam Gambar untuk saya tempelkan di artikel wordpress.
Jawaban nya :



Bagian 3 = Anda adalah analis kebijakan dan etika AI. Kerjakan seluruh tugas berikut dengan pendekatan analitis dan berbasis bukti.
Tugas 1: Evaluasi Klaim Ilmiah
Baca klaim berikut:
“Vaksin mRNA mengubah DNA manusia secara permanen dan menyebabkan peningkatan penyakit autoimun pada 30% penerima.”
Lakukan:
(a) Identifikasi jenis klaim (fakta/opini/konspirasi).
(b) Jelaskan dasar ilmiah cara kerja vaksin mRNA dan bantah atau dukung klaim tersebut dengan bukti.
(c) Identifikasi bias atau logical fallacy dalam klaim.
(d) Jelaskan dampak sosial jika klaim ini menyebar luas.
Tugas 2: Analisis Teks Sejarah
Teks: “Revolusi Industri di Inggris pada abad ke-18 membawa kemakmuran bagi seluruh lapisan masyarakat dan tidak menimbulkan dampak negatif yang signifikan.”
Evaluasi pernyataan tersebut dengan menyebutkan:
- Bukti yang mendukung (minimal 2)
- Bukti yang melemahkan (minimal 2)
- Perspektif yang hilang
- Kesimpulan yang lebih berimbang
Tugas 3: Dilema Etika dan Rekomendasi
Sebuah rumah sakit di daerah terpencil memiliki satu ventilator tersisa. Ada dua pasien:
- Seorang ibu tunggal berusia 35 tahun dengan dua anak kecil; peluang hidup 60% dengan ventilator.
- Seorang peneliti medis berusia 60 tahun yang sedang mengembangkan obat langka; peluang hidup 40% dengan ventilator.
Tanpa ventilator, keduanya diperkirakan meninggal. Anda adalah komite etik. Tentukan:
- Kriteria yang relevan untuk alokasi sumber daya.
- Keputusan yang akan Anda ambil dan justifikasi etisnya (gunakan prinsip utilitarianisme, deontologi, atau etika keutamaan).
- Potensi keberatan terhadap keputusan Anda dan jawaban Anda terhadap keberatan tersebut.
Format: Jawaban di buat/dimasukan dalam Gambar untuk saya tempelkan di artikel wordpress.
Jawaban nya :




Coding Kompleks
Bagian 1 :
Anda adalah seorang software engineer senior yang sedang dievaluasi. Selesaikan seluruh tugas coding berikut. Gunakan bahasa pemrograman yang sesuai atau yang diminta pada tiap bagian. Tulis kode dengan komentar yang jelas, efisien, dan mengikuti praktik terbaik. Jika ada ambiguitas, nyatakan asumsi Anda.
Tugas 1: Algoritma dan Struktur Data
Buat sebuah fungsi dengan nama find_shortest_path yang menerima input berupa:
graph: representasi adjacency list berbobot (dictionary of list of tuple(neighbor, weight)).start: node awal (string atau integer).end: node tujuan.
Fungsi harus mengembalikan:
- List node yang membentuk jalur terpendek dari
startkeend. - Total bobot jalur tersebut.
Jika tidak ada jalur, kembalikanNone.
Implementasikan menggunakan algoritma Dijkstra dengan kompleksitas waktu O((V+E) log V). Sertakan penjelasan singkat tentang cara kerja algoritma Anda di atas fungsi.
Tugas 2: Debugging dan Optimasi
Berikut adalah potongan kode Python yang bermasalah. Kode ini seharusnya menghitung jumlah pasangan elemen dalam list nums yang jumlahnya sama dengan target. Namun ada bug dan tidak efisien.
def count_pairs(nums, target):
count = 0
for i in range(len(nums)):
for j in range(len(nums)):
if i != j and nums[i] + nums[j] == target:
count += 1
return count // 2 # ???
Jawaban nya :
Kedua tugas sudah selesai dalam Python dan seluruh 10 pengujian lulus, termasuk pembandingan pada 150 graf acak dan 250 input penghitung pasangan.
File siap dijalankan: [solusi.py](C:/Users/Lenovo/Documents/Codex/2026-09-09/coding-kompleks-bagian-1-anda-adalah/outputs/solusi.py) · [kode pengujian](C:/Users/Lenovo/Documents/Codex/2026-09-09/coding-kompleks-bagian-1-anda-adalah/outputs/test_solusi.py).
Tugas 1 — Jalur terpendek dengan Dijkstra
Asumsi yang digunakan:
- Graf berarah. Untuk graf tak berarah, cantumkan sisi pada kedua arah.
- Bobot berupa
intataufloat, nonnegatif, bukanNaNatau tak hingga. Penjumlahanfloatdiasumsikan tidak mengalami overflow. - Node dianggap ada jika muncul sebagai key atau tetangga.
- Jika node tidak ada atau tujuan tidak terjangkau, hasilnya
None. - Jika
start == enddan node tersebut ada, hasilnya([start], 0). - Jika beberapa jalur memiliki bobot minimum sama, fungsi mengembalikan salah satunya.
from heapq import heappop, heappush
from itertools import count
from math import isfinite
Node = str | int
Weight = int | float
# Dijkstra mengambil node dengan jarak sementara terkecil dari min-heap.
# Jarak tetangganya diperbarui jika ditemukan jalur yang lebih murah.
# Karena bobot nonnegatif, jarak pada entri minimum yang masih berlaku
# sudah optimal. Parent menyimpan pendahulu untuk merekonstruksi jalur.
# Sisi ganda diringkas agar lazy heap memenuhi O((V + E) log V).
def find_shortest_path(
graph: dict[Node, list[tuple[Node, Weight]]],
start: Node,
end: Node,
) -> tuple[list[Node], Weight] | None:
# Validasi seluruh bobot dan ringkas sisi ganda tanpa mengubah input.
adjacency: dict[Node, dict[Node, Weight]] = {}
nodes: set[Node] = set(graph)
for node, edges in graph.items():
neighbors: dict[Node, Weight] = {}
for neighbor, weight in edges:
if not isinstance(weight, (int, float)):
raise TypeError("Bobot harus berupa int atau float.")
if weight < 0 or (
isinstance(weight, float) and not isfinite(weight)
):
raise ValueError("Bobot harus nonnegatif dan finite.")
nodes.add(neighbor)
if neighbor not in neighbors or weight < neighbors[neighbor]:
neighbors[neighbor] = weight
adjacency[node] = neighbors
if start not in nodes or end not in nodes:
return None
distances: dict[Node, Weight] = {start: 0}
parent: dict[Node, Node] = {}
serial = count()
# Nomor unik mencegah perbandingan node int dengan str saat jarak seri.
heap: list[tuple[Weight, int, Node]] = [
(0, next(serial), start)
]
while heap:
distance, _, node = heappop(heap)
if distance != distances[node]:
continue # Entri lama sudah digantikan jarak yang lebih baik.
if node == end:
path = [end]
while path[-1] != start:
path.append(parent[path[-1]])
path.reverse()
return path, distance
for neighbor, weight in adjacency.get(node, {}).items():
candidate = distance + weight
if (
neighbor not in distances
or candidate < distances[neighbor]
):
distances[neighbor] = candidate
parent[neighbor] = node
heappush(heap, (candidate, next(serial), neighbor))
return None
Contoh penggunaan:
graph = {
"A": [("B", 4), ("C", 1)],
"B": [("D", 1)],
"C": [("B", 2), ("D", 5)],
"D": [],
}
print(find_shortest_path(graph, "A", "D"))
# (['A', 'C', 'B', 'D'], 4)
Cara membacanya: dari A, jarak sementara menuju B adalah 4 dan menuju C adalah 1. Algoritma memproses C terlebih dahulu, lalu menemukan bahwa menuju B melalui C hanya membutuhkan biaya 1 + 2 = 3. Dari B, tujuan D dicapai dengan total biaya 3 + 1 = 4.
Pengecekan entri lama diperlukan karena heapq tidak memperbarui prioritas secara langsung. Entri baru dimasukkan ketika jarak membaik; entri lama diabaikan saat dikeluarkan.
Kompleksitas: normalisasi membutuhkan O(V + E). Setelah sisi ganda diringkas, jumlah sisi efektif E′ maksimal V². Heap menyimpan O(E′ + 1) entri, sehingga biaya tiap operasi heap O(log V). Total waktunya O((V + E) log V) dan ruang tambahannya O(V + E), dengan asumsi operasi dictionary dan aritmetika berbiaya konstan.
Tugas 2 — Debugging dan optimasi count_pairs
Ada koreksi penting terhadap premis soal: kode awal tidak salah jika yang dihitung adalah pasangan indeks berbeda tanpa memperhatikan urutan.
Setiap pasangan valid diperiksa dua kali, yaitu (i, j) dan (j, i). Karena itu, count // 2 memang menghasilkan jawaban benar untuk definisi tersebut. Kekurangannya adalah pemeriksaan berulang dan waktu O(n²).
Aku menggunakan definisi pasangan i < j. Elemen duplikat tetap dihitung berdasarkan indeksnya. Contohnya, [3, 3, 3] dengan target 6 memiliki tiga pasangan: (0, 1), (0, 2), dan (1, 2).
from collections import defaultdict
def count_pairs(nums: list[int], target: int) -> int:
"""Hitung pasangan indeks i < j dengan nums[i] + nums[j] == target."""
frequencies: dict[int, int] = defaultdict(int)
total = 0
for number in nums:
# Setiap kemunculan komplemen sebelumnya membentuk satu pasangan.
complement = target - number
total += frequencies.get(complement, 0)
# Catat setelah menghitung agar elemen tidak berpasangan
# dengan dirinya sendiri.
frequencies[number] += 1
return total
Contoh:
print(count_pairs([1, 5, 7, -1, 5], 6)) # 3
print(count_pairs([3, 3, 3], 6)) # 3
print(count_pairs([3], 6)) # 0
print(count_pairs([], 6)) # 0
Untuk input [1, 5, 7, -1, 5]:
| Angka saat ini | Komplemen | Kemunculan komplemen sebelumnya | Total pasangan |
|---|---|---|---|
| 1 | 5 | 0 | 0 |
| 5 | 1 | 1 | 1 |
| 7 | -1 | 0 | 1 |
| -1 | 7 | 1 | 2 |
| 5 | 1 | 1 | 3 |
Setiap pasangan dihitung tepat saat elemen dengan indeks lebih besar diproses. Jadi, tidak perlu lagi membagi hasil dengan dua.
Kompleksitas: waktu rata-rata O(n) menggunakan hash map, dengan ruang O(k) untuk k angka berbeda. Implementasi ini mengasumsikan nums dan target berupa integer agar perbandingan jumlah bersifat eksak.
Bagian 2 :
Buat sebuah program sederhana dalam bahasa Python yang berfungsi sebagai sistem manajemen kontak dengan fitur:
Menambah kontak (nama, no mor telepon, email).
Menghapus kontak berdasarkan nama.
Mencari kontak berdasarkan nama atau email (case-insensitive).
Menampilkan semua kontak terurut berdasarkan nama.
Batasan tambahan:
Tidak boleh menggunakan library eksternal selain yang ada di standard library.
Gunakan struktur data yang efisien untuk pencarian cepat.
Program harus menangani input yang tidak valid (misal email tanpa ‘@’, nomor telepon bukan angka).
Sediakan antarmuka command-line sederhana (loop menu).
Tulis kode lengkap dengan komentar, dan jelaskan pilihan desain Anda.
Jawaban nya :
Program lengkap sudah dibuat dan 9 pengujian lulus, termasuk validasi input, pencarian, penghapusan, pengurutan, dan alur menu.
Unduh [manajemen_kontak.py](C:/Users/Lenovo/Documents/Codex/2026-09-09/coding-kompleks-bagian-1-anda-adalah/outputs/manajemen_kontak.py) dan [kode pengujiannya](C:/Users/Lenovo/Documents/Codex/2026-09-09/coding-kompleks-bagian-1-anda-adalah/outputs/test_manajemen_kontak.py).
Asumsi
- Nama harus unik tanpa membedakan huruf besar-kecil.
"Ani"dan"ANI"dianggap nama yang sama. - Email boleh digunakan oleh beberapa kontak.
- Pencarian menggunakan kecocokan lengkap, bukan potongan kata.
- Nomor telepon hanya menerima digit
0–9, sesuai batasan soal. - Data disimpan di memori selama program berjalan. Penyimpanan permanen belum termasuk cakupan tugas.
Kode lengkap — Python 3.10+
from dataclasses import dataclass
import re
def normalize(value: str) -> str:
"""Hilangkan spasi tepi dan samakan huruf untuk key pencarian."""
return value.strip().casefold()
@dataclass(frozen=True)
class Contact:
# Immutable agar perubahan dari luar tidak merusak indeks pencarian.
name: str
phone: str
email: str
class ContactManager:
def __init__(self) -> None:
self._by_name: dict[str, Contact] = {}
# Email boleh sama; set menyimpan key nama para pemiliknya.
self._by_email: dict[str, set[str]] = {}
def add_contact(
self,
name: str,
phone: str,
email: str,
) -> Contact:
if not all(
isinstance(value, str)
for value in (name, phone, email)
):
raise ValueError(
"Nama, nomor telepon, dan email harus berupa teks."
)
name = name.strip()
phone = phone.strip()
email = email.strip()
if not name or not name.isprintable():
raise ValueError(
"Nama wajib diisi dan tidak boleh berisi karakter kontrol."
)
# String mempertahankan nol di depan.
# Hanya digit ASCII 0 sampai 9 yang diterima.
if not phone or not phone.isascii() or not phone.isdecimal():
raise ValueError(
"Nomor telepon harus berisi angka 0-9 saja."
)
# Validasi dasar: satu @, kedua sisi terisi, tanpa spasi/kontrol.
if (
not email.isprintable()
or re.fullmatch(r"[^@\s]+@[^@\s]+", email) is None
):
raise ValueError(
"Email harus berbentuk pengguna@domain tanpa spasi."
)
name_key = normalize(name)
if name_key in self._by_name:
raise ValueError(
"Nama tersebut sudah terdaftar. "
"Gunakan nama yang berbeda."
)
# Semua validasi selesai sebelum mengubah kedua indeks.
contact = Contact(name, phone, email)
self._by_name[name_key] = contact
self._by_email.setdefault(
normalize(email), set()
).add(name_key)
return contact
def delete_contact(self, name: str) -> bool:
name_key = normalize(name)
contact = self._by_name.pop(name_key, None)
if contact is None:
return False
# Perbarui indeks email agar tidak menunjuk kontak yang dihapus.
email_key = normalize(contact.email)
owners = self._by_email[email_key]
owners.remove(name_key)
if not owners:
del self._by_email[email_key]
return True
def search_contacts(self, query: str) -> list[Contact]:
"""Cari nama ATAU email secara lengkap, case-insensitive."""
key = normalize(query)
matches = set(self._by_email.get(key, ()))
if key in self._by_name:
matches.add(key)
# Set mencegah hasil ganda jika nama dan email sama.
return [
self._by_name[name_key]
for name_key in sorted(matches)
]
def list_contacts(self) -> list[Contact]:
"""Urutkan berdasarkan nama tanpa membedakan kapital."""
return [
self._by_name[key]
for key in sorted(self._by_name)
]
def display_contacts(contacts: list[Contact]) -> None:
if not contacts:
print("Tidak ada kontak untuk ditampilkan.")
return
for number, contact in enumerate(contacts, start=1):
print(f"{number}. {contact.name}")
print(f" Telepon: {contact.phone}")
print(f" Email : {contact.email}")
def main() -> None:
manager = ContactManager()
print(
"Manajemen Kontak — data hanya disimpan "
"selama program berjalan."
)
try:
while True:
print(
"\n1. Tambah kontak"
"\n2. Hapus kontak"
"\n3. Cari kontak"
"\n4. Tampilkan semua kontak"
"\n0. Keluar"
)
choice = input("Pilih menu: ").strip()
if choice == "1":
name = input("Nama: ")
phone = input("Nomor telepon (angka saja): ")
email = input("Email: ")
try:
contact = manager.add_contact(name, phone, email)
print(
f"Kontak '{contact.name}' berhasil ditambahkan."
)
except ValueError as error:
print(f"Gagal menambah kontak: {error}")
elif choice == "2":
name = input(
"Nama lengkap kontak yang akan dihapus: "
).strip()
if not name:
print("Nama tidak boleh kosong.")
elif manager.delete_contact(name):
print("Kontak berhasil dihapus.")
else:
print("Kontak tidak ditemukan.")
elif choice == "3":
query = input("Nama lengkap atau email: ").strip()
if not query:
print("Kata pencarian tidak boleh kosong.")
else:
display_contacts(
manager.search_contacts(query)
)
elif choice == "4":
display_contacts(manager.list_contacts())
elif choice == "0":
print("Program selesai.")
break
else:
print(
"Pilihan tidak valid. Masukkan 0, 1, 2, 3, atau 4."
)
except (EOFError, KeyboardInterrupt):
# Akhir input atau Ctrl+C menghentikan program tanpa traceback.
print("\nProgram dihentikan.")
if __name__ == "__main__":
main()
Penjelasan pilihan desain
1. Dua dictionary untuk pencarian cepat
Bayangkan dictionary sebagai indeks buku: kita bisa langsung mencari sebuah key tanpa membaca seluruh kontak.
Struktur internalnya kurang lebih seperti ini:
_by_name = {
"ani": Contact("Ani", "08123456789", "[email protected]"),
"budi": Contact("Budi", "08987654321", "[email protected]"),
}
_by_email = {
"[email protected]": {"ani"},
"[email protected]": {"budi"},
}
_by_name digunakan untuk mencari kontak, memeriksa nama duplikat, dan menghapus kontak. _by_email memetakan email ke sekumpulan key nama agar satu email bisa dimiliki beberapa kontak.
Saat menghapus kontak, kedua indeks diperbarui. Jika hanya indeks nama yang dihapus, pencarian email masih bisa menunjuk kontak yang sudah tidak ada.
2. Normalisasi key, pertahankan tampilan asli
strip() menghilangkan spasi di awal dan akhir. casefold() menyamakan kapitalisasi dan mendukung pencocokan Unicode lebih menyeluruh daripada lower().
Nama " Ani " disimpan sebagai "Ani" untuk ditampilkan, sedangkan key pencariannya adalah "ani". Jadi, pengguna bisa mencarinya dengan "ANI" atau "ani".
3. Nomor telepon disimpan sebagai string
Nomor telepon adalah identitas, bukan nilai untuk perhitungan. Mengubah "08123" menjadi integer akan menghilangkan nol di depannya.
Gabungan isascii() dan isdecimal() memastikan input hanya berisi karakter 0–9. Input seperti "08abc", "+628123", dan "0812-3456" ditolak.
4. Validasi sebelum penyimpanan
Seluruh input diperiksa sebelum dictionary diubah. Akibatnya, email yang salah tidak meninggalkan kontak yang baru tersimpan sebagian.
Validasi email bersifat dasar: harus memiliki tepat satu @, bagian sebelum dan sesudahnya terisi, serta tidak mengandung spasi atau karakter kontrol. Validasi ini tidak mengecek apakah alamat tersebut aktif.
5. Logika kontak dipisahkan dari menu
ContactManager mengurus data, sedangkan main() mengurus interaksi terminal. Pemisahan ini memudahkan pengujian dan memungkinkan logika yang sama digunakan kembali jika nanti kamu membuat antarmuka web atau desktop.
Contact menggunakan frozen=True agar nama atau email tidak diubah langsung dari luar dan membuat indeks tidak konsisten.
Kompleksitas
Dengan n jumlah kontak dan k jumlah hasil pencarian:
| Operasi | Kompleksitas rata-rata |
|---|---|
| Menambah kontak | O(1) |
| Menghapus berdasarkan nama | O(1) |
| Mengakses indeks nama/email | O(1) |
| Mengambil dan mengurutkan hasil pencarian | O(k log k) |
| Menampilkan seluruh kontak secara terurut | O(n log n) |
| Penyimpanan data dan indeks | O(n) |
Tabel menganggap panjang masing-masing teks terbatas. Jika panjang input turut dihitung, validasi, normalisasi, dan hashing juga membutuhkan waktu sebanding dengan panjang teksnya.
Untuk menjalankan, buka terminal pada folder tempat file disimpan:
python manajemen_kontak.py
Bagian 3 :
Anda diminta membuat fungsi fetch_user_data(user_id) yang menerima input user_id (string) dan mengembalikan data pengguna dari database simulasi (dictionary). Namun, Anda harus memastikan fungsi tersebut aman dari SQL injection jika nantinya dihubungkan ke database SQL.
Tulis fungsi dengan menggunakan parameterized query (meskipun simulasi dictionary, tunjukkan bagaimana Anda akan menulis query SQL dengan aman).
Jelaskan apa itu SQL injection, bagaimana serangannya bekerja, dan bagaimana pencegahan yang Anda terapkan.
Berikan contoh kode yang rentan dan versi amannya.
Jawaabannya :
Implementasinya selesai dan 6 pengujian lulus, termasuk pembandingan fungsi rentan dengan fungsi aman pada SQLite lokal.
File lengkap: [data_pengguna.py](C:/Users/Lenovo/Documents/Codex/2026-09-09/coding-kompleks-bagian-1-anda-adalah/outputs/data_pengguna.py) · [kode pengujian](C:/Users/Lenovo/Documents/Codex/2026-09-09/coding-kompleks-bagian-1-anda-adalah/outputs/test_data_pengguna.py).
1. Implementasi simulasi dan versi SQL yang aman
Ada perbedaan penting: dictionary tidak mengeksekusi SQL, sehingga parameterized query tidak benar-benar dijalankan pada simulasi dictionary. Agar contohnya akurat, kita menyediakan fetch_user_data(user_id) untuk simulasi, lalu padanannya yang menjalankan parameterized query sungguhan menggunakan sqlite3.
Asumsi:
user_idharus string dan tidak boleh kosong atau hanya berisi spasi.- ID dicocokkan secara persis dan case-sensitive.
- Pengguna yang tidak ditemukan menghasilkan
None. - Kolom
user_idpada database SQL bersifat unik.
import sqlite3
from contextlib import closing
USERS = {
"u001": {
"user_id": "u001",
"name": "Ani",
"email": "[email protected]",
},
"u002": {
"user_id": "u002",
"name": "Budi",
"email": "[email protected]",
},
}
# Struktur SQL tetap; nilai input tidak dimasukkan ke string query.
SELECT_USER_SQL = (
"SELECT user_id, name, email FROM users WHERE user_id = ?"
)
def validate_user_id(user_id: str) -> None:
"""Validasi kontrak input, bukan perlindungan utama SQL injection."""
if not isinstance(user_id, str):
raise TypeError("user_id harus berupa string.")
if not user_id.strip():
raise ValueError("user_id tidak boleh kosong atau hanya spasi.")
def fetch_user_data(user_id: str) -> dict[str, str] | None:
"""Ambil data dari dictionary berdasarkan ID persis."""
validate_user_id(user_id)
# Dictionary memperlakukan input sebagai key, bukan perintah.
# Padanan SQL aman:
# connection.execute(SELECT_USER_SQL, (user_id,))
user = USERS.get(user_id)
# Salinan mencegah pemanggil mengubah data sumber secara langsung.
return user.copy() if user is not None else None
def fetch_user_data_sql(
connection: sqlite3.Connection,
user_id: str,
) -> dict[str, str] | None:
"""Ambil data menggunakan parameterized query SQLite."""
validate_user_id(user_id)
with closing(connection.cursor()) as cursor:
# Query dan parameter diberikan sebagai dua argumen terpisah.
cursor.execute(SELECT_USER_SQL, (user_id,))
row = cursor.fetchone()
if row is None:
return None
return {
"user_id": row[0],
"name": row[1],
"email": row[2],
}
Contoh pemanggilan simulasi:
print(fetch_user_data("u001"))
# {'user_id': 'u001', 'name': 'Ani', 'email': '[email protected]'}
print(fetch_user_data("unknown"))
# None
print(fetch_user_data("' OR 1=1 --"))
# None
Pencarian dictionary membutuhkan waktu rata-rata O(1), dengan asumsi panjang ID terbatas.
2. Apa itu SQL injection?
SQL injection terjadi ketika input pengguna digabungkan ke perintah SQL sehingga database dapat menafsirkannya sebagai kode SQL, bukan sekadar nilai pencarian. Penyerang kemudian dapat mengubah maksud query, misalnya membuat filter pengguna selalu benar. OWASP: SQL Injection Prevention.
Contoh berikut sengaja rentan untuk pembelajaran:
def fetch_users_unsafe(connection, user_id):
# RENTAN: input langsung menjadi bagian dari struktur SQL.
query = (
"SELECT user_id, name, email FROM users "
f"WHERE user_id = '{user_id}'"
)
with closing(connection.cursor()) as cursor:
cursor.execute(query)
return cursor.fetchall()
Jika inputnya "u001", query terlihat normal:
SELECT user_id, name, email FROM users WHERE user_id = 'u001'
Namun, jika inputnya:
' OR 1=1 --
Query berubah menjadi:
SELECT user_id, name, email FROM users WHERE user_id = '' OR 1=1 --'
Pada contoh SQLite ini:
- Tanda
'pertama menutup nilai string yang dibuat aplikasi. OR 1=1menambahkan kondisi yang selalu benar.--menjadikan sisa baris sebagai komentar, termasuk tanda kutip penutup.
Akibatnya, filter cocok dengan seluruh baris. Dalam pengujian lokal, fungsi rentan mengembalikan kedua pengguna meskipun input tersebut bukan ID mereka.
Jika fungsi rentan memakai fetchone(), hasil yang dikembalikan memang hanya satu baris, tetapi kerentanannya tetap ada: filter ID sudah berhasil diubah.
3. Mengapa parameterized query aman untuk kasus ini?
Versi amannya:
cursor.execute(
"SELECT user_id, name, email FROM users WHERE user_id = ?",
(user_id,),
)
Struktur SQL ditulis terlebih dahulu, sedangkan nilai user_id diberikan melalui parameter terpisah. Driver memperlakukan nilai tersebut sebagai data, sehingga isi seperti ' OR 1=1 -- tidak mengubah struktur query. Ini adalah pola yang dianjurkan dokumentasi Python untuk mencegah SQL injection. Dokumentasi sqlite3: parameter binding.
Artinya, database mencari ID yang secara literal bernilai:
' OR 1=1 --
Jika ID itu tidak ada, hasilnya None. Jika memang ada baris dengan ID persis tersebut, hanya baris itulah yang ditemukan—dan ini juga sudah diuji.
Dua detail Python yang perlu diperhatikan:
(user_id,) # Tuple satu elemen: benar untuk parameter posisi.
(user_id) # Tetap string, bukan tuple.
Placeholder juga tidak perlu diberi tanda kutip:
"WHERE user_id = ?" # Benar: placeholder parameter.
"WHERE user_id = '?'" # Salah: mencari string literal '?'.
4. Pencegahan yang diterapkan
- Parameter binding memisahkan nilai input dari struktur SQL.
- Nama tabel dan kolom tetap, sehingga tidak berasal dari input pengguna. Placeholder digunakan untuk nilai; identifier dinamis seperti nama tabel memerlukan allowlist jika dibutuhkan.
- Validasi tipe dan input kosong menjaga kontrak fungsi. Validasi ini melengkapi parameter binding, bukan menggantikannya.
- Tidak menghapus tanda kutip atau memblokir kata SQL secara manual. Input yang mengandung apostrof tetap dapat diproses sebagai nilai literal. OWASP mengutamakan parameterized query dibanding mengandalkan escaping manual. OWASP: pertahanan terhadap SQL injection.
Perlindungan ini menangani SQL injection pada query tersebut. Hak pengguna untuk membaca data milik orang lain tetap perlu ditentukan melalui pemeriksaan otorisasi aplikasi.
Bagian 4 :
Jelaskan perbedaan antara stack dan queue, serta berikan contoh nyata penggunaannya dalam aplikasi sehari-hari. Tulis penjelasan dalam 3–4 paragraf singkat, lalu buat implementasi sederhana keduanya dalam bahasa pemrograman pilihan Anda (boleh pseudocode).
Jawabannya :
Stack adalah struktur data dengan prinsip LIFO (Last In, First Out): elemen yang terakhir masuk akan keluar terlebih dahulu. Bayangkan tumpukan piring—piring yang terakhir diletakkan di atas biasanya diambil pertama. Operasi utamanya adalah push untuk menambah elemen, pop untuk mengambil sekaligus menghapus elemen teratas, dan peek untuk melihatnya tanpa menghapus.
Contoh penggunaan stack adalah fitur Undo pada editor teks. Setiap perubahan disimpan sebagai riwayat tindakan. Ketika pengguna menekan Undo, aplikasi membatalkan tindakan paling baru terlebih dahulu. Fitur Redo dapat dibuat menggunakan stack kedua untuk menyimpan tindakan yang telah dibatalkan.
Queue menggunakan prinsip FIFO (First In, First Out): elemen yang pertama masuk akan keluar terlebih dahulu. Bentuknya seperti antrean kasir. Operasi utamanya adalah enqueue untuk menambah elemen di belakang, dequeue untuk mengambil sekaligus menghapus elemen paling depan, dan peek untuk melihat elemen depan tanpa menghapusnya.
Contoh queue adalah antrean dokumen pada aplikasi pencetakan: dalam sistem tanpa prioritas khusus, dokumen yang masuk lebih awal diproses lebih dahulu. Jadi, pilih stack ketika aplikasi perlu memproses elemen terbaru terlebih dahulu, dan queue ketika aplikasi perlu mempertahankan urutan kedatangan.
Implementasi Python
Stack menggunakan list, sedangkan queue menggunakan collections.deque dari standard library. Asumsinya, mengambil atau melihat elemen pada struktur kosong akan menghasilkan IndexError.
from collections import deque
class Stack:
"""LIFO: elemen terakhir masuk menjadi yang pertama keluar."""
def __init__(self):
self._items = []
def push(self, item):
# Ujung list menjadi bagian teratas stack.
self._items.append(item)
def pop(self):
if self.is_empty():
raise IndexError("Tidak bisa mengambil elemen: stack kosong.")
return self._items.pop()
def peek(self):
if self.is_empty():
raise IndexError("Tidak bisa melihat elemen: stack kosong.")
return self._items[-1]
def is_empty(self):
return len(self._items) == 0
def __len__(self):
return len(self._items)
class Queue:
"""FIFO: elemen pertama masuk menjadi yang pertama keluar."""
def __init__(self):
self._items = deque()
def enqueue(self, item):
# Elemen baru masuk melalui belakang antrean.
self._items.append(item)
def dequeue(self):
if self.is_empty():
raise IndexError("Tidak bisa mengambil elemen: queue kosong.")
# Ambil dari depan tanpa menggeser seluruh elemen lainnya.
return self._items.popleft()
def peek(self):
if self.is_empty():
raise IndexError("Tidak bisa melihat elemen: queue kosong.")
return self._items[0]
def is_empty(self):
return len(self._items) == 0
def __len__(self):
return len(self._items)
if __name__ == "__main__":
stack = Stack()
queue = Queue()
# Urutan masuk sama untuk kedua struktur.
for item in ["A", "B", "C"]:
stack.push(item)
queue.enqueue(item)
print("Teratas stack:", stack.peek()) # C
print("Terdepan queue:", queue.peek()) # A
print("Stack:", [stack.pop() for _ in range(3)])
# Stack: ['C', 'B', 'A']
print("Queue:", [queue.dequeue() for _ in range(3)])
# Queue: ['A', 'B', 'C']
try:
queue.dequeue()
except IndexError as error:
print(error)
# Tidak bisa mengambil elemen: queue kosong.
Kompleksitas: push dan pop pada stack memiliki biaya O(1) secara amortisasi. enqueue dan dequeue dengan deque berbiaya O(1); peek, pengecekan kosong, dan pengambilan panjang juga O(1). Keduanya menggunakan ruang O(n).
Uji Kemudahan Penggunaan dan Kecepatan/Efisiensi
Bagian A: Instruksi Sederhana dan Cepat
Apa ibu kota Indonesia? (Jawab maksimal 5 kata)
Sebutkan 3 manfaat olahraga. (Jawab maksimal 15 kata)
Ubah kalimat ini menjadi kalimat pasif: “Tim developer memperbaiki bug.” (Jawab satu kalimat)
Bagian B: Ringkasan Cepat
Baca paragraf berikut dan ringkas menjadi satu kalimat (maksimal 20 kata):
“Perkembangan kecerdasan buatan dalam satu dekade terakhir telah memicu perubahan besar di berbagai sektor industri, mulai dari manufaktur hingga layanan kesehatan. Meskipun membawa efisiensi dan inovasi, adopsi AI juga menimbulkan kekhawatiran tentang penggantian tenaga kerja manusia dan masalah privasi data. Oleh karena itu, regulasi yang seimbang diperlukan untuk memastikan manfaat AI dapat dirasakan secara luas tanpa mengorbankan hak-hak fundamental.”
Bagian C: Mengikuti Format Ketat
Buat daftar 4 langkah membuat kopi instan. Gunakan format berikut:
text
- [langkah 1]
- [langkah 2]
- [langkah 3]
- [langkah 4]
Jangan tambahkan kalimat lain di luar daftar.
Bagian D: Respons Cepat dalam Batasan
Jelaskan apa itu cloud computing dalam maksimal 30 kata, menggunakan bahasa yang mudah dipahami oleh orang non-teknis.
Bagian E: Konsistensi dan Efisiensi Token
Saya akan bertanya dua kali. Jawab dengan sama persis pada kedua pertanyaan (tidak menambah atau mengurangi).
Pertanyaan 1: “Sebutkan 2 bahasa pemrograman yang paling populer untuk web development.”
Pertanyaan 2 (setelah Anda menjawab pertanyaan 1): ulangi jawaban Anda.
Bagian F: Interaksi Multi-Turn
Saya akan memberikan dua instruksi berurutan. Ikuti keduanya dengan tepat.
Tulis kalimat: “Hari ini cuaca cerah.”
Sekarang ubah kalimat tersebut menjadi pertanyaan ya/tidak. Jawab hanya pertanyaannya saja.
Format jawaban: Cantumkan label bagian (A, B, C, D, E, F) dan langsung tulis jawaban tanpa penjelasan tambahan.
Jawabannya :
A
- Jakarta.
- Menyehatkan jantung, memperkuat otot, dan mengurangi stres.
- Bug diperbaiki oleh tim developer.
B
AI meningkatkan efisiensi dan inovasi, tetapi memerlukan regulasi seimbang untuk melindungi tenaga kerja, privasi data, dan hak fundamental.
C
- Masukkan kopi instan ke dalam cangkir.
- Panaskan air hingga mendidih.
- Tuangkan air panas ke dalam cangkir.
- Aduk hingga larut dan sajikan.
D
Cloud computing adalah penggunaan layanan komputer melalui internet untuk menyimpan data dan menjalankan aplikasi tanpa harus memiliki atau mengurus komputer server sendiri.
E
JavaScript dan Python.
JavaScript dan Python.
F
Apakah hari ini cuaca cerah?
Jadi mana yang Terbaik ?
Kelebihan GPT-6 Astra
- Penalaran Kritis dan Logika: Unggul telak dalam uji coba pola baru dan penalaran tingkat lanjut (mencapai skor 99,9% pada ARC-AGI-3).
- Tugas Kompleks End-to-End: Lebih optimal dalam menyelesaikan alur kerja yang panjang dan rumit secara mandiri.
- Performa Pengembang: Sedikit unggul tipis dalam uji pengembang software (seperti DeepSWE v1.1) dengan skor sekitar 74,1% berbanding 73,7%.
Kelebihan Gemini 3.8
- Pemahaman Video Asli (Native Video Input): Gemini 3.8 Flash mendukung input video secara langsung untuk dianalisis isinya, sementara GPT-6 Astra belum mendukung kemampuan ini secara native.
- Efisiensi Harga: Gemini 3.8 Flash menawarkan biaya penggunaan yang jauh lebih murah (bisa belasan kali lipat lebih ekonomis) dibandingkan Astra.
- Kapasitas Konteks: Gemini CLI memiliki jendela konteks yang sangat panjang, membuatnya lebih unggul untuk pemrosesan teks atau file masif sekaligus.
Kesimpulan secara objektifnya: GPT‑6 Astra lebih unggul pada sejumlah pengujian kemampuan kompleks, sedangkan Gemini 3.8 Flash lebih menarik untuk efisiensi biaya, kecepatan, dan variasi input. Tidak ada yang menang untuk semua kebutuhan.
Saya membandingkan GPT‑6 Astra dengan Gemini 3.8 Flash, varian umum yang tersedia, berdasarkan sumber yang kuakses 9 September 2026. Gemini 3.8 Flash Cyber merupakan varian khusus dengan akses terbatas. Ini analisis dokumentasi dan pengujian pihak ketiga, bukan hasil eksperimen langsung yang kulakukan sendiri. Pengumuman Google.
| Aspek | GPT‑6 Astra | Gemini 3.8 Flash | Penilaian |
|---|---|---|---|
| Kemampuan gabungan, AA Intelligence Index v4.3 | 53 | 41 | Astra unggul pada kumpulan tes ini |
| Penalaran sulit, Humanity’s Last Exam | 55% | 48% | Astra unggul |
| Pemrograman ilmiah, SciCode | 56% | 57% | Sangat dekat; selisih kecil belum membuktikan keunggulan konsisten |
| Penalaran konteks panjang, AA‑LCR v1.1 | 81% | 81% | Setara pada tes ini |
| Biaya rata-rata tertimbang per tugas dalam Intelligence Index | US$3,26 | US$1,24 | Gemini lebih hemat |
Angka di atas berasal dari Artificial Analysis, menggunakan Astra pada pengaturan max dan Gemini pada high. Skor indeks bukan persentase kecerdasan; 53 versus 41 tidak berarti Astra “29% lebih pintar”. Pengaturan tersebut juga tidak menjamin anggaran komputasi yang sama. Perbandingan dan metodologi Artificial Analysis.
Untuk coding, Astra punya keunggulan terukur, dengan biaya dan waktu lebih besar. Pada pengujian agen pemrograman Artificial Analysis:
| Ukuran | Astra dalam Codex | Gemini dalam Antigravity SDK |
|---|---|---|
| Coding Agent Index v1.4 | 67 | 59 |
| Pemahaman repository, SWE‑Atlas‑QnA | 51% | 35% |
| Biaya rata-rata per tugas | US$4,72 | US$2,01 |
| Waktu aktif rata-rata per tugas | 26,8 menit | 7,6 menit |
Ini mengukur model beserta perangkat agennya—alat untuk membaca file, menjalankan perintah, dan mengelola pekerjaan ikut memengaruhi hasil. Jadi, bukti ini mendukung keunggulan kombinasi Astra–Codex pada pengujian tersebut, bukan membuktikan Astra selalu lebih baik pada setiap pekerjaan coding. Pengujian agen Artificial Analysis.
Dari spesifikasi, Gemini lebih fleksibel untuk input multimedia; Astra menyediakan keluaran lebih panjang.
- Astra: konteks 1.050.000 token, keluaran maksimal 128.000 token, input teks dan gambar. Audio/video tidak didukung langsung oleh model ini. Dokumentasi OpenAI.
- Gemini: konteks hingga 1 juta token, keluaran maksimal 64 ribu token, input teks, gambar, audio, dan video. Kapasitas konteks menunjukkan banyaknya materi yang bisa dimasukkan; kualitas memahami seluruh materi harus dinilai lewat pengujian. Model card Google.
Perbedaan harga API besar, tetapi jangan disamakan dengan biaya menyelesaikan pekerjaan. Tarif dasar Astra adalah US$10 input/US$50 output per sejuta token. Gemini memakai harga perkenalan US$0,75/US$3,75 hingga 31 Desember 2026—sekitar 13,3 kali lebih murah per token. Astra menerapkan tarif lebih tinggi untuk input di atas 272 ribu token; biaya nyata juga dipengaruhi cache, token penalaran, dan pengulangan. Harga ini bukan biaya langganan aplikasi. Harga Astra, harga Gemini.
Astra juga tidak selalu menang pada tugas profesional. Dalam evaluasi Model ML, Gemini menang pada kategori financial workflows, dengan skor 76,33 versus Astra 72,36, sekaligus biaya lebih rendah. Namun, pada pencarian informasi lintas dokumen, Astra unggul 78,71 versus 63,23. Ini menunjukkan bahwa jenis pekerjaan sangat menentukan pilihan. Evaluasi Model ML.
Untuk kamu mahasiswa IT sekaligus software engineer pemula, berdasarkan bukti tersebut saya merekomendasikan :
- Gemini 3.8 Flash sebagai pilihan awal jika prioritasmu banyak bereksperimen, respons cepat, biaya API rendah, dan mengolah materi audio/video.
- GPT‑6 Astra untuk pekerjaan sulit ketika kualitas memahami repository, penalaran mendalam, atau analisis lintas dokumen lebih penting daripada biaya dan waktu.
- Untuk memilih langganan aplikasi, nilai juga batas pemakaian dan alat yang kamu dapatkan. Angka biaya API di atas tidak cukup untuk menentukan langganan mana yang lebih menguntungkan.
