KabaLang örnekleri: konsol, masaüstü ve web için dokuz proje

Konsol: fraktal (paralel şeritli 24-bit Mandelbrot/Julia + yakınlaşma),
sudoku (geri izlemeli, canlı animasyon), fatura (JSON → terminal tablosu,
PDF ve Excel).
Masaüstü: hesap makinesi (işlem önceliği, canlı bağlama), odak (Pomodoro),
parola atölyesi (entropi ölçer, SHA-256).
Web: pano (Kanban REST API + SQLite), kisalt (302 yönlendirme, SVG
istatistik), anket (adres başına tek oy, sunucuda çizilen grafik).

Hepsi `kabalang calistir` ile derlenip çalışır; web uygulamaları yalnız
127.0.0.1'i dinler, SQL parametre bağlamalı, HTML çıktısı kaçırılır.
This commit is contained in:
2026-10-03 08:37:47 +03:00
commit e0e4a0d6c7
40 changed files with 2652 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
# Fatura — JSON siparişten terminal tablosu, PDF ve Excel
![Fatura](../../medya/fatura.png)
`siparis.json`'u okur; her kalem için indirim ve KDV hesaplar, KDV'yi
oranlara göre döker ve sonucu üç biçimde verir:
1. Terminalde kutu çizgili, renkli bir fatura tablosu
2. `fatura.pdf` — Türkçe karakterleri ve `₺` işaretini taşıyan, sayfa
numaralı PDF
3. `fatura.xlsx` — tablolar ayrı çalışma sayfalarında
```bash
kabalang calistir fatura.kbl # siparis.json → ./fatura.pdf + ./fatura.xlsx
kabalang calistir fatura.kbl -- baska.json --cikti ~/Belgeler
```
## KabaLang'ın gösterdikleri
| Özellik | Nerede |
|---|---|
| `yapi` + metotlar | `Kalem.brut()`, `matrah()`, `kdv_tutari()` — hesap verinin yanında |
| `sonuc<T, Hata>` | `siparis_oku` dosya yokken ya da JSON bozukken **değerle** hata döner; yok sayılamaz |
| `dene / yakala` | JSON dizisini sonuna kadar gezmek |
| `json` | İç içe erişim: `v["satici"]["ad"]`, `v["kalemler"][i]["adet"]` |
| `kaba.belge` | Aynı belge nesnesinden `pdf_yaz` ve `xlsx_yaz` |
| f-string biçimi | `{ad:<32}`, `{tutar:>15}`, `{k % 100:02d}` — hizalı tablo ve kuruş |
## Para nasıl tutuluyor
Her ara sonuç **kuruşa yuvarlanır** (`kurus()`); `0.1 + 0.2` gibi ikili kesir
artıkları faturaya taşınmaz. `para()` sayıyı Türkçe biçime çevirir:
`1249.9 → 1.249,90 ₺`.
Örnek siparişin toplamları elle de hesaplanıp karşılaştırıldı:
ara toplam 65.439,80 ₺ · indirim 1.879,99 ₺ · KDV 11.748,96 ₺ ·
**genel toplam 75.308,77 ₺**.
> Satıcı ve alıcı bilgileri örnek amaçlı, hayalidir.
+179
View File
@@ -0,0 +1,179 @@
# ╔══════════════════════════════════════════════════════════════════╗
# ║ FATURA — JSON siparişten KDV'li fatura: terminal + PDF + Excel ║
# ║ ║
# ║ siparis.json'u okur, satır satır indirim ve KDV hesaplar, ║
# ║ oranlara göre KDV dökümü çıkarır; sonucu terminalde kutu ║
# ║ çizgili bir tablo olarak basar ve aynı veriden fatura.pdf ile ║
# ║ fatura.xlsx üretir. Para kuruşa yuvarlanarak tutulur. ║
# ║ ║
# ║ kabalang calistir fatura.kbl ║
# ║ kabalang calistir fatura.kbl -- baska.json --cikti ~/Belgeler ║
# ╚══════════════════════════════════════════════════════════════════╝
kullan kaba.sistem
kullan kaba.belge
yapi Kalem:
ad = ""
adet = 0
birim_fiyat = 0.0
indirim = 0 # yüzde
kdv = 0 # yüzde
fonksiyon brut() -> ondalik:
don kurus(birim_fiyat * ondalik(adet))
fonksiyon matrah() -> ondalik:
don kurus(brut() * (1.0 - ondalik(indirim) / 100.0))
fonksiyon kdv_tutari() -> ondalik:
don kurus(matrah() * ondalik(kdv) / 100.0)
# Kuruşa yuvarla: 0.1 + 0.2 gibi ikili kesir artıklarını faturaya taşıma.
fonksiyon kurus(x: ondalik) -> ondalik:
don matematik.yuvarla(x * 100.0) / 100.0
# 1249.9 → "1.249,90 ₺" — Türkçe binlik ve ondalık ayıracı.
fonksiyon para(x: ondalik) -> metin:
k = sayi(matematik.yuvarla(x * 100.0))
tam = metin(k // 100)
gruplu = ""
i = tam.uzunluk()
iken i > 3:
gruplu = "." + tam.dilim(i - 3, 3) + gruplu
i = i - 3
gruplu = tam.dilim(0, i) + gruplu
don f"{gruplu},{k % 100:02d} ₺"
# ── Siparişi oku ─────────────────────────────────────────────────────
# Beklenen hata (dosya yok, bozuk JSON) dönüş değeriyle bildirilir.
fonksiyon siparis_oku(yol: metin) -> sonuc<metin, Hata>:
eger degil dosya.var_mi(yol):
don hata(f"sipariş dosyası bulunamadı: {yol}")
ham = dosya.oku(yol)
eger degil json.gecerli_mi(ham):
don hata(f"{yol} geçerli bir JSON değil")
don tamam(ham)
# ── Terminal tablosu ─────────────────────────────────────────────────
fonksiyon boya(yazi: metin, rgb: metin) -> metin:
don "\033[38;2;" + rgb + "m" + yazi + "\033[0m"
fonksiyon cizgi(sol: metin, orta: metin, sag: metin) -> metin:
don boya(" " + sol + "━".tekrarla(4) + orta + "━".tekrarla(34) + orta + "━".tekrarla(6) + orta + "━".tekrarla(15) + orta + "━".tekrarla(6) + orta + "━".tekrarla(5) + orta + "━".tekrarla(16) + sag, "70;80;110")
fonksiyon satir(no: metin, ad: metin, adet: metin, birim: metin, ind: metin, kdv: metin, tutar: metin) -> metin:
c = boya("┃", "70;80;110")
don f" {c}{no:>3} {c} {ad:<32} {c}{adet:>5} {c}{birim:>14} {c}{ind:>5} {c}{kdv:>4} {c}{tutar:>15} {c}"
# ── Program ──────────────────────────────────────────────────────────
ks = KomutSatiri("fatura", "JSON siparişten KDV'li fatura üretir")
ks.konumsal("siparis", "Sipariş dosyası (varsayılan: siparis.json)")
ks.secenek("cikti", "c", "PDF ve XLSX'in yazılacağı klasör")
c = ks.coz()
eger c.yardim_mi():
c.yardim_yaz()
cikis(0)
eger c.hatali_mi():
c.hata_yaz_ve_cik()
okunan = siparis_oku(c.konumsal("siparis").deger_veya("siparis.json"))
eger okunan.hatali_mi():
konsol.hata_yaz("✗ " + okunan.hata().mesaj() + "\n")
cikis(1)
v = json.coz(okunan.deger())
# JSON dizisinin uzunluğu sorulamıyor; sınırın dışına çıkınca biter.
kalemler = [Kalem()] # boş yapı listesi: bir öğeyle kurup sil
kalemler.sil(0)
i = 0
bitti = yanlis
iken degil bitti:
dene:
j = v["kalemler"][i]
kalemler.ekle(Kalem(metin(j["ad"]), sayi(j["adet"]), ondalik(j["birim_fiyat"]), sayi(j["indirim"]), sayi(j["kdv"])))
i = i + 1
yakala:
bitti = dogru
# ── Hesap ────────────────────────────────────────────────────────────
ara_toplam = 0.0
indirim_toplam = 0.0
kdv_toplam = 0.0
dongu k icinde kalemler:
ara_toplam = ara_toplam + k.brut()
indirim_toplam = indirim_toplam + k.brut() - k.matrah()
kdv_toplam = kdv_toplam + k.kdv_tutari()
matrah_toplam = ara_toplam - indirim_toplam
genel_toplam = kurus(matrah_toplam + kdv_toplam)
# ── Terminal ─────────────────────────────────────────────────────────
no = metin(v["fatura_no"])
tarih = metin(v["tarih"])
satici = metin(v["satici"]["ad"])
alici = metin(v["alici"]["ad"])
yazdir("")
yazdir(boya(f" ◆ FATURA {no}", "125;170;255") + boya(f" {tarih}", "110;120;150"))
yazdir(boya(f" {satici} → {alici}", "200;208;224"))
yazdir(cizgi("┏", "┳", "┓"))
yazdir(satir("#", "Ürün / hizmet", "Adet", "Birim fiyat", "İnd.", "KDV", "Tutar"))
yazdir(cizgi("┣", "╋", "┫"))
s = 1
dongu k icinde kalemler:
ind = "—"
eger k.indirim > 0:
ind = f"%{k.indirim}"
yazdir(satir(metin(s), k.ad, metin(k.adet), para(k.birim_fiyat), ind, f"%{k.kdv}", para(k.matrah())))
s = s + 1
yazdir(cizgi("┗", "┻", "┛"))
fonksiyon toplam_satiri(ad: metin, deger: metin, rgb: metin) -> metin:
don boya(f"{ad:>78}", "150;160;185") + boya(f"{deger:>17}", rgb)
yazdir(toplam_satiri("Ara toplam", para(ara_toplam), "200;208;224"))
yazdir(toplam_satiri("İndirim", "−" + para(indirim_toplam), "248;113;113"))
yazdir(toplam_satiri("KDV matrahı", para(matrah_toplam), "200;208;224"))
dongu oran icinde [20, 10, 1]:
o_matrah = 0.0
o_kdv = 0.0
dongu k icinde kalemler:
eger k.kdv == oran:
o_matrah = o_matrah + k.matrah()
o_kdv = o_kdv + k.kdv_tutari()
eger o_kdv > 0.0:
yazdir(toplam_satiri(f"KDV %{oran} ({para(o_matrah)} üzerinden)", para(o_kdv), "200;208;224"))
yazdir(toplam_satiri("GENEL TOPLAM", para(genel_toplam), "74;222;128"))
# ── Belge: aynı veriden PDF + Excel ──────────────────────────────────
klasor = c.secenek("cikti").deger_veya(".")
b = belge.yeni(f"Fatura {no}")
belge.altbilgi(b, f"{satici} · {no}")
belge.baslik(b, "FATURA", 1)
belge.paragraf(b, f"Fatura no: {no} Tarih: {tarih}")
belge.baslik(b, "Satıcı", 3)
belge.paragraf(b, satici + " — " + metin(v["satici"]["adres"]) + " — " + metin(v["satici"]["vergi"]))
belge.baslik(b, "Alıcı", 3)
belge.paragraf(b, alici + " — " + metin(v["alici"]["adres"]) + " — " + metin(v["alici"]["vergi"]))
belge.baslik(b, "Kalemler", 2)
belge.tablo_basligi(b, ["#", "Ürün / hizmet", "Miktar × fiyat", "İnd. / KDV", "Tutar"])
s = 1
dongu k icinde kalemler:
ind = "—"
eger k.indirim > 0:
ind = f"%{k.indirim}"
belge.tablo_satiri(b, [metin(s), metin(k.ad), f"{k.adet} × {para(k.birim_fiyat)}", f"{ind} / %{k.kdv}", para(k.matrah())])
s = s + 1
belge.baslik(b, "Özet", 2)
belge.tablo_basligi(b, ["Kalem", "Tutar"])
belge.tablo_satiri(b, ["Ara toplam", para(ara_toplam)])
belge.tablo_satiri(b, ["İndirim", "-" + para(indirim_toplam)])
belge.tablo_satiri(b, ["KDV matrahı", para(matrah_toplam)])
belge.tablo_satiri(b, ["KDV toplamı", para(kdv_toplam)])
belge.tablo_satiri(b, ["GENEL TOPLAM", para(genel_toplam)])
belge.vurgu(b, f"Ödenecek tutar: {para(genel_toplam)}")
yazdir("")
eger belge.pdf_yaz(b, klasor + "/fatura.pdf"):
yazdir(boya(f" ✓ {klasor}/fatura.pdf yazıldı", "74;222;128"))
degilse:
yazdir(boya(" ✗ PDF yazılamadı", "248;113;113"))
eger belge.xlsx_yaz(b, klasor + "/fatura.xlsx"):
yazdir(boya(f" ✓ {klasor}/fatura.xlsx yazıldı", "74;222;128"))
belge.kapat(b)
+22
View File
@@ -0,0 +1,22 @@
{
"fatura_no": "A37-2026-000142",
"tarih": "2026-10-02",
"satici": {
"ad": "Atölye 37 Bilişim Ltd. Şti.",
"adres": "Yıldız Teknopark, B Blok No:7, İstanbul",
"vergi": "Boğaziçi VD · 1234567890"
},
"alici": {
"ad": "Mavi Deniz Kafe ve Ortak Çalışma Alanı",
"adres": "Kordon Boyu Cad. No:12, Konak / İzmir",
"vergi": "Konak VD · 9876543210"
},
"kalemler": [
{ "ad": "Mekanik klavye (Türkçe Q)", "adet": 4, "birim_fiyat": 2450.00, "indirim": 10, "kdv": 20 },
{ "ad": "27\" IPS monitör", "adet": 2, "birim_fiyat": 8999.90, "indirim": 5, "kdv": 20 },
{ "ad": "Ergonomik çalışma sandalyesi", "adet": 3, "birim_fiyat": 6340.00, "indirim": 0, "kdv": 20 },
{ "ad": "Yazılım bakım hizmeti (aylık)", "adet": 1, "birim_fiyat": 12500.00, "indirim": 0, "kdv": 20 },
{ "ad": "Toplantı ikramı (kişi başı)", "adet": 12, "birim_fiyat": 185.00, "indirim": 0, "kdv": 10 },
{ "ad": "Kahve çekirdeği 1 kg", "adet": 5, "birim_fiyat": 780.00, "indirim": 0, "kdv": 1 }
]
}
+39
View File
@@ -0,0 +1,39 @@
# Fraktal — terminalde 24 bit renkli Mandelbrot ve Julia
![Fraktal](../../medya/fraktal.png)
Terminali bir tuvale çevirir. Her karakter hücresi **iki piksel** taşır:
üst yarım blok `▀` ön plan rengiyle üst pikseli, arka plan rengiyle alt
pikseli çizer. 100 sütunluk bir terminal böylece 100 × 72 piksellik bir
görüntü olur.
```bash
kabalang calistir fraktal.kbl # Mandelbrot kümesi
kabalang calistir fraktal.kbl -- --tur julia # Julia kümesi (c = -0.8 + 0.156i)
kabalang calistir fraktal.kbl -- --yakinlas # denizatı vadisine 120 karelik dalış
kabalang calistir fraktal.kbl -- -s 160 -r 44 # geniş terminal: 160 sütun × 44 satır
```
## KabaLang'ın gösterdikleri
| Özellik | Nerede |
|---|---|
| `birlikte:` + `baslat` | Görüntü dört şeride bölünür, şeritler **aynı anda** hesaplanır ve sırası korunarak birleştirilir (`kare_ciz`) |
| `sayilabilir` | `Kume.MANDELBROT` / `Kume.JULIA` — kapalı değer kümesi |
| `yapi` | `Kamera` (merkez, görüş genişliği, yineleme sınırı) ve palet `Durak`ları |
| f-string biçimi | `{kam.merkez_x:.5f}{kam.merkez_y:+.5f}i` — işaretli ve hassasiyetli sayı |
| `KomutSatiri` | `--tur`, `--yakinlas`, `--sutun`/`--satir` ve kendiliğinden üretilen `--yardim` |
| Tipli imzalar | `fonksiyon kacis(zx: ondalik, ...) -> ondalik` |
## Nasıl çalışır
* **Kaçış süresi:** `z ← z² + c` yinelenir; `|z|` 2'yi aşarsa nokta kümeden
kaçmıştır. Ne kadar çabuk kaçtığı rengini belirler, hiç kaçmayan nokta
kümenin içidir (lacivert).
* **Palet:** altı renk durağından (derin uzay → gece mavisi → mavi →
camgöbeği → lavanta → beyaz) bir kez 256 tonluk bir liste üretilir.
* **Derin yakınlaşma:** renk, yineleme sayısının üçgen dalgasıdır; böylece
20 yinelemede de 700 yinelemede de paletin tamamı kullanılır.
Bir kare (7.200 piksel, 120 yineleme sınırı) birkaç milisaniyede hesaplanır;
süre başlık satırında yazar.
+171
View File
@@ -0,0 +1,171 @@
# ╔══════════════════════════════════════════════════════════════════╗
# ║ FRAKTAL — terminalde 24 bit renkli Mandelbrot ve Julia kümesi ║
# ║ ║
# ║ Her karakter hücresi İKİ piksel taşır: üst yarım blok `▀`'nin ║
# ║ ön plan rengi üst pikseli, arka plan rengi alt pikseli çizer. ║
# ║ Görüntü dört şeride bölünür ve şeritler AYNI ANDA hesaplanır. ║
# ║ ║
# ║ kabalang calistir fraktal.kbl → Mandelbrot ║
# ║ kabalang calistir fraktal.kbl --tur julia → Julia kümesi ║
# ║ kabalang calistir fraktal.kbl --yakinlas → derinlere dalış║
# ╚══════════════════════════════════════════════════════════════════╝
kullan kaba.sistem
sayilabilir Kume:
MANDELBROT
JULIA
# Kameranın baktığı yer: karmaşık düzlemde merkez ve görüş genişliği.
yapi Kamera:
merkez_x = -0.65
merkez_y = 0.0
genislik = 3.2
sinir = 120 # en fazla kaç yineleme
# ── Renk ─────────────────────────────────────────────────────────────
# Palet, renk duraklarından bir kez üretilir: derin uzay → gece mavisi →
# KabaForce mavisi → camgöbeği → lavanta → beyaz. Aradaki 256 ton doğrusal
# karışımdır; her piksel yalnız listeden bir ton seçer.
yapi Durak:
konum = 0.0
r = 0
g = 0
b = 0
fonksiyon karistir(a: sayi, b: sayi, t: ondalik) -> sayi:
don a + sayi(ondalik(b - a) * t)
fonksiyon palet_uret() -> liste<metin>:
duraklar = [Durak(0.00, 10, 13, 21), Durak(0.18, 26, 42, 108),
Durak(0.40, 55, 126, 244), Durak(0.62, 34, 211, 238),
Durak(0.82, 167, 139, 250), Durak(1.00, 250, 245, 255)]
palet = [] # boş liste sabiti metin listesidir
i = 0
iken i < 256:
t = ondalik(i) / 255.0
k = 0
iken t > duraklar[k + 1].konum:
k = k + 1
a = duraklar[k]
b = duraklar[k + 1]
oran = (t - a.konum) / (b.konum - a.konum)
palet.ekle(f"{karistir(a.r, b.r, oran)};{karistir(a.g, b.g, oran)};{karistir(a.b, b.b, oran)}")
i = i + 1
don palet
PALET = palet_uret()
fonksiyon renk(t: ondalik) -> metin:
eger t < 0.0: # kümenin içi: derin uzay laciverti
don "6;8;14"
don PALET[sayi(t * 255.0)]
# ── Kaçış süresi ─────────────────────────────────────────────────────
# z ← z² + c. |z| 2'yi aşarsa nokta kümeden kaçmıştır; ne kadar
# çabuk kaçtığı rengini belirler. Hiç kaçmazsa -1 döner (kümenin içi).
# Renk yineleme sayısının üçgen dalgasıdır (0 → 1 → 0, her 80 adımda):
# böylece 20 yinelemede de 500 yinelemede de palet baştan sona kullanılır.
fonksiyon kacis(zx: ondalik, zy: ondalik, cx: ondalik, cy: ondalik, sinir: sayi) -> ondalik:
i = 0
iken i < sinir:
x2 = zx * zx
y2 = zy * zy
eger x2 + y2 > 4.0:
dalga = ondalik(i % 80) / 40.0
eger dalga > 1.0:
dalga = 2.0 - dalga
don matematik.karekok(dalga)
zy = 2.0 * zx * zy + cy
zx = x2 - y2 + cx
i = i + 1
don -1.0
fonksiyon piksel(kume: Kume, kam: Kamera, px: sayi, py: sayi, sutun: sayi, satir: sayi) -> ondalik:
# Terminal hücresi kare değil; iki piksel ≈ bir sütun genişliği.
olcek = kam.genislik / ondalik(sutun)
x = kam.merkez_x + (ondalik(px) - ondalik(sutun) / 2.0) * olcek
y = kam.merkez_y + (ondalik(py) - ondalik(satir)) * olcek
eger kume == Kume.JULIA:
don kacis(x, y, -0.8, 0.156, kam.sinir)
don kacis(0.0, 0.0, x, y, kam.sinir)
# Bir şerit: [bas, son) arasındaki karakter satırlarını tek metin olarak üretir.
fonksiyon serit(kume: Kume, kam: Kamera, bas: sayi, son: sayi, sutun: sayi, satir: sayi) -> metin:
cikti = ""
j = bas
iken j < son:
px = 0
iken px < sutun:
ust = renk(piksel(kume, kam, px, 2 * j, sutun, satir))
alt = renk(piksel(kume, kam, px, 2 * j + 1, sutun, satir))
cikti = cikti + "\033[38;2;" + ust + "m\033[48;2;" + alt + "m▀"
px = px + 1
cikti = cikti + "\033[0m\n"
j = j + 1
don cikti
# Dört şeridi dört görevde birlikte hesapla; sıra korunarak birleştir.
fonksiyon kare_ciz(kume: Kume, kam: Kamera, sutun: sayi, satir: sayi) -> metin:
d = satir // 4
resim = "" # birlikte: kendi kapsamıdır, sonucu dışarıda tut
birlikte:
a = baslat serit(kume, kam, 0, d, sutun, satir)
b = baslat serit(kume, kam, d, 2 * d, sutun, satir)
c = baslat serit(kume, kam, 2 * d, 3 * d, sutun, satir)
e = baslat serit(kume, kam, 3 * d, satir, sutun, satir)
resim = a.bekle() + b.bekle() + c.bekle() + e.bekle()
don resim
fonksiyon baslik(kume: Kume, kam: Kamera, sure: sayi) -> metin:
ad = "MANDELBROT"
eger kume == Kume.JULIA:
ad = "JULIA c = -0.8 + 0.156i"
yakinlik = 3.2 / kam.genislik
don f"\033[1;38;2;125;170;255m ◆ {ad}\033[0m\033[38;2;110;120;150m · merkez {kam.merkez_x:.5f}{kam.merkez_y:+.5f}i · ×{yakinlik:.1f} · {kam.sinir} yineleme · {sure} ms\033[0m"
# ── Komut satırı ─────────────────────────────────────────────────────
ks = KomutSatiri("fraktal", "Terminalde 24 bit renkli fraktal çizer")
ks.secenek("tur", "t", "mandelbrot ya da julia")
ks.bayrak("yakinlas", "y", "Mandelbrot'un derinliklerine kare kare dal")
ks.secenek("sutun", "s", "çizim genişliği (karakter, varsayılan 100)")
ks.secenek("satir", "r", "çizim yüksekliği (karakter satırı, varsayılan 36)")
c = ks.coz()
eger c.yardim_mi():
c.yardim_yaz()
cikis(0)
eger c.hatali_mi():
c.hata_yaz_ve_cik()
SUTUN = sayi(c.secenek("sutun").deger_veya("100"))
SATIR = sayi(c.secenek("satir").deger_veya("36")) # 36 karakter satırı = 72 piksel satırı
eger SUTUN < 8 veya SATIR < 4:
konsol.hata_yaz("fraktal: --sutun en az 8, --satir en az 4 olmalı\n")
cikis(2)
kume = Kume.MANDELBROT
kam = Kamera()
eger c.secenek("tur").deger_veya("mandelbrot") == "julia":
kume = Kume.JULIA
kam.merkez_x = 0.0
kam.genislik = 3.0
eger c.bayrak("yakinlas"):
# Denizatı vadisine dalış: her karede görüş %8 daralır.
kam.merkez_x = -0.743643887
kam.merkez_y = 0.131825904
konsol.yaz("\033[?25l\033[2J") # imleci gizle, ekranı temizle
kare = 0
iken kare < 120:
t0 = zaman.milisaniye()
resim = kare_ciz(kume, kam, SUTUN, SATIR)
konsol.yaz("\033[H" + baslik(kume, kam, zaman.milisaniye() - t0) + "\033[K\n" + resim)
kam.genislik = kam.genislik * 0.92
kam.sinir = kam.sinir + 5
uyu(40) # hesap ~3 ms sürüyor; göz için yavaşlat
kare = kare + 1
konsol.yaz("\033[?25h")
degilse:
t0 = zaman.milisaniye()
resim = kare_ciz(kume, kam, SUTUN, SATIR)
yazdir(baslik(kume, kam, zaman.milisaniye() - t0))
konsol.yaz(resim)
+39
View File
@@ -0,0 +1,39 @@
# Sudoku — geri izlemeli çözücü, canlı animasyonla
![Sudoku](../../medya/sudoku.png)
Boş hücreye 1–9 arasındaki ilk uygun rakamı koyar ve ilerler. Çıkmaza
girerse bir önceki hücreye döner (**geri izleme**) ve oradaki bir sonraki
rakamı dener. Her adım ekranda görünür:
* **beyaz** — bulmacada verilen rakam
* **camgöbeği** — çözücünün koyduğu, henüz kesinleşmemiş rakam
* **sarı** — şu an denenen hücre · **kırmızı ✗** — geri alınan hücre
* **yeşil** — çözüm bulunduktan sonra kesinleşen rakamlar
```bash
kabalang calistir sudoku.kbl # animasyonlu (~10 sn)
kabalang calistir sudoku.kbl -- --hizli # yalnız sonuç
kabalang calistir sudoku.kbl -- 3000000000050090002005040000200007001600000587043106000008901000000670800000054 37 --hizli
```
Kendi bulmacanızı 81 haneli bir dizi olarak verebilirsiniz (`0` = boş hücre).
## KabaLang'ın gösterdikleri
| Özellik | Nerede |
|---|---|
| `sinif` + kurucu `kur` | `Cozucu` ızgarayı **kendi üzerinde** değiştirir (metotlar nesnenin kendisinde çalışır) |
| `sayilabilir` | Hücre durumu: `VERILEN · YERLESMIS · DENENIYOR · GERI_ALINDI · KESIN` |
| Tipli liste alanı | `izgara: liste<sayi> = []`, `durum: liste<Hucre> = []` |
| `**` üs işleci | Doğrulamada her grubun `2¹ + … + 2⁹ = 1022` toplamı |
| f-string genişlik | `{self.deneme:5d}` sabit genişlikli sayaç |
## Doğruluk
Program çözümü yazmadan önce `gecerli_mi` ile denetler: her satır, sütun ve
3×3 kutu 1..9'u tam bir kez içermeli. Bu, çözücüden **bağımsız** bir
denetimdir — çözücü hatalı olsaydı ekranda `✓` görünmezdi.
Ölçülen: varsayılan bulmaca 1.682 deneme / 1.631 geri alma; "dünyanın en zor
sudokusu" diye bilinen bulmacalardan biri 243.098 deneme, animasyonsuz ~55 ms.
+197
View File
@@ -0,0 +1,197 @@
# ╔══════════════════════════════════════════════════════════════════╗
# ║ SUDOKU — geri izlemeli çözücü, canlı animasyonla ║
# ║ ║
# ║ Boş hücreye 1..9 arası ilk uygun rakamı koyar ve ilerler. ║
# ║ Çıkmaza girerse bir önceki hücreye döner (geri izleme) ve ║
# ║ oradaki bir sonraki rakamı dener. Her adım ekranda görünür: ║
# ║ sarı = şu an denenen · kırmızı = geri alınan · yeşil = çözüm ║
# ║ ║
# ║ kabalang calistir sudoku.kbl → animasyonlu ║
# ║ kabalang calistir sudoku.kbl --hizli → yalnız sonuç ║
# ╚══════════════════════════════════════════════════════════════════╝
kullan kaba.sistem
BULMACA = "030050040008010500460000012070502080000603000040109030250000098001020600080060020"
sayilabilir Hucre:
VERILEN # bulmacada yazılı gelen rakam
YERLESMIS # çözücünün koyduğu, henüz kesin değil
DENENIYOR
GERI_ALINDI
KESIN
# ── Renkler ──────────────────────────────────────────────────────────
fonksiyon boya(yazi: metin, rgb: metin) -> metin:
don "\033[38;2;" + rgb + "m" + yazi + "\033[0m"
fonksiyon hucre_rengi(h: Hucre) -> metin:
eger h == Hucre.VERILEN:
don "235;240;255"
eger h == Hucre.DENENIYOR:
don "250;204;21"
eger h == Hucre.GERI_ALINDI:
don "248;113;113"
eger h == Hucre.KESIN:
don "74;222;128"
don "34;211;238"
# ── Çözücü ───────────────────────────────────────────────────────────
# Sınıf, ızgarayı kendi üzerinde değiştirir: metotlar nesnenin KENDİSİ
# üzerinde çalışır (işleve geçen liste ise kopyadır).
sinif Cozucu:
izgara: liste<sayi> = []
durum: liste<Hucre> = []
deneme = 0
geri_alma = 0
canli = dogru
fonksiyon kur(self, bulmaca: metin, canli: mantik):
i = 0
iken i < 81:
rakam = sayi(bulmaca.dilim(i, 1))
self.izgara.ekle(rakam)
eger rakam == 0:
self.durum.ekle(Hucre.YERLESMIS)
degilse:
self.durum.ekle(Hucre.VERILEN)
i = i + 1
self.canli = canli
# Aynı satırda, sütunda ya da 3×3 kutuda r rakamı var mı?
fonksiyon uygun_mu(self, konum: sayi, r: sayi) -> mantik:
satir = konum // 9
sutun = konum % 9
kutu = (satir // 3) * 27 + (sutun // 3) * 3
i = 0
iken i < 9:
eger self.izgara[satir * 9 + i] == r veya self.izgara[i * 9 + sutun] == r:
don yanlis
eger self.izgara[kutu + (i // 3) * 9 + i % 3] == r:
don yanlis
i = i + 1
don dogru
# Geri izleme, açık bir yığınla: `bos` boş hücrelerin listesi, `i`
# sıradaki boş hücre. İleri gidemeyince i bir geri çekilir.
fonksiyon coz(self) -> mantik:
bos = [0] # boş SAYI listesi: [] metin listesi olurdu
bos.sil(0)
k = 0
iken k < 81:
eger self.izgara[k] == 0:
bos.ekle(k)
k = k + 1
i = 0
iken i >= 0 ve i < bos.uzunluk():
konum = bos[i]
r = self.izgara[konum] + 1
self.izgara[konum] = 0
iken r <= 9 ve degil self.uygun_mu(konum, r):
r = r + 1
eger r <= 9:
self.deneme = self.deneme + 1
self.izgara[konum] = r
self.durum[konum] = Hucre.DENENIYOR
self.ciz(konum)
self.durum[konum] = Hucre.YERLESMIS
i = i + 1
degilse:
self.geri_alma = self.geri_alma + 1
self.durum[konum] = Hucre.GERI_ALINDI
self.ciz(konum)
self.durum[konum] = Hucre.YERLESMIS
i = i - 1
don i == bos.uzunluk()
fonksiyon tamamla(self):
i = 0
iken i < 81:
eger self.durum[i] != Hucre.VERILEN:
self.durum[i] = Hucre.KESIN
i = i + 1
# ── Çizim ───────────────────────────────────────────────────────
fonksiyon ekran(self) -> metin:
cizgi = boya(" ┣━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━┫", "70;80;110")
cikti = boya(" ┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┓", "70;80;110") + "\n"
s = 0
iken s < 9:
eger s == 3 veya s == 6:
cikti = cikti + cizgi + "\n"
satir = boya(" ┃", "70;80;110")
k = 0
iken k < 9:
d = self.izgara[s * 9 + k]
h = self.durum[s * 9 + k]
yazi = " · "
eger d != 0:
yazi = f" {d} "
eger h == Hucre.GERI_ALINDI:
yazi = " ✗ "
satir = satir + boya(yazi, hucre_rengi(h))
eger k % 3 == 2:
satir = satir + boya("┃", "70;80;110")
k = k + 1
cikti = cikti + satir + "\n"
s = s + 1
cikti = cikti + boya(" ┗━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━┛", "70;80;110") + "\n"
don cikti
fonksiyon ciz(self, konum: sayi):
eger degil self.canli:
don
konsol.yaz("\033[H\n" + boya(" ◆ SUDOKU · geri izleme", "125;170;255") + "\n\n" + self.ekran())
konsol.yaz(f"\n deneme {self.deneme:5d} geri alma {self.geri_alma:5d} hücre {konum // 9 + 1},{konum % 9 + 1} \n")
uyu(3)
# Çözüm gerçekten geçerli mi? Her satır, sütun ve kutu 1..9'u tam bir kez içermeli.
fonksiyon gecerli_mi(izgara) -> mantik:
grup = 0
iken grup < 9:
satir_toplam = 0
sutun_toplam = 0
kutu_toplam = 0
i = 0
iken i < 9:
satir_toplam = satir_toplam + 2 ** izgara[grup * 9 + i]
sutun_toplam = sutun_toplam + 2 ** izgara[i * 9 + grup]
kutu_toplam = kutu_toplam + 2 ** izgara[(grup // 3) * 27 + (grup % 3) * 3 + (i // 3) * 9 + i % 3]
i = i + 1
# 2¹ + 2² + … + 2⁹ = 1022: yalnız 1..9'un her biri bir kez varsa tutar.
eger satir_toplam != 1022 veya sutun_toplam != 1022 veya kutu_toplam != 1022:
don yanlis
grup = grup + 1
don dogru
# ── Program ──────────────────────────────────────────────────────────
ks = KomutSatiri("sudoku", "Geri izlemeli sudoku çözücü")
ks.bayrak("hizli", "h", "Animasyonsuz, yalnız sonucu göster")
ks.konumsal("bulmaca", "81 haneli bulmaca (0 = boş hücre)")
c = ks.coz()
eger c.yardim_mi():
c.yardim_yaz()
cikis(0)
eger c.hatali_mi():
c.hata_yaz_ve_cik()
bulmaca = c.konumsal("bulmaca").deger_veya(BULMACA)
eger bulmaca.uzunluk() != 81:
konsol.hata_yaz("bulmaca 81 haneli olmalı\n")
cikis(2)
cozucu = Cozucu(bulmaca, degil c.bayrak("hizli"))
konsol.yaz("\033[2J\033[?25l")
t0 = zaman.milisaniye()
basardi = cozucu.coz()
sure = zaman.milisaniye() - t0
cozucu.tamamla()
konsol.yaz("\033[H\n" + boya(" ◆ SUDOKU · geri izleme", "125;170;255") + "\n\n" + cozucu.ekran())
eger basardi ve gecerli_mi(cozucu.izgara):
ek = ""
eger cozucu.canli:
ek = " (animasyon dahil)"
yazdir(boya(f"\n ✓ çözüldü — {cozucu.deneme} deneme, {cozucu.geri_alma} geri alma, {sure} ms{ek}", "74;222;128") + "\033[K")
degilse:
yazdir(boya("\n ✗ bu bulmacanın çözümü yok", "248;113;113") + "\033[K")
konsol.yaz("\033[?25h")