Skip to content

Commit

Permalink
feat: better automated notes (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
TN1ck authored May 25, 2024
1 parent 00198ab commit 062b0f7
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 58 deletions.
34 changes: 30 additions & 4 deletions src/components/pages/Game/GameControls/GameControlNumbers.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import * as React from "react";
import {setNumber, setNote, SudokuState} from "src/state/sudoku";
import {setNumber, setNotes, SudokuState} from "src/state/sudoku";
import {SUDOKU_NUMBERS} from "src/engine/utility";
import {CellCoordinates} from "src/engine/types";
import styled from "styled-components";
import Button from "src/components/modules/Button";
import {connect, ConnectedProps} from "react-redux";
import {RootState} from "src/state/rootReducer";
import clsx from "clsx";
import SudokuGame from "src/sudoku-game/SudokuGame";

const SudokuMenuNumbersContainer = styled.div.attrs({
className: "grid w-full overflow-hidden justify-center gap-2 md:grid-cols-3 grid-cols-9 md:mt-0 mt-4",
Expand All @@ -25,7 +26,7 @@ export interface SudokuMenuNumbersStateProps {

export interface SudokuMenuNumbersDispatchProps {
setNumber: typeof setNumber;
setNote: typeof setNote;
setNotes: typeof setNotes;
}

const connector = connect(
Expand All @@ -34,10 +35,11 @@ const connector = connect(
showOccurrences: state.game.showOccurrences,
activeCell: state.game.activeCellCoordinates,
sudoku: state.sudoku,
showHints: state.game.showHints,
}),
{
setNumber,
setNote,
setNotes,
},
);
type PropsFromRedux = ConnectedProps<typeof connector>;
Expand All @@ -49,18 +51,37 @@ class SudokuMenuNumbers extends React.Component<PropsFromRedux> {
{SUDOKU_NUMBERS.map((n) => {
const occurrences = this.props.sudoku.filter((c) => c.number === n).length;

const conflicting = SudokuGame.conflictingFields(this.props.sudoku);
const activeCell = this.props.sudoku[this.props.activeCell!.y * 9 + this.props.activeCell!.x];
const userNotes = activeCell.notes;
const conflictingCell = conflicting[this.props.activeCell!.y * 9 + this.props.activeCell!.x];
const autoNotes = this.props.showHints ? conflictingCell.possibilities : [];

const setNumberOrNote = () => {
if (this.props.notesMode) {
this.props.setNote(this.props.activeCell!, n);
const startingNotes = userNotes.length === 0 && autoNotes.length > 0 ? autoNotes : userNotes;

const newNotes = startingNotes.includes(n)
? startingNotes.filter((note) => note !== n)
: [...userNotes, n];
this.props.setNotes(this.props.activeCell!, newNotes);
} else {
this.props.setNumber(this.props.activeCell!, n);
}
};

return (
<NumberButton
className={clsx("relative font-bold", {
"bg-gray-400": occurrences == 9,
"bg-red-400": this.props.showOccurrences && occurrences > 9,
"bg-sky-600 text-white": this.props.notesMode && userNotes.includes(n) && activeCell.number === 0,
"bg-sky-300":
this.props.notesMode &&
userNotes.length === 0 &&
autoNotes.includes(n) &&
!userNotes.includes(n) &&
activeCell.number === 0,
})}
onClick={setNumberOrNote}
key={n}
Expand All @@ -70,6 +91,11 @@ class SudokuMenuNumbers extends React.Component<PropsFromRedux> {
{occurrences}
</div>
)}
{/* {this.props.notesMode && this.props.showHints && autoNotes.includes(n) && (
<div className="absolute font-normal left-1 top-1 h-3 w-3 rounded-xl text-xxs text-gray opacity-70 ">
{"auto"}
</div>
)} */}
{n}
</NumberButton>
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/pages/Game/Sudoku/Sudoku.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export class Sudoku extends React.PureComponent<SudokuProps> {
const position = positionedCells[i];
const conflicted = conflicting[i];

const notes = showHints ? conflicted.possibilities : c.notes;
const notes = showHints && c.notes.length === 0 ? conflicted.possibilities : c.notes;

const inConflictPath =
this.props.showConflicts &&
Expand Down
35 changes: 21 additions & 14 deletions src/components/pages/Game/Sudoku/SudokuMenuCircle.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import * as React from "react";
import {connect, ConnectedProps} from "react-redux";
import {setNumber, clearNumber, setNote, clearNote} from "src/state/sudoku";
import {setNumber, clearNumber, setNotes} from "src/state/sudoku";
import {SUDOKU_NUMBERS} from "src/engine/utility";
import {Cell} from "src/engine/types";
import styled, {css} from "styled-components";
import THEME from "src/theme";
import {showMenu} from "src/state/game";
import {Bounds} from "src/utils/types";
import {RootState} from "src/state/rootReducer";
import SudokuGame from "src/sudoku-game/SudokuGame";

const MenuCircleContainer = styled.svg`
left: 50%;
Expand Down Expand Up @@ -141,13 +142,14 @@ const connector = connect(
(state: RootState) => {
return {
notesMode: state.game.notesMode,
sudoku: state.sudoku,
showHints: state.game.showHints,
};
},
{
showMenu,
setNumber,
setNote,
clearNote,
setNotes,
clearNumber,
},
);
Expand Down Expand Up @@ -196,8 +198,14 @@ class MenuCircle extends React.Component<MenuCircleOwnProps & PropsFromRedux, {}
const currentMaxRad = currentMinRad + radPerStep;
let isActive = number === cell.number;

const conflicting = SudokuGame.conflictingFields(this.props.sudoku);
const userNotes = this.props.sudoku[this.props.cell.y * 9 + this.props.cell.x].notes;
const conflictingCell = conflicting[this.props.cell.y * 9 + this.props.cell.x];
const autoNotes = this.props.showHints ? conflictingCell.possibilities : [];
const notesToUse = userNotes.length === 0 && autoNotes.length > 0 ? autoNotes : userNotes;

if (this.props.notesMode) {
isActive = cell.notes.includes(number);
isActive = notesToUse.includes(number);
}

const colors = this.props.notesMode
Expand All @@ -220,18 +228,17 @@ class MenuCircle extends React.Component<MenuCircleOwnProps & PropsFromRedux, {}
e.preventDefault();
e.stopPropagation();
}
if (isActive) {
if (this.props.notesMode) {
this.props.clearNote(cell, number);
} else {
this.props.clearNumber(cell);
}
return;
}
const newNotes = notesToUse.includes(number)
? notesToUse.filter((note) => note !== number)
: [...userNotes, number];
if (this.props.notesMode) {
this.props.setNote(cell, number);
this.props.setNotes(cell, newNotes);
} else {
this.props.setNumber(cell, number);
if (isActive) {
this.props.clearNumber(cell);
} else {
this.props.setNumber(cell, number);
}
}
}}
>
Expand Down
8 changes: 4 additions & 4 deletions src/components/pages/Game/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {

import {chooseGame} from "src/state/application";

import {setNumber, setNote, setSudoku} from "src/state/sudoku";
import {setNumber, setNotes, setSudoku} from "src/state/sudoku";

import {Sudoku} from "src/components/pages/Game/Sudoku/Sudoku";

Expand All @@ -38,17 +38,17 @@ import Shortcuts from "./shortcuts/Shortcuts";
import Checkbox from "src/components/modules/Checkbox";
import SUDOKUS from "src/sudoku-game/sudokus";

const sudokuMenuNummbersConnector = connect(
const sudokuMenuNumbersConnector = connect(
(state: RootState) => ({
notesMode: state.game.notesMode,
activeCell: state.game.activeCellCoordinates,
}),
{
setNumber,
setNote,
setNotes,
},
);
const SudokuMenuNumbersConnected = sudokuMenuNummbersConnector(SudokuMenuNumbers);
const SudokuMenuNumbersConnected = sudokuMenuNumbersConnector(SudokuMenuNumbers);

function ClearButton({state, clearGame}: {state: GameStateMachine; clearGame: () => void}) {
return (
Expand Down
24 changes: 14 additions & 10 deletions src/components/pages/Game/shortcuts/GridShortcuts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,27 @@ import hotkeys from "hotkeys-js";
import {SUDOKU_COORDINATES, SUDOKU_NUMBERS} from "src/engine/utility";
import {Cell} from "src/engine/types";
import {showMenu, hideMenu, selectCell, pauseGame, activateNotesMode, deactivateNotesMode} from "src/state/game";
import {setNumber, clearNumber, getHint, setNote, clearNote} from "src/state/sudoku";
import {setNumber, clearNumber, getHint, setNotes} from "src/state/sudoku";
import {ShortcutScope} from "./ShortcutScope";
import {connect} from "react-redux";
import {RootState} from "src/state/rootReducer";
import SudokuGame from "src/sudoku-game/SudokuGame";

interface GameKeyboardShortcutsStateProps {
// TODO: This can actually be null
activeCell: Cell;
sudoku: Cell[];
notesMode: boolean;
showHints: boolean;
}

interface GameKeyboardShortcutsDispatchProps {
showMenu: typeof showMenu;
hideMenu: typeof hideMenu;
selectCell: typeof selectCell;
setNumber: typeof setNumber;
setNote: typeof setNote;
setNotes: typeof setNotes;
clearNumber: typeof clearNumber;
clearNote: typeof clearNote;
pauseGame: typeof pauseGame;
getHint: typeof getHint;
activateNotesMode: typeof activateNotesMode;
Expand Down Expand Up @@ -113,11 +114,14 @@ class GameKeyboardShortcuts extends React.Component<
hotkeys(String(n), ShortcutScope.Game, () => {
if (!this.props.activeCell.initial) {
if (this.props.notesMode) {
if (this.props.activeCell.notes.includes(n)) {
this.props.clearNote(this.props.activeCell, n);
} else {
this.props.setNote(this.props.activeCell, n);
}
const conflicting = SudokuGame.conflictingFields(this.props.sudoku);
const userNotes = this.props.activeCell.notes;
const conflictingCell = conflicting[this.props.activeCell!.y * 9 + this.props.activeCell!.x];
const autoNotes = this.props.showHints ? conflictingCell.possibilities : [];
const notesToUse = userNotes.length === 0 && autoNotes.length > 0 ? autoNotes : userNotes;

const newNotes = notesToUse.includes(n) ? notesToUse.filter((note) => note !== n) : [...userNotes, n];
this.props.setNotes(this.props.activeCell, newNotes);
} else {
this.props.setNumber(this.props.activeCell, n);
}
Expand Down Expand Up @@ -157,13 +161,13 @@ export default connect<GameKeyboardShortcutsStateProps, GameKeyboardShortcutsDis
sudoku: state.sudoku,
activeCell: activeCell!,
notesMode: state.game.notesMode,
showHints: state.game.showHints,
};
},
{
setNumber,
setNote,
setNotes,
clearNumber,
clearNote,
selectCell,
hideMenu,
showMenu,
Expand Down
33 changes: 8 additions & 25 deletions src/state/sudoku.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ export const SET_SUDOKU = "sudoku/SET_SUDOKU";
export const SET_SUDOKU_STATE = "sudoku/SET_SUDOKU_STATE";
const GET_HINT = "sudoku/GET_HINT";
const CLEAR_CELL = "sudoku/CLEAR_CELL";
const SET_NOTE = "sudoku/SET_NOTE";
const CLEAR_NOTE = "sudoku/CLEAR_NOTE";
const SET_NOTES = "sudoku/SET_NOTES";
const SET_NUMBER = "sudoku/SET_NUMBER";
const CLEAR_NUMBER = "sudoku/CLEAR_NUMBER";

Expand All @@ -25,7 +24,7 @@ interface SudokuAction {
}

interface NoteAction extends SudokuAction {
note: number;
notes: number[];
}

export function getHint(cellCoordinates: CellCoordinates) {
Expand All @@ -42,19 +41,11 @@ export function clearCell(cellCoordinates: CellCoordinates) {
};
}

export function setNote(cellCoordinates: CellCoordinates, note: number): NoteAction {
export function setNotes(cellCoordinates: CellCoordinates, notes: number[]): NoteAction {
return {
type: SET_NOTE,
type: SET_NOTES,
cellCoordinates,
note,
};
}

export function clearNote(cellCoordinates: CellCoordinates, note: number): NoteAction {
return {
type: CLEAR_NOTE,
cellCoordinates,
note,
notes,
};
}

Expand Down Expand Up @@ -141,9 +132,7 @@ function fixSudokuNotes(sudoku: SudokuState, newCell: Cell) {

export default function sudokuReducer(state: SudokuState = INITIAL_SUDOKU_STATE, action: AnyAction) {
if (
![SET_NOTE, SET_SUDOKU, CLEAR_NOTE, SET_NUMBER, CLEAR_NUMBER, CLEAR_CELL, GET_HINT, SET_SUDOKU_STATE].includes(
action.type,
)
![SET_NOTES, SET_SUDOKU, SET_NUMBER, CLEAR_NUMBER, CLEAR_CELL, GET_HINT, SET_SUDOKU_STATE].includes(action.type)
) {
return state;
}
Expand All @@ -159,14 +148,8 @@ export default function sudokuReducer(state: SudokuState = INITIAL_SUDOKU_STATE,
const isCell = cell.x === x && cell.y === y;
if (isCell && !cell.initial) {
switch (action.type) {
case SET_NOTE: {
if (cell.notes.find((n) => n === action.note)) {
return {...cell, notes: cell.notes.filter((n) => n !== action.note)};
}
return {...cell, notes: cell.notes.concat([action.note])};
}
case CLEAR_NOTE: {
const notes = cell.notes.filter((n) => n !== action.note);
case SET_NOTES: {
const notes = (action as NoteAction).notes;
return {...cell, notes};
}
case CLEAR_CELL:
Expand Down

0 comments on commit 062b0f7

Please sign in to comment.