
O papel da tela
A tela da web não se limita a desenhar o tabuleiro. Ela precisa reduzir os toques errados do usuário, impedir jogadas duplicadas enquanto espera a resposta do servidor e carregar de novo as partidas salvas. Principalmente em celulares pequenos, é mais seguro não confirmar uma pedra com um único toque.
Etapa 1: Criar a jogada em duas etapas
O primeiro toque em uma interseção vazia mostra apenas uma pedra de pré-visualização dourada. A jogada é enviada ao servidor quando o mesmo ponto é tocado de novo ou quando o botão "Jogar" é pressionado. Tocar em outro ponto só muda a posição da pré-visualização. Até o servidor responder, o botão e a entrada no tabuleiro ficam bloqueados por um momento para que a mesma jogada não seja salva duas vezes.
Etapa 2: Tornar o servidor a fonte oficial do estado da partida
Ao receber uma jogada, o servidor confere o código da partida e a chave de acesso e verifica se é mesmo a vez daquele jogador. Só as jogadas que passam pelo motor de regras são salvas em uma transação, e depois a vez da IA é executada. Não confie no tabuleiro que está no navegador; aplique a nova jogada ao último estado do servidor, para evitar adulterações e conflitos com telas desatualizadas.
- Validar e salvar a jogada do humano.
- Pedir à IA a próxima jogada usando o último tabuleiro salvo.
- Verificar a jogada da IA com o motor de regras.
- Salvar a jogada da IA e o resultado das capturas.
- Devolver à tela o estado mais recente já completo.
Etapa 3: Separar a revisão da continuação
Apertar as setas de voltar e avançar durante a revisão não pode mudar o último estado da partida real. Só quando "Continuar daqui" é escolhido enquanto se vê uma jogada passada é que criamos uma nova variação copiada até aquele ponto. Cortar imediatamente a sequência existente poderia fazer o usuário perder o registro original por engano.
Etapa 4: Mostrar com honestidade o fim e a contagem
Quando os dois lados passam seguidos ou o usuário pede a contagem, dá para calcular o território vazio, as pedras capturadas e o komi das brancas. Mas, se não for possível julgar completamente a vida e morte das pedras mortas no tabuleiro, o resultado deve ser indicado como "contagem de referência". Explicar o que foi contado é mais útil para o usuário do que esconder os limites do cálculo automático.
Lista de verificação antes de publicar
- A partida em andamento é restaurada depois de atualizar a página?
- Uma jogada nunca é salva duas vezes em uma rede lenta?
- É impossível abrir a partida de outra pessoa com uma chave de acesso diferente?
- A partida original continua igual enquanto se veem jogadas passadas?
- O tabuleiro e a sequência de jogadas continuam consistentes quando ocorre um erro?
Ligando tudo até aqui, temos a primeira versão completa. A partir daí, as falhas encontradas nos logs de partidas reais, como escadas, boca de tigre e passes precoces, podem ser avaliadas e corrigidas um tipo de cada vez.
O código real desta etapa
A tela de revisão monta o tabuleiro reproduzindo a sequência salva desde o início até a jogada escolhida. A sequência original nunca é alterada, então avançar e voltar não muda o último estado da partida real.
mariago-web/lib/board.ts
export type ReplayState = {
board: Stone[];
ko: Point | null;
lastMove: Point | null;
capB: number;
capW: number;
passStreak: number;
toPlay: Stone;
};
/** 기보 0..upto 수까지 재현 (upto=0 이면 빈 판). */
export function replayMoves(
moves: Array<{ color: 1 | 2; pass?: boolean; r?: number; c?: number }>,
upto: number,
): ReplayState {
let board = emptyBoard();
let ko: Point | null = null;
let lastMove: Point | null = null;
let capB = 0;
let capW = 0;
let passStreak = 0;
let toPlay: Stone = BLACK;
const n = Math.max(0, Math.min(upto, moves.length));
for (let i = 0; i < n; i++) {
const m = moves[i];
const who = m.color as Stone;
if (m.pass) {
passStreak += 1;
lastMove = null;
} else if (m.r != null && m.c != null) {
const res = tryPlay(board, m.r, m.c, who, ko);
if (res.ok) {
board = res.board;
ko = res.koPoint;
lastMove = { r: m.r, c: m.c };
if (who === BLACK) capB += res.captured;
else capW += res.captured;
passStreak = 0;
}
}
toPlay = who === BLACK ? WHITE : BLACK;
}
return { board, ko, lastMove, capB, capW, passStreak, toPlay };
}Modelo usado: Qwen3-VL-8B-Instruct + adaptador LoRA (lora_mix_qwen_r5). O código-fonte completo e a descrição do modelo estão no post "8. O código-fonte completo e os modelos usados".
COMMENTS · CHAPTER 06
Conectando a partida na web e o salvamento dos registros 0 comentários
Ainda não há comentários. Deixe uma pergunta ou algo que queira acrescentar.
Para publicar um comentário, comece com o Google e registre um apelido e um e-mail.
Começar com o Google