Skip to content

Latest commit

 

History

History
693 lines (548 loc) · 15.1 KB

2023.md

File metadata and controls

693 lines (548 loc) · 15.1 KB

AdventJS 2023

Tabla de contenidos

Retos

Reto #1: 🎁 ¡Primer regalo repetido!

function findFirstRepeated(gifts) {
  let r = ','

  for (const gift of gifts) {
    if (r.includes(`,${gift},`)) return gift
    r += `${gift},`
  }

  return -1
}

Reto #2: 🏭 Ponemos en marcha la fábrica

function manufacture(gifts, materials) {
  return gifts.reduce((acc, gift) => {
    const isManufacturing = [...new Set(gift.split(''))].every((letter) =>
      materials.includes(letter)
    )

    if (!isManufacturing) acc.splice(acc.indexOf(gift), 1)

    return acc

  }, [...gifts])
}

Reto #3: 😏 El elfo travieso

function findNaughtyStep(original, modified) {
  for (let i = 0; i < modified.length; i++) {
    if (original[i] !== modified[i]) {
      return original.length < modified.length ? modified[i] : original[i]
    }
  }

  return ''
}

Reto #4: 😵‍💫 Dale la vuelta a los paréntesis

function decode(message) {
  if (message.includes('(')) {
    message.match(/\([a-zA-Z\s0-9]*\)/g).forEach((match) => {
      message = message.replace(
        match,
        match.slice(1, -1).split('').reverse().join('')
      )
    })

    message = decode(message)
  }

  return message
}

Reto #5: 🛷 El CyberTruck de Santa

function cyberReindeer(road, time) {
  let road2 = `.${road.substring(1)}`

  const symbols = {
    5: road2.replaceAll('|', '*')
  }
  const pictures = [road]

  let x = 0
  for (let i = 1; i < time; i++) {
    road2 = symbols[i] ?? road2
    x += road2[x + 1] !== '|' ?? 1
    pictures.push(road2.substring(0, x) + 'S' + road2.substring(x + 1))
  }

  return pictures
}

Reto #6: 🦌 Los renos a prueba

function maxDistance(movements) {
  const symbols = {
    '>': (a) => a + 1,
    '<': (a) => a - 1
  }
  const movementsArray = movements.split('').filter((move) => move !== '*')

  return (
    Math.abs(
      movementsArray.reduce((acc, movement) => symbols[movement](acc), 0)
    ) +
    movements.length -
    movementsArray.length
  )
}

Reto #7: 📦 Las cajas en 3D

function drawGift(size, symbol) {
  const pound = '#'
  const endLine = '\n'

  if (size === 1) return `${pound}${endLine}`

  const y0 = pound.repeat(size)

  const middle = size - 2
  const yn = `${pound.repeat(size)}${symbol.repeat(middle)}#`

  const upperBox = [y0.padStart(yn.length)]
  const lowerBox = [y0]

  for (let i = 0; i < middle; i++) {
    const row = `#${symbol.repeat(middle)}#${symbol.repeat(i)}#`

    upperBox.push(row.padStart(yn.length))
    lowerBox.unshift(row)
  }

  return [...upperBox, yn, ...lowerBox].join(endLine) + endLine
}

Reto #8: 🏬 Ordenando el almacén

function organizeGifts(gifts) {
  const sizes = [50, 10, 1]

  return gifts.match(/\d*[a-z]/g).reduce((acc, curr) => {
    let amount = Number(curr.slice(0, -1))
    const gift = curr.slice(-1)

    const store = sizes.reduce((acc, size) => {
      const n = Math.floor(amount / size)
      amount -= n * size
      acc.push(n)
      return acc
    }, [])

    const pallets = `[${gift}]`.repeat(store[0])
    const boxes = `{${gift}}`.repeat(store[1])
    const bags = `(${gift.repeat(store[2])})`.replace('()', '')

    acc += `${pallets}${boxes}${bags}`

    return acc
  }, '')
}

Reto #9: 🚦 Alterna las luces

function adjustLights(lights) {
  const pos = {
    0: '🔴',
    1: '🟢'
  }

  return Math.min(
    ...lights.reduce(
      (acc, light, i) => {
        light !== pos[i % 2] ? acc[0]++ : acc[1]++
        return acc
      },
      [0, 0]
    )
  )
}

Reto #10: 🎄 Crea tu propio árbol de navidad

function createChristmasTree(ornaments, height) {
  let o = ''
  const numOrnaments = (height * (height + 1)) / 2
  const ornamentsSet = ornaments
    .repeat(Math.ceil(numOrnaments / ornaments.length))
    .split('')
    .join(' ')

  for (let i = 0; i < height; i++) {
    const start = ((i * (i + 1)) / 2) * 2

    o +=
      ornamentsSet.substring(start, start + i * 2 + 1).padStart(height + i) +
      '\n'
  }

  return o + '|'.padStart(height) + '\n'
}

Reto #11: 📖 Los elfos estudiosos

function getIndexsForPalindrome(word) {
  const wordSplitted = word.split('')
  const middle = wordSplitted.length / 2

  if (
    wordSplitted
      .slice(0, middle)
      .every((c, i) => c === wordSplitted[wordSplitted.length - 1 - i])
  ) {
    return []
  }

  for (let i = 0; i < wordSplitted.length; i++) {
    for (let j = i + 1; j < wordSplitted.length; j++) {
      const wordToTest =
        word.substring(0, i) +
        word[j] +
        word.substring(i + 1, j) +
        word[i] +
        word.substring(j + 1)

      if (
        wordToTest
          .substring(0, middle)
          .split('')
          .every((c, i) => c === wordToTest[wordToTest.length - 1 - i])
      ) {
        return [i, j]
      }
    }
  }

  return null
}

Reto #12: 📸 ¿Es una copia válida?

function checkIsValidCopy(original, copy) {
  if (original.length !== copy.length) return false

  const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#+:. '

  return !original.split('').some((char, i) => {
    const copyChar = copy.charAt(i)

    const originalIndex = alphabet.indexOf(char)
    const copyIndex = alphabet.indexOf(copyChar)

    return (
      (originalIndex < 52 &&
        copyIndex < 52 &&
        char.toLowerCase() !== copyChar.toLowerCase()) ||
      originalIndex > copyIndex
    )
  })
}

Reto #13: ⌚️ Calculando el tiempo

function calculateTime(deliveries) {
  let leftoverTime =
    deliveries.reduce((acc, delivery) => {
      const [hours, minutes, seconds] = delivery.split(':')
      acc += Number(hours) * 3600 + Number(minutes) * 60 + Number(seconds)
      return acc
    }, 0) -
    7 * 3600

  const sign = leftoverTime < 0 ? '-' : ''
  leftoverTime = Math.abs(leftoverTime)
  const leftoverTimeParts = [
    `${Math.floor(leftoverTime / 3600)}`,
    `${Math.floor((leftoverTime % 3600) / 60)}`,
    `${leftoverTime % 60}`
  ]
    .map((part) => part.padStart(2, '0'))
    .join(':')

  return sign + leftoverTimeParts
}

Reto #14: 🚨 Evita la alarma

function maxGifts(houses) {
  houses.push(0)

  for (let i = houses.length - 4; i >= 0; i--) {
    houses[i] += Math.max(houses[i + 2], houses[i + 3])
  }

  return Math.max(houses[0], houses[1])
}

Reto #15: ↔️ Robot autónomo

function autonomousDrive(store, movements) {
  const pathSymbols = {
    freeWay: '.',
    barrier: '*',
    robotPosition: '!'
  }
  const movementsSymbols = {
    R: [1, 0],
    L: [-1, 0],
    U: [0, -1],
    D: [0, 1]
  }

  let x
  let y

  for (let i = 0; i < store.length; i++) {
    const xAux = store[i].indexOf(pathSymbols.robotPosition)

    if (xAux !== -1) {
      x = xAux
      y = i

      break
    }
  }

  store[y] = store[y].replace('!', '.')

  for (const movement of movements) {
    const [x1, y1] = movementsSymbols[movement]

    const yAux = y + y1
    if (!store[yAux]) continue

    const xAux = x + x1
    const nextSymbol = store[yAux][xAux]
    if (!nextSymbol || nextSymbol === pathSymbols.barrier) continue

    x = xAux
    y = yAux
  }

  store[y] =
    store[y].substring(0, x) +
    pathSymbols.robotPosition +
    store[y].substring(x + 1)

  return store
}

Reto #16: ❌ Despliegue en viernes

function transformTree(tree) {
  if (!tree.length) return null

  function child(parent) {
    const value = tree[parent]
    const leftChild = (parent + 0.5) * 2
    const rightChild = leftChild + 1

    if (parent >= tree.length || value === null) return null

    return {
      value,
      left: leftChild >= tree.length ? null : child(leftChild),
      right: rightChild >= tree.length ? null : child(rightChild)
    }
  }

  return {
    value: tree[0],
    left: child(1),
    right: child(2)
  }
}

Reto #17: 🛷 Optimizando el alquiler

function optimizeIntervals(intervals) {
  intervals.sort((a, b) => a[0] - b[0]);

  const result = [intervals[0]];

  for (const val of intervals.slice(1)) {
    const [start, end] = val;
    const max = result[result.length - 1][1];

    start > max
      ? result.push(val)
      : (result[result.length - 1][1] = Math.max(end, max));
  }

  return result;
}

Reto #18: 🔢 El reloj digital

function drawClock(time) {
  const digits = {
    0: ['***', '* *', '* *', '* *', '* *', '* *', '***'],
    1: ['  *', '  *', '  *', '  *', '  *', '  *', '  *'],
    2: ['***', '  *', '  *', '***', '*  ', '*  ', '***'],
    3: ['***', '  *', '  *', '***', '  *', '  *', '***'],
    4: ['* *', '* *', '* *', '***', '  *', '  *', '  *'],
    5: ['***', '*  ', '*  ', '***', '  *', '  *', '***'],
    6: ['***', '*  ', '*  ', '***', '* *', '* *', '***'],
    7: ['***', '  *', '  *', '  *', '  *', '  *', '  *'],
    8: ['***', '* *', '* *', '***', '* *', '* *', '***'],
    9: ['***', '* *', '* *', '***', '  *', '  *', '***'],
    ':': [' ', ' ', '*', ' ', '*', ' ', ' ']
  }

  return time
    .split('')
    .reduce(
      (acc, curr) => {
        const digit = digits[curr]

        for (let i = 0; i < 7; i++) {
          acc[i].push(digit[i])
        }

        return acc
      },
      [[], [], [], [], [], [], []]
    )
    .map((row) => row.join(' ').split(''))
}

Reto #19: 💣 Enfrenta el sabotaje

function revealSabotage(store) {
  for (const [i, row] of store.entries()) {
    for (const [j, col] of row.entries()) {
      if (col === '*') continue

      const nextRow = store[i + 1]
      const prevRow = store[i - 1]

      const adjacentCells = [
        prevRow?.[j - 1],
        prevRow?.[j],
        prevRow?.[j + 1],
        row[j - 1],
        row[j + 1],
        nextRow?.[j - 1],
        nextRow?.[j],
        nextRow?.[j + 1]
      ]

      const count = adjacentCells.reduce(
        (acc, curr) => acc + +(curr === '*'),
        0
      )

      if (count !== 0) {
        row[j] = `${count}`
      }
    }
  }

  return store
}

Reto #20: 🏋️‍♂️ Distribuye el peso

function distributeGifts(weights) {
  const ms = [
    [-1, 0],
    [1, 0],
    [0, -1],
    [0, 1],
    [0, 0]
  ]

  return weights.map((_, i) =>
    weights[i].map((_, j) => {
      let l = 0
      let s = 0

      ms.forEach((k) => {
        const x = j + k[0]
        const y = i + k[1]
        const weight = weights[y] && weights[y][x]

        if (weight) {
          s += weights[y][x]
          l++
        }
      })

      return Math.round(s / l)
    })
  )
}

Reto #21: 🪐 Mensaje binario

function findBalancedSegment(message) {
  let t = 0
  let r = [0, 0]

  for (let i = 0; i < message.length; i++) {
    let l = message.length - i
    let s = message
      .slice(i, message.length + 1)
      .reduce((acc, curr) => acc + curr, 0)

    for (let j = message.length; j > i; j--) {
      l--

      if (l <= r[1]) continue

      s -= message[j] || 0

      if (s * 2 === l + 1 && s > t) {
        t = s
        r = [i, l]
      }
    }
  }

  return r[1] ? [r[0], r[0] + r[1]] : []
}

Reto #22: 🚂 Lenguaje de programación

function compile(code) {
  let c = 0
  let lr = null
  const cs = code.split('')

  for (let i = 0; i < cs.length; i++) {
    const b = cs[i]

    if (b === '%') {
      lr = i
      continue
    }
    if (b === '+') c++
    if (b === '-') c--
    if (b === '*') c *= 2
    if (b === '<' && lr !== null) {
      cs[i] = ''
      i = lr
      continue
    }
    if (b === '¿' && c <= 0) {
      i = cs.findIndex((b2, i2) => b2 === '?' && i2 > i)
      continue
    }
  }

  return c
}

Reto #23: 🍽️ La comida de Navidad

function organizeChristmasDinner(dishes) {
  return Object.entries(
    dishes.reduce((acc, dish) => {
      dish.slice(1).forEach((ingredient) => {
        if (!acc[ingredient]) acc[ingredient] = []
        acc[ingredient].push(dish[0])
      })

      return acc
    }, {})
  ).reduce((acc, [key, value]) => {
    if (value.length > 1) acc.push([key, ...value.sort()])
    return acc
  }, []).sort()
}

Reto #24: 🪜 Brincos en la escalera

function getStaircasePaths(steps, maxJump) {
  const arr = []

  const f = (s, g) => {
    if (s === 0) return arr.push(g)

    for (let i = 1; i <= Math.min(s, maxJump); i++) {
      if (s > 0) f(s - i, g.concat([i]))
    }
  }

  f(steps, [])

  return arr
}

Reto #25: 🗺️ Calculando distancias

function travelDistance(map) {
  let mapCleaned = map.replaceAll(' ', '')

  const mapRowLength = mapCleaned.split('\n')[0].length

  mapCleaned = mapCleaned.replaceAll('\n', '')

  const childrenPositions = mapCleaned
    .replace('S', '')
    .replaceAll('.', '')
    .split('')
    .sort()
  const positions = ['S', ...childrenPositions]

  return positions.reduce((acc, curr, index) => {
    if (index === positions.length - 1) return acc

    const currPosition = mapCleaned.indexOf(curr)
    const nextPosition = mapCleaned.indexOf(positions[index + 1])

    const rowDiff =
      Math.floor(currPosition / mapRowLength) -
      Math.floor(nextPosition / mapRowLength)
    const colDiff =
      (currPosition % mapRowLength) - (nextPosition % mapRowLength)

    return acc + Math.abs(rowDiff) + Math.abs(colDiff)
  }, 0)
}