PITCH: Sudoku: Um jogo feito em JavaScript
Hello guys, hoje eu vou mostrar um projeto pessoal que estou desenvolvendo usando JavaScript, que básicamente é a recriação do jogo sudoku
.
Algoritmo de geração do tabuleiro
Como o projeto tá bem no inicio, hojé ele só esta gerando o tabuleiro de forma randômico, como mostra o gif baixo.
como o algoritmo funciona?
para começar, eu dividir a explicação em 5 partes.
1° O algoritmo começa gerando de forma aleatória um número e uma posição que vai de [0, 80].
DrawNumberAndPosition: function(){ // sortear os números para o square
let position = Math.floor(Math.random() * ((width * hight) - 1) + 1) // gerar a posição aonde o elemento vai ficar na lista
let element = Math.floor(Math.random() * (10 - 1) + 1) // sortear os números
return [position, element]
},
2° Então é verificado se já existe o número na mesma linha e coluna através de duas funcão checkColumnValues
e checkRowValues
que retorna true
ou false
.
// verificar se tem número repetido na mesma coluna
const checkColumnValues = (position, values) => {
let rowIndex = parseInt(position / 9) // calcular a linha apartir do index
let columnIndex = position - (width * rowIndex) // calculo para determinar em qual coluna deve começar a peger os valores
//pegar os valores da coluna e adicionar em um array de verificação
for(let row=0; row<hight; row++){
let index = columnIndex + (width * row)
if(this.board[index] == values) return true
}
return false
}
//verifcar se tem número repetido na mesma linha
const checkRowValues = (position, values) => {
let rowIndex = parseInt(position / 9) // calcular o index da linha apartir da posição
// pegar todos os valores da linha e colocar no array de verificação
for(let column=0; column<width; column++){
let index = column + (width * rowIndex)
if(this.board[index] == values) return true
}
return false
}
Mas existe um bug com esse tipo de geração, como mostra a imagem abaixo.
O algoritomo não consegue saber se já tem um número já existentes no quadrado.
3° para resolver esse problema com número repetidos no mesmo quadrado, eu bolei uma função que verifica quada quadrado do tabuleiro de acordo com a posição gerada.
const checkSquareElements = (position, values) => {
// sequência em que vai ser verificado se o index (posição aonde o n° vai ser colocado)
// em qual área (quadrado do sudoku) ele pertenci
const areaSequence = [
[2,2],
[2,5],
[2,8],
[5,2],
[5,5],
[5,8],
[8,2],
[8,5],
[8,8],
]
//verificar a sequência da área (quadrado do sudoku)
const checkSequence = () => {
for(let i=0; i<areaSequence.length; i++){
if(rowIndex <= areaSequence[i][0] && columnIndex <= areaSequence[i][1]){
return i + 1
}
}
}
let loadColumnValues = [] // memoria que vai carregar os elementos para verificação
let rowIndex = parseInt(position / 9) // calcular a posição da linha apartir do index
let columnIndex = position - (width * rowIndex) // calcular a posição da coluna apartir do index
switch(checkSequence()){
case 1:
for(let column=0; column<3; column++){
for(let row=0; row<3; row++){
let index = column + (width * row)
loadColumnValues.push(this.board[index])
}
}
break;
case 2:
for(let column=3; column<6; column++){
for(let row=0; row<3; row++){
let index = column + (width * row)
loadColumnValues.push(this.board[index])
}
}
break;
case 3:
for(let column=6; column<9; column++){
for(let row=0; row<3; row++){
let index = column + (width * row)
loadColumnValues.push(this.board[index])
}
}
break;
case 4:
for(let column=0; column<3; column++){
for(let row=3; row<6; row++){
let index = column + (width * row)
loadColumnValues.push(this.board[index])
}
}
break;
case 5:
for(let column=3; column<6; column++){
for(let row=3; row<6; row++){
let index = column + (9 * row)
loadColumnValues.push(this.board[index])
}
}
break;
case 6:
for(let column=6; column<9; column++){
for(let row=3; row<6; row++){
let index = column + (width * row)
loadColumnValues.push(this.board[index])
}
}
break;
case 7:
for(let column=0; column<3; column++){
for(let row=6; row<9; row++){
let index = column + (width * row)
loadColumnValues.push(this.board[index])
}
}
break;
case 8:
for(let column=3; column<6; column++){
for(let row=6; row<9; row++){
let index = column + (width * row)
loadColumnValues.push(this.board[index])
}
}
break;
case 9:
for(let column=6; column<9; column++){
for(let row=6; row<9; row++){
let index = column + (width * row)
loadColumnValues.push(this.board[index])
}
}
break;
}
return loadColumnValues.includes(`${values}`) // verificar se tem número repetidos e retonar um [true] ou [false] como resposta
}
- Na primeira parte eu criei um vetor que guarda os valores da coluna e da linha, com esse dados no vetor é possível pegar a posição do ultimo index de quada quadrado.
const areaSequence = [
[2,2],
[2,5],
[2,8],
[5,2],
[5,5],
[5,8],
[8,2],
[8,5],
[8,8],
]
- Com isso, através da posição gerada é calculado em qual linha e coluna um elemento X vai está.
let rowIndex = parseInt(position / 9) // calcular a posição da linha apartir do index
let columnIndex = position - (width * rowIndex) // calcular a posição da coluna apartir do index
- Para saber em qual quadrado o número tá, a função
checkSequence
vai pegar as variáveisrowIndex
ecolumnIndex
vai verificar se o valor é menor do que uns dos valores do vetor e retorna o número do quadrado.
const checkSequence = () => {
for(let i=0; i<areaSequence.length; i++){
if(rowIndex <= areaSequence[i][0] && columnIndex <= areaSequence[i][1]){
return i + 1
}
}
}
- agora é só verificar em um switch case o retorno da função, pegar todos os elementos do quadrado selecionado, salvar em um array e verificar se já existe um número parecido e retornar como
true
efalse
.
switch(checkSequence()){
case 1:
for(let column=0; column<3; column++){
for(let row=0; row<3; row++){
let index = column + (width * row)
loadColumnValues.push(this.board[index])
}
}
break;
case 2:
for(let column=3; column<6; column++){
for(let row=0; row<3; row++){
let index = column + (width * row)
loadColumnValues.push(this.board[index])
}
}
break;
.
.
.
case 8:
for(let column=3; column<6; column++){
for(let row=6; row<9; row++){
let index = column + (width * row)
loadColumnValues.push(this.board[index])
}
}
break;
case 9:
for(let column=6; column<9; column++){
for(let row=6; row<9; row++){
let index = column + (width * row)
loadColumnValues.push(this.board[index])
}
}
break;
}
return loadColumnValues.includes(`${values}`) // verificar se tem número repetidos e retonar um [true] ou [false] como resposta
4° agora é só verificar as funções se o retorno é igual a false
. Se todas as funções retornar false é colocado no board
o nũmero gerado.
//verificar se pode adicionar os números no tabuleiro
if(!checkColumnValues(position,element) && !checkRowValues(position, element) && !checkSquareElements(position,element)){
this.board[position] = `${element}`
i++
}
5° Para determinar o limite de números gerado no tabuleiro.
if(i >= (81 - 36)break
❗ Esse projeto ainda está em desenvolvimento, ainde tem mais coisas para ser implementado!