first commit

This commit is contained in:
2024-04-01 01:56:05 +02:00
commit 5c64b4e147
102 changed files with 10838 additions and 0 deletions

20
src/app.module.ts Normal file
View File

@@ -0,0 +1,20 @@
import { join } from 'path';
import { Module } from '@nestjs/common';
import { ServeStaticModule } from '@nestjs/serve-static';
import { LoginModule } from './login/login.module';
import { SalaChatModule } from './sala-chat/sala-chat.module';
import { BatallaModule } from './batalla/batalla.module';
@Module({
imports: [
ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', 'public'),
}),
LoginModule,
SalaChatModule,
BatallaModule,
],
controllers: [],
providers: []
})
export class AppModule {}

View File

@@ -0,0 +1,19 @@
import { OnGatewayConnection, OnGatewayDisconnect, WebSocketGateway } from '@nestjs/websockets';
import { BatallaService } from './batalla.service';
import { Socket } from 'socket.io';
@WebSocketGateway({ namespace: 'batalla' })
export class BatallaGateway implements OnGatewayConnection, OnGatewayDisconnect {
constructor(private readonly batallaService: BatallaService) {}
handleConnection(client: Socket) {
const {userId,gameId}=client.handshake.auth
}
handleDisconnect(client: Socket) {
}
}

View File

@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { BatallaService } from './batalla.service';
import { BatallaGateway } from './batalla.gateway';
@Module({
providers: [BatallaGateway, BatallaService],
})
export class BatallaModule {}

View File

@@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class BatallaService {}

29
src/battleship/barco.ts Normal file
View File

@@ -0,0 +1,29 @@
export const BarcoTipo = Object.freeze({
FRAGATA: 1,
DESTRUCTOR: 2,
ACORAZADO: 3,
PORTAAVIONES: 4,
});
export default class Barco {
constructor(
public id: number,
public x: number,
public y: number,
public longitud: number,
public orientacion: string,
public impactos: number = 0,
public destruido = false,
) {}
recibirImpacto() {
this.impactos++;
if (this.impactos >= this.longitud) {
this.destruido = true;
}
}
haSidoDestruido(): boolean {
return this.destruido;
}
}

View File

@@ -0,0 +1,57 @@
import Jugador from './jugador';
export default class BattleshipGame{
public jugadorA: Jugador;
public jugadorB: Jugador;
turnoActual: Jugador | null;
constructor(
public idPartida: string,
) {
this.turnoActual = null;
}
setJugadorA(jugador:Jugador){
this.jugadorA=jugador;
}
setJugadorB(jugador:Jugador){
this.jugadorB=jugador;
}
iniciaPartida() {
this.turnoActual = this.jugadorA;
// Iniciar el primer turno
this.realizarTurno();
}
realizarTurno() {
// Realizar las acciones correspondientes al turno actual
// Por ejemplo, mostrar el mapa del turno actual, solicitar un disparo, etc.
// Implementa esta parte según sea necesario
// Luego, alternar el turno al otro jugador
this.turnoActual =
this.turnoActual === this.jugadorA ? this.jugadorB : this.jugadorA;
// Verificar si se ha alcanzado el final del juego
if (this.haFinalizado()) {
this.finalizaPartida();
} else {
// Si no ha finalizado, continuar con el próximo turno
this.realizarTurno();
}
}
haFinalizado(): boolean {
// Aquí debes implementar la lógica para verificar si el juego ha finalizado
// Por ejemplo, si todos los barcos de uno de los jugadores han sido destruidos
// Devuelve true si el juego ha finalizado, de lo contrario, devuelve false
// Implementa esta parte según sea necesario
return false;
}
finalizaPartida() {
// Aquí debes implementar la lógica para finalizar el juego
// Por ejemplo, mostrar el resultado (quién ganó, etc.)
// Implementa esta parte según sea necesario
}
}

49
src/battleship/jugador.ts Normal file
View File

@@ -0,0 +1,49 @@
import Barco, { BarcoTipo } from './barco';
import Mapa, { EstadoCelda } from './mapa';
export default class Jugador {
public mapaFlota: Mapa = new Mapa();
public mapaDeAtaques: Mapa = new Mapa();
public jugadorPreparado: boolean = false;
public barcos: Barco[] = [
new Barco(1, 0, 0, BarcoTipo.PORTAAVIONES, 'VERTICAL'),
new Barco(2, 1, 0, BarcoTipo.ACORAZADO, 'VERTICAL'),
new Barco(3, 2, 0, BarcoTipo.ACORAZADO, 'VERTICAL'),
new Barco(4, 3, 0, BarcoTipo.ACORAZADO, 'VERTICAL'),
new Barco(5, 4, 0, BarcoTipo.DESTRUCTOR, 'VERTICAL'),
new Barco(6, 5, 0, BarcoTipo.DESTRUCTOR, 'VERTICAL'),
new Barco(7, 6, 0, BarcoTipo.DESTRUCTOR, 'VERTICAL'),
new Barco(8, 7, 0, BarcoTipo.FRAGATA, 'VERTICAL'),
new Barco(9, 8, 0, BarcoTipo.FRAGATA, 'VERTICAL'),
];
constructor(public nickname: string) {}
prepararFlota(barcos: Barco[]) {
this.barcos = barcos;
this.mapaFlota.setBarcos(this.barcos);
this.jugadorPreparado = true;
}
setBarcos(barcos: Barco[]) {
this.mapaFlota.setBarcos(barcos);
}
realizarDisparo(x: number, y: number, rival: Jugador): boolean {
const acierto = rival.mapaFlota.verificaDisparo(x, y);
this.mapaDeAtaques.marcaDisparo(x,y,acierto ? EstadoCelda.Golpe : EstadoCelda.Agua);
return acierto;
}
haPerdido(): boolean {
for (const barco of this.barcos) {
if (!barco.destruido) {
return false;
}
}
return true;
}
}

68
src/battleship/mapa.ts Normal file
View File

@@ -0,0 +1,68 @@
import Barco, { BarcoTipo } from './barco';
export enum EstadoCelda {
Vacio = 0,
Agua = -1,
Golpe = -2,
}
export default class Mapa {
celdas: number[][] = [];
barcosMapa: Map<number, Barco> = new Map<number, Barco>();
constructor() {
for (let i = 0; i < 10; i++) {
this.celdas[i] = [];
for (let j = 0; j < 10; j++) {
this.celdas[i][j] = 0;
}
}
}
setBarcos(barcos: Barco | Barco[]) {
const barcosArray = Array.isArray(barcos) ? barcos : [barcos];
for (const barco of barcosArray) {
const incFila = barco.orientacion === 'VERTICAL' ? 1 : 0;
const incColumna = barco.orientacion === 'HORIZONTAL' ? 1 : 0;
for (let i = 0; i < barco.longitud; i++) {
const fila = barco.y + i * incFila;
const columna = barco.x + i * incColumna;
this.celdas[fila][columna] = barco.id;
}
this.barcosMapa.set(barco.id, barco);
}
}
getEstadoCelda(x: number, y: number): EstadoCelda {
return this.celdas[x][y];
}
getBarcoEnCelda(x: number, y: number): Barco | null {
const barcoId = this.celdas[x][y];
if (barcoId > 0) {
return this.barcosMapa.get(barcoId) || null;
}
return null;
}
marcaDisparo(x:number,y:number,valor:number){
this.celdas[x][y]=valor;
}
getInformacionBarcos(): Barco[] {
return Array.from(this.barcosMapa.values());
}
verificaDisparo(x: number, y: number): boolean {
if (this.celdas[x][y] > 0) {
const barco = this.getBarcoEnCelda(x,y);
if (barco) {
barco.recibirImpacto();
this.celdas[x][y] = EstadoCelda.Golpe;
return true;
}
} else {
this.celdas[x][y] = EstadoCelda.Agua;
}
return false;
}
}

View File

@@ -0,0 +1,18 @@
import { OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit, SubscribeMessage, WebSocketGateway } from '@nestjs/websockets';
import { LoginService } from './login.service';
import { Socket } from 'socket.io';
@WebSocketGateway({namespace:'login'})
export class LoginGateway implements OnGatewayConnection, OnGatewayDisconnect{
constructor(private readonly loginService: LoginService) {}
handleConnection(client: any, ...args: any[]) {
}
handleDisconnect(client: any) {
}
@SubscribeMessage('login')
handleLogin(client: Socket, nick: string){
return this.loginService.login(nick);
}
}

12
src/login/login.module.ts Normal file
View File

@@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { LoginService } from './login.service';
import { LoginGateway } from './login.gateway';
import { SharedModule } from 'src/shared/shared.module';
@Module({
imports:[SharedModule],
providers: [LoginGateway,LoginService],
})
export class LoginModule {}

View File

@@ -0,0 +1,18 @@
import { Injectable } from '@nestjs/common';
import { UsuariosService } from 'src/shared/usuarios.service';
@Injectable()
export class LoginService {
constructor(private readonly usuariosService: UsuariosService){}
login(nickname:string){
const usuario=this.usuariosService.obtenerUsuarioPorNickname(nickname);
if (usuario){
return usuario.uuid
} else {
return this.usuariosService.creaUsuario(nickname);
}
}
}

8
src/main.ts Normal file
View File

@@ -0,0 +1,8 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();

View File

@@ -0,0 +1,61 @@
import {
OnGatewayConnection,
OnGatewayDisconnect,
SubscribeMessage,
WebSocketGateway,
WebSocketServer,
} from '@nestjs/websockets';
import { SalaChatService } from './sala-chat.service';
import { Server, Socket } from 'socket.io';
@WebSocketGateway({ namespace: 'salachat' })
export class SalaChatGateway
implements OnGatewayConnection, OnGatewayDisconnect
{
@WebSocketServer()
server: Server;
constructor(private readonly salaChatService: SalaChatService) {}
handleConnection(client: Socket) {
const userId = client.handshake.auth.userId;
const userConectado = this.salaChatService.conectaUsuarioUUID(userId);
if (userConectado){
client.join('chat_general');
client.emit('onConnectRoom',this.salaChatService.listaUsuariosSinPartidas);
client.broadcast.to('chat_general').emit('onUserConnectRoom',userConectado);
}else{
client.disconnect();
}
}
handleDisconnect(client: Socket) {
const userId = client.handshake.auth.userId;
const userDesconectado = this.salaChatService.desconectaUsuarioUUID(userId);
if (userDesconectado){
client.broadcast.to('chat_general').emit('onUserDisconnectRoom',userDesconectado);
}
client.leave('chat_general');
}
@SubscribeMessage('chatMsg')
handleMsg(client: Socket, msg: string) {
const userId = client.handshake.auth.userId;
const user = this.salaChatService.getUsuarioUUID(userId);
if (user) {
this.server.to('chat_general').emit('chatMsg', { uuid:userId, msg });
} else {
client.disconnect();
}
}
sendBroadcastMsg(msg:string){
this.server.to('chat_general').emit('broadcastMsg',msg);
}
@SubscribeMessage('creaPartida')
handleCreaPartida(client: Socket) {
const userId = client.handshake.auth.userId;
const partida= this.salaChatService.creaPartida(userId);
this.server.to('chat_general').emit('on_create_partida',partida);
}
}

View File

@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { SalaChatService } from './sala-chat.service';
import { SalaChatGateway } from './sala-chat.gateway';
import { SharedModule } from 'src/shared/shared.module';
@Module({
imports:[SharedModule],
providers: [SalaChatGateway, SalaChatService],
})
export class SalaChatModule {}

View File

@@ -0,0 +1,58 @@
import { Injectable } from '@nestjs/common';
import { Partida, PartidasService } from 'src/shared/partidas.service';
import { UsuariosService } from 'src/shared/usuarios.service';
@Injectable()
export class SalaChatService {
constructor(
private readonly usuariosService: UsuariosService,
private readonly partidasService: PartidasService,
) {}
get listaUsuariosSinPartidas() {
return Array.from(this.usuariosService.usuarios.values()).map(
({ uuid, nickname, conectado }) => ({
uuid,
nickname,
conectado,
}),
);
}
getUsuarioUUID(uuid: string) {
return this.usuariosService.getUsuarioByUUID(uuid);
}
conectaUsuarioUUID(uuid: string) {
const user = this.usuariosService.getUsuarioByUUID(uuid);
if (user) {
user.conectado = true;
return {
uuid: user.uuid,
nickname: user.nickname,
conectado: user.conectado,
};
} else {
return undefined;
}
}
desconectaUsuarioUUID(uuid: string) {
const user = this.usuariosService.getUsuarioByUUID(uuid);
if (user) {
user.conectado = false;
return {
uuid: user.uuid,
nickname: user.nickname,
conectado: user.conectado,
};
} else {
return undefined;
}
}
creaPartida(uuidJugadorCreador: string) {
const partida = this.partidasService.creaPartida(uuidJugadorCreador);
this.usuariosService.addPartidaToUsuario(uuidJugadorCreador, partida);
return partida;
}
}

View File

@@ -0,0 +1,35 @@
import { v4 as uuidv4 } from 'uuid';
import { Injectable } from '@nestjs/common';
import { UsuariosService } from './usuarios.service';
export class Partida {
constructor(
public uuid: string,
public uuidJugadorA: string,
public nickJugadorA: string = '',
public uuidJugadorB: string = null,
public nickJugadorB: string = null,
public abierta: boolean = true,
) {}
}
@Injectable()
export class PartidasService {
private _partidas: Map<string, Partida> = new Map<string, Partida>();
constructor(private readonly usuariosService: UsuariosService) {}
get partidasAbiertas(): Partida[] {
return Array.from(this._partidas.values()).filter(
(partida) => partida.abierta,
);
}
creaPartida(uuidJugadorA: string) {
const uuid = uuidv4();
const nickJugadorA=this.usuariosService.usuarios.get(uuidJugadorA).nickname;
const partida = new Partida(uuid, uuidJugadorA,nickJugadorA);
this._partidas.set(uuid, partida);
return partida;
}
}

View File

@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { UsuariosService } from './usuarios.service';
import { PartidasService } from './partidas.service';
@Module({
providers:[UsuariosService, PartidasService],
exports:[UsuariosService, PartidasService]
})
export class SharedModule {}

View File

@@ -0,0 +1,49 @@
import { v4 as uuidv4 } from 'uuid';
import { Injectable, Scope } from '@nestjs/common';
import { Partida } from './partidas.service';
class Usuario {
partidas: Partida[] = [];
constructor(
public uuid: string,
public nickname: string,
public conectado: boolean = false,
) {}
}
@Injectable()
export class UsuariosService {
private _usuarios: Map<string, Usuario> = new Map<string, Usuario>();
get usuarios() {
return this._usuarios;
}
getUsuarioByUUID(uuid: string) {
return this._usuarios.get(uuid) ? this._usuarios.get(uuid) : undefined;
}
creaUsuario(nickname: string) {
const uuid = uuidv4();
const usuario = new Usuario(uuid, nickname);
this._usuarios.set(uuid, usuario);
return usuario.uuid;
}
obtenerUsuarioPorNickname(nickname: string): Usuario | undefined {
for (const usuario of this._usuarios.values()) {
if (usuario.nickname === nickname) {
return usuario;
}
}
return undefined;
}
addPartidaToUsuario(uuid: string, partida: Partida) {
this._usuarios.get(uuid).partidas.push(partida);
}
getPartidasUsuario(uuid: string) {
return this._usuarios.get(uuid).partidas;
}
}