Sudoku Oluşturucu (ReactJs)

Kuzey Köse
5 min readFeb 29, 2020

--

Gün geçtikçe Sudoku’nun bilinirliği artıyor ve popülerleşiyor. Bir bulmaca olan sudoku; zaman geçirmek, rakamlarla uğraşmak ve düşünmek için güzel bir yol. Bende bu yazımda sudoku oluşturan bir algoritma yazmak ve sizinle paylaşmak istedim. Öncelikle sudoku neymiş bunu bir gözden geçirelim.

Sudokunun bir çok çeşidi var. Biz klasik sudokuyu inceleyeceğiz ve üzerine düşüneceğiz. 9a 9 karalerden oluşan 81 bölmeli bir kutu olarak düşünelim. Bu karalere 1den başlayarak 9a kadar sayılar yerleştireceğiz ve bu sayıları yerleştirirken üç temel kuralı ele alacağız. Her satırda, her sütunda ve her bölmede tüm rakamlar olmalı ve bir rakam bir kere kullanılmalıdır. Bölmeleri 3e 3 şekinde tanımlayabiliriz. Fig1 de bölmelerin yerilerini görebilirsiniz.

Fig-1.1

Bu uygulamayı geliştirirken ReactJS kullancağız, belki projeyi ilerletir oynanabilen bir sudokuya çeviririz ilerki günlerde. ReactJS daha iyi anlamak istiyorsanız dokümantasyonu okumanızı tavsiye ederim. (reactjs.org)

Kodun tam haline buradan ulaşabilirsiniz.

Kodu yazmaya başlamadan önce düşünmek ve neler yapacağımızı not almak önemli, böylece nasıl bir yol izlememiz gerektiğini görsel olarak görmüş olacağız ve bir planımız olmuş olacak.

9x9 matrix oluşturacağız ve her değere 0 vereceğiz (2d array)Satırları, sütunları ve bölgeleri kontrol eden fonksiyonlar yazalımHer bölmeye gelebilecek sayıları bir array içerisine alalım ve bu sayılardan bir tanesini rastgele seçelimi. Seçtiğimiz sayıyı kutuya yerleştirelim.

Öncelikle ‘sudoku’ adlı bir dizi oluşturalım ve bu dizinin içerisine 9 adet daha dizi yerleştirelim. İçerideki dizilerimizin 9 tane elemanı olsun ve değerlerini 0 olarak tanımlayalım. Bu şekilde sudoku tahtamı oluşturmuş olacağım.

constructor(props) {
super(props);
this.state = {
sudoku: [
[0,0,0,0,0,0,0,0,0,],
[0,0,0,0,0,0,0,0,0,],
[0,0,0,0,0,0,0,0,0,],
[0,0,0,0,0,0,0,0,0,],
[0,0,0,0,0,0,0,0,0,],
[0,0,0,0,0,0,0,0,0,],
[0,0,0,0,0,0,0,0,0,],
[0,0,0,0,0,0,0,0,0,],
[0,0,0,0,0,0,0,0,0,],
]
};
}

Sudokumuzu sayılarla doldurmaya geçmeden önce yapmamız gereken bir diğer aşama gelecek sayının kutuya uygun olup olmadığını değerlendirmektir. Bunun için üç farklı fonksiyon yazacağız ve bu fonksiyonları kullanarak üçüncü aşamamıza ilerleyeceğiz yani sudokunun sayılarını yerleştireceğiz.

İlk fonksiyonumuzun ismi ‘checkRow’ olsun. Bu fonksiyonda kontrol etmemiz gereken önemli nokta, 1den 9 a kadar olan sayıların tekrarsız bir şekilde yazılması. Parantez içerisinde tanımlamış olduğum ‘i’ parametresi benim hangi satır sırasında olduğumu belirleyecek, ‘posibleNumbers’ parametremi ise satırdaki farklı elemanları bulmak için kullanacağım, ‘array’ ise benim sudokum.

checkRow = (i,posibleNumbers, array) => {
for (let j = 0; j < 9; j++) {
if(array[i][j]===randomNumber) {
return false
}
}
return true
}

Buna ek olarak diğer bir fonksiyonumuz ‘checkColumn’ olacak. ‘checkRow’ ile aynı işlemleri yapacak fakat satırlarımda değil sütunlarımda çalışacak.

checkColumn = (j,posibleNumbers, array) => {
for (let i= 0; i< 9; i++) {
if(array[i][j]===randomNumber) {
return false
}
}
return true
}

Üçüncü kontrol aşamamız diğerlerine göre biraz daha karışık gelebilir. Burada gelebilecek sayımı, bölgemin içerisindeki sayılarla kıyaslayacağım ve ona göre seçeceğim. Bunun için sayıyı koyacağım kutunun hangi bölgede olduğunu kararlaştırmam lazım, dilerseniz bunun için ‘takeNumberPosition’ adlı bir fonksiyon yazalım. Satır ve sütun sayılarıma bakarak hangi bölgede çalışmak istediğime karar vermeye çalışacağım ve fonksiyonumun çıktısı bir obje olacak. Objemin iki tane ‘x’ iki tane ‘y’ değeri olacak ve bu değerleri ‘checkBox’ fonksiyonumda sınırları belirlemek için kullanacağım.

takeNumberPosition= (i,j) => {
var object = {
x1:0,
x2:0,
y1:0,
y2:0
}
if (i>=0 && i<3) {
object.x1=0
object.x2=2
}else if (i>=3 && i<6) {
object.x1=3
object.x2=5
}else if (i>=6 && i<9) {
object.x1=6
object.x2=8
}
if (j>=0 && j<3) {
object.y1=0
object.y2=2
}else if (j>=3 && j<6) {
object.y1=3
object.y2=5
}else if (j>=6 && j<9) {
object.y1=6
object.y2=8
}
return object
}

‘takeNumberPosition’ fonksiyonumu kullanarak artık ‘checkBox’ fonksiyonumu yazabilirim. For döngülerinin içinde görülen ‘object.x1’ ve diğerleri sınırlarımı belirliyor ve bölgemin kutularına tek tek bakmamı sağlıyor.

checkBox = (i, j, posibleNumbers, array) => {
var object = this.takeNumberPosition(i,j)
for (let r = object.x1; r <= object.x2; r++) {
for (let c = object.y1; c <= object.y2; c++) {
if(array[r][c]===posibleNumbers){
return false
}
}
}
return true
}

Kontrol fonksiyonlarımızı yazdık. Şimdi biraz düşünme sırası, bu fonksiyonları en verimli şekilde nasıl kullanabilirim? Bir fonksiyon yazacağız ve bu fonksiyonun temeli bir do-while döngüsü olacak. Array[i][j] değerleri 0 ise Do çalışacak. Do’nun içinde ise bir for döngüsü gerçekleşecek ve üzerinde olduğum kutuya gelebilcek sayıları bir dizi içerisine alacak. Bu dizide gelebilecek sayılardan rastgele bir tanesini seçeceğiz ve üzerinde olduğumuz kutunun 0 değerini yeni sayımızla değiştireceğiz.

fillMyBox = (i,j,array) => {
var randomNumber
do {
var myNumberArray = []
for (let k = 1; k < 10; k++) {
if(
this.checkBox(i, j, k, array) &&
this.checkRow(i, k, array) &&
this.checkColumn(j, k, array)){
myNumberArray.push(k)
}
randomNumber = posiArray[Math.floor(Math.random()*myNumberArray.length)] array[i][j]=randomNumber
}
} while (array[i][j] === 0);
}

Yazmış olduğumuz ‘fillMyBox’ methodu 3 tane parametre alıyor. ‘i’ parametresi satır koordinatını, ‘j’ parametresi sütun koordinatını ve ‘array’ ise tahta olarak adlandırdığım bütün sudokunu methoda verecek. Bu parametreleri ‘fillMySudoku’ fonksiyonumun içende kullanacağım. Bu fonksiyonun içinde sudoku[i][j] === undefined kısmı var. Bunu yazma nedenim, nadirende olsa ‘check’ fonksiyonumdaki kontrol kısmı bir sayı bulamıyor çünkü elindeki sayıları öyle bir yerleştiriyor ki, satırın son sayısı uygun gelemiyor ve undefined olarak tanımlanıyor. Eğer bir sayımı undefined olarak tanımlarsa o satırı yeniden doldurmaya başlıyor.

fillMySudoku = () => {
var sudoku = this.state.squares
for (let i = 0; i < 9; i++) {
for (let j = 0; j <9; j++) {
this.check(i,j,sudoku)
if (sudoku[i][j] === undefined) {
j=0
}
}
}
return sudoku
}

‘componentDidMount’ fonksiyonumuzda da ‘fillMySudoku’ yu çalıştırıp state kısmını set edersek her şey yolunda gidecektir.

componentDidMount(){
var sudokuBox = this.fillMySudoku()
this.setState({squares: sudokuBox})
}

Son olarak bunu browser a yansıtmak için ‘render’ metodum var. Bu render metodumun içinde html çalışacak ve ekrana değerleri yazdıracağız.

render() {
return (
<div>
{this.state.squares.map((row, key)=>{
return (<div>{row}</div>)
})}
</div>
);
}

Yazdıklarımızı çalıştırdığımızda browser daki görüntü Fig2 deki resimle benzer olmalıdır.Bundan sonrasını nasıl düzenlemek ve yönetmek istiyorsanız size kalmış. Şekilleri değiştirebilirsiniz, kutuları daha güzel görünür hale getirebilir, hatta bazı sayıları silerek, oynanabilir bir bulmaca haline getirebilirsiniz.

Fig2

Kodun tam haline buradan ulaşabilirsiniz.

--

--

Kuzey Köse
Kuzey Köse

Written by Kuzey Köse

Software Engineer and may be content creator. https://twitter.com/kuzeyks

No responses yet