All files / web/src/arcade-games/music-matching types.ts

100% Statements 78/78
100% Branches 0/0
100% Functions 0/0
100% Lines 78/78

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 791x 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  
/**
 * Music Note Matching Game - Variant-Specific Type Definitions
 *
 * Base types (GamePhase, Difficulty, BaseMatchingCard, etc.) live in the
 * matching-pairs-framework. This file defines only the music-specific
 * extensions.
 */
 
import { z } from 'zod'
import type { BaseMatchingCard, BaseMatchingConfig } from '@/lib/arcade/matching-pairs-framework'
 
// ============================================================================
// Variant-Specific Schemas & Types
// ============================================================================
 
export const MusicCardTypeSchema = z.enum(['staff-note', 'note-name'])
export type MusicCardType = z.infer<typeof MusicCardTypeSchema>
 
export const MusicGameTypeSchema = z.enum(['staff-to-name', 'treble-to-bass'])
export type MusicGameType = z.infer<typeof MusicGameTypeSchema>
 
export const ClefSchema = z.enum(['treble', 'bass', 'both'])
export type ClefOption = z.infer<typeof ClefSchema>
 
export const DifficultySchema = z.union([z.literal(6), z.literal(8), z.literal(12), z.literal(15)])
export type Difficulty = z.infer<typeof DifficultySchema>
 
// ============================================================================
// MusicCard — extends BaseMatchingCard
// ============================================================================
 
export const MusicCardSchema = z.object({
  id: z.string(),
  type: MusicCardTypeSchema,
  pitchClass: z.string(),
  octave: z.number(),
  midiNote: z.number(),
  clef: z.enum(['treble', 'bass']).optional(),
  accidental: z.enum(['sharp', 'flat', 'natural', 'none']).optional(),
  displayName: z.string(),
  friendlyName: z.string().optional(),
  matched: z.boolean(),
  matchedBy: z.string().optional(),
})
 
export type MusicCard = z.infer<typeof MusicCardSchema>
 
// Verify MusicCard extends BaseMatchingCard at the type level
const _cardCheck: BaseMatchingCard = {} as MusicCard
void _cardCheck
 
// ============================================================================
// MusicConfig — extends BaseMatchingConfig
// ============================================================================
 
export const MusicConfigSchema = z.object({
  gameType: MusicGameTypeSchema,
  clef: ClefSchema,
  difficulty: DifficultySchema,
  turnTimer: z.number(),
  skipSetupPhase: z.boolean().optional(),
})
 
export type MusicConfig = z.infer<typeof MusicConfigSchema>
 
// Verify MusicConfig extends BaseMatchingConfig at the type level
const _configCheck: BaseMatchingConfig = {} as MusicConfig
void _configCheck
 
// ============================================================================
// Match Validation Result
// ============================================================================
 
export interface MusicMatchValidationResult {
  isValid: boolean
  reason?: string
  type: 'staff-to-name' | 'treble-to-bass' | 'invalid'
}