3

#PlatziCodingChallenge - Programa una Torre de Jenga Aleatoria

Crea un programa que emule la torre de Jenga usando arreglos bidimensionales.

El jugador debe ser capáz de elegir la posición de la ficha que quiere sacar y el programa debe decidir aleatoriamente si la torre se cae o no.
Además, la probabilidad de que la torre se caiga aleatoriamente debe aumentar cuando se está desequilibrada. Tú puedes determinar cuándo y qué tanto la torre está desequilibrada.
Por ejemplo, si dentro de un rango de 4 filas han sacado 3 fichas a la izquierda y ninguna a la derecha, la probabilidad de caerse al tratar de sacar una ficha debe aumentar.

El programa debe recordar la máxima cantidad de movimientos que logró hacer el jugador antes de que la torre se cayera. Y cada vez que supere su record, aumentar la cantidad de filas a las torres Jenga de los próximos juegos.

Escribe tu comentario
+ 2
2
19943Puntos

Torre de Jenga en JavaScript
Este reto fue divertido pero complicado, asi que implementé el código en una página para que lo puedan ver
https://cristianiniguez.github.io/PlatziCodingChallenge/PlatziCodingChallenge_Dia63/

// Torre de Jenga Aleatoria en JavaScriptconst $jengaContainer = document.querySelector('.jenga-container')

const $messageBox = document.querySelector('.message-box')

let juegoJenga

$messageBox.addEventListener('click', iniciar)

functioniniciar() {
  let numPisos = parseInt(prompt('¿Cuántos pisos quieres?'))
  if (isNaN(numPisos) || numPisos <= 0) {
    alert('Debes ingresar un número mayor que 0')
  } else {
    juegoJenga = new TorreJenga(numPisos)
    $messageBox.removeEventListener('click', iniciar)
    $messageBox.innerHTML = 'Piezas sacadas: <span id="num-intentos">0</span>'
  }
}

functionarraysIguales(array1, array2) {
  if (array1.length === array2.length) {
    return array1.every((el, i) => el === array2[i])
  } else {
    returnfalse
  }
}

functioneventoClickPiezas() {
  const $piezas = document.querySelectorAll('.pieza')
  $piezas.forEach(pieza => {
    pieza.addEventListener('click', e => {
      const { piso, lugar, lleno } = e.target.dataset
      if (lleno) {
        if (!juegoJenga.moverPieza(piso, lugar)) {
          juegoJenga = null
          $jengaContainer.innerHTML = ''
          $messageBox.addEventListener('click', iniciar)
          $messageBox.innerHTML = 'Inicar Juego'
        }
      } else {
        alert('No hay pieza ahí')
      }
    })
  })
}

classTorreJenga{
  constructor(pisos) {
    this.crearTorre(pisos)
    this.jugadas = 0this.dibujarTorre()
  }
  crearTorre(pisos) {
    this.pisos = newArray()
    for (let i = 0; i < pisos; i++) {
      this.pisos.push([1, 1, 1])
    }
  }
  dibujarTorre() {
    $jengaContainer.innerHTML = ''this.pisos.forEach((piso, i) => {
      let caraPiezasHTML = `
        <div class="cara-piezas">
          <div class="pieza" data-piso=${i} data-lugar=${0} data-lleno=${piso[0] === 1}>I</div>
          <div class="pieza" data-piso=${i} data-lugar=${1} data-lleno=${piso[1] === 1}>C</div>
          <div class="pieza" data-piso=${i} data-lugar=${2} data-lleno=${piso[2] === 1}>D</div>
        </div>
      `let caraLadoHTML = `
        <div class="cara-lado">
          <div class="lado">${i}</div>
        </div>
      `let pisoHTML = i % 2 == 0
        ? `<div class="piso">${caraPiezasHTML}${caraLadoHTML}</div>`
        : `<div class="piso">${caraLadoHTML}${caraPiezasHTML}</div>`
      $jengaContainer.innerHTML = pisoHTML + $jengaContainer.innerHTML
      eventoClickPiezas()
    })
  }
  moverPieza(piso, lugar) {
    if (piso < this.pisos.length - 1) { // Las piezas del último piso no se pueden moverthis.pisos[piso][lugar] = 0// Dejando vacío el lugar donde estaba esa piezaconst ultimoPiso = this.pisos[this.pisos.length - 1]
      if (arraysIguales(ultimoPiso, [1, 1, 1])) { // Modificando o agregando el último pisothis.pisos.push([1, 0, 0])
      } elseif (arraysIguales(ultimoPiso, [1, 1, 0])) {
        this.pisos[this.pisos.length - 1] = [1, 1, 1]
      } elseif (arraysIguales(ultimoPiso, [1, 0, 0])) {
        this.pisos[this.pisos.length - 1] = [1, 1, 0]
      }
      if (!this.seCae()) { // Calculando si se caethis.jugadas++
        this.imprimirJugadas()
        this.dibujarTorre()
        returntrue
      } else {
        alert('La torre se cayó. Fin del juego')
        returnfalse
      }
    } else {
      alert('No se puede mover una pieza del último piso')
      returntrue
    }
  }
  seCae() {
    const prob = this.probabilidadDeNoCaerse()
    returnMath.random() > prob
  }
  probabilidadDeNoCaerse() {
    let vacios = [
      [0, 0, 0], // Lado 0 (Izq) -> [Izq, Cen, Der]
      [0, 0, 0] // Lado 1 (Der) -> [Izq, Cen, Der]
    ]
    for (let i = 0; i < this.pisos.length - 1; i++) { // Por cada piso (menos el último)const piso = this.pisos[i];
      if (piso.filter(pieza => pieza === 1).length === 1 && !arraysIguales(piso, [0, 1, 0])) {
        return0
      }
      piso.forEach((pieza, j) => { // Por cada piezaif (pieza === 0) { // Si no hay pieza
          vacios[i % 2][j]++
        }
      })
    }
    // Calculando la probabilidad de no caersereturn vacios.map(lado => 1 - (Math.abs(lado[0] - lado[2]) / this.pisos.length)).reduce((a, b) => a * b)
  }
  imprimirJugadas() {
    const $spanIntentos = document.querySelector('#num-intentos')
    $spanIntentos.innerHTML = this.jugadas
  }
}
2
7689Puntos

Resuelto con js, creo que me complique mucho en ciertas cosas, pero al menos lo hice, cumplo con todos los puntos del reto.

<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Slides</title></head><style>
  * {
    margin: 0;
  }

  .contenedor {
    display: flex;
    flex-direction: column;
    align-items: center;
    height: 100vh;
    min-width: 600px;
  }

  .grid {
    display: grid;
    grid-template-rows: repeat(18, auto);
    grid-template-columns: 50%50%;
    margin: 10px;
  }

  .section {
    min-width: 300px;
    display: flex;
    justify-content: space-around;
  }

  .btn {
    border: 2px solid black;
    border-radius: 6px;
    cursor: pointer;
    padding: 10px;
    margin: 5px;
    width: 100%;
  }

  .btn-n {
    cursor: not-allowed;
  }

</style><body><divclass="contenedor"><h1style="margin: 12px;">Juego de Jenga</h1><divclass="grid"><sectionclass="section">Frontal</section><sectionclass="section">Lado</section></div><divid='torre'class="grid"></div></div><script>// Clase para los bloques del jengaclassBoton{
      constructor(id){
        this.id = id
        this.sacado = false
      }
    }

    let botones = []
    let intentos = 0let intentosMemoria = 0let filas = 6let torre = document.getElementById('torre')
    // Crea la torre al inicio para jugar inmediatamentefor (let i = 0; i < filas; i++){
      if (i % 2 === 0){
        crearFila(i, true)
      } else {
        crearFila(i, false)
      }
    }
    // Esta función me permite crear la torre, teniendo en cuenta el contador i como la fila y el booleano para saber que cara toca, si frontal o ladofunctioncrearFila(i, bool){
      let section1 = document.createElement('section')
      section1.style = "background-color: rgba(0, 110, 255, 0.5);"
      section1.classList = 'section'for (let x = 0; x < 3; x++){
        let button = document.createElement('button')
        button.classList = 'btn'
        button.id = parseInt(filas - i) + '_' + parseInt(x+1)
        button.innerHTML = parseInt(x+1)
        button.addEventListener('click', sacarBoton)
        botones.push(new Boton(parseInt(filas - i) + '_' + parseInt(x+1)))
        section1.appendChild(button)
      }
      let section2 = document.createElement('section')
      section2.style = "background-color: rgba(255, 200, 135, 0.5);"
      section2.classList = 'section'let button = document.createElement('button')
      button.classList = 'btn btn-n'
      button.innerHTML = filas - i
      button.disabled = true
      section2.appendChild(button)
      if (bool){
        torre.appendChild(section1)
        torre.appendChild(section2)
      } else {
        torre.appendChild(section2)
        torre.appendChild(section1)
      }
    }
    // Aquí se hace la validación de que no saquen las fichas de arriba y da paso a que se compruebe si se cae o no la torrefunctionsacarBoton(){
      let botonSelec = document.getElementById(this.id)
      console.log(botonSelec.id, filas)
      if (botonSelec.id === `${filas}_1` || botonSelec.id === `${filas}_2` || botonSelec.id === `${filas}_3`){
        alert('No se puede sacar la ficha de arriba')
      } else {
        intentos++  
        botonSelec.disabled = true
        botonSelec.classList = 'btn btn-n'
        botones.forEach(boton => {
          if (boton.id === botonSelec.id){
            boton.sacado = true
          }
        });
        comprobarCentro(this.id)
        comprobarLados()
      }
    }
    // Aquí se comprueba si es que hace falta la ficha del centro y se saca un lado o viceversa, si se saca el centro y hace falta el ladofunctioncomprobarCentro(id){
      let pulsado = id.split('_')
      if(pulsado[1] === '1' || pulsado[1] === '3'){
        if((botones.find(boton => boton.id === `${pulsado[0]}_2`)).sacado === true){
          resetear()
        }
      } else {
        if((botones.find(boton => boton.id === `${pulsado[0]}_1`)).sacado === true || (botones.find(boton => boton.id === `${pulsado[0]}_3`)).sacado === true){
          resetear()
        }
      }
    }
    // Aquí se comprueban los 2 lados de cada perspectiva, osea frontal y ladofunctioncomprobarLados(){
      let izquierdaFrontal = 0let derechaFrontal = 0let izquierdaLado = 0let derechaLado = 0let frontalesIzquierdos = botones.filter(boton => boton.id.split('_')[1] === '1' && (boton.id.split('_')[0] % 2 === 0))
      let frontalesDerechos = botones.filter(boton => boton.id.split('_')[1] === '3' && (boton.id.split('_')[0] % 2 === 0))
      let ladoIzquierdos = botones.filter(boton => boton.id.split('_')[1] === '1' && (boton.id.split('_')[0] % 2 !== 0))
      let ladoDerechos = botones.filter(boton => boton.id.split('_')[1] === '3' && (boton.id.split('_')[0] % 2 !== 0))

      // Aquí se comprueba si es que aún se puede sostener por los lados dependiendo de la cara, solo soporta 3 máximo, al sacar el 5 de dicho lado, se cae la torre
      comprobar(izquierdaFrontal, frontalesIzquierdos)
      comprobar(derechaFrontal, frontalesDerechos)
      comprobar(izquierdaLado, ladoIzquierdos)
      comprobar(derechaLado, ladoDerechos)

      functioncomprobar(contador, perspectiva){
        perspectiva.forEach(boton => {
          if (boton.sacado === true){
            contador++
          } else {
            contador = 0
          }
          if (contador > 3){
            resetear()
          }
        })
      }
    }

    let primerjuego = false// Aquí se resetea todo y si le suman dos filas hasta que llega a 18, una vez que llega ahí, se termina el juegofunctionresetear(){
      if (intentos - 1 > intentosMemoria && primerjuego === true){
        alert(`Tuviste ${intentos-1} aciertos antes de que se destruya la torre y superaste tu record anterior que era ${intentosMemoria}`)
        intentosMemoria = 0
        intentos = 0
        filas = filas + 2if (filas <= 18){
          torre.innerHTML = ''
          botones = []
          // Aquí se genera la nueva torre de jenga con la nueva cantidad de filasfor (let i = 0; i < filas; i++){
            if (i % 2 === 0){
              crearFila(i, true)
            } else {
              crearFila(i, false)
            }
          }
          primerjuego = false
        } else {
          torre.innerHTML=''
          alert('Se acabo el juego!')
        }
      } elseif (primerjuego === false) {
        alert(`Tuviste ${intentos-1} aciertos antes de que se destruya la torre`)
        primerjuego = trueif (!(intentosMemoria >= intentos)){
          intentosMemoria = intentos - 1
        }
        intentos = 0if (filas <= 18){
          torre.innerHTML = ''
          botones = []
          // Aquí se genera la nueva torre de jenga con la nueva cantidad de filasfor (let i = 0; i < filas; i++){
            if (i % 2 === 0){
              crearFila(i, true)
            } else {
              crearFila(i, false)
            }
          }
        } else {
          torre.innerHTML=''
          alert('Se acabo el juego!')
        }
      } else {
        alert(`Tuviste ${intentos-1} aciertos antes de que se destruya la torre pero no superaste tu record anterior que era ${intentosMemoria}`)
        if (!(intentosMemoria >= intentos)){
          intentosMemoria = intentos - 1
        }
        intentos = 0if (filas <= 18){
          torre.innerHTML = ''
          botones = []
          // Aquí se genera la nueva torre de jenga con la nueva cantidad de filasfor (let i = 0; i < filas; i++){
            if (i % 2 === 0){
              crearFila(i, true)
            } else {
              crearFila(i, false)
            }
          }
        } else {
          torre.innerHTML=''
          alert('Se acabo el juego!')
        }
      }
    }
  </script></body></html>