198 lines
8.3 KiB
Plaintext
198 lines
8.3 KiB
Plaintext
# ╔══════════════════════════════════════════════════════════════════╗
|
|||
|
|
# ║ 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")
|