Échecs en trois dimensions

26

Afin de défendre la décision déconcertante de quelqu'un, les gens disent souvent que cette personne va au-dessus de la tête de tout le monde et joue aux «échecs en trois dimensions». Maintenant, c'est votre chance de jouer aux échecs en 3 dimensions!

Règles

Il existe de nombreuses variantes des échecs 3D , mais pour ce défi, j'ai inventé le mien. Ma version est comme les échecs ordinaires, sauf que les pièces sont à l'intérieur de cubes au lieu de carrés, et ont maintenant une dimension de mouvement supplémentaire. Pour rendre ce simple défi , il y a pas des pions et pas de roque .

Mouvement de pièce

(Les directions de la boussole se réfèrent au mouvement qui se produirait sur un échiquier standard, Up et Down se réfèrent au déplacement vertical sur l'échiquier 3D).

  • Roi - dispose de 26 cases pour un tour donné: N, NE, E, SE, S, SW, W, NW; ainsi que vers le haut, le bas et le haut / bas + l'une des directions de la boussole.
  • Reine - peut se déplacer dans les mêmes directions que le roi, mais autant qu'elle le souhaite dans ces directions.
  • Tour - peut se déplacer dans 6 directions: N, E, S, W, haut et bas,
  • Bishop - a 8 directions de voyage triagonales: NE + haut / bas, SE + haut / bas, SW + haut / bas, NW + haut / bas
  • Knight - déplace 2 espaces sur un axe, puis 1 espace sur un autre. Tout comme les échecs ordinaires, le chevalier est la seule pièce qui peut sauter par-dessus d'autres pièces.

Testeur de pièces

Utilisez cet extrait pour voir comment les différentes pièces se déplacent sur la carte 3D ( astuce : consultez les *Testfonctions dans le JS pour des moyens rapides de déterminer si un carré est un mouvement valide, simplement en fonction de sa distance absolue par rapport à la pièce.):

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>

Défi

Étant donné un tableau n x n x n , déterminez si le roi blanc est en échec et mat.

Contribution

  • (Facultatif) n ≥ 2 - la taille de la carte
  • Le plateau de jeu
    • Peut être sous la forme d'un tableau 1d- 2d- ou 3d-, ou tout autre format similaire. La notation peut être dans n'importe quel format simple. Par exemple, KQRBN (blanc) et kqrbn (noir) avec # pour les cubes vides. Ou utilisez des nombres pour les différentes valeurs.
    • Considérez l'échiquier 3D comme plusieurs planches empilées les unes sur les autres et répertoriées de haut en bas. Ensuite, chaque planche individuelle est notée de gauche à droite, de l'arrière vers l'avant (côté noir vers côté blanc).
    • Imaginez ce cas 2x2x2 donné comme un tableau 3D:
 [
[[bq] [##]]
[[bn] [KQ]]
]

carte "supérieure": carte entrez la description de l'image ici"inférieure":entrez la description de l'image ici

Sortie

  • booléen (valeur vérité / fausse) - vrai si le roi blanc est en échec et mat, faux sinon.

Échec et mat

Le roi blanc vérifie si une pièce noire menace de la capturer au prochain tour de Black. Pour sortir de l'échec, les Blancs doivent mettre son roi en sécurité, le défendre avec une autre pièce ou capturer la pièce menaçante. Si les Blancs n'ont aucun moyen de sortir de l'échec, alors le roi blanc est en échec et mat . Rappelez-vous, si les Blancs ne sont pas en échec, mais ne peuvent pas bouger sans entrer en échec, alors c'est une impasse , qui n'est pas un échec et mat.

spécification

  • Vous ne recevrez pas de tableau où le roi noir essaie de "vérifier" le roi blanc, ni de tableau où les deux rois sont en échec (scénarios impossibles).

Cas de test

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

    entrez la description de l'image ici(III) entrez la description de l'image ici(II) entrez la description de l'image ici(I)

    Sortie: vrai

    Explication: le roi reçoit un chèque de la tour au dernier étage. La tour blanche est incapable de bloquer l'attaque ou de capturer la tour menaçante, donc le roi doit essayer de s'écarter. Examinons les options de déplacement du roi:

    1. c2 (I) - gardé par l'évêque au b3 (II)
    2. b2 (I) - gardé par un chevalier en a2 (III)
    3. c1 (II) - gardé par tour à c1 (III)
    4. b1 (II) - gardé par tour à b1 (III)
    5. c2 (II) - gardé par un chevalier en a2 (III)
    6. b2 (II) - gardé par l'évêque en a1 (I)

Puisque le roi ne peut pas échapper au chèque, c'est un échec et mat!

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

    entrez la description de l'image ici(III) entrez la description de l'image ici(II) entrez la description de l'image ici(I)

    Sortie: faux Explication: Le roi reçoit un chèque de la reine et n'a aucun mouvement pour s'échapper ou bloquer. Cependant, le chevalier peut capturer la reine.

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

    entrez la description de l'image ici(III) entrez la description de l'image ici(II) entrez la description de l'image ici(I)

Sortie: faux Explication: les blancs n'ont aucun moyen de capturer la reine menaçante ou de mettre son roi en sécurité. Cependant, en déplaçant son évêque vers b2 (II), Blanc peut bloquer la menace de la reine.

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

    entrez la description de l'image ici(IV) entrez la description de l'image ici(III) entrez la description de l'image ici(II) entrez la description de l'image ici(I)

    Sortie: vrai Explication: Dans ce cas, le roi reçoit un chèque de l'un des chevaliers et d'une reine. Même si Blanc peut capturer / bloquer l'une des pièces de contrôle, il ne peut pas capturer / bloquer les deux. Par conséquent, Blanc doit essayer de mettre son roi hors de contrôle, mais il n'a pas d'options.

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

    entrez la description de l'image ici(III) entrez la description de l'image ici(II) entrez la description de l'image ici(I)

Sortie: faux Explication: le blanc n'est pas en échec, mais n'a aucun moyen de se déplacer sans entrer en échec. C'est donc une impasse, mais pas un échec et mat.

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

    entrez la description de l'image ici(III) entrez la description de l'image ici(II) entrez la description de l'image ici(I)

Sortie: vrai Explication: Blanc voudrait entrer avec sa reine pour défendre son roi, mais son chevalier bloque le chemin.

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

    entrez la description de l'image ici(III) entrez la description de l'image ici(II) entrez la description de l'image ici(I)

Sortie: vrai Explication: Blanc ne peut pas prendre la reine avec son chevalier, car alors la tour vérifiera le roi blanc.

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

    entrez la description de l'image ici(II) entrez la description de l'image ici(I)

Sortie: faux Explication: les blancs peuvent capturer la reine avec son roi.

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

    entrez la description de l'image ici(II) entrez la description de l'image ici(I)

Sortie: vrai Explication: Cette fois, la tour garde, donc le roi ne peut pas capturer la reine.

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

    entrez la description de l'image ici(III) entrez la description de l'image ici(II) entrez la description de l'image ici(I)

Sortie: faux Explication: Le roi blanc peut s'échapper en capturant le chevalier.

geokavel
la source
Juste un détail, mais ça ne serait pas cell.className = (i + j)%2 == 0 ? "black" : "white"mieux dans l'extrait?
Arnauld
@Arnauld lol, j'ai oublié de réparer la chose la plus évidente.
geokavel
Quelle est la plus grande taille de carte que nous devons prendre en charge?
Weijun Zhou
1
@WeijunZhou Fondamentalement, vous devriez être en mesure de faire les cas de test dans un délai raisonnable pour voir si votre code fonctionne. Pour les plus grands nombres, il suffit de travailler théoriquement avec un temps et une mémoire infinis.
geokavel

Réponses:

5

Rubis , 412 413 octets

->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}

Essayez-le en ligne! Maintenant vérifié sur tous les cas de test. Code augmenté de 1 octet pour corriger un bug sur le cas 5 (cas de blocage.)

Fonction Llambda nécessitant une entrée sous forme de chaîne au format indiqué ci-dessous. Un deuxième paramètre facultatif peut être donné, indiquant quel groupe de 32 codes ASCII doit être pris en compte lors du prochain déplacement (par défaut, ce 2 correspond aux caractères majuscules / blancs, mais la fonction s'appelle récursivement en utilisant 3 correspondant aux caractères minuscules / noirs. )

Niveau de récursivité 1: essaie tous les mouvements possibles pour le blanc (n'importe quel cube vers n'importe quel cube) et parcourt tous les mouvements légaux. Niveau de récursivité 2: Dans chaque cas, il appelle alors lui-même à traverser tous les mouvements possibles pour le noir. Cela revient vrai si le roi blanc a survécu à tous les mouvements noirs possibles. Niveau de récursivité 1: si tous les mouvements blancs possibles conduisent à une situation où le roi blanc ne survit PAS à tous les mouvements noirs possibles, alors retournez vrai (sinon faux.)

En général, une pièce ne peut pas se déplacer vers une case occupée par une pièce amie. Afin de considérer le cas où le blanc ne bouge pas du tout (donc échec et mat ne se bloque pas), le cas où le roi "se déplace" sur la case où il se trouve déjà est également autorisé. Pour des raisons de code court, les autres pièces blanches sont également autorisées à se déplacer vers la place occupée par le roi blanc. C'est un mouvement absurde, mais le permettre n'affecte pas le résultat, donc ce n'est pas un problème.

Les tests suivants sont utilisés pour vérifier si un mouvement est valide pour chaque pièce. x,y,zsont les carrés des distances parcourues dans chaque axe. eest la somme de ceux-ci (d'où le carré de la distance euclidienne) et dest le maximum. Le type de pièce est ET avec 95 pour convertir les valeurs ASCII minuscules en majuscules.

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

Code commenté

->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
la source
Ne pourriez-vous pas jouer au golf en utilisant des valeurs ascii à 1 chiffre? Aussi, vouliez-vous dire "impasse, pas échec et mat" dans le troisième paragraphe?
geokavel
@geokavel La représentation la plus courte d'une seule valeur ascii dans Ruby est ?A(il y a un exemple dans le code) donc c'est toujours 2 octets. Encore mieux que certaines langues qui l'exigent "A". Certaines manipulations ont mieux fonctionné avec les valeurs ASCII plutôt qu'avec les personnages (en particulier, o^k>31ce qui garantit qu'une pièce peut se déplacer vers une case inoccupée ou occupée par une pièce amie mais pas hostile.)
Level River St
Je veux dire mat et non impasse. L'impasse est la situation où le roi est menacé si le joueur bouge. Échec et mat est la situation où le roi est menacé si le joueur bouge, et aussi s'il ne le fait pas.
Level River St
Et si vous utilisiez des valeurs int au lieu des valeurs ascii (c'est-à-dire un tableau d'entiers au lieu d'une chaîne)?
geokavel
@geokavel ints serait probablement plus court, et je pourrais le réviser plus tard car il est spécifiquement autorisé par la spécification. Mais je suis allé avec le format choisi en partie parce qu'il était plus lisible par l'homme (donc plus facile à développer) et en partie parce que j'ai été inspiré par ma réponse qui a fortement influencé ma pensée: codegolf.stackexchange.com/a/45544/15599
Level River St