Skip to content

GersonResplandes/tictactoe-realtime-arena

Repository files navigation

TicTacToe Realtime Arena

Jogo da velha multiplayer em tempo real criado como projeto público de portfólio. O foco do projeto é demonstrar domínio de WebSocket, salas, estado em memória, validação server-side e uma experiência visual moderna.

Este projeto não usa banco de dados, autenticação, histórico de partidas ou placar persistente. A partida existe apenas enquanto a sala está ativa no servidor.

Stack

  • Next.js App Router
  • TypeScript
  • TailwindCSS
  • Socket.IO
  • Servidor Node customizado
  • Estado em memória
  • Husky, lint-staged, commitlint e Prettier

Visão Geral

O jogador informa um apelido e pode criar uma sala ou entrar usando um código numérico curto. Quem cria a sala entra como jogador X. O segundo participante entra como jogador O. A partir do terceiro participante, todos entram como espectadores.

O frontend apenas envia intenções, como criar sala, entrar, jogar em uma célula ou enviar mensagem como espectador. O servidor valida tudo antes de atualizar e transmitir o estado oficial da sala.

Funcionalidades

  • Criação de sala com código numérico de 6 dígitos.
  • Entrada de segundo jogador em tempo real.
  • Espectadores com visualização da partida.
  • Chat exclusivo para espectadores.
  • Tabuleiro 3x3 sincronizado via Socket.IO.
  • Partidas MD3 com placar em memória por sala.
  • Validação server-side de turno, jogador, sala, célula e status.
  • Vitória, empate e vitória por abandono calculados no servidor.
  • Rate limit simples para jogadas e mensagens.
  • Sanitização de apelidos e mensagens.
  • Git hooks e commits com Conventional Commits.

Design System

A interface usa um sistema visual próprio chamado Arena Light, criado para parecer um produto de jogo casual moderno sem perder clareza.

Referências usadas:

  • Lichess: tabuleiro como objeto central e interface sem distrações.
  • Discord Activities: presença dos participantes, entrada rápida e suporte a espectadores.
  • Xbox Accessibility Guidelines: contraste, contexto visível e controles compreensíveis sem depender apenas de cor.

Princípios aplicados:

  • layout board-first, com o tabuleiro no centro da experiência;
  • paleta clara com azul, ciano, âmbar e verde para estados importantes;
  • cards compactos, bordas consistentes e feedback visual de turno;
  • código de sala destacado e fácil de copiar;
  • chat isolado para espectadores para manter jogadores focados na partida.

Arquitetura

src/
  app/
    globals.css
    layout.tsx
    page.tsx
  components/
    arena-client.tsx
  server/
    rooms.ts
  shared/
    game.ts
    socket-events.ts
    types.ts
server.ts

Camadas

  • src/shared/game.ts: regras puras do jogo da velha.
  • src/shared/types.ts: tipos compartilhados entre cliente e servidor.
  • src/shared/socket-events.ts: contrato tipado dos eventos Socket.IO.
  • src/server/rooms.ts: gerenciamento de salas, jogadores, espectadores e chat.
  • server.ts: servidor Node customizado com Next.js e Socket.IO.
  • src/components/arena-client.tsx: interface da arena e comunicação com socket.

Eventos Socket.IO

Evento Direção Descrição
room:create Cliente -> Servidor Cria sala e coloca o socket como jogador X.
room:join Cliente -> Servidor Entra como jogador O ou espectador.
room:state Servidor -> Cliente Transmite o estado oficial da sala.
game:move Cliente -> Servidor Solicita uma jogada em uma célula.
spectator:message Cliente -> Servidor Envia mensagem no chat de espectadores.
room:leave Cliente -> Servidor Sai da sala atual.
room:error Servidor -> Cliente Retorna erro de validação ou operação.

Validação Server-Side

O servidor valida:

  • se a sala existe;
  • se o socket pertence à sala;
  • se o usuário é jogador antes de jogar;
  • se o usuário é espectador antes de enviar chat;
  • se é a vez correta;
  • se a célula está vazia;
  • se o jogo ainda está ativo;
  • se a mensagem respeita limite e rate limit;
  • se a jogada respeita rate limit.

O cliente não define turno, vitória, empate ou abandono. Ele apenas renderiza o estado recebido do servidor.

Fluxo de Salas

  1. Usuário cria uma sala.
  2. Servidor gera um código numérico de 6 dígitos.
  3. Criador entra como X.
  4. Segundo participante entra como O.
  5. Participantes seguintes entram como espectadores.
  6. Todos recebem atualizações via room:state.

Partidas MD3

Cada sala roda uma melhor de 3 em memória:

  • a sala começa na rodada 1;
  • o jogador que cria a sala começa como X;
  • o início da rodada alterna entre X, O e X;
  • vitória por linha soma ponto para o jogador vencedor;
  • empate soma no contador de empates;
  • quem fizer 2 pontos vence a MD3;
  • se as 3 rodadas terminarem sem 2 pontos para ninguém, o maior placar vence;
  • se o placar terminar empatado, a MD3 termina empatada.

Regra de Abandono

Não há reconexão nem recuperação de sessão. Se um jogador desconectar ou sair da sala, o outro jogador vence automaticamente a MD3 por abandono. Se um espectador sair, ele apenas é removido da lista.

Como Rodar Localmente

Instale as dependências:

npm install

Rode em desenvolvimento com o servidor customizado:

npm run dev

Acesse:

http://localhost:3000

Para produção local:

npm run build
npm run start

Scripts

npm run dev
npm run lint
npm run typecheck
npm run format
npm run format:check
npm run build
npm run start

Qualidade de Código

O projeto usa:

  • pre-commit: roda lint-staged com ESLint e Prettier nos arquivos alterados.
  • commit-msg: valida Conventional Commits.
  • pre-push: roda lint, typecheck e build.

Exemplos de commits:

chore: initialize next.js project
chore: configure commit hooks
feat: add tic tac toe domain rules
feat: add in-memory room manager
feat: add socket.io custom server
feat: build realtime arena interface
docs: add architecture documentation

Screenshots

Placeholders para futuras imagens do projeto publicado.

  • Lobby de criação e entrada de sala.
  • Arena com tabuleiro em tempo real.
  • Placar MD3 por rodada.
  • Visualização de espectador com chat.
  • Estado final por vitória, empate ou abandono.

Decisões Técnicas

  • O estado fica em memória para manter o escopo focado em WebSocket.
  • Não há login para reduzir ruído e destacar o fluxo multiplayer.
  • A confirmação de jogadas e status vem sempre do servidor.
  • O chat é exclusivo para espectadores para separar interação social do jogo.
  • O servidor customizado é necessário porque WebSocket não roda no modelo padrão de rotas serverless.

Possíveis Melhorias Futuras

  • Testes automatizados para o gerenciador de salas.
  • Testes end-to-end com múltiplos sockets.
  • Replay local apenas em memória.
  • Modo partida rápida com pareamento automático.
  • Animações extras para vitória e abandono.

About

Realtime multiplayer tic-tac-toe arena built with Next.js, TypeScript, Socket.IO and server-side validation.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors