@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.
Files changed (141) hide show
  1. package/dist/hooks/index.d.ts +27 -0
  2. package/dist/hooks/index.d.ts.map +1 -0
  3. package/dist/hooks/index.js +27 -0
  4. package/dist/hooks/index.js.map +1 -0
  5. package/dist/hooks/useDailyGame.d.ts +64 -0
  6. package/dist/hooks/useDailyGame.d.ts.map +1 -0
  7. package/dist/hooks/useDailyGame.js +120 -0
  8. package/dist/hooks/useDailyGame.js.map +1 -0
  9. package/dist/hooks/useGame.d.ts +104 -0
  10. package/dist/hooks/useGame.d.ts.map +1 -0
  11. package/dist/hooks/useGame.js +546 -0
  12. package/dist/hooks/useGame.js.map +1 -0
  13. package/dist/hooks/useGamePersistence.d.ts +63 -0
  14. package/dist/hooks/useGamePersistence.d.ts.map +1 -0
  15. package/dist/hooks/useGamePersistence.js +124 -0
  16. package/dist/hooks/useGamePersistence.js.map +1 -0
  17. package/dist/hooks/useGameTeaching.d.ts +89 -0
  18. package/dist/hooks/useGameTeaching.d.ts.map +1 -0
  19. package/dist/hooks/useGameTeaching.js +230 -0
  20. package/dist/hooks/useGameTeaching.js.map +1 -0
  21. package/dist/hooks/useGameTimer.d.ts +43 -0
  22. package/dist/hooks/useGameTimer.d.ts.map +1 -0
  23. package/dist/hooks/useGameTimer.js +68 -0
  24. package/dist/hooks/useGameTimer.js.map +1 -0
  25. package/dist/hooks/useHint.d.ts +105 -0
  26. package/dist/hooks/useHint.d.ts.map +1 -0
  27. package/dist/hooks/useHint.js +179 -0
  28. package/dist/hooks/useHint.js.map +1 -0
  29. package/dist/hooks/useLearning.d.ts +100 -0
  30. package/dist/hooks/useLearning.d.ts.map +1 -0
  31. package/dist/hooks/useLearning.js +127 -0
  32. package/dist/hooks/useLearning.js.map +1 -0
  33. package/dist/hooks/useLevelGame.d.ts +68 -0
  34. package/dist/hooks/useLevelGame.d.ts.map +1 -0
  35. package/dist/hooks/useLevelGame.js +128 -0
  36. package/dist/hooks/useLevelGame.js.map +1 -0
  37. package/dist/hooks/useLevels.d.ts +93 -0
  38. package/dist/hooks/useLevels.d.ts.map +1 -0
  39. package/dist/hooks/useLevels.js +98 -0
  40. package/dist/hooks/useLevels.js.map +1 -0
  41. package/dist/hooks/useLocalStorage.d.ts +26 -0
  42. package/dist/hooks/useLocalStorage.d.ts.map +1 -0
  43. package/dist/hooks/useLocalStorage.js +75 -0
  44. package/dist/hooks/useLocalStorage.js.map +1 -0
  45. package/dist/hooks/useSudoku.d.ts +125 -0
  46. package/dist/hooks/useSudoku.d.ts.map +1 -0
  47. package/dist/hooks/useSudoku.js +655 -0
  48. package/dist/hooks/useSudoku.js.map +1 -0
  49. package/dist/hooks/useTechniques.d.ts +92 -0
  50. package/dist/hooks/useTechniques.d.ts.map +1 -0
  51. package/dist/hooks/useTechniques.js +108 -0
  52. package/dist/hooks/useTechniques.js.map +1 -0
  53. package/dist/index.d.ts +42 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +64 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/test/setup.d.ts +2 -0
  58. package/dist/test/setup.d.ts.map +1 -0
  59. package/dist/test/setup.js +35 -0
  60. package/dist/test/setup.js.map +1 -0
  61. package/dist/types/display.d.ts +142 -0
  62. package/dist/types/display.d.ts.map +1 -0
  63. package/dist/types/display.js +94 -0
  64. package/dist/types/display.js.map +1 -0
  65. package/dist/types/game.d.ts +201 -0
  66. package/dist/types/game.d.ts.map +1 -0
  67. package/dist/types/game.js +26 -0
  68. package/dist/types/game.js.map +1 -0
  69. package/dist/types/gamePersistence.d.ts +31 -0
  70. package/dist/types/gamePersistence.d.ts.map +1 -0
  71. package/dist/types/gamePersistence.js +15 -0
  72. package/dist/types/gamePersistence.js.map +1 -0
  73. package/dist/types/index.d.ts +18 -0
  74. package/dist/types/index.d.ts.map +1 -0
  75. package/dist/types/index.js +11 -0
  76. package/dist/types/index.js.map +1 -0
  77. package/dist/types/progress.d.ts +43 -0
  78. package/dist/types/progress.d.ts.map +1 -0
  79. package/dist/types/progress.js +19 -0
  80. package/dist/types/progress.js.map +1 -0
  81. package/dist/types/settings.d.ts +19 -0
  82. package/dist/types/settings.d.ts.map +1 -0
  83. package/dist/types/settings.js +12 -0
  84. package/dist/types/settings.js.map +1 -0
  85. package/dist/types/subscription.d.ts +27 -0
  86. package/dist/types/subscription.d.ts.map +1 -0
  87. package/dist/types/subscription.js +8 -0
  88. package/dist/types/subscription.js.map +1 -0
  89. package/dist/types/sudoku.d.ts +147 -0
  90. package/dist/types/sudoku.d.ts.map +1 -0
  91. package/dist/types/sudoku.js +125 -0
  92. package/dist/types/sudoku.js.map +1 -0
  93. package/dist/utils/auth.d.ts +25 -0
  94. package/dist/utils/auth.d.ts.map +1 -0
  95. package/dist/utils/auth.js +47 -0
  96. package/dist/utils/auth.js.map +1 -0
  97. package/dist/utils/board.d.ts +116 -0
  98. package/dist/utils/board.d.ts.map +1 -0
  99. package/dist/utils/board.js +291 -0
  100. package/dist/utils/board.js.map +1 -0
  101. package/dist/utils/index.d.ts +18 -0
  102. package/dist/utils/index.d.ts.map +1 -0
  103. package/dist/utils/index.js +23 -0
  104. package/dist/utils/index.js.map +1 -0
  105. package/dist/utils/progress.d.ts +44 -0
  106. package/dist/utils/progress.d.ts.map +1 -0
  107. package/dist/utils/progress.js +104 -0
  108. package/dist/utils/progress.js.map +1 -0
  109. package/dist/utils/scramble.d.ts +35 -0
  110. package/dist/utils/scramble.d.ts.map +1 -0
  111. package/dist/utils/scramble.js +270 -0
  112. package/dist/utils/scramble.js.map +1 -0
  113. package/dist/utils/subscription.d.ts +82 -0
  114. package/dist/utils/subscription.d.ts.map +1 -0
  115. package/dist/utils/subscription.js +117 -0
  116. package/dist/utils/subscription.js.map +1 -0
  117. package/dist/utils/sudokuPresenter.d.ts +62 -0
  118. package/dist/utils/sudokuPresenter.d.ts.map +1 -0
  119. package/dist/utils/sudokuPresenter.js +403 -0
  120. package/dist/utils/sudokuPresenter.js.map +1 -0
  121. package/dist/utils/sudokuScrambler.d.ts +61 -0
  122. package/dist/utils/sudokuScrambler.d.ts.map +1 -0
  123. package/dist/utils/sudokuScrambler.js +223 -0
  124. package/dist/utils/sudokuScrambler.js.map +1 -0
  125. package/dist/utils/technique.d.ts +41 -0
  126. package/dist/utils/technique.d.ts.map +1 -0
  127. package/dist/utils/technique.js +106 -0
  128. package/dist/utils/technique.js.map +1 -0
  129. package/dist/utils/theme.d.ts +31 -0
  130. package/dist/utils/theme.d.ts.map +1 -0
  131. package/dist/utils/theme.js +40 -0
  132. package/dist/utils/theme.js.map +1 -0
  133. package/dist/utils/time.d.ts +22 -0
  134. package/dist/utils/time.d.ts.map +1 -0
  135. package/dist/utils/time.js +41 -0
  136. package/dist/utils/time.js.map +1 -0
  137. package/dist/utils/validation.d.ts +107 -0
  138. package/dist/utils/validation.d.ts.map +1 -0
  139. package/dist/utils/validation.js +248 -0
  140. package/dist/utils/validation.js.map +1 -0
  141. package/package.json +79 -0
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Utility exports for Sudojo library
3
+ */
4
+ // Board utilities (legacy - for useGame hook)
5
+ export { BLOCK_SIZE, BOARD_SIZE, cloneBoard, countFilledCells, createGameBoard, getBlockCells, getBlockIndex, getBoardStateString, getColumnCells, getEmptyCells, getPencilmarksString, getRelatedCells, getRowCells, isValidPlacement, parseBoardString, stringifyBoard, TOTAL_CELLS, } from './board';
6
+ // Scramble utilities (legacy - for useGame hook)
7
+ export { noScramble, scrambleBoard } from './scramble';
8
+ // Validation utilities (legacy - for useGame hook)
9
+ export { autoRemovePencilmarks, clearHighlights, countMistakes, getIncorrectCells, getProgressPercentage, isBoardFilled, isCellCorrect, isGameComplete, isValueCorrect, updateCellErrors, updateCellHighlights, validateGameState, } from './validation';
10
+ export { Scrambler, NonScrambler, scrambleBoard as scrambleSudokuBoard, parsePuzzleString, cellsToPuzzleString, cellsToStateString, cellsToInputString, cellsToPencilmarksString, } from './sudokuScrambler';
11
+ export { presentBoard, calculateCellHints, themeColorToCSS, getColorPalette, getCellsWithDigit, getSelectedDigit, computeSelectedDigitCells, } from './sudokuPresenter';
12
+ // Time utilities
13
+ export { formatTime, parseTime } from './time';
14
+ // Progress utilities
15
+ export { calculateStats, calculateStreak, isPuzzleCompleted, getCompletedLevelIds, getCompletedDailyDates, } from './progress';
16
+ // Auth utilities
17
+ export { getFirebaseErrorMessage, getFirebaseErrorCode, formatFirebaseError, } from './auth';
18
+ export { THEME_STORAGE_KEY, getSystemTheme, resolveTheme, isValidThemePreference, } from './theme';
19
+ // Subscription utilities
20
+ export { convertPackageToProduct, parseCustomerInfo, getPeriodDisplayName, isBestValuePlan, getRevenueCatErrorMessage, } from './subscription';
21
+ // Technique utilities
22
+ export { getTechniqueIconUrl, TECHNIQUE_TO_HELP_FILE, HELP_FILE_TO_TECHNIQUE, getHelpFileUrl, getTechniqueFromHelpFile, extractBodyContent, } from './technique';
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,8CAA8C;AAC9C,OAAO,EACL,UAAU,EACV,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,WAAW,GACZ,MAAM,SAAS,CAAC;AAEjB,iDAAiD;AACjD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvD,mDAAmD;AACnD,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,EACb,aAAa,EACb,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,cAAc,CAAC;AAOtB,OAAO,EACL,SAAS,EACT,YAAY,EACZ,aAAa,IAAI,mBAAmB,EACpC,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,iBAAiB;AACjB,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAE/C,qBAAqB;AACrB,OAAO,EACL,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAEpB,iBAAiB;AACjB,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,QAAQ,CAAC;AAIhB,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,sBAAsB,GACvB,MAAM,SAAS,CAAC;AAEjB,yBAAyB;AACzB,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC;AAExB,sBAAsB;AACtB,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,EACtB,cAAc,EACd,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Progress calculation utilities
3
+ */
4
+ import type { CompletedPuzzle, GameStats } from '../types/progress';
5
+ /**
6
+ * Calculate game statistics from completed puzzles
7
+ *
8
+ * @param completedPuzzles - Array of completed puzzle records
9
+ * @param newTime - Optional new time to include in calculations
10
+ * @returns Computed game statistics
11
+ */
12
+ export declare function calculateStats(completedPuzzles: CompletedPuzzle[], newTime?: number): GameStats;
13
+ /**
14
+ * Calculate daily streak based on completions
15
+ *
16
+ * @param completedPuzzles - Array of completed puzzle records
17
+ * @param lastDailyDate - Date of last daily completion (YYYY-MM-DD)
18
+ * @returns Current streak count
19
+ */
20
+ export declare function calculateStreak(completedPuzzles: CompletedPuzzle[], lastDailyDate: string | null): number;
21
+ /**
22
+ * Check if a specific puzzle is completed
23
+ *
24
+ * @param completedPuzzles - Array of completed puzzle records
25
+ * @param type - Puzzle type to check
26
+ * @param id - Puzzle ID to check
27
+ * @returns Whether the puzzle is completed
28
+ */
29
+ export declare function isPuzzleCompleted(completedPuzzles: CompletedPuzzle[], type: 'daily' | 'level', id: string): boolean;
30
+ /**
31
+ * Get completed level IDs
32
+ *
33
+ * @param completedPuzzles - Array of completed puzzle records
34
+ * @returns Array of completed level IDs
35
+ */
36
+ export declare function getCompletedLevelIds(completedPuzzles: CompletedPuzzle[]): string[];
37
+ /**
38
+ * Get completed daily dates
39
+ *
40
+ * @param completedPuzzles - Array of completed puzzle records
41
+ * @returns Array of completed daily dates (YYYY-MM-DD)
42
+ */
43
+ export declare function getCompletedDailyDates(completedPuzzles: CompletedPuzzle[]): string[];
44
+ //# sourceMappingURL=progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../src/utils/progress.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEpE;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,gBAAgB,EAAE,eAAe,EAAE,EACnC,OAAO,CAAC,EAAE,MAAM,GACf,SAAS,CAqCX;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,gBAAgB,EAAE,eAAe,EAAE,EACnC,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,MAAM,CAoCR;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,gBAAgB,EAAE,eAAe,EAAE,EACnC,IAAI,EAAE,OAAO,GAAG,OAAO,EACvB,EAAE,EAAE,MAAM,GACT,OAAO,CAET;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,gBAAgB,EAAE,eAAe,EAAE,GAClC,MAAM,EAAE,CAEV;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,gBAAgB,EAAE,eAAe,EAAE,GAClC,MAAM,EAAE,CAEV"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Progress calculation utilities
3
+ */
4
+ /**
5
+ * Calculate game statistics from completed puzzles
6
+ *
7
+ * @param completedPuzzles - Array of completed puzzle records
8
+ * @param newTime - Optional new time to include in calculations
9
+ * @returns Computed game statistics
10
+ */
11
+ export function calculateStats(completedPuzzles, newTime) {
12
+ const puzzlesWithTime = completedPuzzles.filter(p => p.timeSeconds !== undefined);
13
+ // Calculate total time
14
+ const totalTimePlayed = puzzlesWithTime.reduce((sum, p) => sum + (p.timeSeconds ?? 0), 0) +
15
+ (newTime ?? 0);
16
+ // Calculate average time
17
+ const count = puzzlesWithTime.length + (newTime !== undefined ? 1 : 0);
18
+ const averageTime = count > 0 ? Math.round(totalTimePlayed / count) : null;
19
+ // Calculate best times by type
20
+ const dailyTimes = completedPuzzles
21
+ .filter((p) => p.type === 'daily' && p.timeSeconds !== undefined)
22
+ .map(p => p.timeSeconds);
23
+ const levelTimes = completedPuzzles
24
+ .filter((p) => p.type === 'level' && p.timeSeconds !== undefined)
25
+ .map(p => p.timeSeconds);
26
+ const bestDailyTime = dailyTimes.length > 0 ? Math.min(...dailyTimes) : null;
27
+ const bestLevelTime = levelTimes.length > 0 ? Math.min(...levelTimes) : null;
28
+ return {
29
+ bestDailyTime,
30
+ bestLevelTime,
31
+ averageTime,
32
+ totalTimePlayed,
33
+ };
34
+ }
35
+ /**
36
+ * Calculate daily streak based on completions
37
+ *
38
+ * @param completedPuzzles - Array of completed puzzle records
39
+ * @param lastDailyDate - Date of last daily completion (YYYY-MM-DD)
40
+ * @returns Current streak count
41
+ */
42
+ export function calculateStreak(completedPuzzles, lastDailyDate) {
43
+ if (!lastDailyDate)
44
+ return 0;
45
+ const today = new Date().toISOString().split('T')[0];
46
+ const yesterday = new Date(Date.now() - 86400000).toISOString().split('T')[0];
47
+ // If last daily wasn't today or yesterday, streak is broken
48
+ if (lastDailyDate !== today && lastDailyDate !== yesterday) {
49
+ return 0;
50
+ }
51
+ // Count consecutive days
52
+ const dailyDates = completedPuzzles
53
+ .filter(p => p.type === 'daily')
54
+ .map(p => p.id)
55
+ .sort()
56
+ .reverse();
57
+ let streak = 0;
58
+ let currentDate = lastDailyDate === today ? today : yesterday;
59
+ for (const date of dailyDates) {
60
+ if (currentDate === undefined)
61
+ break;
62
+ if (date === currentDate) {
63
+ streak++;
64
+ // Go back one day
65
+ const previousDay = new Date(currentDate);
66
+ previousDay.setDate(previousDay.getDate() - 1);
67
+ currentDate = previousDay.toISOString().split('T')[0];
68
+ }
69
+ else if (date < currentDate) {
70
+ break;
71
+ }
72
+ }
73
+ return streak;
74
+ }
75
+ /**
76
+ * Check if a specific puzzle is completed
77
+ *
78
+ * @param completedPuzzles - Array of completed puzzle records
79
+ * @param type - Puzzle type to check
80
+ * @param id - Puzzle ID to check
81
+ * @returns Whether the puzzle is completed
82
+ */
83
+ export function isPuzzleCompleted(completedPuzzles, type, id) {
84
+ return completedPuzzles.some(p => p.type === type && p.id === id);
85
+ }
86
+ /**
87
+ * Get completed level IDs
88
+ *
89
+ * @param completedPuzzles - Array of completed puzzle records
90
+ * @returns Array of completed level IDs
91
+ */
92
+ export function getCompletedLevelIds(completedPuzzles) {
93
+ return completedPuzzles.filter(p => p.type === 'level').map(p => p.id);
94
+ }
95
+ /**
96
+ * Get completed daily dates
97
+ *
98
+ * @param completedPuzzles - Array of completed puzzle records
99
+ * @returns Array of completed daily dates (YYYY-MM-DD)
100
+ */
101
+ export function getCompletedDailyDates(completedPuzzles) {
102
+ return completedPuzzles.filter(p => p.type === 'daily').map(p => p.id);
103
+ }
104
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/utils/progress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Board scrambling utilities for creating visually different but equivalent puzzles
3
+ *
4
+ * Scrambling preserves the logical structure of a Sudoku puzzle while making it
5
+ * appear different. This is useful for:
6
+ * - Preventing players from recognizing puzzles they've seen before
7
+ * - Creating variety from a limited puzzle database
8
+ * - Making it harder to look up solutions online
9
+ */
10
+ import type { ScrambleConfig, ScrambleResult } from '../types';
11
+ /**
12
+ * Scrambles a Sudoku board while preserving its logical structure
13
+ *
14
+ * @param puzzle - 81-character puzzle string
15
+ * @param solution - 81-character solution string
16
+ * @param config - Scramble configuration (defaults to all transformations enabled)
17
+ * @returns Scramble result with scrambled puzzle, solution, and digit mapping
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const result = scrambleBoard(puzzle, solution);
22
+ * console.log(result.puzzle); // Scrambled puzzle
23
+ * console.log(result.solution); // Scrambled solution
24
+ * console.log(result.digitMapping); // Map from original to scrambled digits
25
+ * ```
26
+ */
27
+ export declare function scrambleBoard(puzzle: string, solution: string, config?: ScrambleConfig): ScrambleResult;
28
+ /**
29
+ * Creates an identity scramble result (no scrambling)
30
+ * @param puzzle - 81-character puzzle string
31
+ * @param solution - 81-character solution string
32
+ * @returns ScrambleResult with identity mapping
33
+ */
34
+ export declare function noScramble(puzzle: string, solution: string): ScrambleResult;
35
+ //# sourceMappingURL=scramble.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scramble.d.ts","sourceRoot":"","sources":["../../src/utils/scramble.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AA2G/D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,cAAwC,GAC/C,cAAc,CA4JhB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAY3E"}
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Board scrambling utilities for creating visually different but equivalent puzzles
3
+ *
4
+ * Scrambling preserves the logical structure of a Sudoku puzzle while making it
5
+ * appear different. This is useful for:
6
+ * - Preventing players from recognizing puzzles they've seen before
7
+ * - Creating variety from a limited puzzle database
8
+ * - Making it harder to look up solutions online
9
+ */
10
+ import { DEFAULT_SCRAMBLE_CONFIG } from '../types';
11
+ import { BLOCK_SIZE, BOARD_SIZE, parseBoardString, stringifyBoard, } from './board';
12
+ /**
13
+ * Fisher-Yates shuffle algorithm for arrays
14
+ * @param array - Array to shuffle in place
15
+ * @returns The shuffled array
16
+ */
17
+ function shuffleArray(array) {
18
+ for (let i = array.length - 1; i > 0; i--) {
19
+ const j = Math.floor(Math.random() * (i + 1));
20
+ const temp = array[i];
21
+ array[i] = array[j];
22
+ array[j] = temp;
23
+ }
24
+ return array;
25
+ }
26
+ /**
27
+ * Creates a random digit mapping (1-9 -> 1-9)
28
+ * @returns Map from original digit to scrambled digit
29
+ */
30
+ function createDigitMapping() {
31
+ const digits = [1, 2, 3, 4, 5, 6, 7, 8, 9];
32
+ const shuffled = shuffleArray([...digits]);
33
+ const mapping = new Map();
34
+ for (let i = 0; i < digits.length; i++) {
35
+ mapping.set(digits[i], shuffled[i]);
36
+ }
37
+ return mapping;
38
+ }
39
+ /**
40
+ * Creates the reverse of a digit mapping
41
+ * @param mapping - Original digit mapping
42
+ * @returns Reverse mapping (scrambled -> original)
43
+ */
44
+ function reverseDigitMapping(mapping) {
45
+ const reverse = new Map();
46
+ for (const [original, scrambled] of mapping) {
47
+ reverse.set(scrambled, original);
48
+ }
49
+ return reverse;
50
+ }
51
+ /**
52
+ * Applies digit mapping to a board
53
+ * @param board - 9x9 number array
54
+ * @param mapping - Digit mapping
55
+ * @returns New board with mapped digits
56
+ */
57
+ function applyDigitMapping(board, mapping) {
58
+ return board.map(row => row.map(value => {
59
+ if (value === 0)
60
+ return 0;
61
+ return mapping.get(value) ?? value;
62
+ }));
63
+ }
64
+ /**
65
+ * Rotates the board 90 degrees clockwise
66
+ * @param board - Board to rotate
67
+ * @returns New rotated board
68
+ */
69
+ function rotateBoard90(board) {
70
+ const rotated = [];
71
+ for (let col = 0; col < BOARD_SIZE; col++) {
72
+ const newRow = [];
73
+ for (let row = BOARD_SIZE - 1; row >= 0; row--) {
74
+ newRow.push(board[row]?.[col] ?? 0);
75
+ }
76
+ rotated.push(newRow);
77
+ }
78
+ return rotated;
79
+ }
80
+ /**
81
+ * Mirrors the board horizontally (left-right)
82
+ * @param board - Board to mirror
83
+ * @returns New mirrored board
84
+ */
85
+ function mirrorHorizontally(board) {
86
+ return board.map(row => [...row].reverse());
87
+ }
88
+ /**
89
+ * Mirrors the board vertically (top-bottom)
90
+ * @param board - Board to mirror
91
+ * @returns New mirrored board
92
+ */
93
+ function mirrorVertically(board) {
94
+ return [...board].reverse().map(row => [...row]);
95
+ }
96
+ /**
97
+ * Scrambles a Sudoku board while preserving its logical structure
98
+ *
99
+ * @param puzzle - 81-character puzzle string
100
+ * @param solution - 81-character solution string
101
+ * @param config - Scramble configuration (defaults to all transformations enabled)
102
+ * @returns Scramble result with scrambled puzzle, solution, and digit mapping
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * const result = scrambleBoard(puzzle, solution);
107
+ * console.log(result.puzzle); // Scrambled puzzle
108
+ * console.log(result.solution); // Scrambled solution
109
+ * console.log(result.digitMapping); // Map from original to scrambled digits
110
+ * ```
111
+ */
112
+ export function scrambleBoard(puzzle, solution, config = DEFAULT_SCRAMBLE_CONFIG) {
113
+ // Parse the boards
114
+ let puzzleBoard = parseBoardString(puzzle);
115
+ let solutionBoard = parseBoardString(solution);
116
+ // Create digit mapping (applied to both puzzle and solution)
117
+ let digitMapping = new Map();
118
+ for (let i = 1; i <= 9; i++) {
119
+ digitMapping.set(i, i); // Identity mapping by default
120
+ }
121
+ if (config.scrambleDigits) {
122
+ digitMapping = createDigitMapping();
123
+ puzzleBoard = applyDigitMapping(puzzleBoard, digitMapping);
124
+ solutionBoard = applyDigitMapping(solutionBoard, digitMapping);
125
+ }
126
+ // Scramble rows within blocks
127
+ if (config.scrambleRows) {
128
+ // We need to apply the same transformation to both boards
129
+ // Generate the permutation first, then apply to both
130
+ const rowPermutations = [];
131
+ for (let blockRow = 0; blockRow < BLOCK_SIZE; blockRow++) {
132
+ rowPermutations.push(shuffleArray([0, 1, 2]));
133
+ }
134
+ const applyRowPermutation = (board) => {
135
+ for (let blockRow = 0; blockRow < BLOCK_SIZE; blockRow++) {
136
+ const startRow = blockRow * BLOCK_SIZE;
137
+ const perm = rowPermutations[blockRow];
138
+ const rowsCopy = [
139
+ [...(board[startRow] ?? [])],
140
+ [...(board[startRow + 1] ?? [])],
141
+ [...(board[startRow + 2] ?? [])],
142
+ ];
143
+ for (let i = 0; i < BLOCK_SIZE; i++) {
144
+ board[startRow + i] = rowsCopy[perm[i]];
145
+ }
146
+ }
147
+ };
148
+ applyRowPermutation(puzzleBoard);
149
+ applyRowPermutation(solutionBoard);
150
+ }
151
+ // Scramble columns within blocks
152
+ if (config.scrambleColumns) {
153
+ const colPermutations = [];
154
+ for (let blockCol = 0; blockCol < BLOCK_SIZE; blockCol++) {
155
+ colPermutations.push(shuffleArray([0, 1, 2]));
156
+ }
157
+ const applyColPermutation = (board) => {
158
+ for (let blockCol = 0; blockCol < BLOCK_SIZE; blockCol++) {
159
+ const startCol = blockCol * BLOCK_SIZE;
160
+ const perm = colPermutations[blockCol];
161
+ for (let row = 0; row < BOARD_SIZE; row++) {
162
+ const boardRow = board[row];
163
+ if (boardRow) {
164
+ const colsCopy = [
165
+ boardRow[startCol],
166
+ boardRow[startCol + 1],
167
+ boardRow[startCol + 2],
168
+ ];
169
+ for (let i = 0; i < BLOCK_SIZE; i++) {
170
+ boardRow[startCol + i] = colsCopy[perm[i]];
171
+ }
172
+ }
173
+ }
174
+ }
175
+ };
176
+ applyColPermutation(puzzleBoard);
177
+ applyColPermutation(solutionBoard);
178
+ }
179
+ // Scramble row blocks
180
+ if (config.scrambleRowBlocks) {
181
+ const blockOrder = shuffleArray([0, 1, 2]);
182
+ const applyRowBlockPermutation = (board) => {
183
+ const allRows = board.map(row => [...row]);
184
+ const result = [];
185
+ for (let newBlockIndex = 0; newBlockIndex < BLOCK_SIZE; newBlockIndex++) {
186
+ const oldBlockIndex = blockOrder[newBlockIndex];
187
+ for (let i = 0; i < BLOCK_SIZE; i++) {
188
+ result.push(allRows[oldBlockIndex * BLOCK_SIZE + i]);
189
+ }
190
+ }
191
+ return result;
192
+ };
193
+ puzzleBoard = applyRowBlockPermutation(puzzleBoard);
194
+ solutionBoard = applyRowBlockPermutation(solutionBoard);
195
+ }
196
+ // Scramble column blocks
197
+ if (config.scrambleColumnBlocks) {
198
+ const blockOrder = shuffleArray([0, 1, 2]);
199
+ const applyColBlockPermutation = (board) => {
200
+ const result = board.map(() => new Array(BOARD_SIZE).fill(0));
201
+ for (let newBlockIndex = 0; newBlockIndex < BLOCK_SIZE; newBlockIndex++) {
202
+ const oldBlockIndex = blockOrder[newBlockIndex];
203
+ for (let i = 0; i < BLOCK_SIZE; i++) {
204
+ const oldCol = oldBlockIndex * BLOCK_SIZE + i;
205
+ const newCol = newBlockIndex * BLOCK_SIZE + i;
206
+ for (let row = 0; row < BOARD_SIZE; row++) {
207
+ const resultRow = result[row];
208
+ if (resultRow) {
209
+ resultRow[newCol] = board[row]?.[oldCol] ?? 0;
210
+ }
211
+ }
212
+ }
213
+ }
214
+ return result;
215
+ };
216
+ puzzleBoard = applyColBlockPermutation(puzzleBoard);
217
+ solutionBoard = applyColBlockPermutation(solutionBoard);
218
+ }
219
+ // Rotate
220
+ if (config.rotate) {
221
+ const rotations = Math.floor(Math.random() * 4);
222
+ for (let i = 0; i < rotations; i++) {
223
+ puzzleBoard = rotateBoard90(puzzleBoard);
224
+ solutionBoard = rotateBoard90(solutionBoard);
225
+ }
226
+ }
227
+ // Mirror
228
+ if (config.mirror) {
229
+ const mirrorType = Math.floor(Math.random() * 4);
230
+ const applyMirror = (board) => {
231
+ switch (mirrorType) {
232
+ case 1:
233
+ return mirrorHorizontally(board);
234
+ case 2:
235
+ return mirrorVertically(board);
236
+ case 3:
237
+ return mirrorVertically(mirrorHorizontally(board));
238
+ default:
239
+ return board;
240
+ }
241
+ };
242
+ puzzleBoard = applyMirror(puzzleBoard);
243
+ solutionBoard = applyMirror(solutionBoard);
244
+ }
245
+ return {
246
+ puzzle: stringifyBoard(puzzleBoard),
247
+ solution: stringifyBoard(solutionBoard),
248
+ digitMapping,
249
+ reverseDigitMapping: reverseDigitMapping(digitMapping),
250
+ };
251
+ }
252
+ /**
253
+ * Creates an identity scramble result (no scrambling)
254
+ * @param puzzle - 81-character puzzle string
255
+ * @param solution - 81-character solution string
256
+ * @returns ScrambleResult with identity mapping
257
+ */
258
+ export function noScramble(puzzle, solution) {
259
+ const identityMapping = new Map();
260
+ for (let i = 1; i <= 9; i++) {
261
+ identityMapping.set(i, i);
262
+ }
263
+ return {
264
+ puzzle,
265
+ solution,
266
+ digitMapping: identityMapping,
267
+ reverseDigitMapping: identityMapping,
268
+ };
269
+ }
270
+ //# sourceMappingURL=scramble.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scramble.js","sourceRoot":"","sources":["../../src/utils/scramble.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
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
+ import type { Product, Subscription } from '../types/subscription';
8
+ /** RevenueCat Package shape (simplified) */
9
+ interface RevenueCatPackage {
10
+ identifier: string;
11
+ rcBillingProduct?: {
12
+ identifier?: string;
13
+ title?: string;
14
+ description?: string;
15
+ currentPrice?: {
16
+ amountMicros?: number;
17
+ formattedPrice?: string;
18
+ };
19
+ normalPeriodDuration?: string;
20
+ defaultSubscriptionOption?: {
21
+ introPrice?: {
22
+ price?: {
23
+ formattedPrice?: string;
24
+ };
25
+ periodDuration?: string;
26
+ };
27
+ trial?: {
28
+ periodDuration?: string;
29
+ };
30
+ };
31
+ };
32
+ }
33
+ /** RevenueCat CustomerInfo entitlement shape */
34
+ interface RevenueCatEntitlement {
35
+ expirationDate?: number | null;
36
+ latestPurchaseDate?: number | null;
37
+ productIdentifier?: string;
38
+ willRenew?: boolean;
39
+ }
40
+ /** RevenueCat CustomerInfo shape (simplified) */
41
+ interface RevenueCatCustomerInfo {
42
+ entitlements: {
43
+ active: Record<string, RevenueCatEntitlement>;
44
+ };
45
+ }
46
+ /**
47
+ * Convert RevenueCat package to our Product interface
48
+ *
49
+ * @param pkg - RevenueCat package
50
+ * @returns Product object
51
+ */
52
+ export declare function convertPackageToProduct(pkg: RevenueCatPackage): Product;
53
+ /**
54
+ * Parse RevenueCat CustomerInfo into our Subscription interface
55
+ *
56
+ * @param customerInfo - RevenueCat customer info
57
+ * @returns Subscription object
58
+ */
59
+ export declare function parseCustomerInfo(customerInfo: RevenueCatCustomerInfo): Subscription;
60
+ /**
61
+ * Get display name for subscription period
62
+ *
63
+ * @param period - ISO 8601 duration string (e.g., "P1M", "P1Y")
64
+ * @returns Human-readable period name
65
+ */
66
+ export declare function getPeriodDisplayName(period: string | undefined): string;
67
+ /**
68
+ * Check if a plan is the "best value" (typically annual plans)
69
+ *
70
+ * @param period - ISO 8601 duration string
71
+ * @returns Whether this is typically the best value option
72
+ */
73
+ export declare function isBestValuePlan(period: string | undefined): boolean;
74
+ /**
75
+ * Get RevenueCat purchase error message
76
+ *
77
+ * @param errorCode - RevenueCat error code
78
+ * @returns User-friendly error message
79
+ */
80
+ export declare function getRevenueCatErrorMessage(errorCode: number): string;
81
+ export {};
82
+ //# sourceMappingURL=subscription.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../src/utils/subscription.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEnE,4CAA4C;AAC5C,UAAU,iBAAiB;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE;YACb,YAAY,CAAC,EAAE,MAAM,CAAC;YACtB,cAAc,CAAC,EAAE,MAAM,CAAC;SACzB,CAAC;QACF,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,yBAAyB,CAAC,EAAE;YAC1B,UAAU,CAAC,EAAE;gBACX,KAAK,CAAC,EAAE;oBACN,cAAc,CAAC,EAAE,MAAM,CAAC;iBACzB,CAAC;gBACF,cAAc,CAAC,EAAE,MAAM,CAAC;aACzB,CAAC;YACF,KAAK,CAAC,EAAE;gBACN,cAAc,CAAC,EAAE,MAAM,CAAC;aACzB,CAAC;SACH,CAAC;KACH,CAAC;CACH;AAED,gDAAgD;AAChD,UAAU,qBAAqB;IAC7B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,iDAAiD;AACjD,UAAU,sBAAsB;IAC9B,YAAY,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;KAC/C,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CA+BvE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,sBAAsB,GACnC,YAAY,CA2Bd;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAavE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAanE"}