Ajedrez tridimensional

26

Para defender la desconcertante decisión de alguien, la gente suele decir que esa persona está pasando por encima de la cabeza de todos y jugando al "ajedrez tridimensional". ¡Ahora es tu oportunidad de jugar ajedrez tridimensional!

Reglas

Hay muchas variantes del ajedrez 3D , pero para este desafío he inventado el mío. Mi versión es como el ajedrez normal, excepto que las piezas están dentro de cubos en lugar de cuadrados, y ahora tienen una dimensión adicional de movimiento. Para que esto sea simple desafío hay ningún peones y sin enroque .

Movimiento de la pieza

(Las direcciones de la brújula se refieren al movimiento que ocurriría en un tablero de ajedrez estándar, arriba y abajo se refieren a moverse verticalmente en el tablero de ajedrez 3D).

  • Rey : tiene 26 casillas a las que puede ir en un turno dado: N, NE, E, SE, S, SW, W, NW; así como arriba, abajo y arriba / abajo + una de las direcciones de la brújula.
  • Reina : puede moverse en las mismas direcciones que el Rey, pero tan lejos como quiera en esas direcciones.
  • Torre - puede moverse en 6 direcciones: N, E, S, W, Arriba y Abajo,
  • obispo : tiene 8 direcciones de viaje triagonales: NE + arriba / abajo, SE + arriba / abajo, SW + arriba / abajo, NW + arriba / abajo
  • Caballero : mueve 2 espacios en un eje, luego 1 espacio en otro. Al igual que el ajedrez normal, el caballero es la única pieza que puede saltar sobre otras piezas.

Probador de piezas

Use este fragmento para ver cómo se mueven las diferentes piezas en el tablero 3D ( consejo : consulte las *Testfunciones en el JS para ver formas rápidas de determinar si un cuadrado es un movimiento válido, simplemente en función de su distancia absoluta de la pieza):

const color = "Black";
const pieces = ["N","B","R","Q","K"];
const urls = ["https://image.ibb.co/gyS9Cx/Black_N.png","https://image.ibb.co/dknnzc/Black_B.png","https://image.ibb.co/kb3hXx/Black_R.png","https://image.ibb.co/hGO5kH/Black_Q.png","https://image.ibb.co/jApd5H/Black_K.png"];
var dragPiece;
var size = 3;
var index = 0;
function start() {
Array.prototype.add = function(a) {return [this[0]+a[0],this[1]+a[1],this[2]+a[2]]};

document.getElementById("n").onchange=function() {
	size = parseInt(this.value);
	var s = document.getElementsByClassName("selected");
	var pos;
	if(s.length > 0) {
		pos = s[0].pos;
	}
	document.body.removeChild(document.body.firstChild);
	createBoards();
	if(pos != null && valid(...pos)) {
	cellAt(...pos).click();
	}
};
createBoards();
}

function createBoards() {
var boards = document.createElement("div");
boards.style.counterReset = "board-count "+(size+1);
boards.name=size;
for(var x = 0;x<size;x++) {
var t = document.createElement("table");
for(var i = 0;i<size;i++) {
  var row = document.createElement("tr");
  row.className="row";
  for(var j = 0;j<size;j++) {
  	var cell = document.createElement("td");
    cell.className = (size+i+j)%2 == 1 ? "black" : "white";
    var im = document.createElement("img");
    im.draggable = true;
    im.ondragstart = function(e) {dragPiece = this;e.dataTransfer.setData("piece",this.parentElement.name);
    this.parentElement.classList.add("start");
    this.classList.add("dragged");
    };
    im.ondragend = function(e) {this.parentElement.classList.remove("start");this.classList.remove("dragged");};
    im.hidden = true;
    cell.appendChild(im);
    cell.pos = [j,i,x];
    cell.ondragover = function(e) {e.preventDefault();};
    cell.ondragenter = function(e) {this.classList.add("drag");};
    cell.ondragleave = function(e) {this.classList.remove("drag");};
    cell.ondrop = function(e) { e.preventDefault();this.classList.remove("drag");
    if(this != dragPiece.parentElement && this.firstChild.hidden ){
    dragPiece.hidden=true;
    setPiece(this,e.dataTransfer.getData("piece"));
    }
    
    };
    cell.onclick = function() {
    if(this.firstChild.hidden == false && this.classList.contains("selected")) {
		index++;
    	if(index == pieces.length) index = 0;
    }
     	setPiece(this,pieces[index]);
    };
  
    
    row.appendChild(cell);
  }
  t.appendChild(row);
  }
  boards.appendChild(t);
  }
  document.body.insertBefore(boards,document.body.firstChild);
}



function clearHighlighted() {
	var sel =  document.getElementsByClassName("highlighted");
     while(sel.length > 0) {
     	sel[0].classList.remove("highlighted");
     }
}

function setPiece(cell,piece) {
var s=document.getElementsByClassName("selected");
if(s.length > 0){ s[0].firstChild.hidden=true;s[0].classList.remove("selected");}
cell.classList.add("selected");
cell.firstChild.hidden = false;
cell.name = piece;
     	cell.firstChild.src = urls[index];
     clearHighlighted();
     	showMoves(cell,piece);
}

function showMoves(cell,piece) {
	if(piece=="K") selector(cell,kingTest)
	else if(piece=="N") selector(cell,knightTest);
	else if(piece=="Q") selector(cell,queenTest);
	else if(piece=="R") selector(cell,rookTest);
	else if(piece=="B") selector(cell,bishopTest);
}

function cellAt(col,row,board) {
	return document.body.firstChild.children[board].children[row].children[col];
}

function valid(col,row,board) {
	return 0<=col && col<size && 0<=row && row<size && 0<=board && board<size;
}

function select(cell) {
if(cell != null && cell.firstChild.hidden) cell.classList.add("highlighted");
}



function rookTest(dist) {
	var d = [].concat(dist).sort();
	return d[0] == 0 && d[1] == 0;
}

function knightTest(dist) {
	var d = [].concat(dist).sort();
	return d[0] == 0 && d[1] == 1 && d[2] == 2;
}

function kingTest(dist) {
	return dist[0] <= 1 && dist[1] <= 1 && dist[2] <= 1;
}

function bishopTest(dist) {
	return dist[0]==dist[1] && dist[1]==dist[2];
}

function queenTest(dist) {
	var d = [].concat(dist).sort();
	return rookTest(dist) || bishopTest(dist) || (d[0]==0 && d[1]==d[2]) ;
}

function dist(cell,x,y,z) {
	return [Math.abs(cell.pos[0]-x),Math.abs(cell.pos[1]-y),Math.abs(cell.pos[2]-z)];
}

function selector(cell,test) {
	for(var i = 0;i<size;i++) {
		for(var j = 0;j<size;j++) {
			for(var k = 0;k<size;k++) {
			if(test(dist(cell,k,j,i))) {
				var c = cellAt(k,j,i);
				if(c != cell) select(c);
			}
			}
			}
			}
	
}
table
{
	padding: 10px;
  display:inline-block;
}

table:after
{
  counter-increment: board-count -1;
  content: "("counter(board-count,upper-roman)")";
  float:right;
}

td
{
  width:28px;
  height:28px;
  border: 1px solid;
  cursor: pointer;
}

.black
{
  background-color: rgba(127,127,127,0.6);
}

.white
{
  background-color: white;
}


.start {
background-color: rgba(0,204,0,0.6);
}

.highlighted {
background-color: rgba(0,255,0,0.6);
}

.drag
{
background-color: rgba(0,204,255,0.6);
}


.selected {
background-color: green;
cursor: grab;
}

.selected img
{
  display:block;
}

.dragged {
  cursor: grabbing;
}
<body data-size=3 onload="start()"
<label for="n">Size: </label><select id="n">
<option>2</option>
<option selected>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
<option>10</option>
</select>
<div>Click or drag to place the piece. Click on the piece to change its type.</div>
</body>

Reto

Dado un n x n x n tabla , determina si el rey blanco está en jaque mate.

Entrada

  • (Opcional) n ≥ 2 - el tamaño del tablero
  • El tablero de juego
    • Puede estar en forma de matriz 1d- 2d- o 3d, u otro formato similar. La notación puede estar en cualquier formato simple. Por ejemplo, KQRBN (Blanco) y kqrbn (Negro) con # para cubos vacíos. O use números para los diferentes valores.
    • Piense en el tablero de ajedrez 3D como múltiples tableros apilados uno encima del otro y listados de arriba a abajo. Luego, cada tablero individual se anota de izquierda a derecha, de atrás hacia adelante (del lado negro al lado blanco).
    • Imagine este caso 2x2x2 dado como una matriz 3D:
 [
[[bq] [##]]
[[bn] [KQ]]
]

tablero "superior": tablero ingrese la descripción de la imagen aquí"inferior":ingrese la descripción de la imagen aquí

Salida

  • booleano (valor de verdad / falsedad): verdadero si el rey blanco está en jaque mate, falso de lo contrario.

Mate

El rey blanco está bajo control si una pieza negra amenaza con capturarlo en el próximo turno de las negras. Para salir de control, las blancas necesitan mover a su rey a un lugar seguro, defenderlo con otra pieza o capturar la pieza amenazante. Si las blancas no tienen forma de salir de control, entonces el rey blanco está en jaque mate . Recuerde, si las blancas no están en jaque, pero no pueden moverse sin entrar en jaque, entonces es un punto muerto , que no es un jaque mate.

Especificación

  • No se te dará un tablero donde el rey negro está tratando de "controlar" al rey blanco, o un tablero donde ambos reyes están bajo control (escenarios imposibles).

Casos de prueba

  1. n = 3, [###,n##,#rr],[#b#,###,###],[###,###,bRK]

    ingrese la descripción de la imagen aquí(III) ingrese la descripción de la imagen aquí(II) ingrese la descripción de la imagen aquí(I)

    Salida: verdadero

    Explicación: El rey está recibiendo un cheque de la torre en el piso superior. La torre blanca no puede bloquear el ataque o capturar la torre amenazante, por lo que el rey debe intentar apartarse del camino. Consideremos las opciones de movimiento del rey:

    1. c2 (I) - custodiado por el obispo en b3 (II)
    2. b2 (I) - custodiado por un caballero en a2 (III)
    3. c1 (II) - custodiado por la torre en c1 (III)
    4. b1 (II) - custodiado por la torre en b1 (III)
    5. c2 (II) - custodiado por un caballero en a2 (III)
    6. b2 (II) - custodiado por el obispo en a1 (I)

¡Ya que el rey no puede escapar del cheque, es un jaque mate!

  1. n = 3, [b#b,###,###],[###,###,RNR],[#q#,###,#K#]

    ingrese la descripción de la imagen aquí(III) ingrese la descripción de la imagen aquí(II)ingrese la descripción de la imagen aquí(I)

    Salida: falso Explicación: El rey recibe un cheque de la reina y no tiene movimientos para escapar o bloquear. Sin embargo, el caballero puede capturar a la reina.

  2. n = 3, [#q#,#b#,###],[n##,###,###],[#k#,###,#KB]

    ingrese la descripción de la imagen aquí(III) ingrese la descripción de la imagen aquí(II)ingrese la descripción de la imagen aquí(I)

Salida: falso Explicación: Las blancas no tienen forma de capturar a la reina amenazante o de mover a su rey a un lugar seguro. Sin embargo, al mover a su alfil a b2 (II), las blancas pueden bloquear la amenaza de la reina.

  1. n = 4, [####,####,r###,####],[####,#q##,####,####],[##r#,###b,####,BRnn],[####,####,#N##,#KQ#]

    ingrese la descripción de la imagen aquí(IV) ingrese la descripción de la imagen aquí(III) ingrese la descripción de la imagen aquí(II)ingrese la descripción de la imagen aquí (I)

    Salida: verdadera Explicación: en este caso, el rey recibe un cheque de uno de los caballeros y una reina. Aunque las Blancas pueden capturar / bloquear una de las piezas de verificación, no puede capturar / bloquear ambas. Por lo tanto, las blancas deben tratar de sacar a su rey de control, pero no tiene opciones.

  2. n = 3, [###,##b,r#r],[###,###,###],[#k#,###,#K#]

    ingrese la descripción de la imagen aquí(III) ingrese la descripción de la imagen aquí(II) ingrese la descripción de la imagen aquí(I)

Salida: falso Explicación: El blanco no está bajo control, pero no tiene forma de moverse sin entrar en control. Por lo tanto, es un punto muerto, pero no un jaque mate.

  1. n = 3, [##k,###,r#K],[###,n##,#N#],[###,###,#Q#]

    ingrese la descripción de la imagen aquí(III) ingrese la descripción de la imagen aquí(II) ingrese la descripción de la imagen aquí(I)

Resultado: verdadero Explicación: A White le gustaría acercarse a su reina para defender a su rey, pero su caballero está bloqueando el camino.

  1. n = 3, [###,###,##q],[###,###,###],[#k#,###,rNK]

    ingrese la descripción de la imagen aquí(III) ingrese la descripción de la imagen aquí(II) ingrese la descripción de la imagen aquí(I)

Salida: verdadera Explicación: las blancas no pueden llevarse a la reina con su caballero, porque entonces la torre controlará al rey de las blancas.

  1. n = 2, [#q,##],[##,K#]

    ingrese la descripción de la imagen aquí(II) ingrese la descripción de la imagen aquí(I)

Resultado: falso Explicación: El blanco puede capturar a la reina con su rey.

  1. n = 2, [rq,##],[##,K#]

    ingrese la descripción de la imagen aquí(II) ingrese la descripción de la imagen aquí(I)

Salida: verdadera Explicación: Esta vez la torre está vigilando, por lo que el rey no puede capturar a la reina.

  1. n = 3, [###,###,#q#],[###,###,###],[#k#,###,BKn]

    ingrese la descripción de la imagen aquí(III) ingrese la descripción de la imagen aquí(II) ingrese la descripción de la imagen aquí(I)

Resultado: falso Explicación: El rey blanco puede escapar capturando al caballero.

geokavel
fuente
¿Solo un detalle, pero no cell.className = (i + j)%2 == 0 ? "black" : "white"sería mejor en el fragmento?
Arnauld
@Arnauld lol, olvidé arreglar lo más obvio.
geokavel
¿Cuál es el tamaño de placa más grande que necesitamos admitir?
Weijun Zhou
1
@WeijunZhou Básicamente, debería poder hacer los casos de prueba en un tiempo razonable para ver si su código funciona. Para números más grandes solo necesita trabajar teóricamente dado un tiempo y memoria infinitos.
geokavel

Respuestas:

5

Rubí , 412413 bytes

->b,w=2{n=b=~/\n/
g=->h{h[0]-~n*(h[1]-~n*h[2])} 
r=1
(n**6).times{|i|a=b*1     
m=[]
9.times{|j|m<<(j<6?i/n**j%n:m[j-6]-m[j-3])}
x,y,z=v=m[6,3].map{|j|j*j}
d=v.max
e=x+y+z
q=95&o=(t=a[p=g[m[3,3]]]).ord
k=a[s=g[m]].ord
o/32==w&&(o^k>31||k==75)&&((q%8==2&&q%9*d==e||q==81&&x%d+y%d+z%d<1)&&((1...c=d**0.5).map{|j|a[p+g[m[6,3]]/c*j]}+[?#]).max<?A||q==78&&e==5||q==75&&e<4)&&(a[p]=?0;a[s]=t;r&&=w>2?a=~/K/:!f[a,3])}
r}

Pruébalo en línea! Ahora verificado en todos los casos de prueba. El código aumentó en 1 byte para corregir un error en el caso 5 (caso de punto muerto).

Función Llambda que requiere entrada como una cadena en el formato que se muestra a continuación. Se puede proporcionar un segundo parámetro opcional, que indica qué grupo de 32 códigos ASCII se considerarán en el próximo movimiento (de manera predeterminada, estos 2 corresponden a mayúsculas / caracteres blancos, pero la función se llama a sí misma de forma recursiva utilizando 3 correspondientes a caracteres en minúsculas / negros. )

Nivel de recursión 1: Intenta todos los movimientos posibles para el blanco (cualquier cubo a cualquier cubo) y avanza por todos los legales. Nivel de recursión 2: en cada caso, se llama a sí mismo para pasar por todos los movimientos posibles para el negro. Esto se cumple si el rey blanco ha sobrevivido a todos los movimientos negros posibles. Nivel de recursión 1: si todos los movimientos blancos posibles conducen a una situación en la que el rey blanco NO sobrevive a todos los movimientos negros posibles, entonces devuelve verdadero (de lo contrario, falso).

En general, una pieza no puede moverse a una casilla ocupada por una pieza amiga. Para considerar el caso en el que las blancas no se mueven (por lo tanto, el jaque mate no se estanca), también se permite el caso de que el rey "se mueva" a la casilla en la que ya está. Por razones de código corto, las otras piezas blancas también pueden moverse a la casilla ocupada por el rey blanco. Este es un movimiento sin sentido, pero permitirlo no afecta el resultado, por lo que no es un problema.

Las siguientes pruebas se utilizan para verificar si un movimiento es válido para cada pieza. x,y,zson los cuadrados de las distancias recorridas en cada eje. ees la suma de estos (de ahí el cuadrado de la distancia euclidiana) y des el máximo. El tipo de pieza es AND con 95 para convertir valores ASCII en minúsculas en mayúsculas.

Bishop and Rook (ASCII 66 and 82) For the rook e=1*d. For the bishop e=3*d. 
The same code is used for both with q%9 giving 1 and 3 respectively.

Queen (ASCII 81) x%d+y%d+z%d<1 Each axis must be 0 or d, so this sum must be 0.

For the above pieces, any cubes crossed must be checked to ensure they are empty.

Knight (ASCII 78) e=5

King (ASCII 75) e<4

Código comentado

->b,w=2{                                                        #board, colour to move (default upcase/white)
  n=b=~/\n/                                                     #n=board size (index of first newline.)
  g=->h{h[0]-~n*(h[1]-~n*h[2])}                                 #Function to calculate position in string based on array of 3d coordinates.
  r=1                                                           #Return value = truthy.
  (n**6).times{|i|                                              #Iterate through n**6 moves (n**3 start cubes and n**3 end cubes.)
    a=b*1      
    m=[]                                                        #Make an empty array for coordinates.                                             
    9.times{|j|m<<(j<6?i/n**j%n:m[j-6]-m[j-3])}                 #Split i into six base n digits for the start and end coordinates. also derive 3 relative move distances.
    x,y,z=v=m[6,3].map{|j|j*j}                                  #v=array of relative distances squared. x,y,z are the 3 individual relative distances squared.
    d=v.max                                                     #Max of x,y,z                                     
    e=x+y+z                                                     #Square of euclidean distance
    q=95&o=(t=a[p=g[m[3,3]]]).ord                               #t=contents of cube to move from. o=ascii value, q=uppercase of o.
    k=a[s=g[m]].ord                                             #k=ascii value of contents of cube to move to.
    o/32==w&&(o^k>31||k==75)&&                                  #If o is in the right 32 byte range (uppercase or lowercase) AND the destination contains the white king or a character not in the same 32 byte range AND...
      ((q%8==2&&q%9*d==e||q==81&&x%d+y%d+z%d<1)&&               #the piece is a rook, bishop or queen with a valid move (as described in the text) AND..
      ((1...c=d**0.5).map{|j|a[p+g[m[6,3]]/c*j]}+[?#]).max<?A|| #the intervening squares are all empty, OR..
      q==78&&e==5||                                             #the piece is a knight and the move has euclidean distance sqrt(5) OR..
      q==75&&e<4)&&                                             #the piece is a king and the move has euclidean distance <4 THEN
      (a[p]=?0;a[s]=t;r&&=w>2?a=~/K/:!f[a,3])                   #put a 0 in the start cube and put the piece in the end cube. If moved piece is black, is the white king still there? AND with return value.
  }                                                             #If moved piece is white, recursively call the f to carry out the black moves. Does the white king NOT survive some black moves? AND with return value.
r}
Level River St
fuente
¿No podría jugar golf usando valores ascii de 1 dígito? Además, ¿quiso decir "estancamiento no jaque mate" en el tercer párrafo?
geokavel
@geokavel La representación más corta de un único valor ascii en Ruby es ?A(hay un ejemplo en el código), por lo que sigue siendo de 2 bytes. Aún mejor que algunos idiomas que requieren "A". Hubo ciertas manipulaciones que funcionaron mejor con los valores ASCII en lugar de los caracteres (en particular, lo o^k>31que garantiza que una pieza se pueda mover a una casilla desocupada u ocupada por una pieza amiga pero no hostil.)
Level River St
Me refiero a jaque mate, no a punto muerto. El estancamiento es la situación en la que el rey se ve amenazado si el jugador se mueve. Jaque mate es la situación en la que el rey se ve amenazado si el jugador se mueve, y también si no lo hace.
Level River St
¿Qué sucede si usó valores int en lugar de valores ascii (es decir, matriz de ints en lugar de string)?
geokavel
@geokavel ints probablemente sería más corto, y puedo revisarlo más tarde, ya que está específicamente permitido por la especificación. Pero elegí el formato elegido en parte porque era más legible para los humanos (por lo tanto, más fácil de desarrollar) y en parte porque me inspiró esta respuesta que influyó mucho en mi pensamiento: codegolf.stackexchange.com/a/45544/15599
Level River St