
# death-games

> Éste módulo proporciona herramientas para crear pequeños juegos, diseñado principalmente para bots de
> discord.js

  
### Nuevo juego
```javascript
const  Death = require("death-games")
const  game = new Death.<GAME>(opciones)
```
## Shortcuts
 > * [**Hangman**](https://www.npmjs.com/package/death-games#hangman)
 > * [**Russian-Roulette**](https://www.npmjs.com/package/death-games#russianroulette)
 > * [**Buscaminas**](https://www.npmjs.com/package/death-games#buscaminas)
  

# Hangman  

###  PARÁMETROS:

* **Frase**: String con la frase del juego

**OPCIONES:**

* **jugadores**: Array con las ID's de los jugadores del juego actual

* **lowerCase**: true o false, true para que las letras maýusculas en la frase sean descubiertas con minúsculas y visceversa, false para restringir que las mayúsculas se encuentren con letras mayúsculas, y las minúsculas con minúsculas 
> *Default: true*

 * **vidas**: Número con el número de intentos antes de que el juego se pierda automáticamente
> *Default: 7*

**EVENTOS:**

* **end**: 
> **Retorna:** Objeto con la configuración del juego actual


```javascript
//Configuración del juego actual:

game : {
palabra: String, //La frase definida en los parámetros del juego
jugadores: Array, //El array con las ID's de los jugadores definidos en las opciones
lowercase: Boolean, //true si las letras mayusculas pueden ser descubiertas con las minúsculas y visceversa
vidas: Number, //Numero de intentos restantes
turno: String, //String con la ID del jugador del turno actual, (las ID's se especifican en la opción jugadores)
ascii: Array, //Array con el juego ascii: ['_','_','_']
letrasUsadas: Array, //Array con todas las letras que se han usado en el juego actual
letrasIncorrectas: Array, //Array con las letras que ya estaban puestas o que no se encontraban en la frase (puede ser usado para evitar que repitan letras, dándole uso en el colector)
ended: Boolean, //true si el juego ya ha acabado, de lo contrario false
winned: Boolean; //true si se descubrió la palabra por completo, de lo contrario false
}
``` 

**EJEMPLO HANGMAN:**
```javascript
//Ejemplo usando el módulo discord.js
  
const  Death = require("death-games");

let  author = [message.author.id]
let  menciones = message.mentions.users.map(x  =>  x.id);
let  jugadores = author.concat(menciones); //Un array donde el primer elemento es el autor del mensaje, los demás los usuarios mencionados

if(!menciones.length) return  message.channel.send("Tienes que mencionar mínimo a una persona!")
if(menciones.includes(message.author.id)) return message.channel.send("No te puedes mencionar a ti mismo!")
if(message.mentions.users.map(x => x.bot).some(x => x)) return message.channel.send("No puedes mencionar a un bot!")
//*Nota:* El elemento 0 del array jugadores es el que elige la frase!

  const  canal = await  message.author.createDM() //Puedes definir un canal a donde se le preguntará la palabra al usuario

canal.send("Elige tu palabra")

let  palabra;
await  canal.awaitMessages(m  =>  m.author.id == message.author.id && m.content.replace(/[^A-Za-z0-9ñ ]/g,"").length,
{max:  1, time:  20000, errors:["time"]}).then(collected  => {
palabra = collected.first().content.replace(/[^A-Za-z0-9ñ ]/g,"")
}).catch(() =>  canal.send("Tiempo agotado!"))
if(!palabra) return

const  ahorcado = new  Death.Hangman(palabra, {jugadores:  jugadores, lowerCase:  true, vidas: 7})

ahorcado.on("end", game  => {

if(game.winned){ //Si el juego ha terminado y se ha descubierto toda la frase

message.channel.send("El juego ha finalizado! La frase era: **"+game.palabra+"**\n"+
"Descubierto por: **"+client.users.cache.get(game.turno).tag+"**\n\n```"+game.ascii.join(" ")+"```")
return;

}else{ //Si ha terminado pero no han descubierto la frase

message.channel.send("Han perdido! La frase era: **"+game.palabra+"**\n"+
"Último error: **"+client.users.cache.get(game.turno).tag+"**\n\n```\n"+game.ascii.join(" ")+"```")

}

})

message.channel.send(message.author.toString()+" ha elegido su palabra!\n\n"+
"```\n"+ahorcado.game.ascii.join(" ")+"```**Empieza "+client.users.cache.get(ahorcado.game.turno).tag+"**")

const  colector = message.channel.createMessageCollector(msg  =>  msg.author.id == ahorcado.game.turno && /[A-Za-z0-9ñ]/.test(msg.content) && msg.content.length == 1);

colector.on('collect', msg  => {

let encontrado = ahorcado.find(msg.content) //Usamos el método find() para encontrar una letra en la frase, éste retorna true si se encuentra, false si no

if(ahorcado.game.ended){
colector.stop()
return;
}

if(!encontrado) message.channel.send("- Vaya! Parece que la letra "+msg.content+" no se encontraba en la frase!\nLetras incorrectas: **["+ahorcado.game.letrasIncorrectas.join(", ")+"]**")

message.channel.send("```\n"+ahorcado.game.ascii.join(" ")+"\n```**Turno de "+client.users.cache.get(ahorcado.game.turno).tag+"**\nIntentos restantes: **"+ahorcado.game.vidas+"**")

})
```




# RussianRoulette

**OPCIONES:**

* **jugadores**: Array con las ID's de los jugadores del juego actual

* **slots**: Número de huecos en el tambor del revólver
> *Default: 6*

**EJEMPLO RUSSIAN ROULETTE:**
```javascript 
//Un ejemplo del constructor Roulette usando el módulo discord.js

const Death = require("death-games")

  let  author = [message.author.id] //Hacemos que el jugador N.1 siempre sea el autor del mensaje
  let  menciones = message.mentions.users.map(x  =>  x.id); //Obtenemos las ID's de las personas mencionadas
  let  jugadores = author.concat(menciones); //Juntamos ambos arrays en uno mismo

  if(menciones.includes(message.author.id)) return message.channel.send("No te puedes mencionar a ti mismo!")
  if(message.mentions.users.map(x => x.bot).some(x => x)) return message.channel.send("No puedes mencionar a un bot!")

const ruleta = new Death.Roulette({jugadores: jugadores}) //Creamos el juego con el array de ID's de los jugadores, si no hay mencionados sólo juega el autor del mensaje

message.channel.send("Empieza "+message.author.toString())

const colector = message.channel.createMessageCollector(msg => ruleta.game.turno == msg.author.id && !isNaN(msg.content)) 

colector.on('collect', msg  => { //Creamos un colector de mensajes 

if(!Number.isSafeInteger(+(msg.content))) return msg.reply("Necesitas introducir un número más pequeño!") //Si el número es excesivamente grande

let muertoXD = ruleta.elegir(msg.content) //Elegimos el número de veces a girar el tambor del revólver
if(muertoXD){ 
  message.channel.send(msg.author.toString()+" ha muerto! Se ha acabado la ronda!")
  colector.stop()
  return;
}else{
  message.channel.send("Parece que "+msg.author.toString()+" se ha salvado!\nTurno de "+message.guild.members.cache.get(ruleta.game.turno).user.toString()+"\n"+
  "Posición actual: "+ruleta.game.posicion+", Bala: "+ruleta.game.bala)
}

})
```

# Buscaminas

**OPCIONES:**

* **largo**: El número de casillas del largo del tablero (max: 15)
> *Default: 7*

* **ancho**: El número de casillas del ancho del tablero (max: 9)
> *Default: 7*

* **bombas**: Número de bombas que se esparcirán por el tablero
> *Default: 10*

* **charOculto**: Carácter que se usará para las casillas ocultas (no descubiertas)
> *Default: x*

* **chars**: Array con los carácteres que se usarán en el juego (ordenados), si alguno no se proporciona, los carácteres no proporcionados serán los Default
> *Default: [0,1,2,3,4,5,6,7,8,💥]*

**EVENTOS:**

* **win**: 
> **Retorna:** Objeto con la configuración del juego actual


```javascript
//Configuración del juego actual:

game: {
 tablero: {
  largo: Number, //El largo del tablero
  ancho: Number, //El ancho del tablero
  casillas: Number //El total de casillas del tablero (largo * ancho)
          },
 bombas: Number, //El número de bombas colocadas
 open: Array, //El juego sin casillas ocultas (ascii pero todo descubierto)
 ascii: Array, //El juego con las casillas ocultas, se modifica mientras se van descubriendo casillas
 descubiertos: Array, //El juego con las coordenadas descubiertas
 winned: Boolean //true si se han descubierto todas las casillas que no son bombas
           }
      }
``` 

**EJEMPLO BUSCAMINAS:**

```javascript
//Ejemplo de minesweeper usando el módulo discord.js

const Discord = require("discord.js") //Para los embeds
const Death = require("death-games")

const largo = 7
const ancho = 7
const bombas = 10

const caracteres = [":black_large_square:",":one:",":two:",":three:",":four:",":five:",":six:",":seven:",":eight:", ":boom:"]
//Definimos los carácteres que aparecerán en el tablero, casillas vacías, número de bombas adyacentes y el emoji de la bomba

const numerosLaterales = [":black_large_square:",":one:",":two:",":three:",":four:",":five:",":six:",":seven:",":eight:", ":nine:"] 
//Creamos un array con los emojis de las coordenadas del eje Y

   const buscaminas = new Death.Buscaminas({largo: largo, ancho: ancho, bombas: bombas, charOculto: ":x:", chars: caracteres})
  
let coordsLetras = [ [":regional_indicator_a:",":regional_indicator_b:",":regional_indicator_c:",":regional_indicator_d:",
":regional_indicator_e:",":regional_indicator_f:",":regional_indicator_g:",":regional_indicator_h:",
":regional_indicator_i:",":regional_indicator_j:",":regional_indicator_k:",":regional_indicator_l:",
":regional_indicator_m:",":regional_indicator_n:",":regional_indicator_o:"].slice(0, buscaminas.game.tablero.largo) ]
//Creamos un array con los emojis de las coordenadas del eje X

let tablero1 = coordsLetras.concat(buscaminas.game.ascii)
               .flatMap(x => x.join(" ")) //Ponemos las letras del eje X en el tablero

   let tablero2 = []           
               
 tablero1.forEach((x, i) => {
tablero2.push(numerosLaterales[i]+" "+x)
  }) //Ponemos los números del eje Y en el tablero


  message.channel.send(new Discord.MessageEmbed().setDescription(
    tablero2.join("\n")
  ).setColor("RANDOM")) //Mandamos el array del tablero ordenado

buscaminas.on("win", game => {
  message.channel.send("Eso paaaa, la re ganaste en un tablero de "+game.tablero.casillas+" casillas!")
  return;
})

  const colector = message.channel.createMessageCollector(msg => message.author.id == msg.author.id && msg.content.length == 2 && !buscaminas.game.descubiertos.includes(msg.content.toLowerCase()))  

  colector.on('collect', msg  => {

let encontrado = buscaminas.find(msg.content) //Buscamos la coordenada y la descubrimos
let tablero = buscaminas.game.ascii.flatMap(x => x.join(" ")).join("\n")

if(!encontrado){ //Si el encontrado es una bomba
  message.channel.send(new Discord.MessageEmbed().setTitle("Perdiste pa' :(").setDescription(
    tablero
   ).setColor("RANDOM"))
  colector.stop()
  return;
}


let tablero1 = coordsLetras.concat(buscaminas.game.ascii)
               .flatMap(x => x.join(" "))

   let tablero2 = []           
               
 tablero1.forEach((x, i) => {
tablero2.push(numerosLaterales[i]+" "+x)
  })


message.channel.send(new Discord.MessageEmbed().setDescription(
  tablero2.join("\n")
 ).setColor("RANDOM")) //Si no es una bomba, mandamos el tablero actualizado

  })

```


# Actualizaciones
### 1.2.1
> * Se han agregado 2 nuevos juegos, **russian-roulette** y **buscaminas**
> * Se ha actualizado el README 
> * Se han arreglado problemas menores con el juego **hangman**


### 1.1.1
> * Se han corregido problemas con el evento **end**
> * Se ha arreglado un problema al establecer la frase
> * Se han corregido errores en el README
> * Se ha añadido 1 propiedad al constructor:
>   * **game.letrasIncorrectas**: Array


### 1.1.0
> * La función **Hangman.turno()** ahora pasa a **Hangman.game.turno**
> * Se ha arreglado un problema con los jugadores
> * Se ha corregido el README
> * Se ha arreglado un problema con la opción lowerCase.
> * Se han añadido 3 propiedades al constructor: 
>   * **game.vidas**: Number
>    * **game.winned**: Boolean
>     * **game.letrasUsadas**: Array 