diff --git a/.gitignore b/.gitignore
index 7e6a3b796..53e6c00ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-
+.vscode
 # Created by https://www.toptal.com/developers/gitignore/api/android,androidstudio,kotlin
 # Edit at https://www.toptal.com/developers/gitignore?templates=android,androidstudio,kotlin
 
diff --git a/soluciones-javascript/01-fizzbuzz/app.js b/soluciones-javascript/01-fizzbuzz/app.js
new file mode 100644
index 000000000..98dabb19c
--- /dev/null
+++ b/soluciones-javascript/01-fizzbuzz/app.js
@@ -0,0 +1,29 @@
+/*
+ *#1 EL FAMOSO "FIZZ BUZZ"*
+ ***
+ * Escribe un programa que muestre por consola (con un print) los
+ * números de 1 a 100 (ambos incluidos y con un salto de línea entre
+ * cada impresión), sustituyendo los siguientes:
+ * - Múltiplos de 3 por la palabra "fizz".
+ * - Múltiplos de 5 por la palabra "buzz".
+ * - Múltiplos de 3 y de 5 a la vez por la palabra "fizzbuzz".
+ */
+const fizzBuzz = () => {
+
+    for (let i = 1; i <= 100; i++) {
+    
+        if(i % 3 === 0 && i % 5 === 0){
+            console.log("fizzbuzz");
+        }else if (i % 3 === 0) {
+            console.log("fizz");
+        }else if( i % 5 === 0){
+            console.log("buzz");
+        }else{
+            console.log(i);
+        }
+        
+    }
+
+}
+
+fizzBuzz();
\ No newline at end of file
diff --git a/soluciones-javascript/02-anagrama/app.js b/soluciones-javascript/02-anagrama/app.js
new file mode 100644
index 000000000..5fe643f09
--- /dev/null
+++ b/soluciones-javascript/02-anagrama/app.js
@@ -0,0 +1,40 @@
+/*
+ * Escribe una función que reciba dos palabras (String) y retorne
+ * verdadero o falso (Bool) según sean o no anagramas.
+ * - Un Anagrama consiste en formar una palabra reordenando TODAS
+ *   las letras de otra palabra inicial.
+ * - NO hace falta comprobar que ambas palabras existan.
+ * - Dos palabras exactamente iguales no son anagrama.
+ */
+
+const isAnagram = (string1 = '', string2 = '') => {
+
+    //Si algún String está vacío retorna false
+    if(!string1 || !string2 ) return false; 
+    
+    if(string1.length !== string2.length ) return false; 
+    
+    const stringLowerCase1 = string1.toLowerCase().trim();
+    const stringLowerCase2 = string2.toLowerCase().trim();
+
+    //Si las palabras son exactamente iguales retorna false
+    if(stringLowerCase1 === stringLowerCase2) return false;
+
+    const arrayString1 = stringLowerCase1.split("").sort().join('');
+    const arrayString2 = stringLowerCase2.split("").sort().join('');
+    
+    return arrayString1 === arrayString2; 
+    
+}
+
+
+console.log("Es un anagrama (amor + roma): " + isAnagram("amor", "roma"));
+console.log("Es un anagrama (listen + silent): " + isAnagram("listen", "silent"));
+console.log("Es un anagrama (test + test): " + isAnagram("test", "test"));
+console.log("Es un anagrama ( + word): " + isAnagram("", "word"));
+console.log("Es un anagrama (test + testing): " + isAnagram("test", "testing"));
+console.log("Es un anagrama (Listen + Silent): " + isAnagram("Listen", "Silent"));
+console.log("Es un anagrama (Dormitory + Dirty room): " + isAnagram("Dormitory", "Dirty room"));
+
+
+
diff --git a/soluciones-javascript/03-fibonacci/app.js b/soluciones-javascript/03-fibonacci/app.js
new file mode 100644
index 000000000..6777a9940
--- /dev/null
+++ b/soluciones-javascript/03-fibonacci/app.js
@@ -0,0 +1,33 @@
+/*
+ * * LA SUCESIÓN DE FIBONACCI *
+ * Escribe un programa que imprima los 50 primeros números de la sucesión
+ * de Fibonacci empezando en 0.
+ * - La serie Fibonacci se compone por una sucesión de números en
+ *   la que el siguiente siempre es la suma de los dos anteriores.
+ *   0, 1, 1, 2, 3, 5, 8, 13...
+ */
+
+
+const sucesionFibonacci = ( cantidadNumeros ) => {
+
+    if ( cantidadNumeros < 0 ) return console.log(0);
+    
+    let anterior = 0;
+    let actual = 1;
+
+    for (let i = 0; i < cantidadNumeros; i++) {
+        
+        console.log(`${ i + 1 }_:  ${anterior}`);
+        
+        let temp = anterior; 
+        anterior = actual + anterior; 
+        actual = temp; 
+
+    }
+
+
+}
+
+
+
+sucesionFibonacci( 50 );
diff --git a/soluciones-javascript/04-numero-primo/app.js b/soluciones-javascript/04-numero-primo/app.js
new file mode 100644
index 000000000..0d230afa6
--- /dev/null
+++ b/soluciones-javascript/04-numero-primo/app.js
@@ -0,0 +1,24 @@
+/*
+ * Escribe un programa que se encargue de comprobar si un número es o no primo.
+ * Hecho esto, imprime los números primos entre 1 y 100.
+ */
+
+const esNumeroPrimo = (numero) => {
+    if (numero <= 1) return false;
+
+    if (numero === 2) return true;
+
+    for (let i = 2; i <= Math.sqrt(numero); i++) {
+        if (numero % i === 0) {
+            return false;
+        }
+    }
+
+    return true;
+};
+
+for (let i = 2; i < 100; i++) {
+    if (esNumeroPrimo(i)) {
+        console.log(i);
+    }
+}
diff --git a/soluciones-javascript/05-area-poligono/app.js b/soluciones-javascript/05-area-poligono/app.js
new file mode 100644
index 000000000..0fdb4d323
--- /dev/null
+++ b/soluciones-javascript/05-area-poligono/app.js
@@ -0,0 +1,41 @@
+/*
+ * Crea una única función (importante que sólo sea una) que sea capaz
+ * de calcular y retornar el área de un polígono.
+ * - La función recibirá por parámetro sólo UN polígono a la vez.
+ * - Los polígonos soportados serán Triángulo, Cuadrado y Rectángulo.
+ * - Imprime el cálculo del área de un polígono de cada tipo.
+ */
+
+const areaPoligono = ({ tipo = "", datosPoligono = {} }) => {
+
+    const esPositivo = (n) => typeof n === 'number' && n > 0; 
+
+    switch (tipo) {
+        case "Triangulo":
+            if ( esPositivo(datosPoligono.base) && esPositivo(datosPoligono.altura) ) {
+                return (datosPoligono.base * datosPoligono.altura) / 2;
+            }else{
+                throw new Error("Los datos del triangulo deben ser positivos");
+            }
+        case "Cuadrado":
+            if ( esPositivo(datosPoligono.lado) ) {
+                return datosPoligono.lado * datosPoligono.lado;
+            }else{
+                throw new Error("Los datos del Cuadrado deben ser positivos");
+            }    
+        case "Rectangulo": 
+            if ( esPositivo(datosPoligono.base) && esPositivo(datosPoligono.altura) ) {
+                return datosPoligono.base * datosPoligono.altura; 
+            }else{
+                throw new Error("Los datos del Rectangulo deben ser positivos");
+            }
+        default:
+            throw new Error("Especifica un dato correcto");
+    }
+
+}
+
+// Ejemplos de uso
+console.log(areaPoligono({ tipo: "Triangulo", datosPoligono: { base: 2, altura: 4 } }));
+console.log(areaPoligono({ tipo: "Cuadrado", datosPoligono: { lado: 5 } }));
+console.log(areaPoligono({ tipo: "Rectangulo", datosPoligono: { base: 3, altura: 6 } }));
\ No newline at end of file
diff --git a/soluciones-javascript/06-aspect-ratio-image/app.js b/soluciones-javascript/06-aspect-ratio-image/app.js
new file mode 100644
index 000000000..fce15cbc0
--- /dev/null
+++ b/soluciones-javascript/06-aspect-ratio-image/app.js
@@ -0,0 +1,43 @@
+/*
+ * Crea un programa que se encargue de calcular el aspect ratio de una
+ * imagen a partir de una url.
+ * - Url de ejemplo:
+ *   https://es.vitejs.dev/og-image-announcing-vite3.png
+ * - Por ratio hacemos referencia por ejemplo a los "16:9" de una
+ *   imagen de 1920*1080px.
+ */
+
+
+const calcularAspectRatio = async (url) => {
+
+    const img = new Image();
+
+    img.src = url;
+    
+    img.onload = () => {
+        const width = img.width;
+        const height = img.height;
+        
+        // Maximo comun divisor
+        const mcd = ( a, b ) => b === 0 ? a : mcd( b, a % b );
+        
+        console.log(mcd(width, height));
+        
+        const ratioMCD = mcd(width, height); 
+        
+        console.log(`La resolución de la imagen es ${width}x${height}`);
+        console.log(`La relación de aspecto es: ${ width / ratioMCD }:${ height / ratioMCD }`);
+        
+        
+    }
+    
+    img.onerror = () => {
+        console.error('No se pudo cargar la imagen');
+    }
+    
+    return img;
+
+}
+
+const url = "https://cdn.unotv.com/images/2024/03/mazapan-perrito-influencer-143900-1024x576.jpeg"
+calcularAspectRatio(url);
\ No newline at end of file
diff --git a/soluciones-javascript/06-aspect-ratio-image/index.html b/soluciones-javascript/06-aspect-ratio-image/index.html
new file mode 100644
index 000000000..916bfeafc
--- /dev/null
+++ b/soluciones-javascript/06-aspect-ratio-image/index.html
@@ -0,0 +1,11 @@
+
+
+
+    
+    
+    Ejercicio de programación
+
+
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/07-inviertiendo-cadenas/app.js b/soluciones-javascript/07-inviertiendo-cadenas/app.js
new file mode 100644
index 000000000..8ece70480
--- /dev/null
+++ b/soluciones-javascript/07-inviertiendo-cadenas/app.js
@@ -0,0 +1,22 @@
+/*
+ * Crea un programa que invierta el orden de una cadena de texto
+ * sin usar funciones propias del lenguaje que lo hagan de forma automática.
+ * - Si le pasamos "Hola mundo" nos retornaría "odnum aloH"
+ */
+
+const reverseTextString = (string) => {
+
+    const stringFormatter = string.trim();
+    let reverseText = "";
+
+    for (let i = 1; i <= stringFormatter.length; i++) {
+        
+        reverseText += stringFormatter[ stringFormatter.length - i];
+
+    }
+    
+    return reverseText;
+    
+}
+
+console.log(reverseTextString(" Hola Mundo "));
\ No newline at end of file
diff --git a/soluciones-javascript/07-inviertiendo-cadenas/index.html b/soluciones-javascript/07-inviertiendo-cadenas/index.html
new file mode 100644
index 000000000..5a798babe
--- /dev/null
+++ b/soluciones-javascript/07-inviertiendo-cadenas/index.html
@@ -0,0 +1,11 @@
+
+
+
+    
+    
+    Invirtiendo cadenas
+
+
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/08-contando-palabras/app.js b/soluciones-javascript/08-contando-palabras/app.js
new file mode 100644
index 000000000..1bfbb36d1
--- /dev/null
+++ b/soluciones-javascript/08-contando-palabras/app.js
@@ -0,0 +1,25 @@
+/*
+ * Crea un programa que cuente cuantas veces se repite cada palabra
+ * y que muestre el recuento final de todas ellas.
+ * - Los signos de puntuación no forman parte de la palabra.
+ * - Una palabra es la misma aunque aparezca en mayúsculas y minúsculas.
+ * - No se pueden utilizar funciones propias del lenguaje que
+ *   lo resuelvan automáticamente.
+ */
+
+const countWords = (text) => {
+    const cleanedText = text.toLowerCase().replace(/[^\w\s]/g, '');
+
+    const wordsArray = cleanedText.split(/\s+/).filter( word => word !== '');
+
+    const wordCount = {};
+    console.log({cleanedText}, {wordsArray});
+
+    wordsArray.forEach(word => {
+        wordCount[word] = (wordCount[word] || 0) + 1;
+    });
+
+    console.log( { wordsArray, wordCount } );
+};
+
+countWords(" Hola, asd  una páasdlabra d asd asd repetida,, hotra a a dsad sad palabraasd  repetida paasdq3wrlabra o hola ");
diff --git a/soluciones-javascript/08-contando-palabras/index.html b/soluciones-javascript/08-contando-palabras/index.html
new file mode 100644
index 000000000..7e9e5a84d
--- /dev/null
+++ b/soluciones-javascript/08-contando-palabras/index.html
@@ -0,0 +1,12 @@
+
+
+
+    
+    
+    Contando Palabras
+
+
+    Abre la consola y mira el resultado
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/09-decimal-binario/app.js b/soluciones-javascript/09-decimal-binario/app.js
new file mode 100644
index 000000000..1d0d3c7a4
--- /dev/null
+++ b/soluciones-javascript/09-decimal-binario/app.js
@@ -0,0 +1,20 @@
+/*
+ * Crea un programa se encargue de transformar un número
+ * decimal a binario sin utilizar funciones propias del lenguaje que lo hagan directamente.
+ */
+
+const decimalToBinary = (number) => {
+    let numberBinary = [];
+    let numberNew = number; 
+
+    while (numberNew > 0) {
+        numberBinary.unshift(Math.floor(numberNew % 2));
+        numberNew = Math.floor(numberNew / 2);
+    }
+
+    return numberBinary.join("");
+    
+
+};
+
+console.log(decimalToBinary(10));
diff --git a/soluciones-javascript/09-decimal-binario/index.html b/soluciones-javascript/09-decimal-binario/index.html
new file mode 100644
index 000000000..6e7aece82
--- /dev/null
+++ b/soluciones-javascript/09-decimal-binario/index.html
@@ -0,0 +1,12 @@
+
+
+
+    
+    
+    09 Decimal a Binario
+
+
+    Abre la consola para ver el ejercicio
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/10-codigo-morse/app.js b/soluciones-javascript/10-codigo-morse/app.js
new file mode 100644
index 000000000..55fc38d31
--- /dev/null
+++ b/soluciones-javascript/10-codigo-morse/app.js
@@ -0,0 +1,32 @@
+/*
+ * Crea un programa que sea capaz de transformar texto natural a código
+ * morse y viceversa.
+ * - Debe detectar automáticamente de qué tipo se trata y realizar
+ *   la conversión.
+ * - En morse se soporta raya "—", punto ".", un espacio " " entre letras
+ *   o símbolos y dos espacios entre palabras "  ".
+ * - El alfabeto morse soportado será el mostrado en
+ *   https://es.wikipedia.org/wiki/Código_morse.
+ */
+
+console.log({dataMorseCode});
+
+const codigoMorse = (text) => {
+
+    return text.toUpperCase().split('').map( word => {
+        
+        if(dataMorseCode[word]){
+            return dataMorseCode[word]
+        } else if (word === " "){
+            return "/";
+        }else {
+            return "";
+        }
+
+    }).join(" ");
+
+}
+
+console.log(codigoMorse("Prueba x"));
+console.log(codigoMorse("Otra prueba con diferasduhwq signficado, ayuda ´++´{}"));
+console.log(codigoMorse("Me gusta la cigueña, la malta y la inmal también jaja esxs xsxsada"));
\ No newline at end of file
diff --git a/soluciones-javascript/10-codigo-morse/dataMorseCode.js b/soluciones-javascript/10-codigo-morse/dataMorseCode.js
new file mode 100644
index 000000000..63ed31223
--- /dev/null
+++ b/soluciones-javascript/10-codigo-morse/dataMorseCode.js
@@ -0,0 +1,11 @@
+const dataMorseCode = {    
+    A: ".-",     B: "-...",  C: "-.-.",  D: "-..",  
+    E: ".",      F: "..-.",  G: "--.",   H: "....", 
+    I: "..",     J: ".---",  K: "-.-",   L: ".-..", 
+    M: "--",     N: "-.",    Ñ: "--.--", O: "---",  
+    P: ".--.",   Q: "--.-",  R: ".-.",   S: "...",  
+    T: "-",      U: "..-",   V: "...-",  W: ".--",  
+    X: "-..-",   Y: "-.--",  Z: "--..", 
+    '0': '-----', '1': '.----', '2': '..---', '3': '...--', '4': '....-', 
+    '5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.'
+};
diff --git a/soluciones-javascript/10-codigo-morse/index.html b/soluciones-javascript/10-codigo-morse/index.html
new file mode 100644
index 000000000..a0726581e
--- /dev/null
+++ b/soluciones-javascript/10-codigo-morse/index.html
@@ -0,0 +1,13 @@
+
+
+
+    
+    
+    Codigo morse
+
+
+    Abre la consola y mira el resultado
+    
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/11-expresiones-equilibradas/app.js b/soluciones-javascript/11-expresiones-equilibradas/app.js
new file mode 100644
index 000000000..95aa88163
--- /dev/null
+++ b/soluciones-javascript/11-expresiones-equilibradas/app.js
@@ -0,0 +1,48 @@
+/*
+ * Crea un programa que comprueba si los paréntesis, llaves y corchetes
+ * de una expresión están equilibrados.
+ * - Equilibrado significa que estos delimitadores se abren y cieran
+ *   en orden y de forma correcta.
+ * - Paréntesis, llaves y corchetes son igual de prioritarios.
+ *   No hay uno más importante que otro.
+ * - Expresión balanceada: { [ a * ( c + d ) ] - 5 }
+ * - Expresión no balanceada: { a * ( c + d ) ] - 5 }
+ */
+
+/**
+ *
+ * @param {String} expression
+ */
+const isBalanced = (expression) => {
+    const expressionWithoutSpace = expression.replace(/\s+/g, "");
+
+    let stackExpr = [];
+
+    for (let i = 0; i < expressionWithoutSpace.length; i++) {
+        const char = expressionWithoutSpace[i];
+
+        if (char === "{" || char === "[" || char === "(") {
+            stackExpr.push(char);
+        } else if (char === "}" || char === "]" || char === ")") {
+            if (stackExpr.length === 0) {
+                return false;
+            }
+
+            const last = stackExpr.pop();
+
+            if (
+                (char === "}" && last !== "{") ||
+                (char === "]" && last !== "[") ||
+                (char === ")" && last !== "(")
+            ) {
+                return false;
+            }
+        }
+    }
+
+    return stackExpr.length === 0;
+};
+
+console.log(isBalanced("{ [ a * ( c + d ) ] - 5 }"));
+console.log(isBalanced("{ a * ( c + d ) ] - 5 }"));
+console.log(isBalanced("{ [ ((a - b) + (-4 * a)) * ( c + d ) ] - 5 }"));
diff --git a/soluciones-javascript/11-expresiones-equilibradas/index.html b/soluciones-javascript/11-expresiones-equilibradas/index.html
new file mode 100644
index 000000000..e1ec91e64
--- /dev/null
+++ b/soluciones-javascript/11-expresiones-equilibradas/index.html
@@ -0,0 +1,12 @@
+
+
+
+    
+    
+    Expresiones Equilibradas
+
+
+    Abre la consola y mira el resultado
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/12-eliminando-caracteres/app.js b/soluciones-javascript/12-eliminando-caracteres/app.js
new file mode 100644
index 000000000..c30537792
--- /dev/null
+++ b/soluciones-javascript/12-eliminando-caracteres/app.js
@@ -0,0 +1,34 @@
+/*
+ * Crea una función que reciba dos cadenas como parámetro (str1, str2)
+ * e imprima otras dos cadenas como salida (out1, out2).
+ * - out1 contendrá todos los caracteres presentes en la str1 pero NO
+ *   estén presentes en str2.
+ * - out2 contendrá todos los caracteres presentes en la str2 pero NO
+ *   estén presentes en str1.
+ */
+
+/**
+ * Función que recibe dos cadenas de texto como entrada y genera dos nuevas cadenas como salida
+ * - La primera cadena de salida (`out1`) contiene los caracteres presentes en `str1` pero no en `str2`.
+ * - La segunda cadena de salida (`out2`) contiene los caracteres presentes en `str2` pero no en `str1`.
+ * @param {String} str1 Cadena de texto 1
+ * @param {String} str2 Cadena de texto 2
+ * @returns {{ out1: string, out2: string }} Un objeto con dos propiedades:
+ *   - `out1`: Cadena con los caracteres exclusivos de `str1`.
+ *   - `out2`: Cadena con los caracteres exclusivos de `str2`.
+ */
+const eliminandoCaracteres = ( str1, str2 ) => {
+
+    if( str1.trim() === str2.trim() ) return `Cadenas de texto iguales: Cadena 1: ${str1} Cadena 2: ${str2}`;
+
+    const str1Unique = [...new Set(str1)];
+    const str2Unique = [...new Set(str2)];
+
+    const out1 = str1Unique.filter( char  => !str2Unique.includes(char)).join('');
+    const out2 = str2Unique.filter( char  => !str1Unique.includes(char)).join('');
+    
+    return { out1, out2 }
+
+}
+
+console.log(eliminandoCaracteres('cadena similar', 'cadena diferente'));
diff --git a/soluciones-javascript/12-eliminando-caracteres/index.html b/soluciones-javascript/12-eliminando-caracteres/index.html
new file mode 100644
index 000000000..e2b120f24
--- /dev/null
+++ b/soluciones-javascript/12-eliminando-caracteres/index.html
@@ -0,0 +1,12 @@
+
+
+
+    
+    
+    Eliminando caracteres
+
+
+    Abre la consola y observa la magia
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/13-palindromo/app.js b/soluciones-javascript/13-palindromo/app.js
new file mode 100644
index 000000000..63e4b1566
--- /dev/null
+++ b/soluciones-javascript/13-palindromo/app.js
@@ -0,0 +1,32 @@
+/*
+ * #13 ¿Es un Palindromo?
+ * Escribe una función que reciba un texto y retorne verdadero o
+ * falso (Boolean) según sean o no palíndromos.
+ * Un Palíndromo es una palabra o expresión que es igual si se lee
+ * de izquierda a derecha que de derecha a izquierda.
+ * NO se tienen en cuenta los espacios, signos de puntuación y tildes.
+ * Ejemplo: Ana lleva al oso la avellana.
+ */
+
+/**
+ * Función para verificar si una cadena de texto es palindromo o no
+ * @param {String} texto 
+ */
+const esPalindromo = ( texto ) => {
+
+    const textoFormateado = texto
+        .replace(/\s+/g, "")
+        .split('')
+        .map( (char, index, array) => array[ index === 0 ? array.length - 1 : array.length - (index + 1)] )
+        .join('')
+        .toLowerCase();
+
+    return textoFormateado === texto.replace(/\s+/g, "").toLocaleLowerCase();
+
+
+}
+
+console.log(esPalindromo('Ana lleva al oso la avellana'));
+console.log(esPalindromo('Sé verlas al revés'));
+console.log(esPalindromo('Somos o no somos'));
+console.log(esPalindromo('Ana lava lana'));
\ No newline at end of file
diff --git a/soluciones-javascript/13-palindromo/index.html b/soluciones-javascript/13-palindromo/index.html
new file mode 100644
index 000000000..0a2f567a0
--- /dev/null
+++ b/soluciones-javascript/13-palindromo/index.html
@@ -0,0 +1,12 @@
+
+
+
+    
+    
+    Palindromo
+
+
+    Abre La Consola y mira el resultado
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/14-factorial-recursivo/app.js b/soluciones-javascript/14-factorial-recursivo/app.js
new file mode 100644
index 000000000..92034e851
--- /dev/null
+++ b/soluciones-javascript/14-factorial-recursivo/app.js
@@ -0,0 +1,15 @@
+/*
+ * Escribe una función que calcule y retorne el factorial de un número dado
+ * de forma recursiva.
+ */
+
+const factorial = (n) => {
+    
+    if ( n <= 0 ) return 1; 
+
+    return  n * factorial( n - 1 );
+
+}
+
+console.log(factorial(3));
+console.log(factorial(10));
\ No newline at end of file
diff --git a/soluciones-javascript/14-factorial-recursivo/index.html b/soluciones-javascript/14-factorial-recursivo/index.html
new file mode 100644
index 000000000..e529b155e
--- /dev/null
+++ b/soluciones-javascript/14-factorial-recursivo/index.html
@@ -0,0 +1,12 @@
+
+
+
+    
+    
+    Factorial recursivo
+
+
+    Abre la consola y visualiza el resultado
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/15-numero-de-armstrong/app.js b/soluciones-javascript/15-numero-de-armstrong/app.js
new file mode 100644
index 000000000..3f5c54899
--- /dev/null
+++ b/soluciones-javascript/15-numero-de-armstrong/app.js
@@ -0,0 +1,28 @@
+/*
+ * Escribe una función que calcule si un número dado es un número de Armstrong
+ * (o también llamado narcisista).
+ * Si no conoces qué es un número de Armstrong, debes buscar información
+ * al respecto.
+ */
+
+/**
+ * Función para calcular si un número es un número de Armstrong o no.
+ * @param {Number} n : number
+ */
+const esNumeroArmstrong = (n) => {
+    if (n < 0) return false;
+
+    const formattedNumber = n.toString().split("").map(Number);
+    const sumNumber = formattedNumber.reduce(
+        (prev, current) => prev + Math.pow(current, formattedNumber.length),
+        0
+    );
+
+    return sumNumber === n;
+};
+
+console.log(esNumeroArmstrong(153)); // true
+console.log(esNumeroArmstrong(9474)); // true
+console.log(esNumeroArmstrong(9475)); // false
+console.log(esNumeroArmstrong(370)); // true
+
diff --git a/soluciones-javascript/15-numero-de-armstrong/index.html b/soluciones-javascript/15-numero-de-armstrong/index.html
new file mode 100644
index 000000000..b6c9a859a
--- /dev/null
+++ b/soluciones-javascript/15-numero-de-armstrong/index.html
@@ -0,0 +1,12 @@
+
+
+
+    
+    
+    Ejercicio 15
+
+
+    Ejercicio 15 - Abre la consola
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/16-cuantos-dias/app.js b/soluciones-javascript/16-cuantos-dias/app.js
new file mode 100644
index 000000000..b9f1ece3b
--- /dev/null
+++ b/soluciones-javascript/16-cuantos-dias/app.js
@@ -0,0 +1,37 @@
+/*
+ * Crea una función que calcule y retorne cuántos días hay entre dos cadenas
+ * de texto que representen fechas.
+ * - Una cadena de texto que representa una fecha tiene el formato "dd/MM/yyyy".
+ * - La función recibirá dos String y retornará un Int.
+ * - La diferencia en días será absoluta (no importa el orden de las fechas).
+ * - Si una de las dos cadenas de texto no representa una fecha correcta se
+ *   lanzará una excepción.
+ */
+
+/**
+ *
+ * @param {String} fecha1 : 'dd/mm/yyyy'
+ * @param {String} fecha2 : 'dd/mm/yyyy'
+ */
+const cuantosDias = (fecha1, fecha2) => {
+    const regexFecha = /^\d{2}\/\d{2}\/\d{4}$/;
+    if (!regexFecha.test(fecha1) || !regexFecha.test(fecha2))
+        throw new Error("El formato de fechas es erróneo");
+
+    const fechaFormatted1 = new Date(fecha1).getTime();
+    const fechaFormatted2 = new Date(fecha2).getTime();
+
+    const diferenciaDeDias =
+        fechaFormatted1 > fechaFormatted2
+            ? fechaFormatted1 - fechaFormatted2
+            : fechaFormatted2 - fechaFormatted1;
+    const diferenciaDeDiasFormateado = diferenciaDeDias / (1000 * 60 * 60 * 24);
+
+    return diferenciaDeDiasFormateado;
+};
+
+console.log(cuantosDias("04/16/2006", "12/05/2006")); // Esperado: 233
+console.log(cuantosDias("12/05/2006", "04/16/2006")); // Esperado: 233
+console.log(cuantosDias("01/01/2023", "12/31/2023")); // Esperado: 364
+console.log(cuantosDias("01/01/2024", "01/01/2024")); // Esperado: 0
+console.log(cuantosDias("12/05/2006", "04162006"));
diff --git a/soluciones-javascript/16-cuantos-dias/index.html b/soluciones-javascript/16-cuantos-dias/index.html
new file mode 100644
index 000000000..045010469
--- /dev/null
+++ b/soluciones-javascript/16-cuantos-dias/index.html
@@ -0,0 +1,12 @@
+
+
+
+    
+    
+    Cuantos días
+
+
+    Ejercicio 16 - Abre la consola y visualiza el resultado
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/17-en-mayuscula/app.js b/soluciones-javascript/17-en-mayuscula/app.js
new file mode 100644
index 000000000..d21572a66
--- /dev/null
+++ b/soluciones-javascript/17-en-mayuscula/app.js
@@ -0,0 +1,22 @@
+/*
+ * Crea una función que reciba un String de cualquier tipo y se encargue de
+ * poner en mayúscula la primera letra de cada palabra.
+ * - No se pueden utilizar operaciones del lenguaje que
+ *   lo resuelvan directamente.
+ */
+
+/**
+ * 
+ * @param {String} string 
+ * @returns 
+ */
+const inUpperCase = (string) => {
+    return string.split(' ').map(word => {
+        const firstLetterCap = word.charAt(0).toUpperCase();
+        const remainingLetters = word.slice(1);
+        return firstLetterCap + remainingLetters;
+    }).join(' ').trim();
+}
+
+console.log(inUpperCase('debi tirar mas algo'));
+console.log(inUpperCase("  hola   mundo! esto es una prueba   "));
diff --git a/soluciones-javascript/17-en-mayuscula/index.html b/soluciones-javascript/17-en-mayuscula/index.html
new file mode 100644
index 000000000..339870fcf
--- /dev/null
+++ b/soluciones-javascript/17-en-mayuscula/index.html
@@ -0,0 +1,11 @@
+
+
+
+    
+    
+    En Mayuscula
+
+
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/18-carrera-de-obstaculos/app.js b/soluciones-javascript/18-carrera-de-obstaculos/app.js
new file mode 100644
index 000000000..44b9fc5b4
--- /dev/null
+++ b/soluciones-javascript/18-carrera-de-obstaculos/app.js
@@ -0,0 +1,61 @@
+/*
+ * Crea una función que evalúe si un/a atleta ha superado correctamente una
+ * carrera de obstáculos.
+ * - La función recibirá dos parámetros:
+ *      - Un array que sólo puede contener String con las palabras
+ *        "run" o "jump"
+ *      - Un String que represente la pista y sólo puede contener "_" (suelo)
+ *        o "|" (valla)
+ * - La función imprimirá cómo ha finalizado la carrera:
+ *      - Si el/a atleta hace "run" en "_" (suelo) y "jump" en "|" (valla)
+ *        será correcto y no variará el símbolo de esa parte de la pista.
+ *      - Si hace "jump" en "_" (suelo), se variará la pista por "x".
+ *      - Si hace "run" en "|" (valla), se variará la pista por "/".
+ * - La función retornará un Boolean que indique si ha superado la carrera.
+ * Para ello tiene que realizar la opción correcta en cada tramo de la pista.
+ */
+
+/**
+ * Función para determinar si un atleta ha superado correctamente un carrera de obstaculos
+ * @param {Array} acciones Array de palabras run | jump
+ * @param {String} pista String que contiene la pista
+ */
+const carreraObstaculos = ( acciones, pista ) => {
+    
+    if ( acciones.length !== pista.length ) 
+        throw new Error("Las longitudes no coinciden");
+
+    if( !Array.isArray(acciones) || typeof pista !== 'string') 
+        throw new Error("Parámetros inválidos: Se espera un array y un string");
+        
+    let resultado = true;
+    let nuevaPista = '';
+
+    acciones.forEach(( accion, index) => {
+
+        const tramo = pista[index];
+
+        if( tramo === '_' && accion === 'run' ){
+            nuevaPista += tramo;
+        } else if ( tramo === '|' && accion === 'jump' ){
+            nuevaPista += tramo;
+        }else if( tramo === '_' && accion === 'jump' ){
+            nuevaPista += 'x';
+            resultado = false;
+        } else if ( pista[index] === '|' && accion === 'run' ){
+            nuevaPista += '/';
+            resultado = false; 
+        } else {
+            throw new Error("Tramo no identificado");
+        }
+    });
+
+    console.log(nuevaPista);
+    
+    return resultado; 
+
+}
+
+const arrayDeAcciones = ['run', 'run', 'run', 'jump', 'run', 'jump', 'jump', 'jump', 'run', 'run', 'jump', 'run',];
+
+carreraObstaculos( arrayDeAcciones, '___|_|||__|_');
\ No newline at end of file
diff --git a/soluciones-javascript/18-carrera-de-obstaculos/index.html b/soluciones-javascript/18-carrera-de-obstaculos/index.html
new file mode 100644
index 000000000..b113331e2
--- /dev/null
+++ b/soluciones-javascript/18-carrera-de-obstaculos/index.html
@@ -0,0 +1,12 @@
+
+
+
+    
+    
+    Carrera de ]Obstaculos
+
+
+    ABRE LA CONSOLA
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/19-tres-en-raya/app.js b/soluciones-javascript/19-tres-en-raya/app.js
new file mode 100644
index 000000000..5d82f7914
--- /dev/null
+++ b/soluciones-javascript/19-tres-en-raya/app.js
@@ -0,0 +1,97 @@
+/*
+ * Crea una función que analice una matriz 3x3 compuesta por "X" y "O"
+ * y retorne lo siguiente:
+ * - "X" si han ganado las "X"
+ * - "O" si han ganado los "O"
+ * - "Empate" si ha habido un empate
+ * - "Nulo" si la proporción de "X", de "O", o de la matriz no es correcta.
+ *   O si han ganado los 2.
+ * Nota: La matriz puede no estar totalmente cubierta.
+ * Se podría representar con un vacío "", por ejemplo.
+ */
+
+/**
+ * Función de Tres En Raya
+ * @param {Array} matriz del juego por el usuario
+ */
+const tresEnRaya = (matriz) => {
+
+    if ((matriz[0].length !== 3) || (matriz[1].length !== 3) || (matriz[2].length !== 3)) 
+        return "Nulo";
+
+    const arrayDeResultado = [ ...matriz[0], ...matriz[1], ...matriz[2] ];
+
+    const combinacionesGanadoras = [
+        [0, 1, 2],
+        [3, 4, 5],
+        [6, 7, 8],
+        [0, 3, 6],
+        [1, 4, 7],
+        [2, 5, 8],
+        [0, 4, 8],
+        [2, 4, 6],
+    ];
+
+    const resultado = [];
+
+    combinacionesGanadoras.forEach((combinacion) => {
+        const [ a, b, c ] = combinacion;
+
+        if( 
+            arrayDeResultado[a] !== " " &&
+            arrayDeResultado[a] === arrayDeResultado[b] &&
+            arrayDeResultado[a] === arrayDeResultado[c]
+        ){
+            resultado.push(arrayDeResultado[a]);
+        }
+
+    });
+
+    if ( resultado.includes('x') && resultado.includes('o')){
+        return 'Nulo';
+    }
+
+    if (resultado.length === 0) {
+        return 'Empate';
+    }
+
+    if(resultado.length > 0){
+        return resultado[0].toUpperCase();
+    }
+
+    return 'Nulo';
+
+};
+
+console.log(
+    "Gana O: " +
+    tresEnRaya([
+        ["x", "x", "o"],
+        ["x", "o", " "],
+        ["o", " ", " "],
+    ])
+);
+console.log(
+    "Gana x: " +
+    tresEnRaya([
+        ["x", "x", "x"],
+        ["x", "o", "o"],
+        ["o", "o", "x"],
+    ])
+);
+
+console.log(
+    tresEnRaya([
+        ["o", "o", "x"],
+        ["x", "x", "o"],
+        ["o", "o", "x"],
+    ])
+);
+
+console.log(
+    tresEnRaya([
+        ["o", "o", "o"],
+        ["x", "x", "x"],
+        [" ", " ", ""],
+    ])
+);
\ No newline at end of file
diff --git a/soluciones-javascript/19-tres-en-raya/index.html b/soluciones-javascript/19-tres-en-raya/index.html
new file mode 100644
index 000000000..b2229bbb8
--- /dev/null
+++ b/soluciones-javascript/19-tres-en-raya/index.html
@@ -0,0 +1,12 @@
+
+
+
+    
+    
+    Tres en raya
+
+
+    Abre la consola y Visualiza el Resultado
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/20-conversor-tiempo/app.js b/soluciones-javascript/20-conversor-tiempo/app.js
new file mode 100644
index 000000000..e23785be9
--- /dev/null
+++ b/soluciones-javascript/20-conversor-tiempo/app.js
@@ -0,0 +1,24 @@
+/*
+ * Crea una función que reciba días, horas, minutos y segundos (como enteros)
+ * y retorne su resultado en milisegundos.
+ */
+
+const conversorTiempo = (dias, horas, minutos, segundos) => {
+
+    if ( 
+        typeof dias !== "number" || dias < 0 ||
+        typeof horas !== "number" || dias < 0 ||
+        typeof minutos !== "number" || dias < 0||
+        typeof segundos !== "number" || dias < 0
+    )
+        throw new Error("Los datos deben ser númericos y mayor o igual a cero");
+
+    const diasASegundos = (((dias * 24) * 60) * 60);
+    const horasASegundos = ((horas * 60) * 60);
+    const minutosASegundos = ((minutos * 60));
+
+    return ( (diasASegundos + horasASegundos + minutosASegundos) * 1000 );
+
+}
+
+console.log(conversorTiempo(1,1,1,1));
\ No newline at end of file
diff --git a/soluciones-javascript/20-conversor-tiempo/index.html b/soluciones-javascript/20-conversor-tiempo/index.html
new file mode 100644
index 000000000..a7195497f
--- /dev/null
+++ b/soluciones-javascript/20-conversor-tiempo/index.html
@@ -0,0 +1,12 @@
+
+
+
+    
+    
+    Conversor de Tiempo
+
+
+    Abre la consola y mira
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/21-parando-el-tiempo/app.js b/soluciones-javascript/21-parando-el-tiempo/app.js
new file mode 100644
index 000000000..03449e264
--- /dev/null
+++ b/soluciones-javascript/21-parando-el-tiempo/app.js
@@ -0,0 +1,33 @@
+/*
+ * Crea una función que sume 2 números y retorne su resultado pasados
+ * unos segundos.
+ * - Recibirá por parámetros los 2 números a sumar y los segundos que
+ *   debe tardar en finalizar su ejecución.
+ * - Si el lenguaje lo soporta, deberá retornar el resultado de forma
+ *   asíncrona, es decir, sin detener la ejecución del programa principal.
+ *   Se podría ejecutar varias veces al mismo tiempo.
+ */
+
+/**
+ * Función que suma dos números y que los devuelve en cierto intervalo de tiempo
+ * @param {Number} num1 Numero 1 que recibe la función
+ * @param {Number} num2 Numero 2 que recibe la función
+ * @param {Number} segundosFinalizar Numero de tiempo en segundos
+ * @returns Resultado De numeros
+ */
+const parandoElTiempo = async (num1, num2, segundosFinalizar) => {
+    const suma = new Promise((resolve) => {
+        setTimeout(() => {
+            return resolve(num1 + num2); 
+        }, segundosFinalizar * 1000);
+    });
+    return await suma;
+}
+
+parandoElTiempo(2, 3, 3).then((resultado) =>
+    console.log(`Resultado de 2 + 3 después de 3 segundos: ${resultado}`)
+);
+
+parandoElTiempo(5, 7, 2).then((resultado) =>
+    console.log(`Resultado de 5 + 7 después de 2 segundos: ${resultado}`)
+);
\ No newline at end of file
diff --git a/soluciones-javascript/21-parando-el-tiempo/index.html b/soluciones-javascript/21-parando-el-tiempo/index.html
new file mode 100644
index 000000000..d659e7ea7
--- /dev/null
+++ b/soluciones-javascript/21-parando-el-tiempo/index.html
@@ -0,0 +1,12 @@
+
+
+
+    
+    
+    Parando el Tiempo
+
+
+    Abre la consola y mira
+    
+
+
\ No newline at end of file
diff --git a/soluciones-javascript/22-calculadora-txt/Challenge21.txt b/soluciones-javascript/22-calculadora-txt/Challenge21.txt
new file mode 100644
index 000000000..d5b2bd7c1
--- /dev/null
+++ b/soluciones-javascript/22-calculadora-txt/Challenge21.txt
@@ -0,0 +1,13 @@
+5
++
+2
+-
+1
+*
+8
+-
+15
++
+4
+/
+2
\ No newline at end of file
diff --git a/soluciones-javascript/22-calculadora-txt/index.js b/soluciones-javascript/22-calculadora-txt/index.js
new file mode 100644
index 000000000..de11ee0eb
--- /dev/null
+++ b/soluciones-javascript/22-calculadora-txt/index.js
@@ -0,0 +1,55 @@
+/*
+ * Lee el fichero "Challenge21.txt" incluido en el proyecto, calcula su
+ * resultado e imprímelo.
+ * - El .txt se corresponde con las entradas de una calculadora.
+ * - Cada línea tendrá un número o una operación representada por un
+ *   símbolo (alternando ambos).
+ * - Soporta números enteros y decimales.
+ * - Soporta las operaciones suma "+", resta "-", multiplicación "*"
+ *   y división "/".
+ * - El resultado se muestra al finalizar la lectura de la última
+ *   línea (si el .txt es correcto).
+ * - Si el formato del .txt no es correcto, se indicará que no se han
+ *   podido resolver las operaciones.
+ */
+
+const fs = require("fs");
+
+try {
+    const data = fs.readFileSync("./Challenge21.txt", "utf-8");
+    const lines = data.split("\r\n").filter((line) => line.trim() !== "");
+
+    console.log({ lines });
+
+    let resultado = Number(lines[0]);
+
+    for (let i = 1; i < lines.length; i += 2) {
+        let operacion = lines[i];
+        let numero = Number(lines[i + 1]);
+
+        if (isNaN(numero)) {
+            return "Error al Leer el dato";
+        }
+
+        switch (operacion) {
+            case "+":
+                resultado += numero;
+                break;
+            case "-":
+                resultado -= numero;
+                break;
+            case "*":
+                resultado *= numero;
+                break;
+            case "/":
+                resultado /= numero;
+                break;
+            default:
+                return resultado;
+        }
+    }
+
+    console.log({ resultado });
+} catch (err) {
+    console.error("Error al leer el archivo:", err);
+}
diff --git a/soluciones-javascript/23-conjuntos/index.js b/soluciones-javascript/23-conjuntos/index.js
new file mode 100644
index 000000000..91dfcb668
--- /dev/null
+++ b/soluciones-javascript/23-conjuntos/index.js
@@ -0,0 +1,50 @@
+/*
+ * Crea una función que reciba dos array, un booleano y retorne un array.
+ * - Si el booleano es verdadero buscará y retornará los elementos comunes
+ *   de los dos array.
+ * - Si el booleano es falso buscará y retornará los elementos no comunes
+ *   de los dos array.
+ * - No se pueden utilizar operaciones del lenguaje que
+ *   lo resuelvan directamente.
+ */
+
+/**
+ * Función que determina los iguales o no iguales de dos arrays dependiendo del valor del booleano
+ * @param {Array} arr1 Array de valores
+ * @param {Array} arr2 Array de valores
+ * @param {Boolean} boolean Variable que determina el flujo de la función
+ */
+const conjuntos = (arr1, arr2, boolean) => {
+    const resultado = [];
+
+    if (boolean) {
+        for (let i = 0; i < arr1.length; i++) {
+            for (let j = 0; j < arr2.length; j++) {
+                if (arr1[i] === arr2[j]) {
+                    if (!resultado.includes(arr1[i]) || !resultado.includes(arr2[j])) {
+                        resultado.push(arr1[i]);
+                    }
+                }
+            }
+        }
+    } else {
+        for (let i = 0; i < arr1.length; i++) {
+            for (let j = 0; j < arr2.length; j++) {
+                if (arr1[i] !== arr2[j]) {
+                    if (!resultado.includes(arr1[i]) || !resultado.includes(arr2[j])) {
+                        if (!arr1.includes(arr2[j]) && !resultado.includes(arr2[j])) {
+                            resultado.push(arr2[j]);
+                        } else if (!arr2.includes(arr1[i]) && !resultado.includes(arr1[i])) {
+                            resultado.push(arr1[i]);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return resultado;
+};
+
+console.log(conjuntos([1, 23, 4, 56, 7, 89, 10], [1, 23, 4, 5, 6, 67, 8, 1, 210, 10], true));
+console.log(conjuntos([1, 23, 4, 56, 7, 89, 10], [1, 23, 4, 5, 6, 67, 8, 1, 210, 10], false));
diff --git a/soluciones-javascript/24-maximo-comun-divisor-minimo-comun-multiplo/index.js b/soluciones-javascript/24-maximo-comun-divisor-minimo-comun-multiplo/index.js
new file mode 100644
index 000000000..91612ff54
--- /dev/null
+++ b/soluciones-javascript/24-maximo-comun-divisor-minimo-comun-multiplo/index.js
@@ -0,0 +1,19 @@
+/*
+ * Crea dos funciones, una que calcule el máximo común divisor (MCD) y otra
+ * que calcule el mínimo común múltiplo (mcm) de dos números enteros.
+ * - No se pueden utilizar operaciones del lenguaje que
+ *   lo resuelvan directamente.
+ */
+
+const mcd = (a , b) => {
+    return b === 0 ? a : mcd(b, a % b);
+}
+
+const mcm = (a , b) => {
+    return ( a * b ) / mcd(a,b);
+}
+
+console.log(mcd(48, 36));
+console.log(mcd(12, 18));
+console.log(mcm(12, 18));
+console.log(mcm(48, 36));
diff --git a/soluciones-javascript/25-iteration-master/index.js b/soluciones-javascript/25-iteration-master/index.js
new file mode 100644
index 000000000..6071d168d
--- /dev/null
+++ b/soluciones-javascript/25-iteration-master/index.js
@@ -0,0 +1,44 @@
+/*
+ * Quiero contar del 1 al 100 de uno en uno (imprimiendo cada uno).
+ * ¿De cuántas maneras eres capaz de hacerlo?
+ * Crea el código para cada una de ellas.
+ */
+
+
+/**
+ * Función que imprime números de 1 al 100
+ * @param {Number} forma: 1: 'for'  | 2: 'while' | 3: 'Recursividad' 
+ */
+const iterationMaster = (forma) => {
+
+    if(forma === 1){
+
+        for (let i = 1; i <= 100; i++) {
+            console.log(i);
+        }
+
+    } else if ( forma === 2 ) {
+        let i = 1; 
+        while (i <= 100) {
+            console.log(i);
+            i++;
+        }
+    } else if( forma === 3 ) {
+
+        const imprimirRecursivamente = (i = 1) => {
+            if ( i > 100 ) return; 
+            console.log(i);
+            imprimirRecursivamente( i + 1);
+        }
+
+        imprimirRecursivamente();
+    }else {
+        console.log('No hay forma con dicho parametro');
+    }
+
+}
+
+
+// iterationMaster(1);
+//iterationMaster(2);
+iterationMaster(3);
diff --git a/soluciones-javascript/26-piedra-papel-tijera/index.js b/soluciones-javascript/26-piedra-papel-tijera/index.js
new file mode 100644
index 000000000..575841b86
--- /dev/null
+++ b/soluciones-javascript/26-piedra-papel-tijera/index.js
@@ -0,0 +1,66 @@
+/*
+ * Crea un programa que calcule quien gana más partidas al piedra,
+ * papel, tijera.
+ * - El resultado puede ser: "Player 1", "Player 2", "Tie" (empate)
+ * - La función recibe un listado que contiene pares, representando cada jugada.
+ * - El par puede contener combinaciones de "R" (piedra), "P" (papel)
+ *   o "S" (tijera).
+ * - Ejemplo. Entrada: [("R","S"), ("S","R"), ("P","S")]. Resultado: "Player 2".
+ */
+
+/**
+ * Juego de piedra papel o tijera
+ * @param {Array>} jugadas - Lista de pares de jugadas, donde cada par es ["R", "P", "S"]
+ * @return {string} - "Player 1", "Player 2" o "Tie"
+ */
+const piedraPapelTijera = (jugadas) => {
+
+    const puntaje = {
+        player1: 0,
+        player2: 0,
+    }
+
+    const reglas = {
+        R: "S",
+        P: "R",
+        S: "P"
+    };
+
+    jugadas.forEach(([p1, p2]) => {
+        
+        if ( reglas[p1] === p2 ){
+            puntaje.player1++;
+        }  else if ( reglas[p2] === p1 ) {
+            puntaje.player2++;
+        }
+        
+    });
+    
+    const { player1, player2 } = puntaje;
+    
+    return (player1 > player2) ? "Player 1" : 
+           (player2 > player1) ? "Player 2" : "Tie";
+
+}
+
+// 1
+console.log(piedraPapelTijera([
+    ["R", "S"],
+    ["S", "R"],
+    ["P", "S"],
+]));
+
+// 2
+console.log(piedraPapelTijera([
+    ["S", "P"],
+    ["S", "R"],
+    ["P", "R"],
+]));
+
+// Tie
+console.log(piedraPapelTijera([
+    ["R", "S"],
+    ["S", "R"],
+    ["P", "S"],
+    ["S", "P"],
+]));
\ No newline at end of file
diff --git a/soluciones-javascript/27-cuadrado-y-triangulo-2d/index.js b/soluciones-javascript/27-cuadrado-y-triangulo-2d/index.js
new file mode 100644
index 000000000..4e6e40b76
--- /dev/null
+++ b/soluciones-javascript/27-cuadrado-y-triangulo-2d/index.js
@@ -0,0 +1,74 @@
+/*
+ * Crea un programa que dibuje un cuadrado o un triángulo con asteriscos "*".
+ * - Indicaremos el tamaño del lado y si la figura a dibujar es una u otra.
+ * - EXTRA: ¿Eres capaz de dibujar más figuras?
+ */
+
+/**
+ *
+ * @param {*} size
+ * @param {*} type
+ */
+const dibujarFigurasGeometricas = (size, type) => {
+    if (size < 2) throw new Error("El tamaño debe ser 2 o mayor a 2");
+
+    switch (type) {
+        case "cuadrado":
+            dibujarCuadrado(size);
+            break;
+        case "triangulo":
+            dibujarTriangulo(size);
+            break;
+        case "rombo":
+            dibujarRombo(size);
+            break;
+        default:
+            console.log("Tamaño ingresado no existe, ingrese cuadrado - triangulo - rombo");
+            break;
+    }
+};
+
+const dibujarCuadrado = (size) => {
+    
+    const linea = "* ".repeat(size);
+
+    for (let i = 0; i < size; i++) {
+    
+        console.log(linea);
+        
+    }
+
+}
+
+const dibujarTriangulo = (size) => {
+
+    for (let i = 0; i <= size; i++) {
+        
+        console.log( " ".repeat(size - i) + "* ".repeat(i));
+        
+    }
+
+}
+
+const dibujarRombo = (size) => {
+
+    if ( size % 2 === 0){
+        console.log("El tamaño del rombo debe ser impar");
+        return; 
+    }
+
+    let half = Math.floor( size / 2 );
+
+    for (let i = 0; i <= half; i++) {
+        console.log(" ".repeat(half - i) + "* ".repeat(i + 1));
+    }
+
+    for (let i = half - 1; i >= 0; i--) {
+        console.log(" ".repeat(half - i) + "* ".repeat(i + 1));
+    }
+
+}
+
+dibujarFigurasGeometricas(11, 'rombo');
+dibujarFigurasGeometricas(6, 'triangulo');
+dibujarFigurasGeometricas(6, 'cuadrado');
\ No newline at end of file
diff --git a/soluciones-javascript/28-vectores-ortogonales/index.js b/soluciones-javascript/28-vectores-ortogonales/index.js
new file mode 100644
index 000000000..5fed7595c
--- /dev/null
+++ b/soluciones-javascript/28-vectores-ortogonales/index.js
@@ -0,0 +1,29 @@
+/*
+ * Crea un programa que determine si dos vectores son ortogonales.
+ * - Los dos array deben tener la misma longitud.
+ * - Cada vector se podría representar como un array. Ejemplo: [1, -2]
+ */
+
+/**
+ * 
+ * @param {Array} vectorA 
+ * @param {Array} vectorB 
+ * @returns boolean
+ */
+const esVectorOrtogonal = (vectorA, vectorB) => {
+
+    if ( vectorA.length !== vectorB.length ) throw new Error("Los Vectores deben tener la misma longitud");
+    
+    let productoEscalar = 0;
+
+    vectorA.forEach( (vector, index) => {
+        productoEscalar += ( vector * vectorB[index]);
+    });
+
+    return productoEscalar === 0;
+
+}
+
+// Ejemplo de uso:
+console.log(esVectorOrtogonal([1, -2], [2, 1])); // true (son ortogonales)
+console.log(esVectorOrtogonal([1, 2, 3], [4, 5, 6])); // false (no son ortogonales)
\ No newline at end of file
diff --git a/soluciones-javascript/29-maquina-expendedora/index.js b/soluciones-javascript/29-maquina-expendedora/index.js
new file mode 100644
index 000000000..4de05e1d1
--- /dev/null
+++ b/soluciones-javascript/29-maquina-expendedora/index.js
@@ -0,0 +1,98 @@
+/*
+ * Simula el funcionamiento de una máquina expendedora creando una operación
+ * que reciba dinero (array de monedas) y un número que indique la selección
+ * del producto.
+ * - El programa retornará el nombre del producto y un array con el dinero
+ *   de vuelta (con el menor número de monedas).
+ * - Si el dinero es insuficiente o el número de producto no existe,
+ *   deberá indicarse con un mensaje y retornar todas las monedas.
+ * - Si no hay dinero de vuelta, el array se retornará vacío.
+ * - Para que resulte más simple, trabajaremos en céntimos con monedas
+ *   de 5, 10, 50, 100 y 200.
+ * - Debemos controlar que las monedas enviadas estén dentro de las soportadas.
+ */
+
+const productos = [
+    { codigo: "A1", nombre: "Papitas de Pollo", precio: 100 },
+    { codigo: "A3", nombre: "Doritos dinamita", precio: 100 },
+    { codigo: "B1", nombre: "agua", precio: 10 },
+    { codigo: "B2", nombre: "agua con gas", precio: 100 },
+    { codigo: "B3", nombre: "agua con sabor a fresa", precio: 100 },
+    { codigo: "C1", nombre: "Gomitas", precio: 100 },
+    { codigo: "C2", nombre: "Trululu", precio: 100 },
+    { codigo: "C3", nombre: "gomitas acidas", precio: 100 },
+    { codigo: "D1", nombre: "Coca Cola", precio: 200 },
+    { codigo: "D2", nombre: "Fanta", precio: 200 },
+    { codigo: "D3", nombre: "Sprite", precio: 200 },
+    { codigo: "E1", nombre: "Margaritas Naturales", precio: 100 },
+    { codigo: "E2", nombre: "Margaritas Picantes", precio: 100 },
+    { codigo: "E3", nombre: "Doritos", precio: 100 },
+];
+
+const monedasSoportadas = [5, 10, 50, 100, 200];
+
+const calcularCambio = (cambio) => {
+    let resultado = [];
+
+    for (let moneda of monedasSoportadas.sort((a, b) => b - a)) {
+        while (cambio >= moneda) {
+
+            resultado.push(moneda);
+
+            cambio -= moneda;
+        }
+    }
+
+    return resultado; 
+};
+
+/**
+ * Simula el funcionamiento de una máquina expendedora.
+ *
+ * @param {Object} param0 - Objeto con la información del pedido.
+ * @param {number[]} param0.dinero - Array de monedas ingresadas en la máquina.
+ * @param {string} param0.seleccionProducto - Código del producto seleccionado.
+ * @returns {string|Object} Mensaje de error o un objeto con el producto y el cambio.
+ */
+const maquinaExpendedora = ({ dinero, seleccionProducto }) => {
+    // Validar que todas las monedas ingresadas sean soportadas
+    if (!dinero.every((m) => monedasSoportadas.includes(m))) {
+        return "Error: Se han Ingresado monedas no soportadas. Se devuelve el dinero";
+    }
+
+    const producto = productos.find((p) => p.codigo === seleccionProducto);
+
+    const dineroTotal = dinero.reduce((acc, moneda) => acc + moneda, 0);
+
+    // Si el producto no existe, devolver dinero
+    if (!producto) {
+        return "Error: Producto no encontrado. Se devuelve el dinero.";
+    }
+
+    // Si el dinero es insuficiente, devolver dinero
+    if (dineroTotal < producto.precio) {
+        return "Error: Dinero insuficiente. Se devuelve el dinero.";
+    }
+
+    const cambio = calcularCambio(dineroTotal - producto.precio);
+
+    return {
+        producto: producto.nombre,
+        cambio
+    };
+};
+
+console.log(maquinaExpendedora({ dinero: [100, 50, 50], seleccionProducto: "A1" }));
+// { producto: 'Papitas de Pollo', cambio: [100] }
+
+console.log(maquinaExpendedora({ dinero: [5, 10, 50], seleccionProducto: "B1" }));
+// { producto: 'Agua', cambio: [50, 10, 5] }
+
+console.log(maquinaExpendedora({ dinero: [100, 100], seleccionProducto: "D1" }));
+// { producto: 'Coca Cola', cambio: [] }
+
+console.log(maquinaExpendedora({ dinero: [200], seleccionProducto: "Z1" }));
+// "Error: Producto no encontrado. Se devuelve el dinero."
+
+console.log(maquinaExpendedora({ dinero: [500], seleccionProducto: "A1" }));
+// "Error: Se han ingresado monedas no soportadas. Se devuelve el dinero."
diff --git a/soluciones-javascript/30-ordena-lista/index.js b/soluciones-javascript/30-ordena-lista/index.js
new file mode 100644
index 000000000..cf8134f0e
--- /dev/null
+++ b/soluciones-javascript/30-ordena-lista/index.js
@@ -0,0 +1,61 @@
+/*
+ * Crea una función que ordene y retorne una matriz de números.
+ * - La función recibirá un listado (por ejemplo [2, 4, 6, 8, 9]) y un parámetro
+ *   adicional "Asc" o "Desc" para indicar si debe ordenarse de menor a mayor
+ *   o de mayor a menor.
+ * - No se pueden utilizar funciones propias del lenguaje que lo resuelvan
+ *   automáticamente.
+ */
+
+const ordenarAsc = (lista) => {
+    let n = lista.length;
+    for (let i = 0; i < n - 1; i++) {
+        for (let j = 0; j < n - i - 1; j++) {
+            if (lista[j] > lista[j + 1]) {
+                let temp = lista[j];
+                lista[j] = lista[j + 1];
+                lista[j + 1] = temp;
+            }
+        }
+    }
+    return lista;
+};
+
+const ordenarDesc = (lista) => {
+    let n = lista.length;
+    for (let i = 0; i < n - 1; i++) {
+        for (let j = 0; j < n - i - 1; j++) {
+            if (lista[j] < lista[j + 1]) {
+                let temp = lista[j];
+                lista[j] = lista[j + 1];
+                lista[j + 1] = temp;
+            }
+        }
+    }
+    return lista;
+};
+/**
+ * Función para ordenar un array de números
+ * @param {Array} lista 
+ * @return ArrayOrdenado
+ */
+const ordenarLista = ( lista, indicacion ) => {
+    
+    if ( !lista.every((num) => typeof num === "number" )){
+        return "Error: los elementos del array no son un número"
+    };
+
+    switch (indicacion) {
+        case "Asc":
+            return ordenarAsc([...lista]);
+        case "Desc":
+            return ordenarDesc([...lista]);
+        default:
+            return "Error: indicación no válida";
+    }
+
+}
+
+// Pruebas
+console.log(ordenarLista([5, 2, 9, 1, 5, 6], "Asc"));  // [1, 2, 5, 5, 6, 9]
+console.log(ordenarLista([3, 8, 2, 7, 4], "Desc"));   // [8, 7, 4, 3, 2]
diff --git a/soluciones-javascript/31-marco-de-palabras/index.js b/soluciones-javascript/31-marco-de-palabras/index.js
new file mode 100644
index 000000000..aad6fa653
--- /dev/null
+++ b/soluciones-javascript/31-marco-de-palabras/index.js
@@ -0,0 +1,38 @@
+/*
+ * Crea una función que reciba un texto y muestre cada palabra en una línea,
+ * formando un marco rectangular de asteriscos.
+ * - ¿Qué te parece el reto? Se vería así:
+ *   **********
+ *   * ¿Qué   *
+ *   * te     *
+ *   * parece *
+ *   * el     *
+ *   * reto?  *
+ *   **********
+ */
+
+/**
+ * 
+ * @param {String} sentence 
+ */
+const marcoDePalabras = (sentence) => {
+
+    const sentenceLengthMajor = Math.max(...sentence.split(/[^A-Za-zÁ-Úá-úÜüÑñ]+/).map( element => element.length));
+
+    const inicioFinMarco = "*".repeat(sentenceLengthMajor + 4);
+    
+
+    const palabrasSeparadas = inicioFinMarco +  "\n"  + sentence.trim().split(' ').map( word  => {
+        
+        const espacios = word.length === sentenceLengthMajor ? 0 : sentenceLengthMajor - word.length;
+        
+        return "* " + word + " ".repeat(espacios + 1) + "*"; 
+    }).join('\n').concat("\n" + inicioFinMarco);
+    
+    console.log(palabrasSeparadas);
+    
+}
+
+marcoDePalabras("¿Qué te parece el reto?");
+marcoDePalabras("Esto es otro ejemplo más");
+marcoDePalabras("Esto es una declaración de amor");
\ No newline at end of file
diff --git "a/soluciones-javascript/32-a\303\261os-bisiestos/index.js" "b/soluciones-javascript/32-a\303\261os-bisiestos/index.js"
new file mode 100644
index 000000000..02084f308
--- /dev/null
+++ "b/soluciones-javascript/32-a\303\261os-bisiestos/index.js"
@@ -0,0 +1,37 @@
+/*
+ * Crea una función que imprima los 30 próximos años bisiestos
+ * siguientes a uno dado.
+ * - Utiliza el menor número de líneas para resolver el ejercicio.
+ */
+
+const esBisiesto = (year) => {
+    return ((year % 4 === 0  &&  year % 100 !== 0) ||  (year % 400 === 0)); 
+}
+
+const calcularBisiesto = (year) => {
+
+    if (!esBisiesto(year)) {
+        return "Error: debes ingresar un año bisiesto"
+    }
+
+    const proximosBisiestos = [];
+
+    for (let i = 1; i <= 30; i++) {
+
+        year += 4;
+
+        if (esBisiesto(year)) {
+            proximosBisiestos.push(year);
+        } else {
+            i--;
+        }
+        
+    }
+
+    return proximosBisiestos;
+
+}
+
+console.log(calcularBisiesto(2024));
+console.log(calcularBisiesto(2000));
+console.log(calcularBisiesto(1900));
\ No newline at end of file
diff --git a/soluciones-javascript/33-el-segundo/index.js b/soluciones-javascript/33-el-segundo/index.js
new file mode 100644
index 000000000..6c8aa917f
--- /dev/null
+++ b/soluciones-javascript/33-el-segundo/index.js
@@ -0,0 +1,23 @@
+/*
+ * Dado un listado de números, encuentra el SEGUNDO más grande
+ */
+
+/**
+ * 
+ * @param {Array} lista 
+ */
+const elSegundoMasGrande = (lista) => {
+
+    const listaFormateada = lista.filter( (value, index, array) => array.indexOf(value) === index); 
+
+    listaFormateada.sort((a, b) => b - a ).shift();
+
+    return listaFormateada.shift();
+
+}
+
+console.log(elSegundoMasGrande([1,98,2,4,56,8,9,55]));
+console.log(elSegundoMasGrande([100, 100, 50])); // Retorna 50 (Correcto)
+console.log(elSegundoMasGrande([100, 100])); // Retorna 100 (Incorrecto, debería ser undefined o indicar que no hay segundo más grande)
+console.log(elSegundoMasGrande([42])); // Retorna undefined (No hay segundo más grande)
+console.log(elSegundoMasGrande([])); // Retorna undefined (Correcto, pero podría manejarse mejor)
diff --git a/soluciones-javascript/34-ciclo-sexagenario-chino/index.js b/soluciones-javascript/34-ciclo-sexagenario-chino/index.js
new file mode 100644
index 000000000..c0134d11a
--- /dev/null
+++ b/soluciones-javascript/34-ciclo-sexagenario-chino/index.js
@@ -0,0 +1,37 @@
+/*
+ * Crea un función, que dado un año, indique el elemento 
+ * y animal correspondiente en el ciclo sexagenario del zodíaco chino.
+ * - Info: https://www.travelchinaguide.com/intro/astrology/60year-cycle.htm
+ * - El ciclo sexagenario se corresponde con la combinación de los elementos
+ *   madera, fuego, tierra, metal, agua y los animales rata, buey, tigre,
+ *   conejo, dragón, serpiente, caballo, oveja, mono, gallo, perro, cerdo
+ *   (en este orden).
+ * - Cada elemento se repite dos años seguidos.
+ * - El último ciclo sexagenario comenzó en 1984 (Madera Rata).
+ */
+
+const cicloSexagenarioChino = (year) => {
+
+    const elements =  [ "madera", "fuego", "tierra", "metal", "agua" ];
+    const animals =   [ "rata", "buey", "tigre", "conejo", "dragón", "serpiente", "caballo", "oveja", "mono", "gallo", "perro", "cerdo"];
+
+    if ( year < 604) {
+        return "El ciclo sexagenario comenzó en el año 604";
+    }
+
+    const sexagenaryYear = Math.floor((year - 4) % 60);
+    const elementsYear = elements[Math.floor((sexagenaryYear % 10) / 2)];
+    const animalsYear = animals[Math.floor(sexagenaryYear % 12)];
+
+
+    return `El año ${year}: ${elementsYear} ${animalsYear}`;
+
+}
+
+console.log(cicloSexagenarioChino(1924));
+console.log(cicloSexagenarioChino(1946));
+console.log(cicloSexagenarioChino(1984));
+console.log(cicloSexagenarioChino(604));
+console.log(cicloSexagenarioChino(603));
+console.log(cicloSexagenarioChino(1987));
+console.log(cicloSexagenarioChino(2022));
\ No newline at end of file
diff --git a/soluciones-javascript/35-los-numeros-perdidos/index.js b/soluciones-javascript/35-los-numeros-perdidos/index.js
new file mode 100644
index 000000000..3d5989921
--- /dev/null
+++ b/soluciones-javascript/35-los-numeros-perdidos/index.js
@@ -0,0 +1,50 @@
+/*
+ * Dado un array de enteros ordenado y sin repetidos,
+ * crea una función que calcule y retorne todos los que faltan entre
+ * el mayor y el menor.
+ * - Lanza un error si el array de entrada no es correcto.
+ */
+
+/**
+ * 
+ * @param {Array} array 
+ */
+const numerosPerdidos = (array) => {
+
+    if (!Array.isArray(array)) throw new Error("El parámetro debe ser un array.");
+    if (array.length === 0) throw new Error("El array no debe estar vacío.");
+    if (!array.every(num => Number.isInteger(num))) throw new Error("Todos los elementos deben ser números enteros.");
+    
+    // Verificar si el array está ordenado de menor a mayor
+    for (let i = 0; i < array.length - 1; i++) {
+        if (array[i] >= array[i + 1]) {
+            return "El array debe estar ordenado de menor a mayor y sin repetidos.";
+        }
+    }
+    
+    const numerosFaltantes = [];
+
+    for (let i = 0; i < array.length; i++) {
+        
+        const numeroSuperior = array[i + 1] || 0;
+
+        if ( (numeroSuperior - array[i]) > 1){
+            const diferencial = (numeroSuperior - array[i]);  
+            
+            for (let j = 1; j < diferencial; j++) {
+                numerosFaltantes.push(numeroSuperior - (diferencial - j));       
+            }
+
+        }
+
+    }
+
+    return numerosFaltantes;
+
+}
+
+// Pruebas
+console.log(numerosPerdidos([1, 3, 4, 7])); // [2, 5, 6]
+console.log(numerosPerdidos([1, 4, 10]));   // [2, 3, 5, 6, 7, 8, 9]
+console.log(numerosPerdidos([5, 6, 8, 17, 20])); // [7, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19]
+console.log(numerosPerdidos([1, 2, 3, 4, 5])); // []
\ No newline at end of file
diff --git a/soluciones-javascript/36-batalla-pokemon/index.js b/soluciones-javascript/36-batalla-pokemon/index.js
new file mode 100644
index 000000000..2a0915dea
--- /dev/null
+++ b/soluciones-javascript/36-batalla-pokemon/index.js
@@ -0,0 +1,38 @@
+/*
+ * Crea un programa que calcule el daño de un ataque durante
+ * una batalla Pokémon.
+ * - La fórmula será la siguiente: daño = 50 * (ataque / defensa) * efectividad
+ * - Efectividad: x2 (súper efectivo), x1 (neutral), x0.5 (no es muy efectivo)
+ * - Sólo hay 4 tipos de Pokémon: Agua, Fuego, Planta y Eléctrico 
+ *   (buscar su efectividad)
+ * - El programa recibe los siguientes parámetros:
+ *  - Tipo del Pokémon atacante.
+ *  - Tipo del Pokémon defensor.
+ *  - Ataque: Entre 1 y 100.
+ *  - Defensa: Entre 1 y 100.
+ */
+
+const tiposDeEfectividad = {
+    agua: { fuego: 2, planta: 0.5, electrico: 0.5, agua: 1 },
+    fuego: { planta: 2, agua: 0.5, electrico: 1, fuego: 1 },
+    planta: { agua: 2, fuego: 0.5,  electrico: 0.5, planta: 1 },
+    electrico: { agua: 2, planta: 0.5, fuego: 1, electrico: 1 },
+}
+
+const calcularDamageInBattle = (tipoAtacante, tipoDefensor, ataque, defensa) => {
+
+    if (!tiposDeEfectividad[tipoAtacante] || !tiposDeEfectividad[tipoAtacante][tipoDefensor]) {
+        throw new Error("Tipo de Pokémon inválido");
+    }
+
+    const tipoEfectividad = tiposDeEfectividad[tipoAtacante][tipoDefensor];
+
+    return 50 * ( ataque / defensa ) * tipoEfectividad;
+    
+
+}
+
+console.log(calcularDamageInBattle("agua", "electrico", 40, 70));
+console.log(calcularDamageInBattle("agua", "fuego", 80, 50)); // Daño esperado alto (súper efectivo)
+console.log(calcularDamageInBattle("fuego", "agua", 60, 70)); // Daño esperado bajo (no muy efectivo)
+console.log(calcularDamageInBattle("planta", "planta", 90, 90)); // Daño esperado neutro (x1)
\ No newline at end of file
diff --git a/soluciones-javascript/37-los-anillos-del-poder/index.js b/soluciones-javascript/37-los-anillos-del-poder/index.js
new file mode 100644
index 000000000..9cbfe9b6e
--- /dev/null
+++ b/soluciones-javascript/37-los-anillos-del-poder/index.js
@@ -0,0 +1,83 @@
+/*
+ * ¡La Tierra Media está en guerra! En ella lucharán razas leales
+ * a Sauron contra otras bondadosas que no quieren que el mal reine
+ * sobre sus tierras.
+ * Cada raza tiene asociado un "valor" entre 1 y 5:
+ * - Razas bondadosas: Pelosos (1), Sureños buenos (2), Enanos (3),
+ *   Númenóreanos (4), Elfos (5)
+ * - Razas malvadas: Sureños malos (2), Orcos (2), Goblins (2),
+ *   Huargos (3), Trolls (5)
+ * Crea un programa que calcule el resultado de la batalla entre
+ * los 2 tipos de ejércitos:
+ * - El resultado puede ser que gane el bien, el mal, o exista un empate.
+ *   Dependiendo de la suma del valor del ejército y el número de integrantes.
+ * - Cada ejército puede estar compuesto por un número de integrantes variable
+ *   de cada raza.
+ * - Tienes total libertad para modelar los datos del ejercicio.
+ * Ej: 1 Peloso pierde contra 1 Orco
+ *     2 Pelosos empatan contra 1 Orco
+ *     3 Pelosos ganan a 1 Orco
+ */
+
+const razasBondadosas = {
+    pelosos: 1, 
+    sureniosBuenos: 2,
+    enanos: 3,
+    numenoreanos: 4, 
+    elfos: 5
+}
+
+const razasMalvadas = {
+    sureniosMalosMalos: 2, 
+    orcos: 2, 
+    goblins: 2,
+    huargos: 3, 
+    trolls: 5
+}
+
+const calculoRazaVencedora = ( ejercitoBondadoso, ejercitoMalvado ) => {
+    let puntosBondadosos = 0;
+    let puntosMalvados = 0;
+
+    ejercitoBondadoso.forEach(raza => {
+        const [ nombre, cantidad ] = Object.entries(raza)[0];
+
+        if( razasBondadosas[nombre]) {
+            puntosBondadosos += razasBondadosas[nombre] * cantidad;
+        }
+    });
+
+    ejercitoMalvado.forEach(raza => {
+        const [ nombre, cantidad] = Object.entries(raza)[0];
+
+        if( razasMalvadas[nombre]) {
+            puntosMalvados += razasMalvadas[nombre] * cantidad;
+        };
+    });
+
+
+    return puntosBondadosos > puntosMalvados 
+            ? 'El bien triunfa sobre el mal'
+            : puntosMalvados > puntosBondadosos 
+            ? 'El mal triunfa sobre el bien'
+            : 'La batalla fue un empate';
+
+}
+
+const ejercitoBondadoso = [
+    {pelosos: 2,},
+    {sureniosBuenos: 3,},
+    {enanos: 4, },
+    {numenoreanos: 2, },
+    {elfos: 5,},
+];
+const ejercitoMalvado  = [
+    {sureniosMalosMalos: 2,} ,
+    {orcos: 2, },
+    {goblins: 2,},
+    {huargos: 3, },
+    {trolls: 5},
+];
+
+
+console.log(calculoRazaVencedora(ejercitoBondadoso, ejercitoMalvado));
\ No newline at end of file
diff --git a/soluciones-javascript/38-lanzamientos-legend-of-zelda/index.js b/soluciones-javascript/38-lanzamientos-legend-of-zelda/index.js
new file mode 100644
index 000000000..3c3d63484
--- /dev/null
+++ b/soluciones-javascript/38-lanzamientos-legend-of-zelda/index.js
@@ -0,0 +1,54 @@
+/*
+ * ¡Han anunciado un nuevo "The Legend of Zelda"!
+ * Se llamará "Tears of the Kingdom" y se lanzará el 12 de mayo de 2023.
+ * Pero, ¿recuerdas cuánto tiempo ha pasado entre los distintos
+ * "The Legend of Zelda" de la historia?
+ * Crea un programa que calcule cuántos años y días hay entre 2 juegos de Zelda
+ * que tú selecciones.
+ * - Debes buscar cada uno de los títulos y su día de lanzamiento
+ *   (si no encuentras el día exacto puedes usar el mes, o incluso inventártelo)
+ */
+
+/**
+ * Compara dos juegos en función de su nombre y año de lanzamiento.
+ *
+ * @param {{ name: string, releaseYear: string }} juego1 - Primer juego a comparar.
+ * @param {{ name: string, releaseYear: string }} juego2 - Segundo juego a comparar.
+ */
+const lanzamientosLegendOfZelda = (juego1, juego2) => {
+    const { name, releaseYear } = juego1;
+    const { name: name2, releaseYear: releaseYear2 } = juego2;
+
+    const fechaJuego1 = new Date(releaseYear);
+    const fechaJuego2 = new Date(releaseYear2);
+
+    let anios = fechaJuego2.getFullYear() - fechaJuego1.getFullYear() ;
+    let meses = fechaJuego2.getMonth() - fechaJuego1.getMonth();
+    let dias = fechaJuego2.getDate() - fechaJuego1.getDate();
+
+    if ( dias < 0){
+        meses--;
+        const mesAnterior = new Date(fechaJuego2.getFullYear(), fechaJuego2.getMonth(), 0);
+        dias += mesAnterior.getDate();
+    }
+
+    if (meses < 0) {
+        anios--;
+        meses += 12;
+    }
+
+    console.log( { anios, meses, dias } );
+    
+
+};
+
+lanzamientosLegendOfZelda(
+    {
+        name: "The Legend of Zelda: Ocarina of Time",
+        releaseYear: "12/11/1998",
+    },
+    {
+        name: "Zelda: Majoras Mask",
+        releaseYear: "11/17/2000",
+    }
+);
diff --git a/soluciones-javascript/39-binario-a-decimal/index.js b/soluciones-javascript/39-binario-a-decimal/index.js
new file mode 100644
index 000000000..6c92f8b5c
--- /dev/null
+++ b/soluciones-javascript/39-binario-a-decimal/index.js
@@ -0,0 +1,31 @@
+/*
+ * Crea un programa se encargue de transformar un número binario
+ * a decimal sin utilizar funciones propias del lenguaje que
+ * lo hagan directamente.
+ */
+
+/**
+ * 
+ * @param {Number} numeroBinario 
+ */
+const binaryToDecimal = (numeroBinario) => {
+
+    const stringNumeroBinario = numeroBinario.toString();
+    let resultado = 0;
+    let exponente = 0;
+
+    for (let i = 1; i <= stringNumeroBinario.length; i++) {
+        
+        const number = Number(stringNumeroBinario[ stringNumeroBinario.length - i]);
+
+        resultado += (number * Math.pow(2, exponente));
+        exponente++;
+    }
+
+    return resultado; 
+
+}
+
+console.log(binaryToDecimal(1011));
+console.log(binaryToDecimal(1010));
+console.log(binaryToDecimal(11111111));
\ No newline at end of file
diff --git a/soluciones-javascript/40-top-algoritmos/index.js b/soluciones-javascript/40-top-algoritmos/index.js
new file mode 100644
index 000000000..625d4c20c
--- /dev/null
+++ b/soluciones-javascript/40-top-algoritmos/index.js
@@ -0,0 +1,41 @@
+/*
+ * Implementa uno de los algoritmos de ordenación más famosos:
+ * el "Quick Sort", creado por C.A.R. Hoare.
+ * - Entender el funcionamiento de los algoritmos más utilizados de la historia
+ *   Nos ayuda a mejorar nuestro conocimiento sobre ingeniería de software.
+ *   Dedícale tiempo a entenderlo, no únicamente a copiar su implementación.
+ * - Esta es una nueva serie de retos llamada "TOP ALGORITMOS",
+ *   donde trabajaremos y entenderemos los más famosos de la historia.
+ */
+
+/**
+ * 
+ * @param {Array} array 
+ */
+const quickSort = (array) => {
+
+    if (array.length <= 1 ) {
+        return array;
+    }
+
+    const pivot = array[array.length - 1];
+    const left = [];
+    const right = [];
+
+    for (let i = 0; i < array.length - 1; i++) {
+        
+        if (array[i] < pivot ) {
+            left.push(array[i]);
+        } else{
+            right.push(array[i]);
+        }
+
+    }
+
+    console.log({left, right})
+
+    return [ ...quickSort(left), pivot, ...quickSort(right) ];
+
+}
+
+console.log(quickSort([ 8, 9, 3, 7, 1, 2, 6, 4]));
\ No newline at end of file
diff --git a/soluciones-javascript/41-triangulo-de-pascal/index.js b/soluciones-javascript/41-triangulo-de-pascal/index.js
new file mode 100644
index 000000000..c51e3a012
--- /dev/null
+++ b/soluciones-javascript/41-triangulo-de-pascal/index.js
@@ -0,0 +1,41 @@
+/*
+ * Crea una función que sea capaz de dibujar el "Triángulo de Pascal"
+ * indicándole únicamente el tamaño del lado.
+ *
+ * - Aquí puedes ver rápidamente cómo se calcula el triángulo:
+ *   https://commons.wikimedia.org/wiki/File:PascalTriangleAnimated2.gif
+ */
+
+const generarTrianguloPascal = (n) => {
+    let triangulo = [];
+    
+    for (let i = 0; i < n; i++) {
+        triangulo[i] = [];
+        for (let j = 0; j <= i; j++) {
+            if (j === 0 || j === i) {
+                triangulo[i][j] = 1;
+            } else {
+                triangulo[i][j] = triangulo[i - 1][j - 1] + triangulo[i - 1][j];
+            }
+        }
+    }
+    
+    return triangulo;
+}
+
+const imprimirTrianguloPascal = (triangulo) => {
+    let n = triangulo.length;
+    let resultado = "";
+    
+    for (let i = 0; i < n; i++) {
+        let espacio = " ".repeat(n - i);
+        let fila = triangulo[i].join(" ");
+        resultado += espacio + fila + "\n";
+    }
+    
+    console.log(resultado);
+}
+
+let n = 5; // Tamaño del triángulo
+let triangulo = generarTrianguloPascal(n);
+imprimirTrianguloPascal(triangulo);
diff --git a/soluciones-javascript/42-la-ley-de-ohm/index.js b/soluciones-javascript/42-la-ley-de-ohm/index.js
new file mode 100644
index 000000000..88c0cd6c3
--- /dev/null
+++ b/soluciones-javascript/42-la-ley-de-ohm/index.js
@@ -0,0 +1,37 @@
+/*
+ * Crea una función que calcule el valor del parámetro perdido
+ * correspondiente a la ley de Ohm.
+ * - Enviaremos a la función 2 de los 3 parámetros (V, R, I), y retornará
+ *   el valor del tercero (redondeado a 2 decimales).
+ * - Si los parámetros son incorrectos o insuficientes, la función retornará
+ *   la cadena de texto "Invalid values".
+ */
+
+/**
+ * 
+ * @param {{ v: Number, r: Number, i: Number }} param0 
+ */
+const leyDeOhm = ({ v, r, i }) => {
+   
+    const valores = [ v, r, i ]; 
+    const faltantes = valores.filter( value => value === undefined ).length;
+
+    if ( faltantes !== 1 || valores.some( value => value !== undefined && (typeof value !== "number") || value < 0))
+        return "Invalid Values";
+
+    return v === undefined 
+            ? (i * r).toFixed(2) 
+            : r === undefined 
+            ? (v / i).toFixed(2)
+            : i === undefined
+            ? (v / r).toFixed(2)
+            : 'Invalid values';
+}
+
+console.log(leyDeOhm({ v: 0, r: 2, i: 3 })); // "Invalid values"
+console.log(leyDeOhm({ v: undefined, r: 4, i: 5 })); // 20.00
+console.log(leyDeOhm({ v: 12, r: undefined, i: 3 })); // 4.00
+console.log(leyDeOhm({ v: 12, r: 4, i: undefined })); // 3.00
+console.log(leyDeOhm({ v: 12, r: 4, i: 3 })); // "Invalid values"
+console.log(leyDeOhm({ v: -12, r: 4, i: undefined })); // "Invalid values"
+console.log(leyDeOhm({ v: 12, r: "4", i: undefined })); // "Invalid values"
\ No newline at end of file
diff --git a/soluciones-javascript/43-conversor-temperatura/index.js b/soluciones-javascript/43-conversor-temperatura/index.js
new file mode 100644
index 000000000..6b0a4e670
--- /dev/null
+++ b/soluciones-javascript/43-conversor-temperatura/index.js
@@ -0,0 +1,44 @@
+/*
+ * Crea una función que transforme grados Celsius en Fahrenheit
+ * y viceversa.
+ *
+ * - Para que un dato de entrada sea correcto debe poseer un símbolo "°"
+ *   y su unidad ("C" o "F").
+ * - En caso contrario retornará un error.
+ */
+
+/**
+ * 
+ * @param {String} grados 
+ */
+const conversorTemperatura = ( grados ) => {
+
+    const reglaRegex = /^-?\d+(\.\d+)?\s*°\s*[cCfF]$/;
+    
+    if (!reglaRegex.test(grados)) {
+        return "Error en el formato"
+    }
+
+    const numGrado = grados.split('').map((g) => {
+        return !isNaN(Number(g)) ? g : null 
+    }).join('');
+
+    const condicion = grados.split('').filter((letra) => letra === "C" || letra === "F" ).join('');
+
+    if (condicion === "C") {
+
+        return `${numGrado * (9 / 5) + 32} °F`; 
+
+    } else if ( condicion === "F" ){
+
+        return `${(numGrado - 32 ) * (5 / 9)} °C`; 
+
+    } else {
+        return "Error en la letra"
+    }
+}
+
+// Pruebas
+console.log(conversorTemperatura("25 °C"));   // 77.00 °F
+console.log(conversorTemperatura("77 °F"));   // 25.00 °C
+console.log(conversorTemperatura("abc °C"));  // Error en el formato
\ No newline at end of file
diff --git a/soluciones-javascript/44-truco-o-trato/index.js b/soluciones-javascript/44-truco-o-trato/index.js
new file mode 100644
index 000000000..902ac8e88
--- /dev/null
+++ b/soluciones-javascript/44-truco-o-trato/index.js
@@ -0,0 +1,99 @@
+/*
+ * Este es un reto especial por Halloween.
+ * Deberemos crear un programa al que le indiquemos si queremos realizar "Truco
+ * o Trato" y un listado (array) de personas con las siguientes propiedades:
+ * - Nombre de la niña o niño
+ * - Edad
+ * - Altura en centímetros
+ *
+ * Si las personas han pedido truco, el programa retornará sustos (aleatorios)
+ * siguiendo estos criterios:
+ * - Un susto por cada 2 letras del nombre por persona
+ * - Dos sustos por cada edad que sea un número par
+ * - Tres sustos por cada 100 cm de altura entre todas las personas
+ * - Sustos: 🎃 👻 💀 🕷 🕸 🦇
+ *
+ * Si las personas han pedido trato, el programa retornará dulces (aleatorios)
+ * siguiendo estos criterios:
+ * - Un dulce por cada letra de nombre
+ * - Un dulce por cada 3 años cumplidos hasta un máximo de 10 años por persona
+ * - Dos dulces por cada 50 cm de altura hasta un máximo de 150 cm por persona
+ * - Dulces: 🍰 🍬 🍡 🍭 🍪 🍫 🧁 🍩
+ * - En caso contrario retornará un error.
+ */
+
+const trucoOTrato = (decision, arrayDePersonas) => {
+    const sustos = ["🎃", "👻", "💀", "🕷", "🕸", "🦇"];
+    const dulces = ["🍰", "🍬", "🍡", "🍭", "🍪", "🍫", "🧁", "🍩"];
+    const resultado = [];
+
+    if (decision === "Truco") {
+        let sumaEdades = 0;
+
+        arrayDePersonas.forEach((element) => {
+            const [nombre, edad, centimetro] = element;
+
+            // Un susto por cada 2 letras del nombre por persona
+            if (nombre.length % 2 === 0) {
+                for (let i = 0; i < nombre.length / 2; i++) {
+                    resultado.push(sustos[Math.floor(Math.random() * 6)]);
+                }
+            } else {
+                for (let i = 0; i < (nombre.length - 1) / 2; i++) {
+                    resultado.push(sustos[Math.floor(Math.random() * 6)]);
+                }
+            }
+
+            // Dos sustos por cada edad que sea un número par
+            if (edad % 2 === 0) {
+                for (let i = 0; i < 2; i++) {
+                    resultado.push(sustos[Math.floor(Math.random() * 6)]);
+                }
+            }
+
+            sumaEdades += centimetro;
+        });
+
+        // Tres sustos por cada 100 cm de altura entre todas las personas
+        for (let i = 100; i <= sumaEdades; i += 100) {
+            for (let j = 0; j < 3; j++) {
+                resultado.push(sustos[Math.floor(Math.random() * 6)]);
+            }
+        }
+    } else if (decision === "Trato") {
+        arrayDePersonas.forEach((element) => {
+            const [nombre, edad, centimetro] = element;
+
+            // Un dulce por cada letra de nombre
+            for (let i = 0; i < nombre.length; i++) {
+                resultado.push(dulces[Math.floor(Math.random() * 8)]);
+            }
+
+            // Un dulce por cada 3 años cumplidos hasta un máximo de 10 años por persona
+            for (let j = 0; j < edad; j += 3) {
+                resultado.push(dulces[Math.floor(Math.random() * 8)]);
+            }
+
+            // Dos dulces por cada 50 cm de altura hasta un máximo de 150 cm por persona
+            for (let y = 0; y < 150; y += 50) {
+                if ( y > centimetro ) return resultado; 
+                resultado.push(dulces[Math.floor(Math.random() * 8)]);
+            }
+
+        });
+    } else {
+        return "Error"; 
+    }
+
+    return resultado.join(" ");
+};
+
+const personas = [
+    ["Juan", 10, 100],
+    ["Pablo", 8, 120],
+    ["Carla", 7, 80],
+    ["Lina", 9, 110],
+];
+
+console.log("Truco" + trucoOTrato("Truco", personas) + "\n");
+console.log("Trato" + trucoOTrato("Trato", personas) + "\n");
diff --git a/soluciones-javascript/45-bumeranes/index.js b/soluciones-javascript/45-bumeranes/index.js
new file mode 100644
index 000000000..e4b24450c
--- /dev/null
+++ b/soluciones-javascript/45-bumeranes/index.js
@@ -0,0 +1,27 @@
+/*
+ * Crea una función que retorne el número total de bumeranes de
+ * un array de números enteros e imprima cada uno de ellos.
+ * - Un bumerán (búmeran, boomerang) es una secuencia formada por 3 números
+ *   seguidos, en el que el primero y el último son iguales, y el segundo
+ *   es diferente. Por ejemplo [2, 1, 2].
+ * - En el array [2, 1, 2, 3, 3, 4, 2, 4] hay 2 bumeranes ([2, 1, 2]
+ *   y [4, 2, 4]).
+ */
+
+const countBoomerangs = (arrayBoomerangs) => {
+    if (arrayBoomerangs.length < 3) return "El array no tiene suficientes elementos.";
+
+    const boomerangs = [];
+    arrayBoomerangs.forEach((element, index, array) => {
+        if ( element === array[index + 2] && element !== array[index + 1] ) {
+            boomerangs.push([array[index], array[index + 1], array[index + 2]]);
+        }
+    });
+    return `El array tiene ${boomerangs.length} \n **${boomerangs.join('**')}**`;
+}
+
+console.log(countBoomerangs([2, 1, 2, 3, 3, 4, 2, 4])); 
+console.log(countBoomerangs([3, 1, 2, 1, 3, 4, 3, 4])); 
+console.log(countBoomerangs([9, 1, 9, 3, 4, 3, 2, 4]));
+console.log(countBoomerangs([2, 2, 2])); // 0 (caso incorrecto corregido)
+console.log(countBoomerangs([1, 2])); // 0 (array con menos de 3 elementos)
\ No newline at end of file
diff --git a/soluciones-javascript/46-contenedor-de-agua/index.js b/soluciones-javascript/46-contenedor-de-agua/index.js
new file mode 100644
index 000000000..eba0a44d7
--- /dev/null
+++ b/soluciones-javascript/46-contenedor-de-agua/index.js
@@ -0,0 +1,55 @@
+/*
+ * Dado un array de números enteros positivos, donde cada uno
+ * representa unidades de bloques apilados, debemos calcular cuantas unidades
+ * de agua quedarán atrapadas entre ellos.
+ *
+ * - Ejemplo: Dado el array [4, 0, 3, 6, 1, 3].
+ *
+ *          ⏹
+ *          ⏹
+ *   ⏹💧💧 ⏹
+ *   ⏹💧⏹⏹💧  ⏹
+ *   ⏹💧⏹⏹💧  ⏹
+ *   ⏹💧⏹⏹⏹ ⏹
+ *
+ *   Representando bloque con ⏹︎ y agua con 💧, quedarán atrapadas 7 unidades
+ *   de agua. Suponemos que existe un suelo impermeable en la parte inferior
+ *   que retiene el agua.
+ */
+
+const contenedorDeAgua = (array) => {
+    if (array.length < 3) return 0; // Si hay menos de 3 bloques, no puede atraparse agua
+
+    const n = array.length;
+    let aguaAtrapada = 0;
+
+    // Arrays auxiliares para almacenar el máximo a la izquierda y a la derecha
+    let maxIzq = new Array(n).fill(0);
+    let maxDer = new Array(n).fill(0);
+
+    // Rellenar maxIzq
+    maxIzq[0] = array[0];
+    for (let i = 1; i < n; i++) {
+        maxIzq[i] = Math.max(maxIzq[i - 1], array[i]);
+    }
+
+    // Rellenar maxDer
+    maxDer[n - 1] = array[n - 1];
+    for (let i = n - 2; i >= 0; i--) {
+        maxDer[i] = Math.max(maxDer[i + 1], array[i]);
+    }
+
+    // Calcular el agua atrapada en cada posición
+    for (let i = 0; i < n; i++) {
+        aguaAtrapada += Math.max(0, Math.min(maxIzq[i], maxDer[i]) - array[i]);
+    }
+
+    return aguaAtrapada;
+};
+
+// Ejemplo de uso
+console.log(contenedorDeAgua([4, 0, 3, 6, 1, 3])); // Output: 7
+console.log(contenedorDeAgua([4, 0, 3, 6]));
+console.log(contenedorDeAgua([5, 4, 3, 2, 1, 0]));
+console.log(contenedorDeAgua([0, 1, 2, 3, 4, 5]));
+console.log(contenedorDeAgua([4, 0, 3, 6, 1, 3, 0, 1, 6]));
diff --git a/soluciones-javascript/47-donde-esta-el-robot/index.js b/soluciones-javascript/47-donde-esta-el-robot/index.js
new file mode 100644
index 000000000..3dbfb834f
--- /dev/null
+++ b/soluciones-javascript/47-donde-esta-el-robot/index.js
@@ -0,0 +1,58 @@
+/*
+ * Calcula dónde estará un robot (sus coordenadas finales) que se
+ * encuentra en una cuadrícula representada por los ejes "x" e "y".
+ * - El robot comienza en la coordenada (0, 0).
+ * - Para idicarle que se mueva, le enviamos un array formado por enteros
+ *   (positivos o negativos) que indican la secuencia de pasos a dar.
+ * - Por ejemplo: [10, 5, -2] indica que primero se mueve 10 pasos, se detiene,
+ *   luego 5, se detiene, y finalmente 2.
+ *   El resultado en este caso sería (x: -5, y: 12)
+ * - Si el número de pasos es negativo, se desplazaría en sentido contrario al
+ *   que está mirando.
+ * - Los primeros pasos los hace en el eje "y". Interpretamos que está mirando
+ *   hacia la parte positiva del eje "y".
+ * - El robot tiene un fallo en su programación: cada vez que finaliza una
+ *   secuencia de pasos gira 90 grados en el sentido contrario a las agujas
+ *   del reloj.
+ */
+
+/**
+ * 
+ * @param {Array} secuenciaDePasos 
+ */
+const dondeEstaElRobot = ( secuenciaDePasos ) => {
+
+    const coordenadas = { x: 0, y: 0 };
+    const direcciones = ['y+', 'x-', 'y-', 'x+'];
+    
+    for (let i = 0; i < secuenciaDePasos.length; i++) {
+        
+        let direccionActual = direcciones[ i % 4 ];
+        let pasos = secuenciaDePasos[i];
+
+        if(pasos < 0){
+            pasos = Math.abs(pasos);
+            switch (direccionActual) {
+                case 'y+': direccionActual = 'y-'; break;
+                case 'x-': direccionActual = 'x+'; break;
+                case 'y-': direccionActual = 'y+'; break;
+                case 'x+': direccionActual = 'x-'; break;
+            }
+        }
+        
+        switch (direccionActual) {
+            case 'y+': coordenadas.y += pasos; break;
+            case 'x-': coordenadas.x -= pasos; break;
+            case 'y-': coordenadas.y -= pasos; break;
+            case 'x+': coordenadas.x += pasos; break;
+        }
+
+    }
+
+    return coordenadas; 
+
+}
+
+console.log(dondeEstaElRobot([10, 5, -2]));
+console.log(dondeEstaElRobot([-10, -5, 2]));
+console.log(dondeEstaElRobot([-10, -5, 4]));
\ No newline at end of file
diff --git a/soluciones-javascript/48-vocal-mas-comun/index.js b/soluciones-javascript/48-vocal-mas-comun/index.js
new file mode 100644
index 000000000..9880ae4f1
--- /dev/null
+++ b/soluciones-javascript/48-vocal-mas-comun/index.js
@@ -0,0 +1,33 @@
+/*
+ * Crea un función que reciba un texto y retorne la vocal que
+ * más veces se repita.
+ * - Ten cuidado con algunos casos especiales.
+ * - Si no hay vocales podrá devolver vacío.
+ */
+
+/**
+ *
+ * @param {String} string
+ */
+const vocalMasComun = (string) => {
+
+    const vocales = string.toLowerCase().match(/[aeiou]/g);
+    if (!vocales) return '';  // Retorna vacío si no hay vocales
+
+    return (
+        "La letra que más se repite es: " +
+        string.split("")
+            .filter(
+                (word) =>
+                    word === "a" || word === "e" || word === "i" || word === "o" || word === "u"
+            )
+            .reduce((acc, letter) => {
+                acc[letter] = (acc[letter] || 0) + 1;                
+                return acc;
+            })
+    );
+};
+
+console.log(vocalMasComun("Hola yo soy el que no se repite no no no")); // o
+console.log(vocalMasComun("ees es la letraee mas reeepeteee")); // e
+console.log(vocalMasComun("xyz")); // ""
\ No newline at end of file
diff --git a/soluciones-javascript/49-calendario-adviento-2022/index.js b/soluciones-javascript/49-calendario-adviento-2022/index.js
new file mode 100644
index 000000000..531537ba1
--- /dev/null
+++ b/soluciones-javascript/49-calendario-adviento-2022/index.js
@@ -0,0 +1,87 @@
+/*
+ * ¿Conoces el calendario de adviento de la comunidad (https://adviento.dev)?
+ * 24 días, 24 regalos sorpresa relacionados con desarrollo de software,
+ * ciencia y tecnología desde el 1 de diciembre.
+ *
+ * Enunciado: Crea una función que reciba un objeto de tipo "Date" y retorne
+ * lo siguiente:
+ * - Si la fecha coincide con el calendario de aDEViento 2022: Retornará el regalo
+ *   de ese día (a tu elección) y cuánto queda para que finalice el sorteo de ese día.
+ * - Si la fecha es anterior: Cuánto queda para que comience el calendario.
+ * - Si la fecha es posterior: Cuánto tiempo ha pasado desde que ha finalizado.
+ *
+ * Notas:
+ * - Tenemos en cuenta que cada día del calendario comienza a medianoche 00:00:00
+ *   y finaliza a las 23:59:59.
+ * - Debemos trabajar con fechas que tengan año, mes, día, horas, minutos
+ *   y segundos.
+ */
+
+const regalos = [
+    "📚 Guía rápida de Git y GitHub",
+    "💻 Snippet de código para autenticación JWT en Node.js",
+    "⌨️ Atajo de teclado para VS Code que te cambiará la vida",
+    "🎨 Mini curso de Flexbox y CSS Grid en 30 minutos",
+    "🔍 Cheat sheet de expresiones regulares (regex)",
+    "🖼️ Plantilla HTML + Tailwind para un portfolio web",
+    "🧼 Consejo sobre Clean Code: Nombra mejor tus variables",
+    "🐍 Script en Python para automatizar tareas repetitivas",
+    "🗃️ Truco para optimizar consultas en bases de datos SQL",
+    "🖱️ Atajo en la terminal para agilizar tu flujo de trabajo",
+    "🌐 Snippet de código para consumir APIs REST con Fetch",
+    "🛠️ Herramienta para generar datos ficticios para pruebas",
+    "🧩 Extensión de VS Code imprescindible para desarrolladores",
+    "⚛️ Cómo mejorar el rendimiento de tu app React",
+    "🎧 Lista de podcasts de tecnología y programación",
+    "🐳 Introducción a Docker con un ejemplo práctico",
+    "🔐 Explicación sencilla de OAuth y por qué deberías usarlo",
+    "📖 Top 5 libros recomendados sobre desarrollo web",
+    "🚀 Snippet para crear un servidor Express en 2 minutos",
+    "📝 Curso gratuito de JavaScript avanzado",
+    "🎨 Atajos de Figma para diseñadores y devs",
+    "🛡️ Plugin de Chrome para mejorar tu productividad",
+    "🤝 Guía para contribuir a proyectos Open Source",
+    "📄 Template para tu README en GitHub"
+];
+
+/**
+ *
+ * @param {Date} date
+ */
+const calendarioAdviento2022 = ( date ) => {
+
+    const fechaInicio = new Date(2022, 11, 1, 0, 0, 0).getTime();
+    const fechaFin = new Date(2022, 11, 24, 23, 59, 59).getTime();
+    const dateInputInMiliseconds = date.getTime();
+
+
+    if( dateInputInMiliseconds >= fechaInicio && dateInputInMiliseconds <= fechaFin ){
+        const dia = date.getDate();
+        const diaFinal = new Date(2022, 11, dia, 23, 59, 59).getTime();
+        const diferencia = diaFinal - dateInputInMiliseconds;
+        const horasRestantes = Math.floor( diferencia / (1000 * 60 * 60 ));
+        const minutosRestantes = Math.floor( diferencia / (1000 * 60 )) / ( 1000 * 60 );
+
+        return `Regalo del día ${dia}: ${regalos[dia - 1]}. Quedan ${horasRestantes} horas y ${minutosRestantes} minutos para que termine el sorteo de hoy.`;
+
+    }
+
+    if (dateInputInMiliseconds < fechaInicio) {
+        const diferenciaInicio = fechaInicio - dateInputInMiliseconds;  // Diferencia en milisegundos entre ahora y el inicio del calendario
+        const diasRestantes = Math.ceil(diferenciaInicio / (1000 * 60 * 60 * 24));  // Convertir la diferencia a días
+
+        return `El calendario aún no ha comenzado. Faltan ${diasRestantes} días para el 1 de diciembre.`;
+    }
+
+    if (dateInputInMiliseconds > fechaFin) {
+        const diferenciaFinal = dateInputInMiliseconds - fechaFin;  // Diferencia en milisegundos entre ahora y el fin del calendario
+        const diasPasados = Math.floor(diferenciaFinal / (1000 * 60 * 60 * 24));  // Convertir la diferencia a días
+
+        return `El calendario ya ha finalizado. Han pasado ${diasPasados} días desde el 24 de diciembre.`;
+    }
+
+}
+
+console.log(calendarioAdviento2022(new Date(2022, 11, 14, 12, 6, 12))); // Prueba con una fecha en diciembre
+console.log(calendarioAdviento2022(new Date(2022, 10, 30))); // Prueba con una fecha antes del 1 de diciembre
+console.log(calendarioAdviento2022(new Date(2022, 11, 25))); // Prueba con una fecha después del 24 de diciembre
\ No newline at end of file
diff --git a/soluciones-javascript/50-el-detector-de-handles/index.js b/soluciones-javascript/50-el-detector-de-handles/index.js
new file mode 100644
index 000000000..d45f0d77d
--- /dev/null
+++ b/soluciones-javascript/50-el-detector-de-handles/index.js
@@ -0,0 +1,26 @@
+/*
+ * Crea una función que sea capaz de detectar y retornar todos los
+ * handles de un texto usando solamente Expresiones Regulares.
+ * Debes crear una expresión regular para cada caso:
+ * - Handle usuario: Los que comienzan por "@"
+ * - Handle hashtag: Los que comienzan por "#"
+ * - Handle web: Los que comienzan por "www.", "http://", "https://"
+ *   y finalizan con un dominio (.com, .es...)
+ */
+
+const elDetectorDeHandles = ( texto ) => {
+
+    const handleUser = texto.match((/@\w+/g)) || [] ;
+    const handleHashtag = texto.match((/#\w+/g)) || [];
+    const handleWeb = texto.match(/https?:\/\/[\w\-\.]+\.\w{2,}|www\.[\w\-\.]+\.\w{2,}/) || [];
+
+    return {
+        handleUser,
+        handleHashtag,
+        handleWeb,
+    }
+
+}
+
+const texto = "Hola @usuario, visita https://openai.com o www.ejemplo.com. #programacion #regex";
+console.log(elDetectorDeHandles(texto));
\ No newline at end of file
diff --git a/soluciones-javascript/51-la-encriptacion-de-karaca/index.js b/soluciones-javascript/51-la-encriptacion-de-karaca/index.js
new file mode 100644
index 000000000..b2c69f229
--- /dev/null
+++ b/soluciones-javascript/51-la-encriptacion-de-karaca/index.js
@@ -0,0 +1,63 @@
+/*
+ * Crea una función que sea capaz de encriptar y desencriptar texto
+ * utilizando el algoritmo de encriptación de Karaca
+ * (debes buscar información sobre él).
+ */
+
+
+/**
+ * Algoritmo de encriptación de karaca
+ * @param {String} string
+ */
+const encriptarTexto = ( string ) => {
+
+    const convencionVocales = {
+        a: 0,
+        e: 1,
+        i: 2,
+        o: 3,
+        u: 4,
+    };
+
+    const reverseString = string.split('').reverse().map((element) => {
+        for (let i = 0; i < Object.keys(convencionVocales).length; i++) {
+            if( element === Object.keys(convencionVocales)[i]){
+                return Object.values(convencionVocales)[i];
+            }
+        }
+        return element;
+    }).join('');
+
+    return reverseString + "aca";
+
+}
+
+/**
+ * Algoritmo de desencriptación de karaca
+ * @param {String} stringEncriptado
+ */
+const desencriptarTexto = (stringEncriptado) => {
+    const convencionVocales = {
+        a: 0,
+        e: 1,
+        i: 2,
+        o: 3,
+        u: 4,
+    };
+
+    const stringWithoutAca = stringEncriptado.replace('aca', '');
+
+    return stringWithoutAca.split('').map((element) => {
+        for (let i = 0; i < Object.keys(convencionVocales).length; i++) {
+            if( Number(element) === Object.values(convencionVocales)[i]){
+                return Object.keys(convencionVocales)[i];
+            }
+        }
+        return element;
+    }).reverse().join('');
+
+}
+
+const textoEncriptado = encriptarTexto('apple');
+console.log("Texto encriptado: " + textoEncriptado);
+console.log("Texto desencriptado: " + desencriptarTexto(textoEncriptado));
\ No newline at end of file
diff --git a/soluciones-javascript/52-el-reto-random/index.js b/soluciones-javascript/52-el-reto-random/index.js
new file mode 100644
index 000000000..1331d6ea6
--- /dev/null
+++ b/soluciones-javascript/52-el-reto-random/index.js
@@ -0,0 +1,34 @@
+/*
+ * Crea tu propio enunciado para que forme parte de los retos de 2023.
+ * - Ten en cuenta que su dificultad debe ser asumible por la comunidad y seguir
+ * un estilosemejante a los que hemos realizado durante el año.
+ * - Si quieres también puedes proponer tu propia solución al reto
+ *   (en el lenguaje que quieras).
+ */
+
+/*
+ * Enunciado: Escribe un programa que reciba una cadena de texto y devuelva las palabras únicas que contiene,
+ * ignorando mayúsculas, minúsculas y signos de puntuación. Además, muestra cuántas veces aparece cada palabra repetida.
+ * Condiciones:
+ * - El programa debe ignorar signos de puntuación como , . ; : ! ?.
+ * - No debe diferenciar entre mayúsculas y minúsculas (Hola y hola cuentan como la misma palabra).
+ * - Devuelve un listado de palabras ordenado alfabéticamente junto con su frecuencia.
+ */
+
+function contarPalabras(texto) {
+    // Quitar signos de puntuación y convertir a minúsculas
+    const limpio = texto.replace(/[.,;:!?\(\)]/g, "").toLowerCase();
+    const palabras = limpio.split(/\s+/);
+
+    const contador = {};
+    palabras.forEach((palabra) => {
+        contador[palabra] = (contador[palabra] || 0) + 1;
+    });
+
+    const ordenado = Object.keys(contador).sort();
+    ordenado.forEach((palabra) => {
+        console.log(`${palabra}: ${contador[palabra]}`);
+    });
+}
+
+contarPalabras("Hola mundo! Hola a todos en este hermoso mundo.");
diff --git a/soluciones-javascript/53-fizz-buzz-v2/index.js b/soluciones-javascript/53-fizz-buzz-v2/index.js
new file mode 100644
index 000000000..74c9fb1e4
--- /dev/null
+++ b/soluciones-javascript/53-fizz-buzz-v2/index.js
@@ -0,0 +1,24 @@
+/*
+ * Escribe un programa que muestre por consola (con un print) los
+ * números de 1 a 100 (ambos incluidos y con un salto de línea entre
+ * cada impresión), sustituyendo los siguientes:
+ * - Múltiplos de 3 por la palabra "fizz".
+ * - Múltiplos de 5 por la palabra "buzz".
+ * - Múltiplos de 3 y de 5 a la vez por la palabra "fizzbuzz".
+ */
+
+const fizzBuzz = () => {
+    for (let i = 1; i <= 100; i++) {
+        if( i % 3 === 0 && i % 5 === 0){
+            console.log("fizzbuzz");
+        } else if( i % 3 === 0){
+            console.log("fizz");
+        } else if( i % 5 === 0 ){
+            console.log("buzz");
+        } else {
+            console.log(i);
+        }
+    }
+}
+
+fizzBuzz();
\ No newline at end of file
diff --git a/soluciones-javascript/54-el-lenguaje-hacker/index.js b/soluciones-javascript/54-el-lenguaje-hacker/index.js
new file mode 100644
index 000000000..25ca7e74d
--- /dev/null
+++ b/soluciones-javascript/54-el-lenguaje-hacker/index.js
@@ -0,0 +1,55 @@
+/*
+ * Escribe un programa que reciba un texto y transforme lenguaje natural a
+ * "lenguaje hacker" (conocido realmente como "leet" o "1337"). Este lenguaje
+ *  se caracteriza por sustituir caracteres alfanuméricos.
+ * - Utiliza esta tabla (https://www.gamehouse.com/blog/leet-speak-cheat-sheet)
+ *   con el alfabeto y los números en "leet".
+ *   (Usa la primera opción de cada transformación. Por ejemplo "4" para la "a")
+ */
+
+const leetTable = {
+    a: "4",
+    b: "8",
+    c: "(",
+    d: "|)",
+    e: "3",
+    f: "|=",
+    g: "6",
+    h: "#",
+    i: "1",
+    j: "_|",
+    k: "|<",
+    l: "1",
+    m: "|\\/|",
+    n: "|\\|",
+    o: "0",
+    p: "|*",
+    q: "0_",
+    r: "|2",
+    s: "5",
+    t: "7",
+    u: "|_|",
+    v: "\\/",
+    w: "\\/\\/",
+    x: "><",
+    y: "`/",
+    z: "2",
+};
+
+/**
+ * 
+ * @param {String} sentence
+ */
+const convertirTextoALenguajeHacker = (sentence) => {
+
+    return sentence.split('').map((char) => {
+        const lowerChar = char.toLowerCase();
+        if(leetTable[lowerChar]){
+            return char === lowerChar ? leetTable[lowerChar] : leetTable[lowerChar].toUpperCase();
+        }
+        return char;
+    }).join('');
+
+};
+
+console.log(convertirTextoALenguajeHacker("Hacker"));
\ No newline at end of file