Millones eres tú. Nosotros: oscuridad y oscuridad y oscuridad.
¡Pruébalo, lucha contra nosotros!
Sí, escitas, ¡lo somos! Sí, asiáticos, nosotros ...
Alexander Block " escitas "En un
artículo anterior
, hablé mucho sobre mis hallazgos en el campo del diseño y la interfaz de usuario de los juegos de mesa, pero tuve que interrumpir esa historia, se puede decir en el medio, en parte debido al gran volumen del artículo, en parte simplemente porque en ese momento no estaba listo para continuar. siguiente Desde entonces, mucho ha cambiado. Se resolvieron nuevos problemas interesantes, y los juegos que los generaron (no menos interesantes) se agregaron al
lanzamiento . Quiero hablar de esto hoy.
Si alguien recuerda, se trataba del juego "
Abalon ", desarrollado por Michel Lale y Laurent Levy en 1988. Su esencia es empujar las bolas del enemigo fuera del campo. Dos bolas pueden empujar una y tres bolas, un par de bolas de un color diferente. El jugador puede mover sus bolas en el tablero, una a la vez, o en grupos, dos o tres bolas cada una (además, tres bolas deben formar una "fila"). ¿Qué me impidió hacer este juego la última vez?
Obviamente no es el movimiento del grupo en sí. El movimiento simultáneo de varias piezas, dentro de un movimiento, es incluso en
Ajedrez (
enroque ). Y los
rompecabezas de "
rompecabezas deslizantes "
están construidos simplemente para garantizar que dicho movimiento se produzca sincrónicamente y sin problemas. Veamos un juego desarrollado por Robert Abbott en 1975:
Parece un abalón. La única diferencia es que la "fila" no "empuja" la pieza del oponente de su lugar, sino que simplemente la retira del tablero usando una captura de "ajedrez". La victoria se otorga a uno de los jugadores que logró dibujar más en la última fila del tablero de sus piezas que su oponente logró en el mismo momento. Todo el juego se basa en "filas" en movimiento. Es poco probable que tenga éxito en ganar solo piezas solitarias. Así es como se ve un simple movimiento de empuje.
Zrf(define push-1 ( $1 (verify friend?) (while friend? cascade $1 ) (verify not-friend?) add ))
Se trata de la
cascada de palabras mágicas: obliga al intérprete a "liberar" la figura movida al campo actual, tomando desde allí "en la mano" otra figura (no es importante para sí mismo o para el oponente) y continuar moviéndose, ya con la nueva figura "en la mano". En un movimiento, dicha operación se puede realizar repetidamente, moviendo así un número ilimitado de piezas a la vez. Tales casos (y un poco más complejos) también se encuentran en otros juegos: "
Guns ", "
Dameo ", "
Leutwayite Game ", ...
Desde el punto de vista de la interfaz de usuario, los movimientos de "empuje" también se implementan de manera bastante trivial. La etiqueta de campo objetivo familiar (círculo verde) aparece en la figura. Si (de acuerdo con las reglas del juego) podemos comer esta pieza, comemos (captura de ajedrez), de lo contrario, empujamos. Puedes empujar una fila y más de un campo hacia adelante (como en el juego Epaminondas). Por supuesto, codificar tal movimiento será un poco más complicado:
Zrf (define push-2 ( $1 (verify friend?) (while friend? mark $1 (verify not-enemy?) to back cascade $1 ) $1 (verify not-friend?) add ))
La palabra clave to (y su emparejado
desde ) actúa junto con la
cascada . Significa que la figura "fuera de control" debe colocarse en el tablero ahora, y la nueva figura "tomar la mano" un poco más tarde, después de navegar a otro campo. En general, los movimientos de "empuje" son simples, pero hay otro tipo de movimiento grupal para Abalon:
Los llamo movimientos "transversales". Desde el punto de vista de la codificación ZRF, no hay nada complicado en ellos. El problema está en la interfaz de usuario. ¿Cómo "decirle" al programa que el jugador quiere mover no una bola, sino un grupo, si ambas reglas están permitidas? Utilizo el mismo "parpadeo", que fue muy útil para mí en las damas, para marcar la cifra "actual". Solo que ahora hay varias cifras "actuales" en el conjunto.
Un clic en una figura "libre" la agrega al grupo si hay un movimiento en el que están involucradas todas las figuras agregadas al grupo (es aún más fácil no soltar el botón, resaltando todo el grupo con un solo clic del mouse). Si no hay tales movimientos, solo se crea un nuevo grupo, que hasta ahora consiste en una sola pieza. Siempre se muestran círculos verdes para la última figura agregada (esto puede no ser muy obvio, pero puede acostumbrarse). Haga clic repetidamente en cualquier figura "cegadora" inmediatamente restablece todo el grupo.
Por ciertoLos círculos verdes no aparecerán necesariamente simplemente en presencia de figuras "cegadoras". En algunos casos, es posible una situación en la que todas las piezas seleccionadas se incluyen en un movimiento válido, pero no hay un movimiento válido, limitado a mover solo estas formas seleccionadas. Suena un poco confuso, pero aquí hay una ilustración:
En este
juego solo se permiten movimientos simultáneos de grupos de tres piezas (si quedan menos piezas, todos deberían moverse). Todas las figuras seleccionadas se mueven un paso y en la misma dirección. Captura de ajedrez, sus piezas interfieren con el movimiento. Para ganar, debes mantener al menos una de tus piezas en la última línea, en el campamento del enemigo.
El juego en sí, en mi opinión, no es muy interesante, pero, desde el punto de vista de la codificación, esto es una verdadera locura. Cualquier intento de "honestamente" generar todos los movimientos posibles de grupos de tres figuras conduce a una explosión combinatoria. Tienes que engañar (el beneficio de Dagaz lo permite). Para empezar, generamos todos los movimientos válidos de piezas individuales. Es simple:
(define step ( $1 add ))
Hasta que puedas comprobar la posible pelea de tu propia figura, ¡todo esto más tarde! Simplemente vamos en todas las direcciones, siempre que sea posible. A continuación, encienda la "
magia ". Simplemente combinamos todas las combinaciones posibles de tres movimientos de varias piezas en una dirección, creando un producto cartesiano. Después de eso,
descartamos los movimientos que se encuentran con nuestras propias piezas.
¿Por qué no dejarlos caer de inmediato? Por una razón muy simple: una pieza tiene derecho a moverse a un campo ocupado si se libera como parte del mismo movimiento de grupo, y al momento de generar los movimientos "elementales", ¡no hay información sobre la composición de los grupos movidos! Es por eso que amo tanto este proyecto. ¡Él, de vez en cuando, lanza rompecabezas tan interesantes aquí!
La mudanza no tiene que tener lugar en un solo campo, como en Abalone. En el juego
Ordo (y especialmente en
Ordo X ), inventado por Dieter Stein en 2009, los grupos de figuras pueden moverse distancias mucho más largas. La única condición es que las piezas de su color, al final del turno, no se separen (esta es la misma invariante del juego que la necesidad de que el rey deje la amenaza en Ajedrez). El jugador que gana la primera línea del tablero gana.
En este juego hay movimientos tanto longitudinales como transversales de las "filas" de piezas de cualquier tamaño y a cualquier distancia (dentro del tablero, por supuesto). ¡Hay tantas plantillas utilizadas para generar movimientos que lleva más de 5 minutos procesar un
archivo ZRF desarrollado por mí con un
convertidor (la mayoría de los juegos se procesan en segundos)! Se podría suponer que esto conduciría a problemas en la etapa de generar los movimientos, pero esto no es así. La gran mayoría de los movimientos están cortados por los
invariantes del juego.
Una tarea más de rompecabezas cerebral apareció aquíEl hecho es que el mecanismo de selección alterna de figuras que desarrollé para realizar un movimiento grupal, en términos generales, es incompatible con la interfaz de los movimientos de "empuje" implementados por versiones antiguas del controlador. Es simple: para hacer un movimiento de "empuje", debe seleccionar una figura que pueda ir al campo, hasta ahora ocupada por otra figura del grupo movido. Pero no podemos mostrar su campo objetivo, ya que la formación del grupo no se completa, y el movimiento de una sola figura al campo ocupado probablemente esté prohibido por las reglas del juego.
En general, si todo se hace "de acuerdo con las reglas", es necesario hacer clic en todas las figuras del grupo movido una por una y solo después de eso la interfaz mostrará los campos de destino para la última figura agregada. Incluso en Abalon, con sus grupos de un máximo de tres figuras, esto es algo agotador, ¡pero en Ordo generalmente es impensable! Tuve que idear un método especial que automáticamente "expande" el grupo cuando detecta los conflictos descritos anteriormente.
Esto es lo 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; }
¡Pero los movimientos largos de "empuje" están permitidos en Ordo y este algoritmo no funciona! No importa: todas las funciones definidas en Dagaz.Model se pueden redefinir.
De esta manera 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; }
Esta sobrecarga es más fácil para
Takoka . Como no hay movimientos de "empuje" en él (siempre es necesario resaltar claramente todas las piezas incluidas en el grupo), es suficiente para bloquear esta funcionalidad, es decir, simplemente no expanda el grupo:
Dagaz.Model.closure = function(board, move, group) { return group; }
Pido disculpas por el nombre de la función que no dice nada a nadie. Simplemente no podría encontrar un mejor nombre para la acción.

Este
juego también implementa el movimiento grupal, ¡pero su mecánica es completamente diferente! Aquí las figuras se mueven en grupos 3x3, además, los campos vacíos del grupo también son parte del "patrón" movido. La presencia de figuras en uno de los ocho campos externos muestra las direcciones en las que puede moverse, y el relleno del campo central determina si puede mover el "patrón" a una distancia arbitraria o solo a corta distancia, no más de 3 pasos. Para ganar, es necesario destruir el "anillo" del enemigo, un análogo de la figura real (este es un campo vacío, rodeado por todos lados por ocho llenos). Tienes que tener mucho cuidado de no destruir tu anillo también.
GESS resultó ser una verdadera pesadilla, tanto en términos de "
magia " como en términos del
prototipo en sí mismo: el esqueleto del juego. Es suficiente decir que el tablero (20x20, teniendo en cuenta una serie de campos fuera del tablero) consta de dos capas. Toda la capa superior está completamente llena de formas invisibles que controlan el movimiento. El movimiento de las piedras que conforman los "patrones" de los jugadores son solo efectos secundarios de estos movimientos. Desafortunadamente, aún no he logrado desarrollar un bot para este juego.
Al final del artículo, quiero presentarles algo más que no está directamente relacionado con el tema del movimiento grupal de figuras. Este
juego me pidió que hiciera uno de los suscriptores de mi
página de proyecto: Sultan Ratrout. En general, estos son
correctores de pilares ordinarios en un tablero hexagonal. Incluso sin las damas. ¡El concepto de revolución es diferente! ¡El campo de juego en sí mismo es transformable! Disfrútalo.
Me voy de vacaciones ...