# ╔══════════════════════════════════════════════════════════════════╗ # ║ 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 = [] durum: liste = [] 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")