Sebelum satu baris kode pun ditulis, kita perlu memetakan ruang lingkup: struktur apa saja yang akan divisualisasikan, format output seperti apa yang realistis di terminal, dan keterbatasan apa yang harus kita akui. Terminal bukan kanvas grafis — kita bekerja dengan sel monospace karakter dan tidak ada posisi pixel. Pada bagian ini kita merancang kontrak antara model (struktur data) dan view (renderer) agar kode pada Bagian 2 dan 3 dapat tumbuh tanpa refactor besar.
Cakupan Struktur Data #
Kita akan memvisualisasikan tiga struktur yang paling sering muncul di buku DSA:
- Linked list — node dengan satu pointer
next. Visualisasi alami: rantai horizontal. - Binary tree — node dengan
leftdanright. Visualisasi alami: tree vertikal dengan root di atas. - Graph berarah — node dengan daftar tetangga. Visualisasi alami: adjacency list teks, karena graph 2D penuh membutuhkan tata letak yang sulit dihitung.
Struktur lain (stack, queue, hash table) tidak dimasukkan karena representasinya sederhana (cukup cetak elemen secara linear) dan tidak menambah konsep baru.
Format Output per Struktur #
Berikut kontrak format output yang akan dipatuhi renderer pada Bagian 3:
Linked list:
[a] -> [b] -> [c] -> null
Binary tree (in-order layout):
[1]
/ \
[2] [3]
/ \ / \
[4] [5] [6] [7]
Graph (adjacency list):
0 -> 1, 2
1 -> 2
2 -> 0Batasan Terminal yang Harus Diterima #
Terminal memiliki tiga batasan yang memengaruhi rancangan renderer:
- Sel monospace — setiap karakter menempati satu kolom dengan lebar sama. Ini memudahkan perhitungan posisi karena tidak perlu mengukur pixel.
- Tidak ada API gambar — kita hanya bisa mencetak karakter ke koordinat (baris, kolom) tertentu menggunakan
std::cout. Tidak adamoveCursorportabel yang kita pakai di sini. - Lebar terbatas — terminal biasanya 80 kolom. Bila tree terlalu lebar, output akan terbungkus. Solusi yang akan kita pilih pada Bagian 3: simpan grid karakter di
std::vector<std::string>, isi sel pada koordinat yang dihitung, lalu cetak seluruh grid.
Pemisahan Model dan View #
Arsitektur tool mengikuti pola model-view sederhana:
Model hanya menyimpan data dan pointer. Renderer menerima referensi ke model dan menghasilkan std::vector<std::string> berisi grid karakter. View mencetak setiap baris dengan std::cout. Pemisahan ini membuat renderer dapat diuji tanpa terminal: cukup bandingkan vector string yang dihasilkan.
Kontrak Antarmuka Minimal #
Berikut kontrak minimal yang akan kita jaga pada Bagian 2 dan 3. Kode lengkapnya baru muncul di bagian berikutnya, tetapi kontrak ini menjadi panduan:
// Bagian 2 (model)
struct LinkedList { /* ... */ };
struct BinaryTree { /* ... */ };
struct Graph { /* ... */ };
// Bagian 3 (renderer)
std::vector<std::string> render(const LinkedList& l);
std::vector<std::string> render(const BinaryTree& t);
std::vector<std::string> render(const Graph& g);
// main()
int main() {
LinkedList l = buildSampleList();
for (const auto& line : render(l)) std::cout << line << "\n";
return 0;
}Ringkasan Bagian 1 #
Kita telah memilih tiga struktur (linked list, binary tree, graph), menetapkan format output per struktur, dan memisahkan tanggung jawab antara model dan renderer. Batasan terminal diterima sebagai fakta: tidak ada API gambar, lebar terbatas, dan sel monospace. Pada Bagian 2, kita membangun kelas model yang akan menjadi masukan renderer.