AdventJS 2023: Reto del Día 8
Tags: spanish, javascript, webdev, programming
Published: 2023-12-09 23:23:39

Solución al [reto #8](https://adventjs.dev/es/challenges/2023/8) del [AdventJS 2023](https://adventjs.dev/es)

[Solución del reto anterior](https://dev.to/fenriuz/adventjs-2023-reto-del-dia-7-57nm)

[Solución del siguiente reto](https://dev.to/fenriuz)

{%- # TOC start (generated with https://github.com/derlin/bitdowntoc) -%}

- [Descripción del Reto](#descripción-del-reto)
- [Análisis](#análisis)
   * [Entrada](#entradas)
   * [Salida](#salida)
   * [Consideraciones](#consideraciones)
- [Solución](#solución)
   * [Código](#código)
   * [Soluciones de la comunidad](#soluciones-de-la-comunidad)

{%- # TOC end -%}


## Descripción del Reto

Los elfos están muy ocupados en el taller de Santa Claus organizando regalos 🎁 para la víspera de Navidad 🎄.

El formato de entrada es especial, ya que indica el número de regalos y el tipo de regalo con letras de la `a` a la `z`. Por ejemplo, `'66a11b'` significa 66 regalos `a` y 11 regalos `b`.

Los elfos tienen un sistema especial para organizar los regalos:

- Cada 10 regalos del mismo tipo se empaquetan en una caja, representada por `{x}`. Por ejemplo, 20 regalos tipo a se empaquetan en 2 cajas así: `{a}{a}`.
- Cada 5 cajas se apilan en un palé, representado por `[x]`. Por ejemplo, 10 cajas de `a` se apilan en 2 palés de esta manera: `[a][a]`
- Cualquier regalo adicional se coloca en una bolsa, representada por `()` y se colocan todas dentro. Por ejemplo 4 regalos de b se colocan en una bolsa así `(bbbb)`

Los regalos luego se colocan en el siguiente orden: palés, cajas y bolsas. Y los regalos aparecen en el mismo orden que la cadena de entrada.

Tu tarea es escribir una función `organizeGifts` que tome una cadena de regalos como argumento y devuelva una cadena representando el almacén.

```javascript
const result1 = organizeGifts(`76a11b`)
console.log(result1)
// '[a]{a}{a}(aaaaaa){b}(b)'

/* Explicación:

  76a: 76 regalos tipo 'a' se empaquetarían en 7 cajas y sobrarían 6 regalos, resultando en 1 palé [a] (por las primeras 5 cajas), 2 cajas sueltas {a}{a} y una bolsa con 6 regalos (aaaaaa)

  11b: 11 regalos tipo 'b' se empaquetarían en 1 caja y sobraría 1 regalo, resultando en 1 caja suelta {b} y una bolsa con 1 regalo (b)
*/
```

## Análisis
El objetivo es desglozar el string en partes, para dividir las cantidades de cada regalo, una vez hecho eso se pueden empaquetar como lo marcaron los requerimientos.

### Entrada

1. Gifts(`gifts`): Un string con la cantidad de cada tipo de regalo.

### Salida

- Un string con los regalos empaquetados.

### Consideraciones

- El valor de retorno debe ir en el mismo orden de la entrada, o sea, siguiendo el orden de los regalos.

## Solución
Podemos tomar el string de entrada y dividirlo entre la cantidad de regalos de cada tipo, usando RegExp. Una vez hecho eso iteramos entre cada uno de ellos y procedemos a dividir para encontral cantidad de palés, cajas y bolsas.

### Código

```javascript
/**
 * Organiza una lista de regalos.
 *
 * @param {string} gifts - La lista de regalos a organizar.
 * @returns {string} - La representación organizada de los regalos.
 */
function organizeGifts(gifts) {
  let res = "";
  // Busca secuencias de una o más cifras numéricas seguidas de una letra minúscula
  const giftsSplit = gifts.match(/\d+[a-z]/g);
  
  // Iterar sobre cada regalo en el array giftsSplit
  for (const gift of giftsSplit) {
    const quantity = Number(gift.slice(0, -1));
    const giftType = gift.charAt(gift.length - 1);
    
    // Calcular el número de palés necesarios
    const pallets = `[${giftType}]`.repeat(Math.floor(quantity / 50));
    
    // Calcular el resto después de empaquetar en palés
    const remainder = quantity % 50;
    
    // Calcular el número de cajas necesarias
    const boxes = `{${giftType}}`.repeat(Math.floor(remainder / 10));
    
    // Calcular los regalos restantes después de empaquetar en cajas
    const remainderGifts = giftType.repeat(remainder % 10);
    
    // Verificar si hay regalos restantes y crear una bolsa
    const bags = remainderGifts && `(${remainderGifts})`;
    
    // Concatenar los palés, cajas y bolsas para el regalo actual
    res += pallets + boxes + bags;
  }

  // Devolver la representación organizada de los regalos
  return res;
}
```

### Soluciones de la comunidad

Solución por [cristianstu](https://github.com/cristianstu):

```javascript
function organizeGifts(gifts) {
  const matches = [...gifts.matchAll(/(\d+)([a-z])/g)];

  return matches.map(([,qtty, letter]) => {
    qtty = +qtty

    const pales = Math.trunc(qtty / 50)
    const boxes = Math.trunc((qtty - (50 * pales)) / 10)
    const bags = qtty - (pales * 50) - (boxes * 10)

    return `[${letter}]`.repeat(pales) +
           `{${letter}}`.repeat(boxes) +
           `(${letter})`.repeat(bags).replace(/\)\(/g, '')

  }).join('');
}
```

Solución por [jamerrq](https://github.com/jamerrq/advent-js-2023/blob/master/src/challenges/08.ts):

```javascript
function organizeGifts (gifts: string): string {
  const giftsRegex = /(\d+)([a-z])/g
  const giftsMatches = gifts.matchAll(giftsRegex)
  let ans = ''
  for (const match of giftsMatches) {
    const [, qty, symbol] = match
    let left = +qty
    ans = `${ans}${`[${symbol}]`.repeat((left - (left % 50)) / 50)}`
    left -= 50 * ((left - (left % 50)) / 50)
    ans = `${ans}${`{${symbol}}`.repeat((left - (left % 10)) / 10)}`
    left -= 10 * (left - (left % 10)) / 10
    const x = ((left - 1) + ((left - 1) >> 31)) ^ ((left - 1) >> 31)
    ans = `${ans}${`(${symbol.repeat(left)})`.repeat((left + 1 - x) / 2)}`
  }
  return ans
}
```

Y ese fue el reto para el 8 de diciembre y sus soluciones. Dale like si te ha gustado el reto o la solución!
¿Tienes otra solución alternativa? ¡Déjala en los comentarios!