Skip to content

Commit 41d17ce

Browse files
committed
Seperate concerns into their own headers
1 parent a9be3bf commit 41d17ce

File tree

6 files changed

+224
-176
lines changed

6 files changed

+224
-176
lines changed

src/coord.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* Copyright 2023 Arjun Aravind */
2+
#ifndef SRC_COORD_H_
3+
#define SRC_COORD_H_
4+
5+
#include<utility>
6+
7+
namespace sudoku {
8+
9+
typedef std::pair<int, int> Coord;
10+
int GRID_LEN = 9;
11+
12+
} // namespace sudoku
13+
14+
#endif // SRC_COORD_H_

src/coord_utils.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/* Copyright 2023 Arjun Aravind */
2+
#ifndef SRC_COORD_UTILS_H_
3+
#define SRC_COORD_UTILS_H_
4+
5+
#include<chrono>
6+
#include<random>
7+
#include<set>
8+
#include<utility>
9+
#include<vector>
10+
11+
#include"../src/coord.h"
12+
13+
namespace sudoku {
14+
15+
Coord get_next_cell_coord(Coord coord) {
16+
/* Function which returns the next successive coordinate for a
17+
* Sudoku grid, given a current coordinate. */
18+
if (coord.second == GRID_LEN-1 && coord.first == GRID_LEN-1)
19+
return coord;
20+
else if (coord.second == GRID_LEN-1)
21+
return std::make_pair(coord.first+1, 0);
22+
return std::make_pair(coord.first, coord.second + 1);
23+
}
24+
25+
std::set<Coord> get_N_random_cell_coords(int n) {
26+
std::random_device rd; // obtain a random number from hardware
27+
std::mt19937 gen(rd()); // seed the generator
28+
std::uniform_int_distribution<> distr(0, GRID_LEN-1); // define the range
29+
30+
std::set<Coord> random_cell_coords;
31+
32+
while (n > 0) {
33+
auto cell_coord = std::make_pair(distr(gen), distr(gen));
34+
auto inserted = random_cell_coords.insert(cell_coord);
35+
36+
if (!inserted.second) continue; // Element already existed.
37+
n--;
38+
}
39+
40+
return random_cell_coords;
41+
}
42+
43+
} // namespace sudoku
44+
45+
#endif // SRC_COORD_UTILS_H_
Lines changed: 31 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
11
/* Copyright 2023 Arjun Aravind */
2-
#ifndef SRC_SUDOKU_SUITE_H_
3-
#define SRC_SUDOKU_SUITE_H_
4-
#endif // SRC_SUDOKU_SUITE_H_
2+
#ifndef SRC_GRID_H_
3+
#define SRC_GRID_H_
54

6-
#include<iostream>
7-
#include<fstream>
85
#include<array>
6+
#include<fstream>
7+
#include<iostream>
98
#include<set>
9+
#include<stdexcept>
1010
#include<string>
11-
#include<vector>
12-
#include<algorithm>
1311
#include<utility>
14-
#include<stdexcept>
15-
#include<chrono>
16-
#include<random>
17-
18-
namespace sudoku {
1912

20-
typedef std::pair<int, int> Coord;
13+
#include"../src/coord.h"
2114

22-
int GRID_LEN = 9;
15+
namespace sudoku {
2316

2417
class Grid {
2518
/* A data structure that holds the Sudoku puzzle. */
@@ -176,6 +169,28 @@ class Grid {
176169
return (element_found != coords_that_were_pre_filled.end());
177170
}
178171

172+
/*------------------------*/
173+
/* Cell-related Functions */
174+
175+
std::vector<int> get_possible_values_for_cell_at_coord(Coord coord) {
176+
std::vector<int> values = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
177+
std::vector<int> filtered_values(values.size());
178+
179+
auto it = std::copy_if(
180+
values.begin(), values.end(),
181+
filtered_values.begin(),
182+
[this, coord] (int value) -> bool {
183+
return !(
184+
this->value_exists_elsewhere_in_column(coord, value) ||
185+
this->value_exists_elsewhere_in_row(coord, value) ||
186+
this->value_exists_elsewhere_in_3x3_grid(coord, value));
187+
});
188+
189+
// Shrink vector to remove empty elements.
190+
filtered_values.resize(std::distance(filtered_values.begin(), it));
191+
return filtered_values;
192+
}
193+
179194
/*--------------------*/
180195
/* Operator Overloads */
181196

@@ -206,166 +221,6 @@ std::ostream& operator<< (std::ostream& out, Grid grid) {
206221
return out;
207222
}
208223

209-
/*------------------*/
210-
/* COORD FUNCTIONS */
211-
/*------------------*/
212-
213-
Coord get_next_cell_coord(Coord coord) {
214-
/* Function which returns the next successive coordinate for a
215-
* Sudoku grid, given a current coordinate. */
216-
if (coord.second == GRID_LEN-1 && coord.first == GRID_LEN-1)
217-
return coord;
218-
else if (coord.second == GRID_LEN-1)
219-
return std::make_pair(coord.first+1, 0);
220-
return std::make_pair(coord.first, coord.second + 1);
221-
}
222-
223-
std::set<Coord> get_N_random_cell_coords(int n) {
224-
std::random_device rd; // obtain a random number from hardware
225-
std::mt19937 gen(rd()); // seed the generator
226-
std::uniform_int_distribution<> distr(0, GRID_LEN-1); // define the range
227-
228-
std::set<Coord> random_cell_coords;
229-
230-
while (n > 0) {
231-
auto cell_coord = std::make_pair(distr(gen), distr(gen));
232-
auto inserted = random_cell_coords.insert(cell_coord);
233-
234-
if (!inserted.second) continue; // Element already existed.
235-
n--;
236-
}
237-
238-
return random_cell_coords;
239-
}
240-
241-
std::vector<int> get_possible_values_for_cell_at_coord(
242-
const Grid& grid,
243-
Coord coord
244-
) {
245-
std::vector<int> values = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
246-
std::vector<int> filtered_values(values.size());
247-
248-
auto it = std::copy_if(
249-
values.begin(), values.end(),
250-
filtered_values.begin(),
251-
[&grid, coord] (int value) -> bool {
252-
return !(
253-
grid.value_exists_elsewhere_in_column(coord, value) ||
254-
grid.value_exists_elsewhere_in_row(coord, value) ||
255-
grid.value_exists_elsewhere_in_3x3_grid(coord, value));
256-
});
257-
258-
// Shrink vector to remove empty elements.
259-
filtered_values.resize(std::distance(filtered_values.begin(), it));
260-
return filtered_values;
261-
}
262-
263-
/*----------------------*/
264-
/* GENERATION FUNCTIONS */
265-
/*----------------------*/
266-
267-
268-
bool fill_with_valid_solution(
269-
Grid *grid,
270-
Coord curr_coord = std::make_pair(0, 0)
271-
) {
272-
auto next_coord = get_next_cell_coord(curr_coord);
273-
274-
auto values = get_possible_values_for_cell_at_coord(*grid, curr_coord);
275-
if (values.size() == 0) return false;
276-
277-
// We randomise the values so that we get a random solution each time.
278-
auto rnd_seed = std::chrono::system_clock::now().time_since_epoch().count();
279-
std::shuffle(
280-
values.begin(),
281-
values.end(),
282-
std::default_random_engine(rnd_seed));
283-
284-
for (auto value : values) {
285-
grid->update(curr_coord, value);
286-
if (curr_coord == std::make_pair(8, 8)) return true; // Done
287-
288-
bool next_cell_is_filled = fill_with_valid_solution(grid, next_coord);
289-
if (next_cell_is_filled) return true;
290-
291-
/* If this value didn't work, we need to clear the grid of all the
292-
* values that have been filled as a result of this. */
293-
grid->clear_values_starting_from_coord(curr_coord);
294-
}
295-
296-
return false;
297-
}
298-
299-
void remove_values_from_solution(Grid *grid, int values_to_remove) {
300-
auto random_cell_coords = get_N_random_cell_coords(values_to_remove);
301-
for (auto coord : random_cell_coords) grid->update(coord, 0);
302-
}
303-
304-
/*-----------------*/
305-
/* SOLVE FUNCTIONS */
306-
/*-----------------*/
307-
308-
bool _solve(
309-
Grid *grid,
310-
Coord cell_coord = std::make_pair(0, 0)
311-
) {
312-
auto next_coord = get_next_cell_coord(cell_coord);
313-
314-
if (grid->coord_was_pre_filled(cell_coord)) {
315-
if (cell_coord == std::make_pair(8, 8)) return true;
316-
return _solve(grid, next_coord);
317-
}
318-
319-
auto values = get_possible_values_for_cell_at_coord(*grid, cell_coord);
320-
if (values.size() == 0) return false;
321-
322-
for (auto value : values) {
323-
grid->update(cell_coord, value);
324-
if (cell_coord == std::make_pair(8, 8)) return true; // Solved!
325-
326-
bool next_cell_is_solved = _solve(grid, next_coord);
327-
if (next_cell_is_solved) return true;
328-
329-
/* If this value didn't work, we need to clear the grid of all the
330-
* values that have been filled as a result of this. */
331-
grid->clear_values_starting_from_coord(cell_coord);
332-
}
333-
334-
if (cell_coord == std::make_pair(0, 0)) throw std::logic_error(
335-
"This puzzle doesn't have a solution!");
336-
337-
return false;
338-
}
339-
340-
/*-----------------*/
341-
/* SUITE FUNCTIONS */
342-
/*-----------------*/
343-
344-
void solve(Grid *grid) {
345-
_solve(grid);
346-
}
347-
348-
bool is_valid_solution(
349-
const Grid& grid,
350-
Coord curr_coord = std::make_pair(0, 0)
351-
) {
352-
int value = grid.get(curr_coord);
353-
if (value == 0) return false; // It's unfinished.
354-
else if (
355-
grid.value_exists_elsewhere_in_column(curr_coord, value) ||
356-
grid.value_exists_elsewhere_in_row(curr_coord, value) ||
357-
grid.value_exists_elsewhere_in_3x3_grid(curr_coord, value))
358-
return false;
359-
if (curr_coord == std::make_pair(8, 8)) return true;
360-
else
361-
return is_valid_solution(grid, get_next_cell_coord(curr_coord));
362-
}
363-
364-
Grid generate_puzzle() {
365-
Grid grid;
366-
fill_with_valid_solution(&grid);
367-
remove_values_from_solution(&grid, 30);
368-
return grid;
369-
}
370-
371224
} // namespace sudoku
225+
226+
#endif // SRC_GRID_H_

src/sudoku_generator.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/* Copyright 2023 Arjun Aravind */
2+
#ifndef SRC_SUDOKU_GENERATOR_H_
3+
#define SRC_SUDOKU_GENERATOR_H_
4+
#endif // SRC_SUDOKU_GENERATOR_H_
5+
6+
#include<chrono>
7+
#include<random>
8+
#include<utility>
9+
10+
#include"../src/grid.h"
11+
#include"../src/coord_utils.h"
12+
13+
namespace sudoku {
14+
15+
bool fill_with_valid_solution(
16+
Grid *grid,
17+
Coord curr_coord = std::make_pair(0, 0)
18+
) {
19+
auto next_coord = get_next_cell_coord(curr_coord);
20+
21+
auto values = grid->get_possible_values_for_cell_at_coord(curr_coord);
22+
if (values.size() == 0) return false;
23+
24+
// We randomise the values so that we get a random solution each time.
25+
auto rnd_seed = std::chrono::system_clock::now().time_since_epoch().count();
26+
std::shuffle(
27+
values.begin(),
28+
values.end(),
29+
std::default_random_engine(rnd_seed));
30+
31+
for (auto value : values) {
32+
grid->update(curr_coord, value);
33+
if (curr_coord == std::make_pair(8, 8)) return true; // Done
34+
35+
bool next_cell_is_filled = fill_with_valid_solution(grid, next_coord);
36+
if (next_cell_is_filled) return true;
37+
38+
/* If this value didn't work, we need to clear the grid of all the
39+
* values that have been filled as a result of this. */
40+
grid->clear_values_starting_from_coord(curr_coord);
41+
}
42+
43+
return false;
44+
}
45+
46+
void remove_values_from_solution(Grid *grid, int values_to_remove) {
47+
auto random_cell_coords = get_N_random_cell_coords(values_to_remove);
48+
for (auto coord : random_cell_coords) grid->update(coord, 0);
49+
}
50+
51+
Grid generate_puzzle() {
52+
Grid grid;
53+
fill_with_valid_solution(&grid);
54+
remove_values_from_solution(&grid, 30);
55+
return grid;
56+
}
57+
58+
} // namespace sudoku

src/sudoku_solver.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/* Copyright 2023 Arjun Aravind */
2+
#ifndef SRC_SUDOKU_SOLVER_H_
3+
#define SRC_SUDOKU_SOLVER_H_
4+
#endif // SRC_SUDOKU_SOLVER_H_
5+
6+
#include"../src/grid.h"
7+
#include"../src/coord_utils.h"
8+
9+
namespace sudoku {
10+
11+
bool _solve(
12+
Grid *grid,
13+
Coord cell_coord = std::make_pair(0, 0)
14+
) {
15+
auto next_coord = get_next_cell_coord(cell_coord);
16+
17+
if (grid->coord_was_pre_filled(cell_coord)) {
18+
if (cell_coord == std::make_pair(8, 8)) return true;
19+
return _solve(grid, next_coord);
20+
}
21+
22+
auto values = grid->get_possible_values_for_cell_at_coord(cell_coord);
23+
if (values.size() == 0) return false;
24+
25+
for (auto value : values) {
26+
grid->update(cell_coord, value);
27+
if (cell_coord == std::make_pair(8, 8)) return true; // Solved!
28+
29+
bool next_cell_is_solved = _solve(grid, next_coord);
30+
if (next_cell_is_solved) return true;
31+
32+
/* If this value didn't work, we need to clear the grid of all the
33+
* values that have been filled as a result of this. */
34+
grid->clear_values_starting_from_coord(cell_coord);
35+
}
36+
37+
if (cell_coord == std::make_pair(0, 0)) throw std::logic_error(
38+
"This puzzle doesn't have a solution!");
39+
40+
return false;
41+
}
42+
43+
void solve(Grid *grid) {
44+
_solve(grid);
45+
}
46+
47+
} // namespace sudoku

0 commit comments

Comments
 (0)