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 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | 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)
}
|