From 7a5cc33eebde33f0df2af3bc7fb82029d3059b24 Mon Sep 17 00:00:00 2001 From: luca0N! Date: Mon, 16 Aug 2021 23:18:22 -0300 Subject: [PATCH] Added missing files --- client.js | 39 +++++++ query.js | 35 ++++++ room.js | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 387 insertions(+) create mode 100644 client.js create mode 100644 query.js create mode 100644 room.js diff --git a/client.js b/client.js new file mode 100644 index 0000000..2f09b8e --- /dev/null +++ b/client.js @@ -0,0 +1,39 @@ +/* + 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 . + + Entre em contato comigo por e-mail via . +*/ + +class Client { + constructor(address, nickname, socket){ + this.address = address; + this.nickname = nickname; + this.socket = socket; + this.uas = Date.now(); // Última Ação Significativa: determina o tempo em que o último evento significativo deste jogador ocorreu. Utilizado para detectar usuários inativos. + this.score = 0; + + this.options = []; + this.pings = []; + } + addScore(points){ + this.score += points; + return points; + } +} + +module.exports = Client; + diff --git a/query.js b/query.js new file mode 100644 index 0000000..df38091 --- /dev/null +++ b/query.js @@ -0,0 +1,35 @@ +/* + 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 . + + Entre em contato comigo por e-mail via . +*/ + +// Oct 11, 2020 + +class Query { + constructor(type, source, request, extra){ + this.type = type; + this.source = source; + this.request = request; + + if (extra !== undefined) + this.extra = extra; + } +} + +module.exports = Query; + diff --git a/room.js b/room.js new file mode 100644 index 0000000..7582151 --- /dev/null +++ b/room.js @@ -0,0 +1,313 @@ +/* + 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 . + + Entre em contato comigo por e-mail via . +*/ + +class Room { + /** + * Room object. + * @param string sala The room name. + * @param Array An array which contains all players connected to this room. + * @param string The leader nickname. + * @param string The room status. + */ + 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. + 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); + + for (let x = tmpJf.length; x > 0; x--){ + // Pegar um jogador aleatório da fila. + let num = Room.gerarNúmeroAleatório(tmpJf.length); + this.jf.push(tmpJf[num]); + tmpJf.splice(num, 1); + } + + 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 = Room.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 + this.pei = []; // Palavras escolhidas inexistentes + this.ldc = []; // Letras descobertas + this.jpa = null; // Jogador que escolheu a palavra atual (Jogador Palavra Atual) + this.palavra = null; + this.tin = 0; + + // 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. + } + + /** + * 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]; + } + + /** + * 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){ + // Este termo já foi enviado? + if (this.lee.indexOf(termo) !== -1 + || this.lei.indexOf(termo) !== -1) + resultadoTermo.resultado = "LETTER_ALREADY_CHOSEN"; + // A palavra escolhida possui a letra enviada? + else if (this.palavra.indexOf(termo) === -1){ + this.lei.push(termo); + resultadoTermo.resultado = "LETTER_NOT_PRESENT"; + } else { + resultadoTermo.letrasPreenchidas = this.preencherCampos(termo); + this.lee.push(termo); + resultadoTermo.resultado = "LETTER_PRESENT"; + } + return resultadoTermo; + } else { + // Esta palavra já foi enviada? + if (this.pei.indexOf(termo) !== -1){ + resultadoTermo.resultado = "TERM_ALREADY_CHOSEN"; + return resultadoTermo; + } + this.pei.push(termo); + let palavraCorreta = this.palavra === termo; + resultadoTermo.resultado = palavraCorreta ? "TERM_GUESSED" : "TERM_NOT_GUESSED"; + 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 2020. + */ + 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[Room.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[Room.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 = Room;