All files / web/src/arcade-games/card-sorting/utils validation.ts

0% Statements 0/102
0% Branches 0/1
0% Functions 0/1
0% Lines 0/102

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                                                                                                                                                                                                             
import type { SortingCard } from '../types'

/**
 * Place a card at a specific position (simple replacement, can leave gaps)
 * This is used when clicking directly on a slot
 * Returns old card if slot was occupied
 */
export function placeCardAtPosition(
  placedCards: (SortingCard | null)[],
  cardToPlace: SortingCard,
  position: number
): { placedCards: (SortingCard | null)[]; replacedCard: SortingCard | null } {
  const newPlaced = [...placedCards]
  const replacedCard = newPlaced[position]
  newPlaced[position] = cardToPlace
  return { placedCards: newPlaced, replacedCard }
}

/**
 * Insert a card at a specific position, shifting existing cards and compacting
 * This is used when clicking a + (insert) button
 * Returns new placedCards array with no gaps
 */
export function insertCardAtPosition(
  placedCards: (SortingCard | null)[],
  cardToPlace: SortingCard,
  insertPosition: number,
  totalSlots: number
): { placedCards: (SortingCard | null)[]; excessCards: SortingCard[] } {
  // Create working array
  const newPlaced = new Array(totalSlots).fill(null)

  // Copy existing cards, shifting those at/after position
  for (let i = 0; i < placedCards.length; i++) {
    if (placedCards[i] !== null) {
      if (i < insertPosition) {
        // Before insert position - stays same
        newPlaced[i] = placedCards[i]
      } else {
        // At or after position - shift right
        if (i + 1 < totalSlots) {
          newPlaced[i + 1] = placedCards[i]
        } else {
          // Card would fall off, will be handled by compaction
          newPlaced[i + 1] = placedCards[i]
        }
      }
    }
  }

  // Place new card at insert position
  newPlaced[insertPosition] = cardToPlace

  // Compact to remove gaps (shift all cards left)
  const compacted: SortingCard[] = []
  for (const card of newPlaced) {
    if (card !== null) {
      compacted.push(card)
    }
  }

  // Fill final array with compacted cards (no gaps)
  const result = new Array(totalSlots).fill(null)
  for (let i = 0; i < Math.min(compacted.length, totalSlots); i++) {
    result[i] = compacted[i]
  }

  // Any excess cards are returned
  const excess = compacted.slice(totalSlots)

  return { placedCards: result, excessCards: excess }
}

/**
 * Remove card at position
 */
export function removeCardAtPosition(
  placedCards: (SortingCard | null)[],
  position: number
): { placedCards: (SortingCard | null)[]; removedCard: SortingCard | null } {
  const removedCard = placedCards[position]

  if (!removedCard) {
    return { placedCards, removedCard: null }
  }

  // Remove card and compact
  const compacted: SortingCard[] = []
  for (let i = 0; i < placedCards.length; i++) {
    if (i !== position && placedCards[i] !== null) {
      compacted.push(placedCards[i] as SortingCard)
    }
  }

  // Fill new array
  const newPlaced = new Array(placedCards.length).fill(null)
  for (let i = 0; i < compacted.length; i++) {
    newPlaced[i] = compacted[i]
  }

  return { placedCards: newPlaced, removedCard }
}