Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | import {
CONSTANT_IDS,
EXPLORATION_DISPLAY,
} from '@/components/toys/number-line/talkToNumber/explorationRegistry'
import type { GameResultsReport } from '@/lib/arcade/game-sdk/types'
import { finalizeSongContext, songDetail, songMoment } from '@/lib/arcade/song-context'
import type { GameValidator, ValidationResult } from '@/lib/arcade/validation/types'
import type { ConstantExplorerMove, ConstantExplorerState } from './types'
function buildConstantExplorerSongContext(
symbol: string,
name: string,
value: number | undefined
): NonNullable<GameResultsReport['songContext']> {
return finalizeSongContext({
summary: `Explored the constant ${symbol} (${name})`,
details: [
songDetail('Signature constant', `${symbol} ${name}`),
value !== undefined ? songDetail('Approximate value', value.toFixed(6)) : undefined,
],
dramaticMoments: [
songMoment('Opening beat', `the discovery detour opened on ${symbol}`),
songMoment('Signature items', `${symbol} and ${name}`),
],
strategyNotes: ['Discovery break focused on noticing a famous number pattern'],
outcome: `explored ${symbol}`,
})
}
/**
* Validator for constant-explorer.
*
* Constant explorations are passive (no game moves). The validator exists
* to satisfy the game registry interface and to build results reports
* for scoreboard persistence (needed for "balance" selection mode).
*/
class ConstantExplorerValidator
implements GameValidator<ConstantExplorerState, ConstantExplorerMove>
{
validateMove(): ValidationResult {
return { valid: false, error: 'Constant explorer has no moves' }
}
isGameComplete(state: ConstantExplorerState): boolean {
return state.phase === 'complete'
}
getInitialState(config: unknown): ConstantExplorerState {
const c = config as { constantId?: string } | undefined
return {
constantId: c?.constantId ?? null,
phase: 'idle',
}
}
getResultsReport(state: ConstantExplorerState, _config: unknown): GameResultsReport {
const constantId = state.constantId ?? 'unknown'
const display = CONSTANT_IDS.has(constantId) ? EXPLORATION_DISPLAY[constantId] : null
const symbol = display?.symbol ?? constantId
const name = display?.name ?? constantId
const value = display?.value
const now = Date.now()
const durationMs = state.startedAt ? now - state.startedAt : 0
return {
gameName: 'constant-explorer',
gameDisplayName: 'Math Discovery',
gameIcon: '\uD83D\uDD2D',
durationMs,
completedNormally: true,
startedAt: state.startedAt ?? now,
endedAt: now,
gameMode: 'single-player',
playerCount: 1,
playerResults: [
{
playerId: state.playerId ?? 'unknown',
playerName: state.playerName ?? 'Explorer',
playerEmoji: '\uD83D\uDD2D',
userId: state.playerId ?? 'unknown',
score: 1, // Binary: explored or not
rank: 1,
},
],
itemsCompleted: 1,
itemsTotal: 1,
completionPercent: 100,
leaderboardEntry: {
normalizedScore: 100,
category: 'discovery',
// Encode constantId in difficulty so we can query per-constant play counts
difficulty: constantId,
},
customStats: [
{
label: 'Constant',
value: `${symbol} ${name}`,
icon: '\uD83D\uDD2D',
highlight: true,
},
...(value !== undefined
? [
{
label: 'Value',
value: `${value.toFixed(6)}...`,
icon: '\uD83D\uDCCA',
},
]
: []),
],
headline: `Explored ${symbol}!`,
subheadline: name,
resultTheme: 'success',
celebrationType: 'stars',
songContext: buildConstantExplorerSongContext(symbol, name, value),
}
}
}
export const constantExplorerValidator = new ConstantExplorerValidator()
|