Skip to content

Commit

Permalink
Merge pull request #15 from Hack-Weekly/feature/show-errors
Browse files Browse the repository at this point in the history
Feature/show errors
  • Loading branch information
jiajunxd authored Aug 16, 2023
2 parents 819a0ac + 40de5b7 commit 57d7a00
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 21 deletions.
19 changes: 16 additions & 3 deletions sudoku-app/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import Theme from './Theme.js';
import Sudoku from './logic/SudokuGenerator.js';
import Header from './Header.js';
import Buttons from './Buttons.js';
import { sudokuSolver, sudokuChecker } from './logic/SudokuSolver.js';
import { sudokuSolver, sudokuChecker, generateErrorGrid } from './logic/SudokuSolver.js';

function App() {
const [grid, setGrid] = useState(Array(9).fill(Array(9).fill('')));
const [givenGrid, setGivenGrid] = useState(Array(9).fill(Array(9).fill('')));
const [grid, setGrid] = useState(new Array(9).fill().map(() => new Array(9).fill('')));
const [givenGrid, setGivenGrid] = useState(new Array(9).fill().map(() => new Array(9).fill('')));
const [errorsGrid, setErrorsGrid] = useState(new Array(9).fill().map(() => new Array(9).fill(false)));
const [errorsVisibility, setErrorsVisibility] = useState(false)
const [solution, setSolution] = useState([]);
const [remainingTime, setRemainingTime] = useState(0);
const [timerId, setTimerId] = useState(null)
Expand Down Expand Up @@ -46,6 +48,8 @@ function App() {
);
setGrid(newGrid);

setErrorsGrid(generateErrorGrid(newGrid))

if (isFullyFilled(newGrid)) {
if (sudokuChecker(newGrid.map(row => row.slice()))) {
alert("Sudoku solved!");
Expand Down Expand Up @@ -79,6 +83,7 @@ function App() {
setGivenGrid(sudoku.mat);
setGrid(sudoku.mat);
setSolution([]);
setErrorsGrid(new Array(9).fill().map(() => new Array(9).fill(false)));
};

const solveForMe = () => {
Expand All @@ -92,6 +97,10 @@ function App() {
stopTimer()
};

const toggleErrors = () => {
setErrorsVisibility(!errorsVisibility)
}

const startTimer = (minutes) => {
setRemainingTime(minutes * 60);
};
Expand All @@ -104,18 +113,22 @@ function App() {
<div className="App">
<Header />
<SudokuGrid
errorsGrid={errorsGrid}
givenGrid={givenGrid}
grid={grid}
solution={solution}
handleInputChange={(rowIndex, colIndex, value) =>
handleGridChange(rowIndex, colIndex, value)}
errorsVisibility={errorsVisibility}
/>
<Buttons
handleDifficultySelection={(difficulty) =>
handleDifficultySelection(difficulty)}
solveForMe={solveForMe}
startTimer={startTimer}
remainingTime={remainingTime}
toggleErrors={toggleErrors}
errorsVisibility={errorsVisibility}
/>
<Theme />
</div>
Expand Down
3 changes: 2 additions & 1 deletion sudoku-app/src/Buttons.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect } from "react";

function Buttons({ startTimer, handleDifficultySelection, solveForMe, remainingTime }) {
function Buttons({ startTimer, handleDifficultySelection, solveForMe, remainingTime, toggleErrors, errorsVisibility }) {
const modes = ["easy", "medium", "hard"];

useEffect(() => {
Expand All @@ -16,6 +16,7 @@ function Buttons({ startTimer, handleDifficultySelection, solveForMe, remainingT
</div>
<div className="Buttons">
<button className="button" onClick={solveForMe}>Solve for Me</button>
<button className="button" onClick={toggleErrors}>{errorsVisibility ? "Hide Errors" : "Show Errors"}</button>
</div>
<div className="timer">Time remaining: {Math.floor(remainingTime / 60)}:{(remainingTime % 60).toString().padStart(2, '0')}</div>

Expand Down
9 changes: 7 additions & 2 deletions sudoku-app/src/SudokuGrid.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
}

.r-border {
border-right: 2px solid rgb(49, 43, 51);
border-right: 3px solid rgb(49, 43, 51);
}

.t-border {
border-top: 2px solid rgb(49, 43, 51);
border-top: 3px solid rgb(49, 43, 51);
}

.sudoku-cell-given {
Expand Down Expand Up @@ -51,4 +51,9 @@
.button {
font-size: 1rem;
}
}

input.cell-error {
color: red;
caret-color: black;
}
13 changes: 4 additions & 9 deletions sudoku-app/src/SudokuGrid.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import './SudokuGrid.css';

const SudokuGrid = ({ givenGrid, grid, solution, handleInputChange }) => {
const SudokuGrid = ({ errorsGrid, givenGrid, grid, solution, handleInputChange, errorsVisibility }) => {
return (
<div className="sudoku-grid">
{grid.map((rowArray, rowIndex) => (
Expand All @@ -11,8 +11,9 @@ const SudokuGrid = ({ givenGrid, grid, solution, handleInputChange }) => {
type="text"
className={
`sudoku-cell
${rowIndex === 2 || rowIndex === 5 ? "t-border" : ""}
${colIndex === 2 || colIndex === 5 ? "r-border" : ""}`}
${rowIndex === 3 || rowIndex === 6 ? "t-border" : ""}
${colIndex === 2 || colIndex === 5 ? "r-border" : ""}
${errorsVisibility && errorsGrid[rowIndex][colIndex] ? "cell-error" : ""}`}
value={solution.length > 0 ? solution[rowIndex][colIndex] : cellValue}
maxLength="1"
readOnly={givenGrid[rowIndex][colIndex] !== ""}
Expand All @@ -28,9 +29,3 @@ const SudokuGrid = ({ givenGrid, grid, solution, handleInputChange }) => {
};

export default SudokuGrid;






2 changes: 1 addition & 1 deletion sudoku-app/src/logic/SudokuGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default class Sudoku {
let index = 0;
for (let i = 0; i < this.SRN; i++) {
for (let j = 0; j < this.SRN; j++) {
this.mat[row + i][col + j] = numbers[index];
this.mat[row + i][col + j] = `${numbers[index]}`;
index++;
}
}
Expand Down
43 changes: 38 additions & 5 deletions sudoku-app/src/logic/SudokuSolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const isEmpty = grid => grid === '';
* @returns {boolean} returns a boolean that determines if
* the puzzle was solved.
*/
export function sudokuSolver(data) {
function sudokuSolver(data) {
for (let row = 0; row < 9; row++) {
for (let col = 0; col < 9; col++) {
if (!isEmpty(data[row][col])) continue;
Expand All @@ -45,7 +45,7 @@ export function sudokuSolver(data) {
}


export function sudokuChecker(board) {
function sudokuChecker(board) {
const AVAILABLE_NUMBERS = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let set = new Set();

Expand All @@ -54,20 +54,53 @@ export function sudokuChecker(board) {
if (parseInt(board[row][col] == NaN |
!AVAILABLE_NUMBERS.includes(parseInt(board[row][col]))) |
isEmpty(board[row][col])) return false;

if (set.has(
"row" + row + "" + board[row][col],
"col" + col + "" + board[row][col],
"grid" + Math.ceil((row + 1)/3.0) + Math.ceil((col + 1)/3.0) + board[row][col])) return false;
"grid" + Math.ceil((row + 1) / 3.0) + Math.ceil((col + 1) / 3.0) + board[row][col])) return false;
else {
set.add(
"row" + row + "" + board[row][col],
"col" + col + "" + board[row][col],
"grid" + Math.ceil((row + 1)/3.0) + Math.ceil((col + 1)/3.0) + board[row][col]);
"grid" + Math.ceil((row + 1) / 3.0) + Math.ceil((col + 1) / 3.0) + board[row][col]);
}
}
}

return true;
}

/**
* Generate error grid that maps to grid data
* @param {string[][]} data 2D array of number strings in sudoku board
* @returns {boolean[][]} 2D array of boolean with true as invalid cells and false as valid cells
*/
function generateErrorGrid(data) {
const errors = new Array(9).fill().map(() => new Array(9).fill(0));

// Adapted from isValid function above
const isValid = (row, col, k) => {
for (let i = 0; i < 9; i++) {
const m = 3 * Math.floor(row / 3) + Math.floor(i / 3);
const n = 3 * Math.floor(col / 3) + i % 3;
// Ignore the same (row, col) to not mark it as invalid
if ((data[row][i] == k && i !== col) || (data[i][col] == k && i !== row) || (data[m][n] == k && (m !== row || n !== col))) {
return false;
}
}
return true;
}

for (let row = 0; row < 9; row++) {
for (let col = 0; col < 9; col++) {
if (isEmpty(data[row][col])) continue;
if (!isValid(row, col, data[row][col])) {
errors[row][col] = true;
}
}
}
return errors;
}

export { sudokuSolver, isValid, sudokuChecker, generateErrorGrid }

1 comment on commit 57d7a00

@vercel
Copy link

@vercel vercel bot commented on 57d7a00 Aug 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

sage-giraffe-sudoku – ./sudoku-app

sage-giraffe-sudoku-sagegiraffe.vercel.app
sage-giraffe-sudoku-delta.vercel.app
sage-giraffe-sudoku-git-main-sagegiraffe.vercel.app

Please sign in to comment.