|
1 | | -# Reto 5 |
| 1 | +# Reto 6 |
2 | 2 |
|
3 | | -Santa 🎅 está probando su nuevo trineo eléctrico, el CyberReindeer, en una carretera del Polo Norte. La carretera se representa con una cadena de caracteres, donde: |
| 3 | +Los elfos están catalogando los renos de Santa 🦌 según la distancia que pueden recorrer. |
4 | 4 |
|
5 | | -- . = Carretera |
6 | | -- S = Trineo de Santa |
7 | | -- \* = Barrera abierta |
8 | | -- | = Barrera cerrada |
| 5 | +Para ello tienen una cadena de texto movements donde cada caracter representa la dirección del movimiento del reno: |
9 | 6 |
|
10 | | -Ejemplo de carretera: `S...|....|.....` |
| 7 | +- \> = Avanza a la derecha |
| 8 | +- \< = Avanza a la izquierda |
| 9 | +- \* = Puede avanzar o retroceder |
11 | 10 |
|
12 | | -Cada unidad de tiempo, **el trineo avanza una posición a la derecha**. Si encuentra una barrera cerrada, se detiene hasta que la barrera se abra. Si está abierta, la atraviesa directamente. |
| 11 | +Por ejemplo, si el movimiento es >>\*<, va hacia la derecha dos veces, luego puede ir a derecha o izquierda (lo que maximice la distancia recorrida final) y luego ir a la izquierda. |
13 | 12 |
|
14 | | -**Todas las barreras empiezan cerradas**, pero después de 5 unidades de tiempo, se abren todas **para siempre.** |
| 13 | +Los elfos quieren saber cuál es la máxima distancia que recorre el reno al **finalizar todos los movimientos**. |
15 | 14 |
|
16 | | -**Crea una función que simule el movimiento del trineo** durante un tiempo dado y **devuelva un array** de cadenas representando el estado de la carretera en cada unidad de tiempo: |
| 15 | +**En el ejemplo anterior, la máxima distancia que recorre el reno es 2**. Va a la derecha dos veces +2, luego con el \* puede ir a la derecha otra vez para maximizar la distancia +1 y luego va a la izquierda -1. |
| 16 | + |
| 17 | +Crea una función maxDistance que reciba la cadena de texto movements y devuelva **la máxima distancia** que puede recorrer el reno en **cualquier dirección**: |
17 | 18 |
|
18 | 19 | ```js |
19 | | -const road = "S..|...|.."; |
20 | | -const time = 10; // unidades de tiempo |
21 | | -const result = cyberReindeer(road, time); |
22 | | - |
23 | | -/* -> result: |
24 | | -[ |
25 | | -'S..|...|..', // estado inicial |
26 | | -'.S.|...|..', // avanza el trineo la carretera |
27 | | -'..S|...|..', // avanza el trineo la carretera |
28 | | -'..S|...|..', // el trineo para en la barrera |
29 | | -'..S|...|..', // el trineo para en la barrera |
30 | | -'...S..._..', // se abre la barrera, el trineo avanza |
31 | | -'..._S.._..', // avanza el trineo la carretera |
32 | | -'..._.S._..', // avanza el trineo la carretera |
33 | | -'..._..S_..', // avanza el trineo la carretera |
34 | | -'..._...S..', // avanza por la barrera abierta |
35 | | -] |
36 | | -*/ |
37 | | -``` |
| 20 | +const movements = ">>*<"; |
| 21 | +const result = maxDistance(movements); |
| 22 | +console.log(result); // -> 2 |
38 | 23 |
|
39 | | -El resultado es un **array donde cada elemento muestra la carretera en cada unidad de tiempo**. |
| 24 | +const movements2 = "<<<>"; |
| 25 | +const result2 = maxDistance(movements2); |
| 26 | +console.log(result2); // -> 2 |
40 | 27 |
|
41 | | -Ten en cuenta que **si el trineo está en la misma posición que una barrera**, entonces toma su lugar en el array. |
| 28 | +const movements3 = ">***>"; |
| 29 | +const result3 = maxDistance(movements3); |
| 30 | +console.log(result3); // -> 5 |
| 31 | +``` |
42 | 32 |
|
43 | | -Los elfos se **inspiraron en este** [**reto de Code Wars**](https://www.codewars.com/kata/5d0ae91acac0a50232e8a547/javascript). |
| 33 | +Ten en cuenta que no importa si es a la izquierda o la derecha, la distancia es **el valor absoluto de la distancia recorrida máxima al finalizar los movimientos**. |
44 | 34 |
|
45 | 35 | # Solución |
46 | 36 |
|
47 | | -Vamos a basar la solución en un regex que reemplazará `S.` y `S*`, ya que son los únicos movimientos válidos, pero tenemos un problema, y es que si pasamos por un `*`, debemos volver a ponerlo cuando hayamos avanzado nuevamente y esa posición quede atrás. |
48 | | - |
49 | | -Además, no olvidar que en el momento que pasen 5 segundos o iteraciones, debemos convertir todas las `|` a `*`. |
| 37 | +Lo primero que debemos hacer es encontrar la cantidad de movimientos a cada dirección, `>` para derecha y `<` para izquierda, la distancia que en realidad se alejo desde donde inicio, es la resta entre derecha e izquierda, el problema que surge es cuando se movio más veces a la izquierda, ya que nos dará un número negativo, ya que de todas formas el número esta bien, solo debemos quitar el negativo, esto se conoce como _valor absoluto_ y lo logramos con `Math.abs()` |
50 | 38 |
|
51 | | -Lo que haremos para conservar los `*` es revisar si el reno se movió, en ese caso guardaremos la posición a la que se movió y en el siguiente movimiento la reemplazaremos, cosa que solo pasará hasta que el reno se pueda mover, ya que nuestro regex solo se ejecuta en movimientos válidos. |
| 39 | +```js |
| 40 | +Math.abs(-5); // 5 |
| 41 | +``` |
52 | 42 |
|
53 | | -Para guardar la posición y siguiente posición del reno, debemos usar una variable auxiliar, porque la del tiempo no mantiene los mismos valores de la posición del reno, puesto que a veces este no se mueve, esta variable, llamada `a` solo aumentará valor si el reno se movió: |
| 43 | +Encontrar la cantidad de movimientos a cada dirección se puede lograr de muchas formas, una de ellas usando regex para contar la cantidad de `<` `>`: |
54 | 44 |
|
55 | 45 | ```js |
56 | | -const newRoad = road.replace(/S[\.\*]/, `${b}S`); |
57 | | -if (newRoad != road) { |
58 | | - a++; |
59 | | - b = road[a]; |
60 | | -} |
| 46 | +let distance = 0; |
61 | 47 |
|
62 | | -// Se agrega el movimiento a la lista |
| 48 | +let right = movements.match(/>/g)?.length ?? 0; |
| 49 | +let left = movements.match(/</g)?.length ?? 0; |
63 | 50 |
|
64 | | -road = newRoad; |
65 | | -moves.push(road); |
| 51 | +distance += right; |
| 52 | +distance -= left; |
66 | 53 | ``` |
67 | 54 |
|
68 | | -Algunas consideraciones: |
| 55 | +Ahora solo quedan la cantidad de movimientos extra que deben maximizar el resultado, ya que nuestra distancia ya esta en numeros positivos, es como si en los casos en los que recorre más distancia a la izquierda, se hubiese invertido y hubiese recorrido más a la derecha. Es decir, que da igual el caso, siempre debemos sumar la cantidad de `*`. |
| 56 | +
|
| 57 | +Se puede realizar otro regex para encontrar la cantidad de `*`, pero esto no es óptimo, ya que en realidad tenemos ese numero, solo debemos restar de la cantidad total de movimientos los movimientos de izquierda y derecha, ya que si sacamos estos, solo queda la cantidad de movimientos extra: |
69 | 58 |
|
70 | | -- `b` se debe iniciar en `let b = "."` |
71 | | -- `moves` por defecto ya trae el camino original `let moves = [road]` |
72 | | -- Ya que tenemos el camino original en `moves`, solo ejecutaremos el ciclo `time-1` veces `for (let i = 1; i < time; i++)` |
| 59 | +```js |
| 60 | +let extra = movements.length - (right + left); |
| 61 | +``` |
| 62 | +
|
| 63 | +Ahora si debemos usar `Math.abs()` y a este valor absoluto sumarle los movimiento extra: |
| 64 | +
|
| 65 | +```js |
| 66 | +return Math.abs(distance) + extra; |
| 67 | +``` |
0 commit comments