1
+ const newGrid = ( size ) => {
2
+ let arr = new Array ( size ) ;
3
+
4
+ for ( let i = 0 ; i < size ; i ++ ) {
5
+ arr [ i ] = new Array ( size ) ;
6
+ }
7
+
8
+ for ( let i = 0 ; i < Math . pow ( size , 2 ) ; i ++ ) {
9
+ arr [ Math . floor ( i / size ) ] [ i % size ] = CONSTANT . UNASSIGNED ;
10
+ }
11
+
12
+ return arr ;
13
+ }
14
+
15
+ // check duplicate number in col
16
+ const isColSafe = ( grid , col , value ) => {
17
+ for ( let row = 0 ; row < CONSTANT . GRID_SIZE ; row ++ ) {
18
+ if ( grid [ row ] [ col ] === value ) return false ;
19
+ }
20
+ return true ;
21
+ }
22
+
23
+ // check duplicate number in row
24
+ const isRowSafe = ( grid , row , value ) => {
25
+ for ( let col = 0 ; col < CONSTANT . GRID_SIZE ; col ++ ) {
26
+ if ( grid [ row ] [ col ] === value ) return false ;
27
+ }
28
+ return true ;
29
+ }
30
+
31
+ // check duplicate number in 3x3 box
32
+ const isBoxSafe = ( grid , box_row , box_col , value ) => {
33
+ for ( let row = 0 ; row < CONSTANT . BOX_SIZE ; row ++ ) {
34
+ for ( let col = 0 ; col < CONSTANT . BOX_SIZE ; col ++ ) {
35
+ if ( grid [ row + box_row ] [ col + box_col ] === value ) return false ;
36
+ }
37
+ }
38
+ return true ;
39
+ }
40
+
41
+ // check in row, col and 3x3 box
42
+ const isSafe = ( grid , row , col , value ) => {
43
+ return isColSafe ( grid , col , value ) && isRowSafe ( grid , row , value ) && isBoxSafe ( grid , row - row % 3 , col - col % 3 , value ) && value !== CONSTANT . UNASSIGNED ;
44
+ }
45
+
46
+ // find unassigned cell
47
+ const findUnassignedPos = ( grid , pos ) => {
48
+ for ( let row = 0 ; row < CONSTANT . GRID_SIZE ; row ++ ) {
49
+ for ( let col = 0 ; col < CONSTANT . GRID_SIZE ; col ++ ) {
50
+ if ( grid [ row ] [ col ] === CONSTANT . UNASSIGNED ) {
51
+ pos . row = row ;
52
+ pos . col = col ;
53
+ return true ;
54
+ }
55
+ }
56
+ }
57
+ return false ;
58
+ }
59
+
60
+ // shuffle arr
61
+ const shuffleArray = ( arr ) => {
62
+ let curr_index = arr . length ;
63
+
64
+ while ( curr_index !== 0 ) {
65
+ let rand_index = Math . floor ( Math . random ( ) * curr_index ) ;
66
+ curr_index -= 1 ;
67
+
68
+ let temp = arr [ curr_index ] ;
69
+ arr [ curr_index ] = arr [ rand_index ] ;
70
+ arr [ rand_index ] = temp ;
71
+ }
72
+
73
+ return arr ;
74
+ }
75
+
76
+ // check puzzle is complete
77
+ const isFullGrid = ( grid ) => {
78
+ return grid . every ( ( row , i ) => {
79
+ return row . every ( ( value , j ) => {
80
+ return value !== CONSTANT . UNASSIGNED ;
81
+ } ) ;
82
+ } ) ;
83
+ }
84
+
85
+ const sudokuCreate = ( grid ) => {
86
+ let unassigned_pos = {
87
+ row : - 1 ,
88
+ col : - 1
89
+ }
90
+
91
+ if ( ! findUnassignedPos ( grid , unassigned_pos ) ) return true ;
92
+
93
+ let number_list = shuffleArray ( [ ...CONSTANT . NUMBERS ] ) ;
94
+
95
+ let row = unassigned_pos . row ;
96
+ let col = unassigned_pos . col ;
97
+
98
+ number_list . forEach ( ( num , i ) => {
99
+ if ( isSafe ( grid , row , col , num ) ) {
100
+ grid [ row ] [ col ] = num ;
101
+
102
+ if ( isFullGrid ( grid ) ) {
103
+ return true ;
104
+ } else {
105
+ if ( sudokuCreate ( grid ) ) {
106
+ return true ;
107
+ }
108
+ }
109
+
110
+ grid [ row ] [ col ] = CONSTANT . UNASSIGNED ;
111
+ }
112
+ } ) ;
113
+
114
+ return isFullGrid ( grid ) ;
115
+ }
116
+
117
+ const sudokuCheck = ( grid ) => {
118
+ let unassigned_pos = {
119
+ row : - 1 ,
120
+ col : - 1
121
+ }
122
+
123
+ if ( ! findUnassignedPos ( grid , unassigned_pos ) ) return true ;
124
+
125
+ grid . forEach ( ( row , i ) => {
126
+ row . forEach ( ( num , j ) => {
127
+ if ( isSafe ( grid , i , j , num ) ) {
128
+ if ( isFullGrid ( grid ) ) {
129
+ return true ;
130
+ } else {
131
+ if ( sudokuCreate ( grid ) ) {
132
+ return true ;
133
+ }
134
+ }
135
+ }
136
+ } )
137
+ } )
138
+
139
+ return isFullGrid ( grid ) ;
140
+ }
141
+
142
+ const rand = ( ) => Math . floor ( Math . random ( ) * CONSTANT . GRID_SIZE ) ;
143
+
144
+ const removeCells = ( grid , level ) => {
145
+ let res = [ ...grid ] ;
146
+ let attemps = level ;
147
+ while ( attemps > 0 ) {
148
+ let row = rand ( ) ;
149
+ let col = rand ( ) ;
150
+ while ( res [ row ] [ col ] === 0 ) {
151
+ row = rand ( ) ;
152
+ col = rand ( ) ;
153
+ }
154
+ res [ row ] [ col ] = CONSTANT . UNASSIGNED ;
155
+ attemps -- ;
156
+ }
157
+ return res ;
158
+ }
159
+
160
+ // generate sudoku base on level
161
+ const sudokuGen = ( level ) => {
162
+ let sudoku = newGrid ( CONSTANT . GRID_SIZE ) ;
163
+ let check = sudokuCreate ( sudoku ) ;
164
+ if ( check ) {
165
+ let question = removeCells ( sudoku , level ) ;
166
+ return {
167
+ original : sudoku ,
168
+ question : question
169
+ }
170
+ }
171
+ return undefined ;
172
+ }
0 commit comments