Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: better automated notes #8

Merged
merged 1 commit into from
May 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading