2020-12-31 17:23:58 +00:00
/ *
Força : um ( livre ) clone do jogo Forca
Copyright ( C ) 2020 luca0N !
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < https : //www.gnu.org/licenses/>.
Entre em contato comigo por e - mail via < luca0n @ luca0n . com > .
* /
class Sala {
/ * *
* Objeto Sala .
* @ param string sala O nome da sala .
* @ param Array A lista de clientes .
* @ param string O apelido do líder .
* @ param string O estado da sala .
* /
constructor ( sala , clientes , líder , estado , opções ) {
this . sala = sala ;
this . clientes = clientes ;
this . opções = opções ;
this . uas = Date . now ( ) ; // Última Ação Significante: marca o tempo em que um último evento significante tenha acontecido. Caso este evento tenha acontecido muito tempo atrás, esta sala será apagada.
this . líder = líder === undefined ? clientes [ 0 ] . apelido : líder ;
this . estado = estado === undefined ? "AGUARDANDO_JOGADORES" : estado ;
this . pontuaçãoMeta = 0 ;
this . tin = 0 ; // tentativas incorretas
this . jfr = [ ] ; // fila de jogadores para rodadas
this . banidos = [ ] ;
}
/ * *
* Inicia uma nova partida nesta sala .
* @ since 19 de outubro de 2020.
* /
novaPartida ( ) {
this . estado = 'EM_PARTIDA' ;
// Popular a fila JFR.
2021-01-03 02:13:51 +00:00
this . jf = [ ] ;
let tmpJf = [ ] ;
for ( let x = 0 ; x < this . clientes . length ; x ++ )
if ( this . clientes [ x ] . apelido !== this . vezDe )
tmpJf . push ( this . clientes [ x ] . apelido ) ;
2020-12-31 17:23:58 +00:00
2021-01-03 02:13:51 +00:00
for ( let x = tmpJf . length ; x > 0 ; x -- ) {
// Pegar um jogador aleatório da fila.
let num = Sala . gerarNúmeroAleatório ( tmpJf . length ) ;
this . jf . push ( tmpJf [ num ] ) ;
tmpJf . splice ( num , 1 ) ;
}
2020-12-31 17:23:58 +00:00
let tmpJfr = [ ] ; // JFR temporária, utilizado para popular a JFR verdadeira.
for ( let x = 0 ; x < this . clientes . length ; x ++ )
tmpJfr . push ( this . clientes [ x ] . apelido ) ;
for ( let x = tmpJfr . length ; x > 0 ; x -- ) {
// Pegar um jogador aleatório da fila.
let num = Sala . gerarNúmeroAleatório ( tmpJfr . length ) ;
this . jfr . push ( tmpJfr [ num ] ) ;
tmpJfr . splice ( num , 1 ) ;
}
this . novaRodada ( ) ;
}
/ * *
* Inicia uma nova rodada nesta sala , escolhendo um jogador aleatório .
* @ returns null
* @ since 05 de novembro de 2020.
* /
novaRodada ( ) {
this . lei = [ ] ; // Letras escolhidas inexistentes
this . lee = [ ] ; // Letras escolhidas existentes
2021-01-03 02:42:47 +00:00
this . pei = [ ] ; // Palavras escolhidas inexistentes
2020-12-31 17:23:58 +00:00
this . ldc = [ ] ; // Letras descobertas
this . jpa = null ; // Jogador que escolheu a palavra atual (Jogador Palavra Atual)
this . palavra = null ;
this . tin = 0 ;
2021-01-03 02:13:51 +00:00
2020-12-31 17:23:58 +00:00
// Vamos escolher um jogador aleatório.
if ( this . jfr . indexOf ( this . vezDe ) === this . jfr . length - 1 )
// Fim da fila JFR atingido. Voltar para o começo.
this . vezDe = null ;
this . vezDe = this . vezDe === undefined || this . vezDe === null ? this . jfr [ 0 ] : this . jfr [ this . jfr . indexOf ( this . vezDe ) + 1 ] ; // Escolher o primeiro jogador na fila caso o limite tenha sido atingido, ou escolher o próximo jogador na fila caso contrário.
2021-01-03 02:13:51 +00:00
}
/ * *
* Retorna o próximo item da fila JF .
* @ returns String O próximo item da fila JF .
* @ since 02 / 01 / 2020
* /
próxItemJf ( ) {
let pv1 = this . jf [ this . jf . indexOf ( this . termoVezDe ) + 1 ] ;
if ( pv1 !== undefined )
return pv1 ;
return this . jf [ 0 ] ;
}
2020-12-31 17:23:58 +00:00
/ * *
* Calcula e define a quantidade de letras na palavra atual .
* @ since 23 de outubro de 2020.
* /
definirPalavraLetrasQtd ( ) {
let letrasQtd = 0 ;
for ( let x = 0 ; x < this . palavra . length ; x ++ )
if ( this . palavra [ x ] !== ' ' )
letrasQtd ++ ;
this . palavraLetrasQtd = letrasQtd ;
}
/ * *
* Deduz se é possível que um jogador descubra a palavra atual baseado na quantidade de letras descobertas da palavra .
* @ returns boolean Verdadeiro caso mais de 75 % da palavra tenha sido descoberto ou caso apenas falte uma letra para descobrir a palavra inteira .
* @ since 23 de outubro de 2020.
* /
possívelDescoberta ( ) {
let ld = 0 ;
for ( let x = 0 ; x < this . palavra . length ; x ++ )
if ( this . ldc [ x ] !== undefined )
ld ++ ;
// Pelo menos 75% da palavra deve ter sido descoberta para retornar o evento de descoberta de palavra.
// Caso a palavra seja pequena, então pelo menos uma letra restante deve estar faltando.
if ( ld / this . palavraLetrasQtd >= 0.75 ) {
return true ;
} else {
// Menos de 75% da palavra foi descoberta. Caso apenas uma letra esteja faltando, então retornar verdadeiro de qualquer maneira.
return this . palavraLetrasQtd - 1 === ld ;
}
}
/ * *
* Retorna uma lista contendo as posições dos espaços na palavra atual .
* @ param String busca O alvo para procurar na palavra atual .
* @ returns Array Lista contendo as posições dos espaços na palavra atual .
* @ since 22 de outubro de 2020.
* /
procurar ( busca ) {
let espaços = [ ] ;
for ( var x = 0 ; x < this . palavra . length ; x ++ ) {
if ( this . palavra [ x ] === busca )
espaços . push ( x ) ;
}
return espaços ;
}
/ * *
* Esta função processa o termo enviado por um jogador .
* @ param string termo O termo enviado pelo jogador escolhido .
* @ returns "LETRA_INEXISTENTE" caso a letra inserida não exista na palavra atual ; "LETRAS_PREENCHIDAS" caso a letra inserida apareça na palavra atual .
* @ since 19 de outubro de 2020.
* /
processarTermo ( termo ) {
termo = termo . toUpperCase ( ) ;
let resultadoTermo = { letrasPreenchidas : 0 , resultado : null } ;
if ( termo . length === 1 ) {
2020-12-31 19:00:43 +00:00
// Este termo já foi enviado?
if ( this . lee . indexOf ( termo ) !== - 1
|| this . lei . indexOf ( termo ) !== - 1 )
resultadoTermo . resultado = "LETRA_JÁ_ESCOLHIDA" ;
2020-12-31 17:23:58 +00:00
// A palavra escolhida possui a letra enviada?
2020-12-31 19:00:43 +00:00
else if ( this . palavra . indexOf ( termo ) === - 1 ) {
this . lei . push ( termo ) ;
resultadoTermo . resultado = "LETRA_INEXISTENTE" ;
} else {
2020-12-31 17:23:58 +00:00
resultadoTermo . letrasPreenchidas = this . preencherCampos ( termo ) ;
2020-12-31 19:00:43 +00:00
this . lee . push ( termo ) ;
resultadoTermo . resultado = "LETRAS_PREENCHIDAS" ;
2020-12-31 17:23:58 +00:00
}
return resultadoTermo ;
} else {
2021-01-03 02:42:47 +00:00
// Esta palavra já foi enviada?
if ( this . pei . indexOf ( termo ) !== - 1 ) {
resultadoTermo . resultado = "PALAVRA_JÁ_ESCOLHIDA" ;
return resultadoTermo ;
}
this . pei . push ( termo ) ;
2020-12-31 17:23:58 +00:00
let palavraCorreta = this . palavra === termo ;
resultadoTermo . resultado = palavraCorreta ? "PALAVRA_CORRETA" : "PALAVRA_INCORRETA" ;
if ( palavraCorreta ) {
for ( var x = 0 ; x < this . palavra . length ; x ++ )
if ( this . ldc [ x ] === undefined )
resultadoTermo . letrasPreenchidas ++ ;
}
}
return resultadoTermo ;
}
/ * *
* Gera um jogador aleatório . Esta função é utilizada para escolher a vez de alguma pessoa aleatoriamente sem ecolher pessoas que já foram escolhidas .
* @ returns string O apelido do jogador escolhido .
* @ since 19 de outubro de 2019.
* /
gerarJogadorAleatório ( ) {
// Se todos os jogadores já tiverem sido escolhidos, então redefinir a fila de jogadores.
if ( this . jf . length === this . clientes . length - 1 )
this . jf = [ ] ;
var clientesPossíveis = [ ] ;
for ( var x = 0 ; x < this . clientes . length ; x ++ ) {
var ca = this . clientes [ x ] ; // Cliente atual
if ( ca . apelido !== this . jpa // A pessoa que escolheu a palavra não pode ser escolhida.
&& this . jf . indexOf ( ca . apelido ) === - 1 ) { // Jogadores que já foram escolhidos não podem ser escolhidos novamente.
clientesPossíveis . push ( ca . apelido ) ;
}
}
var je = clientesPossíveis [ Sala . gerarNúmeroAleatório ( clientesPossíveis . length ) ] ; // Jogador escolhido
return je ;
}
/ * *
* Gera um jogador aleatório para uma nova rodada .
* @ returns String O apelido do jogador escolhido .
* @ since 25 de dezembro de 2020.
* /
gerarJogadorAleatórioRodada ( ) {
// Se todos os jogadores já tiverem sido escolhidos, então redefinir a fila de jogadores.
if ( this . jfr . length === this . clientes . length - 1 )
this . jfr = [ ] ;
let clientesPossíveis = [ ] ;
for ( let x = 0 ; x < this . clientes . length ; x ++ ) {
let ca = this . clientes [ x ] ; // Cliente atual
if ( this . jfr . indexOf ( ca . apelido ) === - 1 ) // Jogadores que já foram escolhidos não podem ser escolhidos novamente.
clientesPossíveis . push ( ca . apelido ) ;
}
let je = clientesPossíveis [ Sala . gerarNúmeroAleatório ( clientesPossíveis . length ) ] ; // Jogador escolhido
return je ;
}
/ * *
* Preenche os campos com a letra especificada .
* @ param string letra A letra desejada .
* @ since 19 de outubro de 2020.
* /
preencherCampos ( letra ) {
let qtd = 0 ; // quantidade de campos preenchidos
for ( let x = 0 ; x < this . palavra . length ; x ++ ) {
if ( this . palavra [ x ] === letra ) {
this . ldc [ x ] = letra ;
qtd ++ ;
}
}
return qtd ;
}
/ * *
* Retorna o vencedor da partida atual caso exista .
* @ returns Object O cliente do jogador que venceu a partida ou nulo caso não há um vencedor .
* @ since 23 de dezembro de 2020.
* /
receberVencedor ( ) {
let pv = [ ] ; // Lista de possíveis vencedores. Adicionar jogadores que ultrapassaram a meta aqui. Caso mais de um cliente seja adicionado aqui, então conceder vitória ao jogador que tiver a maior quantidade de pontos ou retornar nulo caso houve um empate.
for ( let x = 0 ; x < this . clientes . length ; x ++ )
if ( this . clientes [ x ] . pontos >= this . pontuaçãoMeta )
pv . push ( this . clientes [ x ] ) ;
if ( pv . length === 1 )
return pv [ 0 ] ;
else if ( pv . length === 0 )
return null ;
else {
pv . sort ( function ( a , b ) {
return b . pontos - a . pontos ;
} ) ;
// Houve um empate?
return pv [ 0 ] . pontos === pv [ 1 ] . pontos ? null // Houve um empate; retornar nulo.
: pv [ 0 ] ; // Não houve um empate. Retornar o cliente que ficou no topo.
}
}
/ * *
* Checa se o endereço dado está banido nesta sala .
* @ param String endereço O endereço remoto do cliente .
* @ returns Verdadeiro caso o endereço esteja banido nesta sala , falso caso contrário .
* @ since 24 de dezembro de 2020.
* /
banido ( endereço ) {
for ( let x = 0 ; x < this . banidos . length ; x ++ )
if ( this . banidos [ x ] === endereço )
return true ;
return false ;
}
/ * *
* Gera um número aleatório baseado no argumento providenciado .
* @ param int máximo O número máximo desejado .
* @ since 15 de outubro de 2020.
* /
static gerarNúmeroAleatório ( máximo ) {
var rnd = Math . random ( ) ;
var num = Math . floor ( rnd * máximo ) ;
return num ;
}
}
module . exports = Sala ;