Scacchi tridimensionali


26

Al fine di difendere la sconcertante decisione di qualcuno, la gente spesso dice che quella persona sta superando la testa di tutti e sta giocando a "scacchi tridimensionali". Adesso hai la possibilità di giocare a scacchi tridimensionali!

Regole

Esistono molte varianti di scacchi 3D , ma per questa sfida ho inventato la mia. La mia versione è proprio come gli scacchi regolari, tranne per il fatto che i pezzi sono all'interno di cubi anziché quadrati, e ora hanno una dimensione aggiuntiva di movimento. Per semplificare questa sfida non ci sono pedine e non arrocco .

Movimento dei pezzi

(Le direzioni della bussola si riferiscono al movimento che si verificherebbe su una scacchiera standard, Su e Giù si riferiscono al movimento verticale sulla scacchiera 3D).

  • re - ha 26 quadrati che può andare in un determinato turno: N, NE, E, SE, S, SW, W, NW; così come su, giù e su / giù + una delle direzioni della bussola.
  • Regina : può muoversi nelle stesse direzioni del Re, ma per quanto desidera in quelle direzioni.
  • Torre : può spostarsi in 6 direzioni: N, E, S, W, Su e Giù,
  • Bishop - ha 8 direzioni di viaggio triagonali: NE + Su / Giù, SE + Su / Giù, SW + Su / Giù, NW + Su / Giù
  • Knight : sposta 2 spazi su un asse, quindi 1 spazio su un altro. Proprio come gli scacchi regolari, il cavaliere è l'unico pezzo che può saltare su altri pezzi.

Piece Tester

Usa questo frammento per vedere come i diversi pezzi si muovono sulla tavola 3D ( suggerimento : controlla le *Testfunzioni in JS per modi rapidi per determinare se un quadrato è una mossa valida, semplicemente in base alla sua distanza assoluta dal pezzo.):

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>

Sfida

Dato un n x n x n board, determinare se il re bianco è in scacco matto.

Ingresso

  • (Opzionale) n ≥ 2 - la dimensione della scheda
  • Il tabellone
    • Può essere nella forma di 1d-2d- o 3d-array o altri formati simili. La notazione può essere in qualsiasi formato semplice. Ad esempio, KQRBN (bianco) e kqrbn (nero) con # per i cubi vuoti. Oppure, utilizzare i numeri per i diversi valori.
    • Pensa alla scacchiera 3D come a più schede sovrapposte una sopra l'altra e elencate dall'alto verso il basso. Quindi, ogni singola scheda viene annotata da sinistra a destra, dalla parte posteriore a quella anteriore (dal lato nero al lato bianco).
    • Immagina questo caso 2x2x2 dato come un array 3D:
 [
[[Bq] [##]]
[[Bn] [KQ]]
]

Tavola "superiore": tavola inserisci qui la descrizione dell'immagine"inferiore":inserisci qui la descrizione dell'immagine

Produzione

  • booleano (valore verità / falsità) - vero se il re bianco è in scacco matto, falso altrimenti.

Scacco matto

Il re bianco è sotto controllo se un pezzo nero minaccia di catturarlo al prossimo turno di Black. Per sfuggire al controllo, White deve spostare il suo re in salvo, difenderlo con un altro pezzo o catturare il pezzo minaccioso. Se il bianco non ha modo di sfuggire al controllo, allora il re bianco è in scacco matto . Ricorda, se il Bianco non è sotto controllo, ma non può muoversi senza essere sotto controllo, allora è una situazione di stallo , che non è un scacco matto.

specificazione

  • Non ti verrà data una tavola in cui il re nero sta cercando di "controllare" il re bianco, o una tavola in cui entrambi i re sono sotto controllo (scenari impossibili).

Casi test

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

    inserisci qui la descrizione dell'immagine(III) inserisci qui la descrizione dell'immagine(II) inserisci qui la descrizione dell'immagine(I)

    Uscita: vero

    Spiegazione: Il re sta ricevendo un assegno dalla torre all'ultimo piano. La torre bianca non è in grado di bloccare l'attacco o catturare la torre minacciosa, quindi il re deve cercare di allontanarsi. Consideriamo le opzioni di mossa del re:

    1. c2 (I) - custodito dal vescovo a b3 (II)
    2. b2 (I) - custodito dal cavaliere a a2 (III)
    3. c1 (II) - custodito da torre in c1 (III)
    4. b1 (II) - custodito da torre a b1 (III)
    5. c2 (II) - custodito dal cavaliere ad a2 (III)
    6. b2 (II) - custodito dal vescovo a a1 (I)

Dal momento che il re non può sfuggire all'assegno, è uno scacco matto!

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

    inserisci qui la descrizione dell'immagine(III) inserisci qui la descrizione dell'immagine(II) inserisci qui la descrizione dell'immagine(I)

    Uscita: falso Spiegazione: Il re riceve un assegno dalla regina e non ha mosse con cui fuggire o bloccare. Tuttavia, il cavaliere può catturare la regina.

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

    inserisci qui la descrizione dell'immagine(III) inserisci qui la descrizione dell'immagine(II) inserisci qui la descrizione dell'immagine(I)

Uscita: falso Spiegazione: Il bianco non ha modo di catturare la regina minacciosa o di spostare il suo re in salvo. Tuttavia, spostando il suo vescovo in b2 (II), White può bloccare la minaccia della regina.

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

    inserisci qui la descrizione dell'immagine(IV) inserisci qui la descrizione dell'immagine(III) inserisci qui la descrizione dell'immagine(II) inserisci qui la descrizione dell'immagine(I)

    Uscita: vero Spiegazione: In questo caso il re riceve un assegno da uno dei cavalieri e una regina. Anche se White può catturare / bloccare uno dei pezzi da controllare, non può catturare / bloccare entrambi. Pertanto, White deve provare a spostare il re senza controllo, ma non ha opzioni.

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

    inserisci qui la descrizione dell'immagine(III) inserisci qui la descrizione dell'immagine(II) inserisci qui la descrizione dell'immagine(I)

Output: false Spiegazione: Il bianco non è sotto controllo, ma non ha modo di muoversi senza essere controllato. Pertanto, è una situazione di stallo, ma non un scacco matto.

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

    inserisci qui la descrizione dell'immagine(III) inserisci qui la descrizione dell'immagine(II) inserisci qui la descrizione dell'immagine(I)

Output: true Spiegazione: White vorrebbe piombare con la sua regina per difendere il suo re, ma il suo cavaliere sta bloccando il percorso.

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

    inserisci qui la descrizione dell'immagine(III) inserisci qui la descrizione dell'immagine(II) inserisci qui la descrizione dell'immagine(I)

Uscita: vero Spiegazione: Il bianco non può prendere la regina con il suo cavaliere, perché allora il corvo controllerà il re di Bianco.

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

    inserisci qui la descrizione dell'immagine(II) inserisci qui la descrizione dell'immagine(I)

Uscita: falso Spiegazione: Il bianco può catturare la regina con il suo re.

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

    inserisci qui la descrizione dell'immagine(II) inserisci qui la descrizione dell'immagine(I)

Output: true Spiegazione: Questa volta il corvo fa la guardia, quindi il re non può catturare la regina.

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

    inserisci qui la descrizione dell'immagine(III) inserisci qui la descrizione dell'immagine(II) inserisci qui la descrizione dell'immagine(I)

Uscita: falso Spiegazione: Il re bianco può scappare catturando il cavaliere.


Solo un dettaglio, ma non lo farebbe cell.className = (i + j)%2 == 0 ? "black" : "white" sarebbe meglio nello snippet?
Arnauld,

@Arnauld lol, ho dimenticato di risolvere la cosa più ovvia.
geokavel,

Qual è la dimensione della scheda più grande che dobbiamo supportare?
Weijun Zhou

1
@WeijunZhou Fondamentalmente dovresti essere in grado di fare i casi di test in un ragionevole lasso di tempo per vedere se il tuo codice funziona. Per numeri più grandi ha solo bisogno di funzionare teoricamente dato il tempo e la memoria infiniti.
geokavel,

Risposte:


5

Rubino , 412 413 byte

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

Provalo online! Ora controllato su tutti i casi di test. Codice aumentato di 1 byte per correggere un bug nel caso 5 (caso di stallo).

Funzione di Llambda che richiede input come stringa nel formato mostrato sotto. È possibile fornire un secondo parametro facoltativo, che indica quale gruppo di 32 codici ASCII deve essere considerato nella mossa successiva (per impostazione predefinita questo 2 corrisponde a caratteri maiuscoli / bianchi, ma la funzione si chiama ricorsivamente usando 3 corrispondenti a caratteri minuscoli / neri. )

Livello di ricorsione 1: prova tutte le mosse possibili per il bianco (da qualsiasi cubo a qualsiasi cubo) e passa attraverso tutte quelle legali. Livello di ricorsione 2: In ogni caso, quindi, si chiama per passare attraverso tutte le possibili mosse per il nero. Ciò ritorna vero se il re bianco è sopravvissuto a tutte le possibili mosse nere. Livello di ricorsione 1: Se tutte le possibili mosse bianche portano a una situazione in cui il re bianco NON sopravvive a tutte le possibili mosse nere, allora restituisce vero (altrimenti falso).

In generale, un pezzo non può spostarsi in una casella occupata da un pezzo amico. Per considerare il caso in cui il bianco non si muove affatto (quindi lo scacco matto non si ferma), è consentito anche il caso in cui il re "si sposta" nella casella in cui si trova. Per motivi di codice breve, anche gli altri pezzi bianchi possono spostarsi nella piazza occupata dal re bianco. Questa è una mossa senza senso, ma permetterlo non influisce sul risultato, quindi non è un problema.

I seguenti test vengono utilizzati per verificare se una mossa è valida per ogni pezzo. x,y,zsono i quadrati delle distanze percorse in ciascun asse.eè la somma di questi (da cui il quadrato della distanza euclidea) ed dè il massimo. Il tipo di pezzo è ANDed con 95 per convertire i valori ASCII minuscoli in maiuscoli.

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

Codice commentato

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

Non potresti giocare a golf usando valori ASCII a 1 cifra? Inoltre, intendevi "stallo non scacco matto" nel terzo paragrafo?
geokavel,

@geokavel La rappresentazione più breve di un singolo valore ASCII in Ruby è ?A(c'è un esempio nel codice), quindi è ancora 2 byte. Ancora meglio di alcune lingue che richiedono "A". Ci sono state alcune manipolazioni che andavano meglio con i valori ASCII piuttosto che con i personaggi (in particolare o^k>31ciò assicura che un pezzo possa spostarsi in un quadrato non occupato o in uno occupato da un pezzo amico ma non ostile.)
Level River St

Intendo scacco matto non stallo. Lo stallo è la situazione in cui il re è minacciato se il giocatore si muove. Scacco matto è la situazione in cui il re è minacciato se il giocatore si muove, e anche se non lo fa.
Level River St

Che cosa succede se si utilizzano valori int anziché valori ascii (ovvero array di ints anziché string)?
geokavel,

@geokavel ints probabilmente sarebbe più breve, e potrei rivederlo in seguito poiché è specificamente consentito dalle specifiche. Ma sono andato con il formato scelto in parte perché era più leggibile dall'uomo (quindi più facile da sviluppare) e in parte perché sono stato ispirato da questa mia risposta che ha fortemente influenzato il mio pensiero: codegolf.stackexchange.com/a/45544/15599
Level River St
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.