@sudobility/sudojo_lib 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/index.d.ts +27 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +27 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/useDailyGame.d.ts +64 -0
- package/dist/hooks/useDailyGame.d.ts.map +1 -0
- package/dist/hooks/useDailyGame.js +120 -0
- package/dist/hooks/useDailyGame.js.map +1 -0
- package/dist/hooks/useGame.d.ts +104 -0
- package/dist/hooks/useGame.d.ts.map +1 -0
- package/dist/hooks/useGame.js +546 -0
- package/dist/hooks/useGame.js.map +1 -0
- package/dist/hooks/useGamePersistence.d.ts +63 -0
- package/dist/hooks/useGamePersistence.d.ts.map +1 -0
- package/dist/hooks/useGamePersistence.js +124 -0
- package/dist/hooks/useGamePersistence.js.map +1 -0
- package/dist/hooks/useGameTeaching.d.ts +89 -0
- package/dist/hooks/useGameTeaching.d.ts.map +1 -0
- package/dist/hooks/useGameTeaching.js +230 -0
- package/dist/hooks/useGameTeaching.js.map +1 -0
- package/dist/hooks/useGameTimer.d.ts +43 -0
- package/dist/hooks/useGameTimer.d.ts.map +1 -0
- package/dist/hooks/useGameTimer.js +68 -0
- package/dist/hooks/useGameTimer.js.map +1 -0
- package/dist/hooks/useHint.d.ts +105 -0
- package/dist/hooks/useHint.d.ts.map +1 -0
- package/dist/hooks/useHint.js +179 -0
- package/dist/hooks/useHint.js.map +1 -0
- package/dist/hooks/useLearning.d.ts +100 -0
- package/dist/hooks/useLearning.d.ts.map +1 -0
- package/dist/hooks/useLearning.js +127 -0
- package/dist/hooks/useLearning.js.map +1 -0
- package/dist/hooks/useLevelGame.d.ts +68 -0
- package/dist/hooks/useLevelGame.d.ts.map +1 -0
- package/dist/hooks/useLevelGame.js +128 -0
- package/dist/hooks/useLevelGame.js.map +1 -0
- package/dist/hooks/useLevels.d.ts +93 -0
- package/dist/hooks/useLevels.d.ts.map +1 -0
- package/dist/hooks/useLevels.js +98 -0
- package/dist/hooks/useLevels.js.map +1 -0
- package/dist/hooks/useLocalStorage.d.ts +26 -0
- package/dist/hooks/useLocalStorage.d.ts.map +1 -0
- package/dist/hooks/useLocalStorage.js +75 -0
- package/dist/hooks/useLocalStorage.js.map +1 -0
- package/dist/hooks/useSudoku.d.ts +125 -0
- package/dist/hooks/useSudoku.d.ts.map +1 -0
- package/dist/hooks/useSudoku.js +655 -0
- package/dist/hooks/useSudoku.js.map +1 -0
- package/dist/hooks/useTechniques.d.ts +92 -0
- package/dist/hooks/useTechniques.d.ts.map +1 -0
- package/dist/hooks/useTechniques.js +108 -0
- package/dist/hooks/useTechniques.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/test/setup.d.ts +2 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/dist/test/setup.js +35 -0
- package/dist/test/setup.js.map +1 -0
- package/dist/types/display.d.ts +142 -0
- package/dist/types/display.d.ts.map +1 -0
- package/dist/types/display.js +94 -0
- package/dist/types/display.js.map +1 -0
- package/dist/types/game.d.ts +201 -0
- package/dist/types/game.d.ts.map +1 -0
- package/dist/types/game.js +26 -0
- package/dist/types/game.js.map +1 -0
- package/dist/types/gamePersistence.d.ts +31 -0
- package/dist/types/gamePersistence.d.ts.map +1 -0
- package/dist/types/gamePersistence.js +15 -0
- package/dist/types/gamePersistence.js.map +1 -0
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +11 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/progress.d.ts +43 -0
- package/dist/types/progress.d.ts.map +1 -0
- package/dist/types/progress.js +19 -0
- package/dist/types/progress.js.map +1 -0
- package/dist/types/settings.d.ts +19 -0
- package/dist/types/settings.d.ts.map +1 -0
- package/dist/types/settings.js +12 -0
- package/dist/types/settings.js.map +1 -0
- package/dist/types/subscription.d.ts +27 -0
- package/dist/types/subscription.d.ts.map +1 -0
- package/dist/types/subscription.js +8 -0
- package/dist/types/subscription.js.map +1 -0
- package/dist/types/sudoku.d.ts +147 -0
- package/dist/types/sudoku.d.ts.map +1 -0
- package/dist/types/sudoku.js +125 -0
- package/dist/types/sudoku.js.map +1 -0
- package/dist/utils/auth.d.ts +25 -0
- package/dist/utils/auth.d.ts.map +1 -0
- package/dist/utils/auth.js +47 -0
- package/dist/utils/auth.js.map +1 -0
- package/dist/utils/board.d.ts +116 -0
- package/dist/utils/board.d.ts.map +1 -0
- package/dist/utils/board.js +291 -0
- package/dist/utils/board.js.map +1 -0
- package/dist/utils/index.d.ts +18 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +23 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/progress.d.ts +44 -0
- package/dist/utils/progress.d.ts.map +1 -0
- package/dist/utils/progress.js +104 -0
- package/dist/utils/progress.js.map +1 -0
- package/dist/utils/scramble.d.ts +35 -0
- package/dist/utils/scramble.d.ts.map +1 -0
- package/dist/utils/scramble.js +270 -0
- package/dist/utils/scramble.js.map +1 -0
- package/dist/utils/subscription.d.ts +82 -0
- package/dist/utils/subscription.d.ts.map +1 -0
- package/dist/utils/subscription.js +117 -0
- package/dist/utils/subscription.js.map +1 -0
- package/dist/utils/sudokuPresenter.d.ts +62 -0
- package/dist/utils/sudokuPresenter.d.ts.map +1 -0
- package/dist/utils/sudokuPresenter.js +403 -0
- package/dist/utils/sudokuPresenter.js.map +1 -0
- package/dist/utils/sudokuScrambler.d.ts +61 -0
- package/dist/utils/sudokuScrambler.d.ts.map +1 -0
- package/dist/utils/sudokuScrambler.js +223 -0
- package/dist/utils/sudokuScrambler.js.map +1 -0
- package/dist/utils/technique.d.ts +41 -0
- package/dist/utils/technique.d.ts.map +1 -0
- package/dist/utils/technique.js +106 -0
- package/dist/utils/technique.js.map +1 -0
- package/dist/utils/theme.d.ts +31 -0
- package/dist/utils/theme.d.ts.map +1 -0
- package/dist/utils/theme.js +40 -0
- package/dist/utils/theme.js.map +1 -0
- package/dist/utils/time.d.ts +22 -0
- package/dist/utils/time.d.ts.map +1 -0
- package/dist/utils/time.js +41 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/utils/validation.d.ts +107 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +248 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subscription utilities
|
|
3
|
+
*
|
|
4
|
+
* These functions work with RevenueCat SDK types to convert to our domain models.
|
|
5
|
+
* The RevenueCat types are passed as generics to avoid direct SDK dependency.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Convert RevenueCat package to our Product interface
|
|
9
|
+
*
|
|
10
|
+
* @param pkg - RevenueCat package
|
|
11
|
+
* @returns Product object
|
|
12
|
+
*/
|
|
13
|
+
export function convertPackageToProduct(pkg) {
|
|
14
|
+
const product = pkg.rcBillingProduct;
|
|
15
|
+
const subscriptionOption = product?.defaultSubscriptionOption;
|
|
16
|
+
const result = {
|
|
17
|
+
identifier: pkg.identifier,
|
|
18
|
+
price: product?.currentPrice?.amountMicros
|
|
19
|
+
? (product.currentPrice.amountMicros / 1000000).toFixed(2)
|
|
20
|
+
: '0',
|
|
21
|
+
priceString: product?.currentPrice?.formattedPrice ?? '$0',
|
|
22
|
+
title: product?.title ?? pkg.identifier,
|
|
23
|
+
description: product?.description ?? '',
|
|
24
|
+
};
|
|
25
|
+
if (product?.identifier !== undefined) {
|
|
26
|
+
result.productId = product.identifier;
|
|
27
|
+
}
|
|
28
|
+
if (product?.normalPeriodDuration !== undefined) {
|
|
29
|
+
result.period = product.normalPeriodDuration;
|
|
30
|
+
}
|
|
31
|
+
if (subscriptionOption?.introPrice?.price?.formattedPrice !== undefined) {
|
|
32
|
+
result.introPrice = subscriptionOption.introPrice.price.formattedPrice;
|
|
33
|
+
}
|
|
34
|
+
if (subscriptionOption?.introPrice?.periodDuration !== undefined) {
|
|
35
|
+
result.introPricePeriod = subscriptionOption.introPrice.periodDuration;
|
|
36
|
+
}
|
|
37
|
+
if (subscriptionOption?.trial?.periodDuration !== undefined) {
|
|
38
|
+
result.freeTrialPeriod = subscriptionOption.trial.periodDuration;
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Parse RevenueCat CustomerInfo into our Subscription interface
|
|
44
|
+
*
|
|
45
|
+
* @param customerInfo - RevenueCat customer info
|
|
46
|
+
* @returns Subscription object
|
|
47
|
+
*/
|
|
48
|
+
export function parseCustomerInfo(customerInfo) {
|
|
49
|
+
const hasActiveEntitlement = Object.keys(customerInfo.entitlements.active).length > 0;
|
|
50
|
+
const activeEntitlement = Object.values(customerInfo.entitlements.active)[0];
|
|
51
|
+
if (hasActiveEntitlement && activeEntitlement) {
|
|
52
|
+
const subscription = { isActive: true };
|
|
53
|
+
if (activeEntitlement.expirationDate != null) {
|
|
54
|
+
subscription.expirationDate = new Date(activeEntitlement.expirationDate);
|
|
55
|
+
}
|
|
56
|
+
if (activeEntitlement.latestPurchaseDate != null) {
|
|
57
|
+
subscription.purchaseDate = new Date(activeEntitlement.latestPurchaseDate);
|
|
58
|
+
}
|
|
59
|
+
if (activeEntitlement.productIdentifier !== undefined) {
|
|
60
|
+
subscription.productIdentifier = activeEntitlement.productIdentifier;
|
|
61
|
+
}
|
|
62
|
+
if (activeEntitlement.willRenew !== undefined) {
|
|
63
|
+
subscription.willRenew = activeEntitlement.willRenew;
|
|
64
|
+
}
|
|
65
|
+
return subscription;
|
|
66
|
+
}
|
|
67
|
+
return { isActive: false };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get display name for subscription period
|
|
71
|
+
*
|
|
72
|
+
* @param period - ISO 8601 duration string (e.g., "P1M", "P1Y")
|
|
73
|
+
* @returns Human-readable period name
|
|
74
|
+
*/
|
|
75
|
+
export function getPeriodDisplayName(period) {
|
|
76
|
+
if (!period)
|
|
77
|
+
return '';
|
|
78
|
+
const periodMap = {
|
|
79
|
+
P1W: 'Weekly',
|
|
80
|
+
P1M: 'Monthly',
|
|
81
|
+
P3M: 'Quarterly',
|
|
82
|
+
P6M: 'Semi-Annual',
|
|
83
|
+
P1Y: 'Annual',
|
|
84
|
+
P12M: 'Annual',
|
|
85
|
+
};
|
|
86
|
+
return periodMap[period] ?? period;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Check if a plan is the "best value" (typically annual plans)
|
|
90
|
+
*
|
|
91
|
+
* @param period - ISO 8601 duration string
|
|
92
|
+
* @returns Whether this is typically the best value option
|
|
93
|
+
*/
|
|
94
|
+
export function isBestValuePlan(period) {
|
|
95
|
+
return period === 'P1Y' || period === 'P12M';
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get RevenueCat purchase error message
|
|
99
|
+
*
|
|
100
|
+
* @param errorCode - RevenueCat error code
|
|
101
|
+
* @returns User-friendly error message
|
|
102
|
+
*/
|
|
103
|
+
export function getRevenueCatErrorMessage(errorCode) {
|
|
104
|
+
switch (errorCode) {
|
|
105
|
+
case 1:
|
|
106
|
+
return 'Purchase cancelled';
|
|
107
|
+
case 2:
|
|
108
|
+
return 'Store problem occurred. Please try again later.';
|
|
109
|
+
case 3:
|
|
110
|
+
return 'Purchase not allowed on this device';
|
|
111
|
+
case 7:
|
|
112
|
+
return 'Network error. Please check your connection.';
|
|
113
|
+
default:
|
|
114
|
+
return 'Purchase failed. Please try again.';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=subscription.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription.js","sourceRoot":"","sources":["../../src/utils/subscription.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sudoku presenter - port of renderable/SudokuPresenter.kt
|
|
3
|
+
*
|
|
4
|
+
* Handles all display logic for the Sudoku board including:
|
|
5
|
+
* - Cell background colors based on selection state
|
|
6
|
+
* - Cell border colors for selected cells
|
|
7
|
+
* - Text colors (given, input, hint actions)
|
|
8
|
+
* - Hint visualization (areas, cells)
|
|
9
|
+
* - Pencilmark coloring
|
|
10
|
+
*/
|
|
11
|
+
import type { SudokuCell } from '../types/sudoku';
|
|
12
|
+
import { type CellDisplayState, type HintCell, type HintStep, ThemeColor, type UIColorPalette } from '../types/display';
|
|
13
|
+
/**
|
|
14
|
+
* Convert ThemeColor to actual CSS color - matches RendererColor.color
|
|
15
|
+
*/
|
|
16
|
+
export declare function themeColorToCSS(palette: UIColorPalette, themeColor: ThemeColor | null): string | null;
|
|
17
|
+
/**
|
|
18
|
+
* Get the color palette for the current theme
|
|
19
|
+
*/
|
|
20
|
+
export declare function getColorPalette(isDarkMode: boolean): UIColorPalette;
|
|
21
|
+
/**
|
|
22
|
+
* Process hint areas and cells into a map of cell hints
|
|
23
|
+
* Matches BoardPresenter.calculateCellHints
|
|
24
|
+
*/
|
|
25
|
+
export declare function calculateCellHints(hintStep: HintStep | null): Map<number, HintCell> | null;
|
|
26
|
+
export interface PresentBoardOptions {
|
|
27
|
+
/** The 81 cells of the board */
|
|
28
|
+
cells: SudokuCell[];
|
|
29
|
+
/** Currently selected cell index (0-80) or null */
|
|
30
|
+
selectedIndex: number | null;
|
|
31
|
+
/** Whether to show errors (compare input vs solution) */
|
|
32
|
+
showErrors: boolean;
|
|
33
|
+
/** Current hint step (if any) */
|
|
34
|
+
hintStep?: HintStep | null;
|
|
35
|
+
/** Set of cell indices with the selected digit (for digit highlighting) */
|
|
36
|
+
selectedDigitCells?: Set<number> | null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Generate display states for all cells
|
|
40
|
+
* This is the main presenter function that matches the Kotlin renderable behavior
|
|
41
|
+
*/
|
|
42
|
+
export declare function presentBoard(options: PresentBoardOptions): CellDisplayState[];
|
|
43
|
+
/**
|
|
44
|
+
* Get indices of cells that contain a specific digit (given or input)
|
|
45
|
+
* Used for digit highlighting mode
|
|
46
|
+
*/
|
|
47
|
+
export declare function getCellsWithDigit(cells: SudokuCell[], digit: number): Set<number>;
|
|
48
|
+
/**
|
|
49
|
+
* Get the selected digit for digit highlighting mode
|
|
50
|
+
* Matches Kotlin SudokuInteractor.selectedDigit logic:
|
|
51
|
+
* - If selected cell has a given value: return given
|
|
52
|
+
* - If selected cell has a CORRECT input (input === solution): return input
|
|
53
|
+
* - Otherwise: return null (no digit highlighting)
|
|
54
|
+
*/
|
|
55
|
+
export declare function getSelectedDigit(cells: SudokuCell[], selectedIndex: number | null): number | null;
|
|
56
|
+
/**
|
|
57
|
+
* Compute selectedDigitCells based on selected cell
|
|
58
|
+
* Returns Set of cell indices that have the same digit as selected cell
|
|
59
|
+
* Returns null if selected cell doesn't have a highlightable digit
|
|
60
|
+
*/
|
|
61
|
+
export declare function computeSelectedDigitCells(cells: SudokuCell[], selectedIndex: number | null): Set<number> | null;
|
|
62
|
+
//# sourceMappingURL=sudokuPresenter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sudokuPresenter.d.ts","sourceRoot":"","sources":["../../src/utils/sudokuPresenter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,QAAQ,EACb,KAAK,QAAQ,EAGb,UAAU,EAGV,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AA0F1B;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,UAAU,GAAG,IAAI,GAC5B,MAAM,GAAG,IAAI,CA4Bf;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,OAAO,GAAG,cAAc,CAEnE;AAMD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,QAAQ,GAAG,IAAI,GACxB,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,IAAI,CAoC9B;AAuMD,MAAM,WAAW,mBAAmB;IAClC,gCAAgC;IAChC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,mDAAmD;IACnD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,yDAAyD;IACzD,UAAU,EAAE,OAAO,CAAC;IACpB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;CACzC;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,gBAAgB,EAAE,CAuF7E;AAMD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,UAAU,EAAE,EACnB,KAAK,EAAE,MAAM,GACZ,GAAG,CAAC,MAAM,CAAC,CAQb;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,UAAU,EAAE,EACnB,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,MAAM,GAAG,IAAI,CAiBf;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,UAAU,EAAE,EACnB,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAIpB"}
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sudoku presenter - port of renderable/SudokuPresenter.kt
|
|
3
|
+
*
|
|
4
|
+
* Handles all display logic for the Sudoku board including:
|
|
5
|
+
* - Cell background colors based on selection state
|
|
6
|
+
* - Cell border colors for selected cells
|
|
7
|
+
* - Text colors (given, input, hint actions)
|
|
8
|
+
* - Hint visualization (areas, cells)
|
|
9
|
+
* - Pencilmark coloring
|
|
10
|
+
*/
|
|
11
|
+
import { blockOf, columnOf, rowOf } from '../types/sudoku';
|
|
12
|
+
import { SudokuColor, ThemeColor, UIColorDark, UIColorLight, } from '../types/display';
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Block Definition (matches PlayBoard.blocks)
|
|
15
|
+
// =============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* Block class - matches Kotlin Block class
|
|
18
|
+
*/
|
|
19
|
+
class Block {
|
|
20
|
+
constructor(index) {
|
|
21
|
+
this.index = index;
|
|
22
|
+
const blockRow = Math.floor(index / 3);
|
|
23
|
+
const blockCol = index % 3;
|
|
24
|
+
this.cellIndices = [];
|
|
25
|
+
for (let r = 0; r < 3; r++) {
|
|
26
|
+
for (let c = 0; c < 3; c++) {
|
|
27
|
+
const row = blockRow * 3 + r;
|
|
28
|
+
const col = blockCol * 3 + c;
|
|
29
|
+
this.cellIndices.push(row * 9 + col);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Row class - matches Kotlin Row class
|
|
36
|
+
*/
|
|
37
|
+
class Row {
|
|
38
|
+
constructor(index) {
|
|
39
|
+
this.index = index;
|
|
40
|
+
this.cellIndices = Array.from({ length: 9 }, (_, col) => index * 9 + col);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Column class - matches Kotlin Column class
|
|
45
|
+
*/
|
|
46
|
+
class Column {
|
|
47
|
+
constructor(index) {
|
|
48
|
+
this.index = index;
|
|
49
|
+
this.cellIndices = Array.from({ length: 9 }, (_, row) => row * 9 + index);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// =============================================================================
|
|
53
|
+
// Color Conversion (matches CellPresenter.colorOf)
|
|
54
|
+
// =============================================================================
|
|
55
|
+
/**
|
|
56
|
+
* Convert SudokuColor to ThemeColor - matches CellPresenter.colorOf
|
|
57
|
+
*/
|
|
58
|
+
function sudokuColorToTheme(sudokuColor) {
|
|
59
|
+
switch (sudokuColor) {
|
|
60
|
+
case SudokuColor.BLUE:
|
|
61
|
+
return ThemeColor.SELECTED;
|
|
62
|
+
case SudokuColor.GREEN:
|
|
63
|
+
return ThemeColor.SUCCESS;
|
|
64
|
+
case SudokuColor.YELLOW:
|
|
65
|
+
return ThemeColor.WARNING_SECONDARY;
|
|
66
|
+
case SudokuColor.ORANGE:
|
|
67
|
+
return ThemeColor.WARNING;
|
|
68
|
+
case SudokuColor.RED:
|
|
69
|
+
return ThemeColor.ERROR;
|
|
70
|
+
case SudokuColor.WHITE:
|
|
71
|
+
return ThemeColor.BACKGROUND;
|
|
72
|
+
case SudokuColor.LIGHT_GRAY:
|
|
73
|
+
return ThemeColor.BACKGROUND_SECONDARY;
|
|
74
|
+
case SudokuColor.BLACK:
|
|
75
|
+
return ThemeColor.LABEL;
|
|
76
|
+
case SudokuColor.GRAY:
|
|
77
|
+
return ThemeColor.LABEL_SECONDARY;
|
|
78
|
+
case SudokuColor.CLEAR:
|
|
79
|
+
return ThemeColor.CLEAR;
|
|
80
|
+
default:
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Convert ThemeColor to actual CSS color - matches RendererColor.color
|
|
86
|
+
*/
|
|
87
|
+
export function themeColorToCSS(palette, themeColor) {
|
|
88
|
+
switch (themeColor) {
|
|
89
|
+
case ThemeColor.NONE:
|
|
90
|
+
case ThemeColor.CLEAR:
|
|
91
|
+
return palette.clear;
|
|
92
|
+
case ThemeColor.SELECTED:
|
|
93
|
+
return palette.systemPurple;
|
|
94
|
+
case ThemeColor.SUCCESS:
|
|
95
|
+
return palette.systemBlue;
|
|
96
|
+
case ThemeColor.WARNING_SECONDARY:
|
|
97
|
+
return palette.systemYellow;
|
|
98
|
+
case ThemeColor.WARNING:
|
|
99
|
+
return palette.systemOrange;
|
|
100
|
+
case ThemeColor.ERROR:
|
|
101
|
+
return palette.systemRed;
|
|
102
|
+
case ThemeColor.BACKGROUND:
|
|
103
|
+
return palette.systemBackground;
|
|
104
|
+
case ThemeColor.BACKGROUND_SECONDARY:
|
|
105
|
+
return palette.secondarySystemBackground;
|
|
106
|
+
case ThemeColor.LABEL:
|
|
107
|
+
return palette.label;
|
|
108
|
+
case ThemeColor.LABEL_SECONDARY:
|
|
109
|
+
return palette.secondaryLabel;
|
|
110
|
+
case ThemeColor.DISABLED:
|
|
111
|
+
return palette.systemGray;
|
|
112
|
+
default:
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Get the color palette for the current theme
|
|
118
|
+
*/
|
|
119
|
+
export function getColorPalette(isDarkMode) {
|
|
120
|
+
return isDarkMode ? UIColorDark : UIColorLight;
|
|
121
|
+
}
|
|
122
|
+
// =============================================================================
|
|
123
|
+
// Hint Processing (matches BoardPresenter.calculateCellHints)
|
|
124
|
+
// =============================================================================
|
|
125
|
+
/**
|
|
126
|
+
* Process hint areas and cells into a map of cell hints
|
|
127
|
+
* Matches BoardPresenter.calculateCellHints
|
|
128
|
+
*/
|
|
129
|
+
export function calculateCellHints(hintStep) {
|
|
130
|
+
if (!hintStep)
|
|
131
|
+
return null;
|
|
132
|
+
const hintsCell = new Map();
|
|
133
|
+
// Process areas first
|
|
134
|
+
hintStep.areas?.forEach(area => {
|
|
135
|
+
let cellIndices;
|
|
136
|
+
switch (area.type) {
|
|
137
|
+
case 'block':
|
|
138
|
+
cellIndices = new Block(area.index).cellIndices;
|
|
139
|
+
break;
|
|
140
|
+
case 'row':
|
|
141
|
+
cellIndices = new Row(area.index).cellIndices;
|
|
142
|
+
break;
|
|
143
|
+
case 'column':
|
|
144
|
+
cellIndices = new Column(area.index).cellIndices;
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
cellIndices.forEach(index => {
|
|
148
|
+
hintsCell.set(index, {
|
|
149
|
+
index,
|
|
150
|
+
color: area.color,
|
|
151
|
+
fill: true, // Areas always use fill
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
// Process cells (overrides areas)
|
|
156
|
+
hintStep.cells?.forEach(cell => {
|
|
157
|
+
hintsCell.set(cell.index, cell);
|
|
158
|
+
});
|
|
159
|
+
return hintsCell;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Determine background and border colors for a cell
|
|
163
|
+
* Matches BlockPresenter.color exactly
|
|
164
|
+
*/
|
|
165
|
+
function getCellColors(cellIndex, cellBlockIndex, cellRowIndex, cellColumnIndex, cellHasValue, selectedIndex, selectedBlockIndex, selectedRowIndex, selectedColumnIndex, selectedDigitCells) {
|
|
166
|
+
// Default background based on block (checkerboard pattern)
|
|
167
|
+
const defaultBackgroundColor = cellBlockIndex % 2 === 0
|
|
168
|
+
? ThemeColor.BACKGROUND_SECONDARY
|
|
169
|
+
: ThemeColor.BACKGROUND;
|
|
170
|
+
if (selectedIndex === null) {
|
|
171
|
+
return { backgroundColor: defaultBackgroundColor, borderColor: null };
|
|
172
|
+
}
|
|
173
|
+
if (selectedDigitCells !== null) {
|
|
174
|
+
// Digit highlighting mode
|
|
175
|
+
if (selectedDigitCells.has(cellIndex)) {
|
|
176
|
+
// Highlighted cells (have the same digit)
|
|
177
|
+
return { backgroundColor: ThemeColor.SELECTED, borderColor: null };
|
|
178
|
+
}
|
|
179
|
+
// Check if this cell is "impossible" (in same row/col/block as highlighted cells)
|
|
180
|
+
let isImpossible = cellHasValue;
|
|
181
|
+
if (!isImpossible) {
|
|
182
|
+
for (const highlightedIndex of selectedDigitCells) {
|
|
183
|
+
const hRow = rowOf(highlightedIndex);
|
|
184
|
+
const hCol = columnOf(highlightedIndex);
|
|
185
|
+
const hBlock = blockOf(highlightedIndex);
|
|
186
|
+
if (cellRowIndex === hRow ||
|
|
187
|
+
cellColumnIndex === hCol ||
|
|
188
|
+
cellBlockIndex === hBlock) {
|
|
189
|
+
isImpossible = true;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (isImpossible) {
|
|
195
|
+
return { backgroundColor: ThemeColor.LABEL_SECONDARY, borderColor: null };
|
|
196
|
+
}
|
|
197
|
+
// Possible cells
|
|
198
|
+
return { backgroundColor: defaultBackgroundColor, borderColor: null };
|
|
199
|
+
}
|
|
200
|
+
// Normal selection mode
|
|
201
|
+
if (selectedIndex === cellIndex) {
|
|
202
|
+
// Selected cell: default background + SELECTED border
|
|
203
|
+
return {
|
|
204
|
+
backgroundColor: defaultBackgroundColor,
|
|
205
|
+
borderColor: ThemeColor.SELECTED,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
if (selectedBlockIndex === cellBlockIndex ||
|
|
209
|
+
selectedRowIndex === cellRowIndex ||
|
|
210
|
+
selectedColumnIndex === cellColumnIndex) {
|
|
211
|
+
// Same row, column or block: SELECTED background
|
|
212
|
+
return { backgroundColor: ThemeColor.SELECTED, borderColor: null };
|
|
213
|
+
}
|
|
214
|
+
// Other cells
|
|
215
|
+
return { backgroundColor: defaultBackgroundColor, borderColor: null };
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Determine what digit and color to display in a cell
|
|
219
|
+
* Matches CellPresenter.present logic
|
|
220
|
+
*/
|
|
221
|
+
function getCellText(cell, showErrors, hintCell) {
|
|
222
|
+
// Hint select action takes priority
|
|
223
|
+
if (hintCell?.actions?.select != null) {
|
|
224
|
+
return {
|
|
225
|
+
digit: hintCell.actions.select,
|
|
226
|
+
textColor: ThemeColor.SELECTED,
|
|
227
|
+
isGiven: false,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
// Hint unselect action (wrong digit to remove)
|
|
231
|
+
if (hintCell?.actions?.unselect != null) {
|
|
232
|
+
return {
|
|
233
|
+
digit: hintCell.actions.unselect,
|
|
234
|
+
textColor: ThemeColor.ERROR,
|
|
235
|
+
isGiven: false,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
// User input
|
|
239
|
+
if (cell.input !== null) {
|
|
240
|
+
let textColor;
|
|
241
|
+
if (showErrors) {
|
|
242
|
+
textColor =
|
|
243
|
+
cell.input === cell.solution ? ThemeColor.SUCCESS : ThemeColor.ERROR;
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
textColor = ThemeColor.LABEL_SECONDARY;
|
|
247
|
+
}
|
|
248
|
+
return { digit: cell.input, textColor, isGiven: false };
|
|
249
|
+
}
|
|
250
|
+
// Given (original)
|
|
251
|
+
if (cell.given !== null) {
|
|
252
|
+
return { digit: cell.given, textColor: ThemeColor.LABEL, isGiven: true };
|
|
253
|
+
}
|
|
254
|
+
return { digit: null, textColor: null, isGiven: false };
|
|
255
|
+
}
|
|
256
|
+
// =============================================================================
|
|
257
|
+
// Pencilmark Logic (matches CellPresenter.present pencilmark section)
|
|
258
|
+
// =============================================================================
|
|
259
|
+
/**
|
|
260
|
+
* Get pencilmark display states
|
|
261
|
+
* Matches CellPresenter.present pencilmark logic
|
|
262
|
+
*/
|
|
263
|
+
function getPencilmarks(cell, hintCell) {
|
|
264
|
+
const cellPencilmarks = cell.pencilmarks
|
|
265
|
+
? new Set(cell.pencilmarks)
|
|
266
|
+
: new Set();
|
|
267
|
+
const adding = hintCell?.actions?.add ? new Set(hintCell.actions.add) : null;
|
|
268
|
+
const removing = hintCell?.actions?.remove
|
|
269
|
+
? new Set(hintCell.actions.remove)
|
|
270
|
+
: null;
|
|
271
|
+
const highlighting = hintCell?.actions?.highlight
|
|
272
|
+
? new Set(hintCell.actions.highlight)
|
|
273
|
+
: null;
|
|
274
|
+
const result = [];
|
|
275
|
+
for (let pencilmark = 1; pencilmark <= 9; pencilmark++) {
|
|
276
|
+
let color = null;
|
|
277
|
+
if (highlighting?.has(pencilmark)) {
|
|
278
|
+
color = ThemeColor.SELECTED;
|
|
279
|
+
}
|
|
280
|
+
else if (adding?.has(pencilmark)) {
|
|
281
|
+
color = ThemeColor.SUCCESS;
|
|
282
|
+
}
|
|
283
|
+
else if (removing?.has(pencilmark)) {
|
|
284
|
+
color = ThemeColor.ERROR;
|
|
285
|
+
}
|
|
286
|
+
else if (cellPencilmarks.has(pencilmark)) {
|
|
287
|
+
color = ThemeColor.LABEL_SECONDARY;
|
|
288
|
+
}
|
|
289
|
+
if (color !== null) {
|
|
290
|
+
result.push({ digit: pencilmark, color });
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return result;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Generate display states for all cells
|
|
297
|
+
* This is the main presenter function that matches the Kotlin renderable behavior
|
|
298
|
+
*/
|
|
299
|
+
export function presentBoard(options) {
|
|
300
|
+
const { cells, selectedIndex, showErrors, hintStep = null, selectedDigitCells = null, } = options;
|
|
301
|
+
// Calculate hint cell map
|
|
302
|
+
const cellHints = calculateCellHints(hintStep);
|
|
303
|
+
// Get selected cell properties (if any)
|
|
304
|
+
const _selectedCell = selectedIndex !== null ? cells[selectedIndex] : null;
|
|
305
|
+
void _selectedCell; // Reserved for future use
|
|
306
|
+
const selectedBlockIndex = selectedIndex !== null ? blockOf(selectedIndex) : null;
|
|
307
|
+
const selectedRowIndex = selectedIndex !== null ? rowOf(selectedIndex) : null;
|
|
308
|
+
const selectedColumnIndex = selectedIndex !== null ? columnOf(selectedIndex) : null;
|
|
309
|
+
// Generate display state for each cell
|
|
310
|
+
return cells.map((cell, index) => {
|
|
311
|
+
const cellBlockIndex = blockOf(index);
|
|
312
|
+
const cellRowIndex = rowOf(index);
|
|
313
|
+
const cellColumnIndex = columnOf(index);
|
|
314
|
+
const cellHasValue = cell.input !== null || cell.given !== null;
|
|
315
|
+
// Get hint for this cell
|
|
316
|
+
const hintCell = cellHints?.get(index) ?? null;
|
|
317
|
+
// Get base colors
|
|
318
|
+
const { backgroundColor, borderColor } = getCellColors(index, cellBlockIndex, cellRowIndex, cellColumnIndex, cellHasValue, selectedIndex, selectedBlockIndex, selectedRowIndex, selectedColumnIndex, selectedDigitCells);
|
|
319
|
+
// Apply hint colors if present
|
|
320
|
+
let finalBgColor = backgroundColor;
|
|
321
|
+
let finalBorderColor = borderColor;
|
|
322
|
+
if (hintCell) {
|
|
323
|
+
if (hintCell.fill) {
|
|
324
|
+
// Hint uses fill: override background
|
|
325
|
+
const hintBgColor = sudokuColorToTheme(hintCell.color);
|
|
326
|
+
if (hintBgColor !== null) {
|
|
327
|
+
finalBgColor = hintBgColor;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
// Hint uses border
|
|
332
|
+
const hintBdrColor = sudokuColorToTheme(hintCell.color ?? SudokuColor.BLUE);
|
|
333
|
+
if (hintBdrColor !== null) {
|
|
334
|
+
finalBorderColor = hintBdrColor;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
// Get text info
|
|
339
|
+
const { digit, textColor, isGiven } = getCellText(cell, showErrors, hintCell);
|
|
340
|
+
// Get pencilmarks if no digit
|
|
341
|
+
const pencilmarks = digit === null ? getPencilmarks(cell, hintCell) : [];
|
|
342
|
+
return {
|
|
343
|
+
index,
|
|
344
|
+
backgroundColor: finalBgColor,
|
|
345
|
+
borderColor: finalBorderColor,
|
|
346
|
+
textColor,
|
|
347
|
+
digit,
|
|
348
|
+
isGiven,
|
|
349
|
+
pencilmarks,
|
|
350
|
+
};
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
// =============================================================================
|
|
354
|
+
// Utility: Get cells with a specific digit
|
|
355
|
+
// =============================================================================
|
|
356
|
+
/**
|
|
357
|
+
* Get indices of cells that contain a specific digit (given or input)
|
|
358
|
+
* Used for digit highlighting mode
|
|
359
|
+
*/
|
|
360
|
+
export function getCellsWithDigit(cells, digit) {
|
|
361
|
+
const result = new Set();
|
|
362
|
+
cells.forEach((cell, index) => {
|
|
363
|
+
if (cell.given === digit || cell.input === digit) {
|
|
364
|
+
result.add(index);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
return result;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Get the selected digit for digit highlighting mode
|
|
371
|
+
* Matches Kotlin SudokuInteractor.selectedDigit logic:
|
|
372
|
+
* - If selected cell has a given value: return given
|
|
373
|
+
* - If selected cell has a CORRECT input (input === solution): return input
|
|
374
|
+
* - Otherwise: return null (no digit highlighting)
|
|
375
|
+
*/
|
|
376
|
+
export function getSelectedDigit(cells, selectedIndex) {
|
|
377
|
+
if (selectedIndex === null)
|
|
378
|
+
return null;
|
|
379
|
+
const cell = cells[selectedIndex];
|
|
380
|
+
if (!cell)
|
|
381
|
+
return null;
|
|
382
|
+
// Given value takes priority
|
|
383
|
+
if (cell.given !== null) {
|
|
384
|
+
return cell.given;
|
|
385
|
+
}
|
|
386
|
+
// Only correct input triggers digit highlighting
|
|
387
|
+
if (cell.input !== null && cell.input === cell.solution) {
|
|
388
|
+
return cell.input;
|
|
389
|
+
}
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Compute selectedDigitCells based on selected cell
|
|
394
|
+
* Returns Set of cell indices that have the same digit as selected cell
|
|
395
|
+
* Returns null if selected cell doesn't have a highlightable digit
|
|
396
|
+
*/
|
|
397
|
+
export function computeSelectedDigitCells(cells, selectedIndex) {
|
|
398
|
+
const selectedDigit = getSelectedDigit(cells, selectedIndex);
|
|
399
|
+
if (selectedDigit === null)
|
|
400
|
+
return null;
|
|
401
|
+
return getCellsWithDigit(cells, selectedDigit);
|
|
402
|
+
}
|
|
403
|
+
//# sourceMappingURL=sudokuPresenter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sudokuPresenter.js","sourceRoot":"","sources":["../../src/utils/sudokuPresenter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sudoku board scrambler - ported from renderable/utils/Scrambler.kt
|
|
3
|
+
*
|
|
4
|
+
* Generates permutations for rows, columns, and digits to create unique puzzles
|
|
5
|
+
* while preserving Sudoku validity.
|
|
6
|
+
*/
|
|
7
|
+
import { type SudokuCell } from '../types/sudoku';
|
|
8
|
+
export interface ScramblerProtocol {
|
|
9
|
+
scramble9(symmetrical: boolean): number[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Scrambler implementation that matches the Kotlin version
|
|
13
|
+
*/
|
|
14
|
+
export declare const Scrambler: ScramblerProtocol;
|
|
15
|
+
/**
|
|
16
|
+
* Non-scrambler that returns identity permutation
|
|
17
|
+
*/
|
|
18
|
+
export declare const NonScrambler: ScramblerProtocol;
|
|
19
|
+
export interface ScrambleResult {
|
|
20
|
+
/** Scrambled cells array */
|
|
21
|
+
cells: SudokuCell[];
|
|
22
|
+
/** Digit mapping from original (1-9) to scrambled (1-9) */
|
|
23
|
+
digitMapping: Map<number, number>;
|
|
24
|
+
/** Reverse digit mapping from scrambled to original */
|
|
25
|
+
reverseDigitMapping: Map<number, number>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Scramble a board using the given scrambler
|
|
29
|
+
*
|
|
30
|
+
* @param scrambler - Scrambler protocol implementation
|
|
31
|
+
* @param cells - Original 81 cells
|
|
32
|
+
* @param symmetrical - Whether to use symmetrical scrambling
|
|
33
|
+
* @returns Scrambled cells and digit mapping
|
|
34
|
+
*/
|
|
35
|
+
export declare function scrambleBoard(scrambler: ScramblerProtocol, cells: SudokuCell[], symmetrical?: boolean): ScrambleResult;
|
|
36
|
+
/**
|
|
37
|
+
* Parse a puzzle string (81 chars of 0-9 or .) into cells
|
|
38
|
+
*
|
|
39
|
+
* @param puzzle - 81 character string
|
|
40
|
+
* @param solution - 81 character solution string (optional)
|
|
41
|
+
* @returns Array of 81 cells
|
|
42
|
+
*/
|
|
43
|
+
export declare function parsePuzzleString(puzzle: string, solution?: string): SudokuCell[];
|
|
44
|
+
/**
|
|
45
|
+
* Convert cells to puzzle string
|
|
46
|
+
*/
|
|
47
|
+
export declare function cellsToPuzzleString(cells: SudokuCell[]): string;
|
|
48
|
+
/**
|
|
49
|
+
* Convert cells to current state string (given + input)
|
|
50
|
+
*/
|
|
51
|
+
export declare function cellsToStateString(cells: SudokuCell[]): string;
|
|
52
|
+
/**
|
|
53
|
+
* Convert cells to input-only string
|
|
54
|
+
*/
|
|
55
|
+
export declare function cellsToInputString(cells: SudokuCell[]): string;
|
|
56
|
+
/**
|
|
57
|
+
* Convert cells to pencilmarks string (comma-separated)
|
|
58
|
+
* Matches Kotlin: pencilmarksParam - returns empty string for null pencilmarks
|
|
59
|
+
*/
|
|
60
|
+
export declare function cellsToPencilmarksString(cells: SudokuCell[]): string;
|
|
61
|
+
//# sourceMappingURL=sudokuScrambler.d.ts.map
|