---
title: "Xadrez"
description: "Um tabuleiro de xadrez — os lances legais se acendem, a peça na mão diz por que uma casa é recusada, um peão pergunta em que vai se transformar, e um bot responde com arrastes de verdade."
canonical_url: "https://zizigy.github.io/vue-dnd-kit/pt/docs/examples/chess"
---

> Index of every page on this site: [llms.txt](https://zizigy.github.io/vue-dnd-kit/llms.txt)

<example height="36rem" hint="Arraste uma peça branca, ou use Tab e Space; o Bot joga com as pretas" name="chess" title="Xadrez">



</example>

## O que observar

- **Square.vue**: cada uma das 64 casas é um alvo de drop cujo `accept` é uma função. Ela é
consultada enquanto uma peça é arrastada, então a casa aceita só os lances legais daquela peça;
um drop em qualquer outro lugar é recusado e a peça volta ao lugar. As casas legais se acendem a
partir de `isAccepting`: nenhum estado do próprio jogo acompanha o arraste.
- **Piece.vue**: um draggable simples, `disabled` quando não é a vez do seu lado. `keyboardMode: 'droppables'` faz as setas pularem entre as casas que aceitam a peça: os lances legais dela, nada
mais. `snapCenterToCursor` mantém a peça centralizada sob o ponteiro, e um toque arrasta na hora
(`activation`). `canDrag` impede que você mexa nas peças do bot e no tabuleiro enquanto o código
joga, sem desativar nada: arrastes iniciados por código não têm evento de entrada, então
`canDrag` não é consultado para eles.
- **chess.ts** e **game.ts**: as regras e o jogo, sem nenhum arrastar e soltar neles: lances
legais com xeque, roque, en passant, promoção, empates por falta de material, a notação, desfazer.
Um lance no `onDrop` cria uma nova posição, e o overlay pousa na peça movida.

## A peça na mão

**PieceOverlay.vue** é o componente de `overlay` das peças. Ele lê as props que todo overlay
recebe e diz o que um drop na casa sob ele faria: sobre uma casa recusada (`over` definido,
`accepted` falso) a peça fica vermelha e dá o motivo; sobre uma captura, ela mostra um alvo e o que
captura. Quando o drop está decidido (`status: 'dropping'`), a dica some e a peça se assenta.

```ts [PieceOverlay.vue]
const props = defineProps<{
  active: Active;
  over: Over | null;
  accepted: boolean;
  status: DnDStatus;
}>();

const hint = computed(() => {
  const square = props.over ? String(props.over.id) : null;
  if (props.status !== 'dragging' || !square || square === piece.value.square) return null;
  if (props.accepted) {
    const taken = game.takes(piece.value.id, square);
    return taken ? { type: 'capture', text: `Takes ${NAMES[taken.kind]}` } : null;
  }
  // "Pinned", "King in check", "Not a legal move"
  return { type: 'refused', text: game.whyNot(piece.value.id, square) };
});
```

`Board.vue` desenha uma seta da casa de onde a peça veio até a casa sob ela, a partir do `active` e
do `over` de `useDnD()`. Os `haptics` do provider vibram um arraste por toque sobre uma casa legal
e quando um drop é recusado; os `announcements` em `index.vue` falam os mesmos motivos: "f7,
pinned".

## Promoção: um drop que espera uma resposta

Sobre a última fileira, um peão na mão mostra a peça em que vai se transformar: o `overOverlay` da
própria casa (`PromotionOverlay.vue`) toma o lugar do da peça. Ao soltar, o `onBeforeDrop` da casa
retorna uma promise, e o overlay espera sobre a casa enquanto **PromotionPicker.vue**, um
elemento simples da página ao lado dela, pergunta qual peça. Uma peça responde `'accept'`, Escape
ou Cancel `'reject'` (o peão volta ao lugar), e Keep dragging `'continue'`: o peão volta a seguir
o ponteiro, e o próximo clique o solta e pergunta de novo.

```ts [Square.vue]
makeDroppable(el, {
  id: props.square,
  accept: ({ active }) => game.canMove(active.id, props.square),
  // Shown instead of the piece's overlay while a pawn is over the last rank.
  overOverlay: computed(() =>
    held.value?.kind === 'P' && isLastRank(props.square) ? PromotionOverlay : undefined,
  ),
  // A promise: the drop waits on the square until the picker answers.
  onBeforeDrop: ({ active }) =>
    game.promotes(active.id, props.square) ? game.askPromotion(props.square) : 'accept',
  onDrop: ({ active }) => game.move(String(active.id), props.square),
});
```

O `onBeforeDrop` de um alvo de drop recebe o evento de arraste simples e só é consultado quando o
`accept` dele aceitou o arraste; o de uma lista ordenável recebe o `SortableDropEvent` da lista,
com o `result` do drop. O `overOverlay` do alvo é lido mais uma vez depois do `onDrop`, para o pouso:
ele verifica o peão como ele foi pego (`active.data`), não o jogo, onde a essa altura ele já é uma
dama.

## O bot, os replays e o roque: arrastes executados por código

**autoplay.ts** joga lances com `@vue-dnd-kit/actions`: os do bot (`bot.ts`, um guloso), os do
**Replay**, e o passo da torre em todo roque, incluindo os seus. Cada um é um arraste de verdade:
pego, deslizado sobre o tabuleiro um quadro por vez, solto através do `accept` e do `onDrop` da
casa, anunciado e animado como os seus. Uma promoção roteirizada já traz a sua peça, então o
seletor não abre; Escape cancela um arraste roteirizado como qualquer outro.

```ts [autoplay.ts]
const { startDrag } = useDnDActions();

const drag = startDrag(id); // from the piece's center
for (let frame = 1; frame <= FRAMES; frame++) {
  const t = easeOut(frame / FRAMES);
  const point = { x: start.x + (end.x - start.x) * t, y: start.y + (end.y - start.y) * t };
  if (!(await drag.moveTo(point))) return false; // cancelled meanwhile (Escape)
}
return drag.drop(); // true once it has landed, false if the square refused it
```

O roque é jogado em dois movimentos, como à mão: o rei anda duas colunas, depois a torre dele é
arrastada por cima dele, então a torre nunca pula.

## Capturas, desfazer e um novo jogo

As peças capturadas vão para o **Tray.vue** do seu lado: uma lista ordenável usada só pelo
`animateChanges` (`disabled`, nada é arrastado ali). O `enter` dela é uma função: uma nova peça voa para
dentro a partir da casa em que foi capturada, e as outras abrem espaço.

```ts [Tray.vue]
makeSortableList(tray, {
  items: () => props.pieces,
  getKey: (piece) => `taken-${piece.id}`,
  disabled: true,
  animateChanges: { enter: flyIn, leave: false },
});
```

Undo e New game mudam a posição sem arraste, então **glide.ts** os anima à mão (FLIP): cada peça
voa de onde estava, em uma casa ou em uma bandeja, para onde está agora. Contra o bot, Undo desfaz
o seu lance junto com a resposta dele.

Leia mais: [Decidindo um drop](https://zizigy.github.io/docs/guides/drop-decisions) ·
[O overlay](https://zizigy.github.io/docs/guides/overlay#targets-that-change-the-overlay) ·
[Arrastes programáticos](https://zizigy.github.io/docs/guides/sensors#programmatic-drags) ·
[Mudanças nos dados: `animateChanges`](https://zizigy.github.io/docs/guides/animations#data-changes-animatechanges) ·
[Acessibilidade](https://zizigy.github.io/docs/guides/accessibility)

## Sitemap

See the full [sitemap](https://zizigy.github.io/vue-dnd-kit/sitemap.md) for all pages.
