Appearance
🎮 Code Runner — Debug Python Code!
Bạn là Junior Data Analyst mới vào công ty DataMart Việt Nam. Ngày đầu tiên, senior giao cho bạn 7 đoạn Python code xử lý dữ liệu bán hàng — nhưng tất cả đều có bug! Mission: tìm và sửa lỗi trước khi CEO cần báo cáo chiều nay! 🐛
🎯 Mục tiêu học tập
Sau khi hoàn thành game, bạn sẽ:
- Nhận diện TypeError — lỗi kiểu dữ liệu khi tính toán
- Phát hiện NameError — biến chưa định nghĩa hoặc sai tên
- Sửa IndexError — truy cập phần tử ngoài phạm vi list
- Tránh off-by-one error — lệch chỉ số khi duyệt list/range
- Xử lý logic error — code chạy nhưng ra kết quả sai
- Debug file handling error — đọc/ghi file CSV, JSON sai cách
- Fix function error — return sai chỗ, thiếu parameter, scope sai
📜 Luật chơi
┌──────────────────────────────────────────────────────┐
│ BẠN = Bug Hunter 🐛🔍 │
│ CODE = 7 đoạn Python xử lý dữ liệu bán hàng │
│ MỖI VÒNG = 1 đoạn code có bug → chọn cách sửa đúng │
│ 3 LỰA CHỌN mỗi vòng — chỉ 1 đáp án đúng │
│ MỤC TIÊU = Thu thập ≥ 80 XP để đạt hạng Gold 🥇 │
└──────────────────────────────────────────────────────┘Cách tính điểm mỗi vòng:
| Thành phần | XP |
|---|---|
| Trả lời đúng | +10 XP (Vòng 1–2), +12 XP (Vòng 3–4), +15 XP (Vòng 5–6), +18 XP (Vòng 7) |
| Trả lời sai | +0 XP |
| Không dùng hint | +2 XP bonus ⚡ |
| Giải thích đúng loại bug | +3 XP bonus 🧠 |
Tổng XP tối đa: 10+10+12+12+15+15+18 = 92 XP (chưa tính bonus)
🏆 Bảng xếp hạng & Huy hiệu
Ranks
| Hạng | XP | Mô tả |
|---|---|---|
| 🥇 Gold — Senior Debugger | ≥ 80 XP | Bạn là debug master! Sẵn sàng code Pandas |
| 🥈 Silver — Bug Spotter | ≥ 55 XP | Tốt! Cần luyện thêm logic & file handling |
| 🥉 Bronze — Code Newbie | ≥ 35 XP | Ổn cho ngày đầu — ôn lại data types & loops |
| 💀 Game Over | < 35 XP | Quay lại đọc Buổi 7 rồi thử lại nhé! |
Huy hiệu đặc biệt
| Badge | Điều kiện | Mô tả |
|---|---|---|
| 🎯 Perfect Round | Đúng 1 vòng + không dùng hint | Hoàn hảo! |
| 🔥 Hot Streak | 3 vòng liên tiếp đúng | Chuỗi lửa! |
| 🧠 Bug Identifier | Gọi đúng tên loại bug ≥ 5 vòng | Bạn biết bug từ xa! |
| ⚡ Speed Demon | Hoàn thành 7 vòng trong < 10 phút | Nhanh như chớp! |
| 🏆 Full Clear | Đúng tất cả 7 vòng | Huyền thoại! |
| 🐛 First Bug | Đúng vòng đầu tiên | Bước đầu tốt lành! |
| 💡 No Hints Needed | Không dùng hint cả game | Tự lực cánh sinh! |
| 🛡️ Comeback King | Sai 2 vòng đầu, đúng 5 vòng sau | Không bỏ cuộc! |
🎲 Chỉ số theo dõi
| Chỉ số | Icon | Mô tả | Mục tiêu |
|---|---|---|---|
| Debug Accuracy | 🎯 | Số vòng trả lời đúng / tổng 7 vòng | ≥ 6/7 |
| Speed | ⏱️ | Tổng thời gian hoàn thành game | < 15 phút |
| Bug Types Found | 🐛 | Số loại bug khác nhau bạn nhận diện đúng | ≥ 5 loại |
📋 Kịch bản chi tiết
🐛 Vòng 1: TypeError — "Cộng số với chuỗi" ⭐ Dễ
Đoạn code đọc doanh thu từ CSV và tính tổng — nhưng bị lỗi!
💬 Slack từ Senior DA:
"Em ơi, code tính tổng doanh thu bị crash — chạy được vài dòng thì báo lỗi. Em xem sửa giúp anh nhé!"
Code có lỗi:
python
import csv
def calculate_total_revenue(filename):
total = 0
with open(filename, "r") as file:
reader = csv.DictReader(file)
for row in reader:
total = total + row["revenue"] # 💥 Bug ở đây!
return total
result = calculate_total_revenue("sales.csv")
print(f"Tổng doanh thu: {result:,} VNĐ")Lỗi hiển thị: TypeError: unsupported operand type(s) for +: 'int' and 'str'
Lựa chọn:
| Cách sửa | Dòng sửa | |
|---|---|---|
| A | total = total + int(row["revenue"]) | Dòng 8 |
| B | total = str(total) + row["revenue"] | Dòng 8 |
| C | total = total + float(row["revenue"]) | Dòng 8 |
💡 Hint (−2 XP)
csv.DictReader đọc tất cả giá trị dưới dạng str — kể cả số. Cần chuyển đổi kiểu dữ liệu trước khi cộng. Doanh thu có thể có số thập phân (VD: 1500000.50).
Đáp án & Giải thích
✅ Đáp án đúng: C — total = total + float(row["revenue"])
Loại bug: TypeError — cộng int với str
Giải thích: csv.DictReader trả về tất cả values dưới dạng str. Dòng row["revenue"] trả về "1500000" (string), không phải 1500000 (number). Dùng float() thay vì int() vì doanh thu có thể có số thập phân. Đáp án B sai vì nối chuỗi, không phải cộng số!
XP: +10 | Bonus: +2 (no hint), +3 (đúng loại bug)
🐛 Vòng 2: NameError — "Biến chưa tồn tại" ⭐ Dễ
Code phân loại đơn hàng theo giá trị — nhưng biến bị sai tên!
💬 Slack từ Marketing Manager:
"Em chạy script phân loại đơn hàng thì báo lỗi NameError — em check lại code giùm chị nhé!"
Code có lỗi:
python
def classify_order(amount):
if amount >= 5000000:
category = "VIP"
elif amount >= 1000000:
category = "Standard"
else:
categori = "Basic" # 💥 Bug ở đây!
return category
orders = [500000, 1200000, 8000000, 300000]
for order_amount in orders:
print(f"{order_amount:,} VNĐ → {classify_order(order_amount)}")Lỗi hiển thị: NameError: name 'category' is not defined (khi amount < 1000000)
Lựa chọn:
| Cách sửa | Dòng sửa | |
|---|---|---|
| A | Sửa categori = "Basic" thành category = "Basic" | Dòng 7 |
| B | Thêm category = "" ở đầu function | Dòng 2 |
| C | Sửa return category thành return categori | Dòng 8 |
💡 Hint (−2 XP)
Xem kỹ cách viết tên biến — Python phân biệt chữ hoa/thường và từng ký tự. So sánh tên biến ở nhánh else với các nhánh khác.
Đáp án & Giải thích
✅ Đáp án đúng: A — Sửa typo categori → category
Loại bug: NameError — biến category chưa được gán trong nhánh else (vì gán vào categori)
Giải thích: Ở nhánh else, typo categori (thiếu chữ y) tạo ra biến mới thay vì gán vào category. Khi return category, biến này chưa được gán → NameError. Đáp án B "chữa cháy" nhưng không sửa gốc bug. Đáp án C return sai biến.
XP: +10 | Bonus: +2 (no hint), +3 (đúng loại bug)
🐛 Vòng 3: IndexError — "Vượt phạm vi list" ⭐⭐ Trung bình
Code lấy top 3 sản phẩm bán chạy — nhưng list chỉ có 2 phần tử!
💬 Slack từ Product Manager:
"Script lấy top 3 bị crash — anh nghĩ có category nào chỉ có ít sản phẩm thôi."
Code có lỗi:
python
def get_top3_products(sales_data):
sorted_products = sorted(sales_data, key=lambda x: x["revenue"], reverse=True)
top3 = [
sorted_products[0]["name"],
sorted_products[1]["name"],
sorted_products[2]["name"], # 💥 Bug khi list < 3 phần tử!
]
return top3
# Category "Sách" chỉ có 2 sản phẩm
books = [
{"name": "Python Data Science", "revenue": 5000000},
{"name": "SQL Cookbook", "revenue": 3200000},
]
print(get_top3_products(books))Lỗi hiển thị: IndexError: list index out of range
Lựa chọn:
| Cách sửa | |
|---|---|
| A | top3 = [p["name"] for p in sorted_products[:3]] — dùng slicing |
| B | Thêm if len(sorted_products) >= 3: trước khi truy cập index |
| C | top3 = sorted_products[0:3]["name"] — slice rồi lấy name |
💡 Hint (−2 XP)
Python list slicing (list[:3]) không bao giờ gây IndexError — nếu list có ít hơn 3 phần tử, nó trả về tất cả phần tử có. Cách nào dùng slicing đúng cú pháp?
Đáp án & Giải thích
✅ Đáp án đúng: A — Dùng list comprehension + slicing sorted_products[:3]
Loại bug: IndexError — truy cập index cứng khi list không đủ phần tử
Giải thích: sorted_products[2] crash khi list chỉ có 2 phần tử (index 0, 1). Slicing [:3] an toàn — trả về tối đa 3, không crash nếu ít hơn. Đáp án B hoạt động nhưng không xử lý trường hợp < 3 (bỏ qua luôn). Đáp án C sai cú pháp — không thể ["name"] trên list.
XP: +12 | Bonus: +2 (no hint), +3 (đúng loại bug)
🐛 Vòng 4: Off-by-one Error — "Thiếu 1 tháng" ⭐⭐ Trung bình
Code tính doanh thu Q4 (tháng 10, 11, 12) — nhưng thiếu tháng 12!
💬 Slack từ CFO:
"Tổng doanh thu Q4 sao thấp quá — em check lại xem có đúng 3 tháng không?"
Code có lỗi:
python
monthly_revenue = {
1: 50000000, 2: 45000000, 3: 62000000,
4: 58000000, 5: 71000000, 6: 68000000,
7: 75000000, 8: 82000000, 9: 79000000,
10: 95000000, 11: 110000000, 12: 135000000,
}
def calculate_quarter_revenue(monthly_data, quarter):
"""Tính doanh thu theo quý. Q1=1-3, Q2=4-6, Q3=7-9, Q4=10-12."""
start_month = (quarter - 1) * 3 + 1
end_month = quarter * 3
total = 0
for month in range(start_month, end_month): # 💥 Bug ở đây!
total += monthly_data[month]
return total
q4_revenue = calculate_quarter_revenue(monthly_revenue, 4)
print(f"Doanh thu Q4: {q4_revenue:,} VNĐ")
# Kết quả: 205,000,000 — THIẾU tháng 12 (135,000,000)!Lựa chọn:
| Cách sửa | Dòng sửa | |
|---|---|---|
| A | for month in range(start_month, end_month + 1): | Dòng 13 |
| B | end_month = quarter * 3 + 1 | Dòng 11 |
| C | for month in range(start_month, end_month): và sửa start_month = (quarter - 1) * 3 | Dòng 10 + 13 |
💡 Hint (−2 XP)
range(10, 12) trong Python tạo ra [10, 11] — không bao gồm số cuối! Q4 cần tháng 10, 11, 12.
Đáp án & Giải thích
✅ Đáp án đúng: A — range(start_month, end_month + 1)
Loại bug: Off-by-one error — range() trong Python là exclusive ở cận trên
Giải thích: range(10, 12) chỉ tạo [10, 11], bỏ sót tháng 12. Thêm + 1 vào end: range(10, 13) → [10, 11, 12]. Đáp án B thay đổi end_month tại chỗ khai báo — hoạt động nhưng làm sai ngữ nghĩa biến. Đáp án C sửa sai start_month (Q4 phải bắt đầu từ 10, không phải 9).
XP: +12 | Bonus: +2 (no hint), +3 (đúng loại bug)
🐛 Vòng 5: Logic Error — "Tính sai trung bình" ⭐⭐⭐ Khó
Code tính average order value — chạy không báo lỗi, nhưng kết quả SAI!
💬 Slack từ Senior DA:
"Em ơi, average order value = 2.5 triệu? Cao quá — gần bằng doanh thu cao nhất rồi. Check lại logic nhé."
Code có lỗi:
python
def avg_order_value(orders):
"""Tính giá trị đơn hàng trung bình (chỉ đơn completed)."""
total = 0
count = 0
for order in orders:
if order["status"] == "completed":
total += order["amount"]
count += 1
avg = total / count # 💥 Bug: tính avg TRONG vòng lặp!
return avg
sample_orders = [
{"id": 1, "amount": 500000, "status": "completed"},
{"id": 2, "amount": 1200000, "status": "cancelled"},
{"id": 3, "amount": 3000000, "status": "completed"},
{"id": 4, "amount": 800000, "status": "completed"},
]
print(f"Avg Order Value: {avg_order_value(sample_orders):,.0f} VNĐ")
# Output: 2,150,000 — SAI! Đúng phải là (500000+3000000+800000)/3 = 1,433,333Lựa chọn:
| Cách sửa | |
|---|---|
| A | Di chuyển avg = total / count ra ngoài vòng for, thụt lề ngang hàng với for |
| B | Thêm if count > 0: trước dòng avg = total / count |
| C | Sửa thành avg = total / len(orders) ở ngoài vòng lặp |
💡 Hint (−2 XP)
Xem indentation (thụt lề) của dòng avg = total / count — nó nằm bên trong hay bên ngoài vòng for? Kết quả avg phải tính sau khi duyệt xong tất cả đơn hàng.
Đáp án & Giải thích
✅ Đáp án đúng: A — Di chuyển avg = total / count ra ngoài vòng for
Loại bug: Logic error — indentation sai khiến avg tính lại mỗi iteration
Giải thích: Dòng avg = total / count bị thụt vào trong for → tính avg sau MỖI dòng, kết quả cuối = avg của lần cuối (sai). Cần kéo ra ngoài for để tính trung bình SAU KHI duyệt hết. Đáp án B thêm guard nhưng vẫn trong loop. Đáp án C chia cho len(orders) = 4 (bao gồm cả cancelled) thay vì 3 (chỉ completed).
XP: +15 | Bonus: +2 (no hint), +3 (đúng loại bug)
🐛 Vòng 6: File Handling Error — "File ghi đè thay vì nối thêm" ⭐⭐⭐ Khó
Code ghi báo cáo hàng ngày vào file — nhưng mỗi ngày chạy lại mất dữ liệu cũ!
💬 Slack từ BI Manager:
"Anh chạy script ghi báo cáo mỗi ngày, nhưng file chỉ có dữ liệu ngày cuối — 29 ngày trước biến mất hết!"
Code có lỗi:
python
import csv
def save_daily_report(date, revenue, order_count, filename):
"""Ghi báo cáo hàng ngày vào file CSV."""
with open(filename, "w", newline="") as file: # 💥 Bug ở đây!
writer = csv.writer(file)
writer.writerow(["date", "revenue", "order_count"])
writer.writerow([date, revenue, order_count])
# Chạy mỗi ngày
save_daily_report("2026-02-16", 15000000, 42, "monthly_report.csv")
save_daily_report("2026-02-17", 18000000, 55, "monthly_report.csv")
save_daily_report("2026-02-18", 12000000, 38, "monthly_report.csv")
# File chỉ chứa dữ liệu ngày 18/02 — 2 ngày trước bị ghi đè!Lựa chọn:
| Cách sửa | |
|---|---|
| A | Đổi "w" thành "a" — nhưng bỏ dòng header writerow(["date", ...]) hoặc check file rỗng |
| B | Đổi "w" thành "r+" — đọc trước rồi ghi thêm |
| C | Thêm file.seek(0, 2) trước khi ghi — nhảy đến cuối file |
💡 Hint (−2 XP)
File mode trong Python: "w" = write (tạo mới / ghi đè), "a" = append (nối thêm cuối file), "r" = read only. Bạn muốn thêm dòng mới vào file đã có.
Đáp án & Giải thích
✅ Đáp án đúng: A — Đổi "w" thành "a" và xử lý header
Loại bug: File handling error — "w" mode ghi đè toàn bộ file mỗi lần mở
Giải thích: Mode "w" xóa sạch nội dung cũ và ghi mới. Mode "a" (append) nối thêm vào cuối file. Tuy nhiên, cần bỏ header khi append (hoặc check os.path.getsize(filename) == 0 để chỉ ghi header lần đầu). Đáp án B "r+" cần file đã tồn tại + phải seek thủ công. Đáp án C không hoạt động với mode "w" — file đã bị xóa sạch khi mở.
XP: +15 | Bonus: +2 (no hint), +3 (đúng loại bug)
🐛 Vòng 7: Function Error — "Return sai chỗ" ⭐⭐⭐⭐ BOSS
Code tìm sản phẩm bán chạy nhất mỗi danh mục — chỉ trả về 1 danh mục!
💬 Slack từ CEO:
"Em ơi, anh cần top product MỖI danh mục — 5 category mà chỉ thấy 1? Báo cáo board meeting 30 phút nữa!"
Code có lỗi:
python
def top_product_per_category(products):
"""Tìm sản phẩm có doanh thu cao nhất mỗi danh mục."""
categories = {}
for product in products:
cat = product["category"]
rev = product["revenue"]
if cat not in categories:
categories[cat] = {"name": product["name"], "revenue": rev}
elif rev > categories[cat]["revenue"]:
categories[cat] = {"name": product["name"], "revenue": rev}
return categories # 💥 Bug: return TRONG vòng lặp!
all_products = [
{"name": "iPhone 16", "category": "Điện Tử", "revenue": 85000000},
{"name": "Áo thun Uniqlo", "category": "Thời Trang", "revenue": 32000000},
{"name": "Galaxy S25", "category": "Điện Tử", "revenue": 72000000},
{"name": "Nồi cơm điện", "category": "Gia Dụng", "revenue": 18000000},
{"name": "Quần jean Levi's", "category": "Thời Trang", "revenue": 41000000},
{"name": "Máy xay sinh tố", "category": "Gia Dụng", "revenue": 25000000},
]
result = top_product_per_category(all_products)
for cat, info in result.items():
print(f"{cat}: {info['name']} ({info['revenue']:,} VNĐ)")
# Chỉ in ra: Điện Tử: iPhone 16 — thiếu Thời Trang và Gia Dụng!Lựa chọn:
| Cách sửa | |
|---|---|
| A | Di chuyển return categories ra ngoài vòng for — bỏ thụt lề 1 cấp |
| B | Thêm if len(categories) == 3: return categories — return khi đủ 3 category |
| C | Đổi return categories thành yield categories — dùng generator |
💡 Hint (−2 XP)
Xem vị trí của return — nó nằm bên trong vòng for. Function sẽ trả về ngay sau khi xử lý phần tử đầu tiên — không bao giờ duyệt hết list! Đây là bug cực phổ biến mà DA hay gặp.
Đáp án & Giải thích
✅ Đáp án đúng: A — Di chuyển return categories ra ngoài vòng for
Loại bug: Function error — return bên trong loop khiến function dừng sớm
Giải thích: return ở indentation level 2 (trong for) → function return ngay sau item đầu tiên! Kéo return ra ngoài for (indentation level 1) → duyệt hết tất cả sản phẩm rồi mới return. Đáp án B hardcode số category = 3, không linh hoạt. Đáp án C dùng yield thay đổi hẳn cách dùng function — phải dùng list() hoặc for ở ngoài.
XP: +18 | Bonus: +2 (no hint), +3 (đúng loại bug)
📊 Tổng kết
Bảng tổng hợp bug
| Vòng | Loại bug | Độ khó | XP | Bài học |
|---|---|---|---|---|
| 1 | TypeError | ⭐ Dễ | 10 | CSV đọc mọi thứ thành str — luôn convert type |
| 2 | NameError | ⭐ Dễ | 10 | Typo tên biến → Python tạo biến mới thay vì gán |
| 3 | IndexError | ⭐⭐ TB | 12 | Dùng slicing [:n] thay vì index cứng [n] |
| 4 | Off-by-one | ⭐⭐ TB | 12 | range() exclusive cận trên — luôn nhớ +1 |
| 5 | Logic Error | ⭐⭐⭐ Khó | 15 | Indentation = logic trong Python — 1 space sai = kết quả sai |
| 6 | File Handling | ⭐⭐⭐ Khó | 15 | "w" ghi đè, "a" nối thêm — chọn đúng mode |
| 7 | Function Error | ⭐⭐⭐⭐ Boss | 18 | return trong loop = dừng sớm — bug phổ biến nhất |
Công thức tính điểm
XP tổng = Σ (XP mỗi vòng đúng) + Σ (No-hint bonus) + Σ (Bug ID bonus)
= (max 92) + (max 14) + (max 21) = max 127 XP🎯 Mẹo debug cho DA
Ghi nhớ 3 bước debug:
- Đọc error message — Python nói rõ loại lỗi (TypeError, NameError...) và dòng nào
- Check data type —
print(type(variable))để xem kiểu dữ liệu - Check indentation — logic error thường do thụt lề sai 1 cấp