tresenraya
Version:
Módulo para facilitar la creación del popular juego llamado tres en raya en tus proyectos
254 lines (171 loc) • 10.1 kB
JavaScript
const EventEmitter = require('events');
const mejorPos = require('./funciones/mejorPos.js');
module.exports.partidas = [];
module.exports.partida = class Partida extends EventEmitter {
constructor(opciones = { fichas: [ '❌', '⭕' ], jugadores: [ 'Jugador 1', 'Jugador 2' ], tablero: [ '1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣' ] }) {
super();
try {
if(!this['_comprobaciones'](opciones)) return;
} catch(e) {
throw new Error(e.message);
}
}
elegir(pos) {
if(this.finalizado) return false;//throw new Error('¡La partida ya ha finalizado!');
if(!pos) throw new Error('Debes especificar la posición en la que quieres que se añada la ficha (del 1 al 9)');
if(isNaN(pos) || (Number(pos) < 1 || Number(pos) > 9)) throw new TypeError(pos + ' no es un número válido (debes introducir un número del 1 al 9)');
if(this.opciones.fichas.includes(this.tablero.array[pos-1])) throw new Error('Ya hay una ficha posicionada en la posición ' + pos + ' del tablero. Recuerda usar el método llamado "disponible" para comprobar si ya hay una ficha posicionada en esa posición del tablero.');
this.turno.paso++;
this.tablero.array[pos-1] = this.opciones.fichas[this.opciones.jugadores.indexOf(this.turno.jugador)];
this.tablero.string = this.tablero.array.slice(0, 3).join(' ') + '\n' + this.tablero.array.slice(3, 6).join(' ') + '\n' + this.tablero.array.slice(6, 9).join(' ');
const selecciones = require('./jsons/selecciones.json').ganadoras;
if(selecciones.some(x => !x.some(p => this.opciones.fichas[this.opciones.jugadores.indexOf(this.turno.jugador)] != (this.tablero.array[p])))) {
this.perdedor = this.opciones.jugadores.find(x => x != this.turno.jugador);
this.emit('ganador', this.turno.jugador, this.tablero, this.turno.paso);
this.finalizado = true;
return;
}
let n = 0;
this.tablero.array.forEach(p => {
if(this.opciones.fichas.includes(p)) {
n++;
}
});
if(n >= 9) {
this.emit('empate', this.opciones.jugadores, this.tablero, this.turno.paso);
this.finalizado = true;
return;
}
this.turno.jugador = this.opciones.jugadores.find(x => x != this.turno.jugador);
this.turno.ficha = this.opciones.fichas[this.opciones.jugadores.indexOf(this.turno.jugador)];
const sels = require('./jsons/selecciones.json').mejorPos.slice(0, -4);/*[
{ ya: [0, 6], seleccion: 4 },
{ ya: [0, 2], seleccion: 2 },
{ ya: [0, 1], seleccion: 3 },
{ ya: [3, 4], seleccion: 6 },
{ ya: [6, 7], seleccion: 9 },
{ ya: [3, 6], seleccion: 1 },
{ ya: [4, 7], seleccion: 2 },
{ ya: [5, 8], seleccion: 3 },
{ ya: [0, 3], seleccion: 7 },
{ ya: [1, 4], seleccion: 8 },
{ ya: [2, 5], seleccion: 9 },
{ ya: [1, 2], seleccion: 1 },
{ ya: [4, 5], seleccion: 4 },
{ ya: [7, 8], seleccion: 7 },
{ ya: [3, 5], seleccion: 5 },
{ ya: [6, 8], seleccion: 8 },
{ ya: [1, 7], seleccion: 5 },
{ ya: [2, 8], seleccion: 6 },
{ ya: [0, 4], seleccion: 9 },
{ ya: [2, 4], seleccion: 7 },
{ ya: [0, 8], seleccion: 5 },
{ ya: [2, 6], seleccion: 5 },
{ ya: [4, 8], seleccion: 1 },
{ ya: [6, 4], seleccion: 3 },
{ ya: [0, 4], seleccion: 9 }
];*/
this.opciones.jugadores.slice(0, 2).forEach(j => {
let nums = [];
let n = 0;
const p = this.opciones.fichas[this.opciones.jugadores.indexOf(j)];
sels.filter(x => !x.ya.some(f => this.tablero.array[f] != p) && !this.opciones.fichas.includes(this.tablero.array[x.seleccion-1]))
.forEach((y) => {
if(!nums.includes((y.ya).reduce((a, b) => a.toString() + b.toString()))) {
nums.push((y.ya).reduce((a, b) => a.toString() + b.toString()));
n++;
}
});
//p = Math.floor((((/*this.opciones.tablero.filter(x => x === p).length*/n) + ((n) / 1.15)) * 100) / 9);
if(j == this.turno.jugador) {
this.turno.posibilidades = n;
}
const k = j.split(/ +/g).join('_').toLowerCase();
/*this.posibilidades[k] = {
porcentaje: p,
numero: n
}*/
this.posibilidades[k] = n;
});
}
disponible(pos) {
if(!pos) throw new Error('Debes especificar la posición en la que quieres verificar si está disponible para posicionar una ficha (número del 1 al 9)');
if(isNaN(pos) || (Number(pos) < 1 || Number(pos) > 9)) throw new TypeError(pos + ' no es un número válido (debes introducir un número del 1 al 9)');
return !(this.opciones.fichas.includes(this.tablero.array[pos-1]));
}
pasar() {
if(this.finalizado) throw new Error('La partida ha finalizado, no se puede pasar a otro turno.');//throw new Error('¡La partida ya ha finalizado!');
this.turno.paso++;
this.turno.jugador = this.opciones.jugadores.find(x => x != this.turno.jugador);
this.turno.ficha = this.opciones.fichas[this.opciones.jugadores.indexOf(this.turno.jugador)];
return true;
}
finalizar(razon = '') {
if(this.finalizado) return false;
this.finalizado = true;
this.emit('finalizado', this.opciones.jugadores, this.tablero, this.turno, (razon || ''));
return true;
}
mejorPos(favor) {
return mejorPos(this.tablero.array, this.opciones.fichas, (favor || 'x'));
}
_comprobaciones(opciones) {
if(!opciones.fichas) opciones.fichas = [ '❌', '⭕' ];
if(!opciones.jugadores) opciones.jugadores = [ 'Jugador 1', 'Jugador 2' ];
if(!opciones.tablero) opciones.tablero = [ '1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣' ];
if(Object.entries(opciones).filter(x => ['fichas', 'jugadores', 'tablero'].includes(x[0])).some(x => !(x[1] instanceof Array))) {
const opcion = Object.entries(opciones).filter(x => ['fichas', 'jugadores', 'tablero'].includes(x[0])).find(x => !(x[1] instanceof Array))[0];
throw new TypeError('No has introducido un Array en \'opciones.' + opcion + '\'');
return false;
}
if(!opciones.fichas[1]) throw new TypeError('Debes introducir dos valores en el array de fichas.');
if(opciones.fichas.slice(0, 2).some(x => typeof(x) !== 'string')) throw new TypeError('Algún valor de algún elemento del Array de fichas no es un String.');
if(opciones.fichas[0].toLowerCase() == opciones.fichas[1].toLowerCase()) {
const arrayString = (JSON.stringify(opciones.fichas)).split(',').join(', ');
throw new TypeError('Los valores de los elementos del array de fichas (' + arrayString + ') son iguales, deben ser diferentes.');
return false;
}
if(opciones.fichas.slice(0, 2).some(f => opciones.tablero.some(t => t.toLowerCase() == f.toLowerCase()))) {
throw new TypeError('Algún elemento del array opciones.tablero es igual a algún elemento del array opciones.fichas');
return false;
}
if(!opciones.jugadores[1]) throw new TypeError('Debes introducir dos valores en el array de jugadores.');
if(opciones.jugadores.slice(0, 2).some(x => typeof(x) !== 'string')) throw new TypeError('Algún valor de algún elemento del Array de jugadores no es un String.');
if(opciones.jugadores[0].toLowerCase() == opciones.jugadores[1].toLowerCase()) {
const arrayString = (JSON.stringify(opciones.jugadores)).split(',').join(', ');
throw new TypeError('Los valores de los elementos del array de jugadores (' + arrayString + ') son iguales, deben ser diferentes.');
return false;
}
if(!opciones.tablero[8]) throw new TypeError('Debes introducir nueve valores en el array tablero.');
if(opciones.tablero.slice(0, 9).some(x => typeof(x) !== 'string')) throw new TypeError('Algún valor de algún elemento del Array tablero no es un String.');
if(opciones.id) {
if(typeof(opciones.id) != 'string') throw new TypeError("Debes introducir un String en 'opciones.id'");
if(module.exports.partidas.includes(opciones.id)) throw new RangeError('Ya hay una partida iniciada con esa ID.');
module.exports.partidas.push(opciones.id);
}
opciones.fichas = opciones.fichas.slice(0, 2);
opciones.jugadores = opciones.jugadores.slice(0, 2);
opciones.tablero = opciones.tablero.slice(0, 9);
this.opciones = opciones;
this.tablero = { array: opciones.tablero, string: (opciones.tablero.slice(0, 3).join(' ') + '\n' + opciones.tablero.slice(3, 6).join(' ') + '\n' + opciones.tablero.slice(6, 9).join(' ')) };
this.turno = { jugador: (opciones.jugadores[Math.floor(Math.random() * 2)]), paso: 0, posibilidades: 0 };
this.turno.ficha = this.opciones.fichas[this.opciones.jugadores.indexOf(this.turno.jugador)];
this.perdedor = null;
this.finalizado = false;
this.posibilidades = {};
opciones.jugadores.slice(0, 2).forEach(j => {
const k = j.split(/ +/g).join('_').toLowerCase();
/*this.posibilidades[k] = {
porcentaje: 0,
numero: 0
};*/
this.posibilidades[k] = 0;
});
['ganador', 'empate', 'finalizado'].map(e => {
this.on(e, () => {
module.exports.partidas = module.exports.partidas.filter(id => id != opciones.id);
});
});
return true;
}
}