Newer
Older
ournorth2021 / test.html
LuisOlaya on 8 Apr 2021 8 KB primer
<!DOCTYPE html>
<html lang="en" >

<head>
    <meta charset="UTF-8">
    <title>Crucigrama OurNorth</title>
  
    <link href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta.2/css/bootstrap.css'> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.18/vue.min.js"></script>

<style>
    
    /*Downloaded from https://www.codeseek.co/arandaschimpf/crucigrama-vRgKZP */
.container {
  margin-top: 3vh;
}

.table-container {
  display: flex;
  flex-direction: column;
  align-items: center;
}

table {
  border-collapse: collapse;
  font-size: 18px;
}

td {
  width: 36px;
  height: 36px;
  border: 1px solid black;
  text-align: center;
  position: relative;
  text-transform: uppercase;
  font-family: arial;
}

td.empty {
  background: #ff9f55;
    background: #ffffff;
    border: 0;
}

td.selected {
  background: lightblue;
}

td.start {
  cursor: pointer;  
}

td.start label {
  position: absolute;
  top: 0;
  left: 2px;
  text-align: left;
  font-size: 10px;
}

td.start:hover {
  background: #eee;
}

td.start.selected:hover {
  background: #ddf;
}

.mensaje {
  position: absolute;
  color: white;
  left: 25vw;
  text-align: center;
  border-radius: 8px;
  padding: 10px;
  width: 50vw;
  z-index: 1000;
  background: rgba(0, 0, 255, 0.9)
}

.mensaje button {
  margin-top: 10px;
}
    </style>

  
</head>

<body>
    
    <div align="center"><h2>De click sobre el número para activar el cricigrama</h2></div>

  <div id="app" class="container" @keyup.escape="selected = undefined">
  <div class="table-container" style="display:none;" v-show="true">
    <div class="timer">{{cronometro}}</div>
    <div class="mensaje" v-if="mensaje !== undefined">
      <div class="content">{{mensaje}}</div>
      <button @click="mensaje = undefined" class="btn btn-primary">OK</button>
    </div> 
    <table>
      <tr v-for="(row, y) in matrix" :key="y">
        <td v-for="(cell, x) in row" :class="{empty: cell.empty, start: !!cell.start, selected: cell.words.includes(selected)}" @click="selectWord(cell.start)">
          <label v-if="!!cell.start">{{cell.start}}</label>
          {{cell.words.some(i => completed[i]) ? cell.letter : ' '}}
        </td>
      </tr>
    </table>
    <div v-if="selected !== undefined" style="text-align: center;">
      <p class="pista" v-if="pista">
        {{pista}}
      </p>
      <input v-model="answer" ref="input" @keyup.enter="corregir"/>
      <button @click="corregir" class="btn btn-primary">Colocar</button>
      <button @click="solucion" class="btn btn-danger">Pista</button>
    </div>
    <hr>
    <button class="btn btn-block btn-primary" @click="finalizar">Finalizar</button>
  </div>  
  <h3 v-show="false">Cargando....</h3>
</div>
  <script src='https://unpkg.com/vue'></script>

  

    <script>
    /*Downloaded from https://www.codeseek.co/arandaschimpf/crucigrama-vRgKZP */
// Arreglo de palabras indicando la posición de su inicio, su sentido (vertical u horizontal),
// la palabra en cuestión y la pista que se presenta al usuario
const palabras = [
  {
    pos: [0, 0],
    sentido: 0,
    palabra: 'gravedad',
    pista: 'Fuerza que nos mantiene unidos a la superficie del planeta'
  },
  {
    pos: [2, 0],
    sentido: 1,
    palabra: 'agua',
    pista: 'Compuesta por dos moléculas de hidrógeno y una de oxígeno'
  },
  {
    pos: [0, 3],
    sentido: 0,
    palabra: 'plantas',
    pista: 'Renuevan el aire que respiramos'
  },
  {
    pos: [4, 3],
    sentido: 1,
    palabra: 'tierra',
    pista: 'Planeta en donde vivimos'
  },
  {
    pos: [0, 5],
    sentido: 0,
    palabra: 'oxigeno',
    pista: 'Gas incoloro e inodoro esencial para la vida'
  },
    {
    pos: [1, 8],
    sentido: 0,
    palabra: 'casa',
    pista: 'Donde Vivimos'
  }
]

// Objeto default para celdas vacías de la grilla
const empty = {
  start: false,
  letter: '',
  words: [],
  empty: true
}

new Vue({
  el: '#app',
  data () {
    return {
      // Arreglo de booleanos indicando si una palabra fue completada
      completed: Array(palabras.length).fill(false),
      // Entero indicando la palabra que fue seleccionada para completar
      selected: undefined,
      // String donde se guarda lo que ingresa el usuario
      answer: '',
      // Cantidad de veces que se solicitó una pista
      penalties: 0,
      // Temporizador en segundos desde el comienzo de la partida. Comienza en 5 minutos.
      timer: 60 * 5,
      // La tabla que será armada al inicio, conteniendo todas las celdas
      matrix: [],
      // Mensaje final a mostrar
      mensaje: undefined
    }
  },
  created () {
    // Creación de la tabla que contiene las celdas.
    const width = palabras.reduce((max, cur) => 
                                  Math.max(max, cur.pos[0] + (cur.sentido === 0 ? cur.palabra.length : 1)), 0)
    const height = palabras.reduce((max, cur) => 
                                  Math.max(max, cur.pos[1] + (cur.sentido === 1 ? cur.palabra.length : 1)), 0)
    let matrix = Array(height).fill(0).map(() => Array(width).fill(null).map(() => empty))
    palabras.forEach((palabra, index) => {
      const [x, y] = palabra.pos
      palabra.palabra.split('').forEach((l, i) => {
        let cell = matrix[y + (palabra.sentido ? i : 0)][x + (palabra.sentido ? 0 : i)]
        if (cell === empty) {
          cell = matrix[y + (palabra.sentido ? i : 0)][x + (palabra.sentido ? 0 : i)] = {words: []}
        }
        cell.empty = false
        cell.words.push(index)
        if (i === 0) {
          cell.start = index + 1
        }
        cell.letter = l
      })
    })
    this.matrix = matrix
    
    // Control del temporizador y disparador del evento final cuando éste se acabe
    this.$options.interval = setInterval(() => {
      this.timer--
      if (this.timer <= 0) {
        clearInterval(this.$options.interval)
        this.finalizar()
      }
    }, 1000)
  },
  computed: {
    // Contiene la pista de la palabra seleccionada
    pista () {
      if (this.selected === undefined) return undefined
      return `${palabras[this.selected].sentido ? 'Vertical' : 'Horizontal'} ${this.selected + 1}: ${palabras[this.selected].pista}`
    },
    // Formato a mostrar del cronómetro
    cronometro () {
      const minutes = Math.floor(this.timer/60).toString().padStart(2, '0')
      const seconds = Math.floor(this.timer%60).toString().padStart(2, '0')
      return `${minutes}:${seconds}`
    }
  },
  methods: {
    selectWord (index) {
      if (index > 0) {
        this.selected = index - 1
        this.answer = ''
        setTimeout(() => this.$refs.input.focus(), 50)
      }
    },
    // Se fija si la palabra ingresada es correcta y de ser así, modifica el arreglo de palabras completas
    corregir () {
      const solucion = palabras[this.selected].palabra
      const answer = this.answer.toLowerCase()
      if (answer === solucion) {
        this.completed[this.selected] = true
        this.selected = undefined
      }
    },
    // Agrega una letra correcta más a la respuesta actual
    solucion () {
      const solucion = palabras[this.selected].palabra
      const answer = this.answer.toLowerCase()
      if (answer === solucion) {
        return
      }
      if (answer !== solucion.slice(0, answer.length)) {
        this.penalties++
        this.answer = ''
      }
      this.answer = solucion.slice(0, this.answer.length + 1)
      this.penalties++
    },
    // Calcula el puntaje final del jugador en base a las respuestas correctas y las penalidades por pistas
    finalizar () {
      const total = this.completed.reduce((total, current, i) => total + palabras[i].palabra.length, 0)
      const completo = this.completed.reduce((total, current, i) => current ? total + palabras[i].palabra.length : total, 0)
      const tempScore = Math.ceil(100 * completo / total)
      const finalScore = Math.max(tempScore - this.penalties, 0)
      if (tempScore < 100) {
        this.penalties++
      }
      this.mensaje = `
        Tu puntuación es ${finalScore}%.
      `
    }
  }
})
    
    
    
    </script>




</body>

</html>