30. Merancang sebuah class kecil — Solusi PR

File solusi .lua ada di exercises/30/homework/solutions/.

Soal 1 — Class Counter

Solusi lengkap.

local Counter = {}
Counter.__index = Counter

function Counter.new()
    return setmetatable({ count = 0 }, Counter)
end
function Counter:increment() self.count = self.count + 1 end
function Counter:get() return self.count end
function Counter:reset() self.count = 0 end

local c = Counter.new()
c:increment(); c:increment(); c:increment()
print(c:get())   -- 3
c:reset()
print(c:get())   -- 0

Soal 2 — Health yang dibatasi

Cara berpikir tentangnya. Terapkan aturan "tetap di antara 0 dan max" di dalam heal dan damage, sehingga tidak ada pemanggil yang bisa mendorong health keluar dari rentang tersebut.

Solusi lengkap.

local Health = {}
Health.__index = Health

function Health.new(max)
    return setmetatable({ max = max, current = max }, Health)
end
function Health:heal(n)
    self.current = self.current + n
    if self.current > self.max then self.current = self.max end
end
function Health:damage(n)
    self.current = self.current - n
    if self.current < 0 then self.current = 0 end
end
function Health:get() return self.current end

local h = Health.new(100)
h:damage(30); print(h:get())   -- 70
h:heal(1000); print(h:get())   -- 100  (dibatasi di max)
h:damage(9999); print(h:get()) -- 0    (dibatasi di 0)

Soal 3 — Sakelar lampu

Solusi lengkap.

local Switch = {}
Switch.__index = Switch

function Switch.new()
    return setmetatable({ on = false }, Switch)
end
function Switch:toggle() self.on = not self.on end
function Switch:isOn() return self.on end

local s = Switch.new()
print(s:isOn())   -- false
s:toggle(); print(s:isOn())   -- true
s:toggle(); print(s:isOn())   -- false

self.on = not self.on membalik nilai boolean setiap kali dipanggil — seluruh logika sakelar dalam satu baris.

Tantangan — Stack dengan pengaman

Masalah. :pop() pada stack kosong mengembalikan nil alih-alih crash.

Solusi lengkap.

local Stack = {}
Stack.__index = Stack

function Stack.new()
    return setmetatable({ items = {} }, Stack)
end
function Stack:push(v) table.insert(self.items, v) end
function Stack:pop() return table.remove(self.items) end
function Stack:size() return #self.items end

local s = Stack.new()
s:push("a"); s:push("b")
print(s:size())   -- 2
print(s:pop())    -- b
print(s:pop())    -- a
print(s:pop())    -- nil   (kosong, tapi tidak crash)
print(s:size())   -- 0

table.remove pada list kosong mengembalikan nil alih-alih error, jadi pengamannya sudah ada di dalamnya — tapi pahami kenapa ini aman.

Selesai?

Ini adalah akhir dari Bagian 6. Kamu sudah bisa membuat class, membuat banyak objek, melakukan pewarisan, meng-override method, dan merancang antarmuka publik yang bersih dan aman. Bagian 6 memiliki dua mini-proyek: Sistem Inventaris dan Pertarungan Monster, keduanya dibangun dari objek-objek yang bekerja sama.