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 | import type { MusicCard, MusicMatchValidationResult } from '../types' /** * Validate staff-to-name match: * One card must be staff-note, the other must be note-name, and they must share the same MIDI note. */ export function validateStaffToNameMatch( card1: MusicCard, card2: MusicCard ): MusicMatchValidationResult { // Cards must be different types if (card1.type === card2.type) { return { isValid: false, reason: 'Must match a staff note with a note name', type: 'invalid', } } // One must be staff-note, one must be note-name const hasStaff = card1.type === 'staff-note' || card2.type === 'staff-note' const hasName = card1.type === 'note-name' || card2.type === 'note-name' if (!hasStaff || !hasName) { return { isValid: false, reason: 'Must match a staff note with a note name', type: 'invalid', } } // MIDI notes must match if (card1.midiNote !== card2.midiNote) { return { isValid: false, reason: 'Notes do not match', type: 'invalid', } } return { isValid: true, type: 'staff-to-name', } } /** * Validate treble-to-bass match: * Both cards must be staff-note, different clefs, same MIDI note. */ export function validateTrebleToBassMatch( card1: MusicCard, card2: MusicCard ): MusicMatchValidationResult { // Both must be staff-note if (card1.type !== 'staff-note' || card2.type !== 'staff-note') { return { isValid: false, reason: 'Both cards must be staff notes', type: 'invalid', } } // Must be different clefs if (card1.clef === card2.clef) { return { isValid: false, reason: 'Cards must be from different clefs', type: 'invalid', } } // MIDI notes must match if (card1.midiNote !== card2.midiNote) { return { isValid: false, reason: 'Notes do not match', type: 'invalid', } } return { isValid: true, type: 'treble-to-bass', } } /** * Main validation function — determines which validation to use based on card types. */ export function validateMatch(card1: MusicCard, card2: MusicCard): MusicMatchValidationResult { // Cannot match the same card with itself if (card1.id === card2.id) { return { isValid: false, reason: 'Cannot match card with itself', type: 'invalid', } } // Cannot match already matched cards if (card1.matched || card2.matched) { return { isValid: false, reason: 'Cannot match already matched cards', type: 'invalid', } } // Determine match type from card types const hasNoteName = card1.type === 'note-name' || card2.type === 'note-name' if (hasNoteName) { return validateStaffToNameMatch(card1, card2) } // Both are staff-note: treble-to-bass mode return validateTrebleToBassMatch(card1, card2) } |