Você é milhões. Nós - trevas e trevas e trevas.
Experimente, lute conosco!
Sim, citas - nós somos! Sim, asiáticos - nós ...
Alexander Block " Citas "Em um
artigo anterior
, falei muito sobre minhas descobertas no campo do design e da interface do usuário dos jogos de tabuleiro, mas tive que interromper essa história, você pode dizer no meio, em parte por causa do grande volume do artigo, em parte simplesmente porque naquele momento eu não estava pronto para continuar. próximo. Desde então, muita coisa mudou. Novos problemas interessantes foram resolvidos e os jogos que os geraram (não menos interessantes) foram adicionados ao
lançamento . Eu quero falar sobre isso hoje.
Se alguém se lembra, era sobre o jogo "
Abalon ", desenvolvido por Michel Lale e Laurent Levy em 1988. Sua essência é empurrar as bolas do inimigo para fora do campo. Duas bolas podem empurrar uma e três bolas - um par de bolas de uma cor diferente. O jogador pode mover suas bolas no tabuleiro, uma de cada vez, ou em grupos, duas ou três bolas cada (além disso, três bolas devem formar uma “linha”). O que me impediu de fazer este jogo da última vez?
Obviamente não é o próprio movimento do grupo. O movimento simultâneo de várias peças, dentro de um movimento, é uniforme no
xadrez . E os "
quebra-cabeças deslizantes "
são construídos simplesmente para garantir que esse movimento ocorra de maneira síncrona e suave. Vejamos um jogo desenvolvido por Robert Abbott em 1975:
Parece um Abalon. A única diferença é que a "linha" não "empurra" a peça do oponente de seu lugar, mas simplesmente a remove do tabuleiro usando uma captura de "xadrez". A vitória é concedida a um dos jogadores que conseguiu desenhar mais na última linha do tabuleiro de suas peças do que seu oponente conseguiu no mesmo momento. Todo o jogo é construído sobre o movimento de "linhas". É improvável que consiga ganhar apenas peças solitárias. É assim que uma simples jogada de empurrão se parece.
Zrf(define push-1 ( $1 (verify friend?) (while friend? cascade $1 ) (verify not-friend?) add ))
Trata-se da
cascata de palavras mágicas - força o intérprete a "liberar" a figura movida para o campo atual, retirando daí "na mão" outra figura (não é importante para o seu ou o oponente) e continuar em movimento, já com a nova figura "na mão". Em uma jogada, essa operação pode ser executada repetidamente, movendo assim um número ilimitado de peças por vez. Tais casos (e um pouco mais complexos) também são encontrados em outros jogos - "
Guns ", "
Dameo ", "
Leutwayite Game ", ...
Do ponto de vista da interface do usuário, movimentos "push" também são implementados de maneira bastante trivial. O rótulo conhecido do campo de destino (círculo verde) aparece na figura. Se (de acordo com as regras do jogo) pudermos comer essa peça - comemos (captura de xadrez), caso contrário - empurramos. Você pode avançar uma linha e mais de um campo (como no jogo Epaminondas). Obviamente, codificar essa mudança será um pouco mais complicado:
Zrf (define push-2 ( $1 (verify friend?) (while friend? mark $1 (verify not-enemy?) to back cascade $1 ) $1 (verify not-friend?) add ))
A palavra-chave to (e seu par
de ) atua em conjunto com a
cascata . Isso significa que a figura “fora de mão” deve ser colocada no tabuleiro agora, e a nova figura “pega na mão” um pouco mais tarde, depois de navegar para outro campo. Em geral, “empurrar” os movimentos é simples, mas há outro tipo de movimento de grupo no Abalon:
Eu os chamo de movimentos "transversais". Do ponto de vista da codificação ZRF, não há nada complicado nelas. O problema está na interface do usuário. Como "dizer" ao programa que o jogador deseja mover não uma bola, mas um grupo, se ambos os movimentos são permitidos pelas regras? Eu uso o mesmo "piscar", que foi tão útil para mim em damas, para marcar a figura "atual". Somente agora existem várias figuras "atuais" no conjunto.
Um clique em uma figura "livre" o adiciona ao grupo se houver uma mudança na qual todas as figuras adicionadas ao grupo estejam envolvidas (é ainda mais fácil não soltar o botão, destacando o grupo inteiro com um clique do mouse). Se não houver tais movimentos, apenas um novo grupo será criado, até agora constituído por uma peça. Círculos verdes sempre são mostrados para a última figura adicionada (isso pode não ser muito óbvio, mas você pode se acostumar). O clique repetido em qualquer figura "ofuscante" redefine imediatamente todo o grupo.
By the wayOs círculos verdes não aparecerão necessariamente simplesmente na presença de figuras "ofuscantes". Em alguns casos, é possível uma situação em que todas as peças selecionadas sejam incluídas em algum movimento válido, mas não há movimento válido, limitado a mover apenas essas formas selecionadas. Parece um pouco confuso, mas aqui está uma ilustração:
Neste
jogo, apenas movimentos simultâneos de grupos de três peças são permitidos (se houver menos peças, todos devem se mover). Todas as figuras selecionadas se movem um passo e na mesma direção. Captura de xadrez, suas peças interferem no movimento. Para ganhar, você deve segurar pelo menos uma de suas peças na última linha, no campo do inimigo.
O jogo em si, na minha opinião, não é muito interessante, mas, do ponto de vista da codificação, isso é loucura real. Qualquer tentativa de "honestamente" gerar todos os movimentos possíveis de grupos de três figuras leva a uma explosão combinatória. Você precisa enganar (o benefício do Dagaz permite isso). Para começar, geramos todos os movimentos válidos de peças únicas. É simples:
(define step ( $1 add ))
Até que você possa verificar a possível luta de sua própria figura, tudo isso mais tarde! Apenas seguimos em todas as direções, sempre que possível. Em seguida, ative a "
mágica ". Simplesmente combinamos todas as combinações possíveis de três movimentos de várias peças em uma direção, criando um produto cartesiano. Depois disso,
descartamos movimentos que se deparam com nossas próprias peças.
Por que não largá-los imediatamente? Por uma razão muito simples - uma peça tem o direito de mover-se para um campo ocupado se for liberada como parte do mesmo movimento do grupo e, no momento de gerar os movimentos "elementares", não há informações sobre a composição dos grupos movidos! É por isso que amo tanto esse projeto. De vez em quando, ele joga esses quebra-cabeças interessantes aqui!
A mudança não precisa ocorrer em apenas um campo, como no Abalone. No jogo
Ordo (e especialmente no
Ordo X ), inventado por Dieter Stein em 2009, grupos de figuras podem se mover muito mais longe. A única condição é que as peças de sua cor, no final do turno, não sejam separadas (esta é a mesma invariante do jogo que a necessidade do rei deixar a ameaça no xadrez). O jogador que vencer a primeira linha do tabuleiro vence.
Neste jogo, existem movimentos longitudinais e transversais das “linhas” de peças de qualquer tamanho e a qualquer distância (dentro do tabuleiro, é claro). Existem tantos modelos usados para gerar movimentos que leva mais de 5 minutos para processar um
arquivo ZRF desenvolvido por mim com um
conversor (a maioria dos jogos é processada em segundos)! Pode-se supor que isso levaria a problemas na fase de geração dos movimentos, mas não é assim. A grande maioria dos movimentos é cortada pela
invariante do jogo.
Mais uma tarefa de quebra-cabeça cerebral apareceu aquiO fato é que o mecanismo de seleção alternada de figuras que desenvolvi para executar um movimento de grupo, de um modo geral, é incompatível com a interface de movimentos de “empurrar”, implementada por versões antigas do controlador. É simples: para fazer um movimento de "empurrar", você precisa selecionar uma figura com capacidade de ir para o campo, até agora ocupada por outra figura do grupo movido. Mas não podemos exibir seu campo de destino, já que a formação do grupo não está completa, e a mudança de uma única figura para o campo ocupado é provavelmente proibida pelas regras do jogo.
Em geral, se tudo for feito "de acordo com as regras", é necessário clicar em todas as figuras do grupo movido uma por uma e somente depois disso a interface exibirá os campos de destino para a última figura adicionada. Mesmo em Abalon, com seus grupos de no máximo três figuras, isso é um pouco cansativo, mas em Ordo é geralmente impensável! Eu tive que inventar um método especial que “expande” automaticamente o grupo quando ele detecta os conflitos descritos acima.
Aqui está o que parece para Abalone Dagaz.Model.closure = function(board, move, group) { var r = []; _.each(group, function(pos) { r.push(pos); }); for (var i = 0; i < r.length; i++) { var pos = r[i]; _.each(move.actions, function(a) { if ((a[0] !== null) && (a[1] !== null) && (a[0][0] == pos)) { var p = a[1][0]; var piece = board.getPiece(p); if ((piece !== null) && (piece.player == board.player) && (_.indexOf(r, p) < 0)) { r.push(p); } } }); } return r; }
Mas movimentos longos de "empurrar" são permitidos no Ordo e esse algoritmo não funciona! Não importa - todas as funções definidas no Dagaz.Model podem ser redefinidas.
Desta forma Dagaz.Model.closure = function(board, move, group) { var design = board.game.design; var r = []; _.each(group, function(pos) { r.push(pos); }); for (var i = 0; i < r.length; i++) { var pos = r[i]; _.each(move.actions, function(a) { if ((a[0] !== null) && (a[1] !== null) && (a[0][0] == pos)) { var target = a[1][0]; var x = Dagaz.Model.getX(pos); var y = Dagaz.Model.getY(pos); var dx = sign(Dagaz.Model.getX(target) - x); var dy = sign(Dagaz.Model.getY(target) - y); var dir = design.findDirection(pos, pos + (dy * Dagaz.Model.WIDTH) + dx); if (dir !== null) { while ((pos !== null) && (pos != target)) { var piece = board.getPiece(pos); if ((piece === null) || (piece.player != board.player)) break; if (_.indexOf(r, pos) < 0) { r.push(pos); } pos = design.navigate(board.player, pos, dir); } } } }); } return r; }
Essa sobrecarga é mais fácil para
Takoka . Como não há movimentos de empurrar (é sempre necessário destacar claramente todas as peças incluídas no grupo), basta bloquear essa funcionalidade, ou seja, simplesmente não expandir o grupo:
Dagaz.Model.closure = function(board, move, group) { return group; }
Peço desculpas pelo nome da função que não diz nada a ninguém. Eu simplesmente não conseguia criar um nome melhor para a ação.

Este
jogo também implementa o movimento do grupo, mas sua mecânica é completamente diferente! Aqui as figuras se movem em grupos 3x3. Além disso, os campos vazios do grupo também fazem parte do “padrão” movido. A presença de figuras em um dos oito campos externos mostra as direções nas quais você pode se mover, e o preenchimento do campo central determina se você pode mover o "padrão" para uma distância arbitrária ou apenas a uma curta distância, não mais que 3 etapas. Para vencer, é necessário destruir o "anel" do inimigo - um análogo da figura real (este é um campo vazio, cercado de oito lados por todos os lados). Você tem que ter muito cuidado para não destruir seu anel também.
O GESS acabou sendo um pesadelo real, tanto em termos de "
mágica " quanto em termos do próprio
protótipo - o esqueleto do jogo. Basta dizer que o quadro (20x20, levando em consideração vários campos fora do quadro) consiste em duas camadas. Toda a camada superior é completamente preenchida com formas invisíveis que controlam o movimento. O movimento das pedras que compõem os “padrões” dos jogadores são apenas efeitos colaterais desses movimentos. Infelizmente, ainda não consegui desenvolver um bot para este jogo.
No final do artigo, quero apresentar uma outra coisa que não está diretamente relacionada ao tópico do movimento de figuras em grupo. Foi-me pedido que este
jogo fosse um dos assinantes da
página do meu projeto - Sultan Ratrout. Em geral, esses são
verificadores comuns de
pilar em uma placa hexagonal. Mesmo sem as damas. O conceito de revolução é diferente! O próprio campo de jogo é transformável! Aproveite.
Vou de férias ...