Szachy Trójwymiarowe

26

Aby bronić czyjejś zdumiewającej decyzji, ludzie często mówią, że ta osoba idzie ponad głowę i gra w „trójwymiarowe szachy”. Teraz masz szansę zagrać w trójwymiarowe szachy!

Zasady

Istnieje wiele wariantów gry w szachy 3D , ale do tego wyzwania stworzyłem własne. Moja wersja jest jak zwykłe szachy, tyle że kawałki są w kostkach zamiast kwadratów i mają teraz dodatkowy wymiar ruchu. Aby to wyzwanie proste istnieją żadne pionkami i nie roszady .

Ruch częściowy

(Kierunki kompasu odnoszą się do ruchu, który miałby miejsce na standardowej szachownicy, w górę i w dół odnoszą się do ruchu w pionie na szachownicy 3D).

  • Król - ma 26 pól, do których może przejść w danej turze: N, NE, E, SE, S, SW, W, NW; oraz w górę, w dół i w górę / w dół + jeden z kierunków kompasu.
  • Królowa - może poruszać się w tych samych kierunkach co król, ale tak daleko, jak chce w tych kierunkach.
  • Gawron - może poruszać się w 6 kierunkach: N, E, S, W, Góra i Dół,
  • Bishop - ma 8 trójkątnych kierunków podróży: NE + góra / dół, SE + góra / dół, SW + góra / dół, NW + góra / dół
  • Rycerz - przenosi 2 pola o jedną oś, a następnie 1 pole o drugą. Podobnie jak zwykłe szachy, rycerz jest jedynym pionkiem, który może przeskoczyć nad innymi pionkami.

Tester sztuk

Użyj tego fragmentu, aby zobaczyć, jak różne elementy poruszają się na planszy 3D ( wskazówka : sprawdź *Testfunkcje w JS, aby szybko dowiedzieć się, czy kwadrat jest prawidłowym ruchem, po prostu na podstawie jego bezwzględnej odległości od elementu.):

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>

Wyzwanie

Biorąc pod uwagę planszę n x n x n , sprawdź, czy biały król jest w szachach.

Wkład

  • (Opcjonalnie) n ≥ 2 - rozmiar planszy
  • Plansza do gry
    • Może być w postaci tablicy 1d-2d lub 3d lub innego podobnego formatu. Notacja może mieć dowolny prosty format. Na przykład KQRBN (biały) i kqrbn (czarny) z # dla pustych kostek. Lub użyj liczb dla różnych wartości.
    • Pomyśl o szachownicy 3D jako o wielu planszach ułożonych jeden na drugim i uszeregowanych od góry do dołu. Następnie każda tablica jest notowana od lewej do prawej, od tyłu do przodu (strona czarna do białej).
    • Wyobraź sobie ten przypadek 2x2x2 podany w postaci tablicy 3D:
 [
[[bq] [##]]
[[bn] [KQ]]
]

Tablica „górna”: tablica wprowadź opis zdjęcia tutaj„dolna”:wprowadź opis zdjęcia tutaj

Wydajność

  • boolean (wartość prawda / fałsz) - prawda, jeśli biały król jest w szachach, w przeciwnym razie fałsz.

Szach mat

Biały król jest w ryzach, jeśli czarny pion grozi, że przejmie go w następnej turze Blacka. Aby wymknąć się spod kontroli, białe muszą przenieść swojego króla w bezpieczne miejsce, bronić go innym kawałkiem lub schwytać groźny element. Jeśli biały nie ma sposobu, aby wymknąć się z kontroli, biały król jest w szachach . Pamiętaj, że jeśli białe nie są w szachach, ale nie mogą się poruszać bez wchodzenia w kratkę, oznacza to impas , który nie jest matą.

Specyfikacja

  • Nie dostaniesz planszy, na której czarny król próbuje „sprawdzić” białego króla, ani planszy, na której obaj królowie są w ryzach (niemożliwe scenariusze).

Przypadki testowe

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

    wprowadź opis zdjęcia tutaj(III) wprowadź opis zdjęcia tutaj(II) wprowadź opis zdjęcia tutaj(I)

    Wyjście: prawda

    Objaśnienie: Król otrzymuje czek z wieży na najwyższym piętrze. Biała wieża nie jest w stanie zablokować ataku ani przejąć groźnej wieży, więc król musi spróbować zejść z drogi. Rozważmy opcje ruchu króla:

    1. c2 (I) - strzeżony przez biskupa w b3 (II)
    2. b2 (I) - strzeżony przez rycerza w a2 (III)
    3. c1 (II) - strzeżony przez wieżę w c1 (III)
    4. b1 (II) - strzeżony przez wieżę w b1 (III)
    5. c2 (II) - strzeżony przez rycerza w a2 (III)
    6. b2 (II) - strzeżony przez biskupa w a1 (I)

Ponieważ król nie może uciec czek, jest to mat!

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

    wprowadź opis zdjęcia tutaj(III) wprowadź opis zdjęcia tutaj(II) wprowadź opis zdjęcia tutaj(I)

    Wyjście: fałsz Objaśnienie: Król otrzymuje czek od królowej i nie ma żadnych ruchów, aby uciec lub zablokować. Rycerz może jednak schwytać królową.

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

    wprowadź opis zdjęcia tutaj(III) wprowadź opis zdjęcia tutaj(II) wprowadź opis zdjęcia tutaj(I)

Wyjście: fałsz Objaśnienie: Białe nie mają szansy na schwytanie groźnej królowej lub przeniesienie swojego króla w bezpieczne miejsce. Jednak przesuwając swojego biskupa do b2 (II), białe mogą zablokować zagrożenie królowej.

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

    wprowadź opis zdjęcia tutaj(IV) wprowadź opis zdjęcia tutaj(III) wprowadź opis zdjęcia tutaj(II) wprowadź opis zdjęcia tutaj(I)

    Wyjście: prawda Objaśnienie: W tym przypadku król otrzymuje czek od jednego z rycerzy i królowej. Chociaż białe potrafią uchwycić / zablokować jeden z elementów kontrolnych, nie mogą uchwycić / zablokować obu. Dlatego białe muszą spróbować odsunąć króla spod kontroli, ale nie ma żadnych opcji.

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

    wprowadź opis zdjęcia tutaj(III) wprowadź opis zdjęcia tutaj(II) wprowadź opis zdjęcia tutaj(I)

Wyjście: fałsz Objaśnienie: Białe nie są w szachach, ale nie mogą się poruszać bez wchodzenia w kratkę. Dlatego jest to impas, ale nie mat.

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

    wprowadź opis zdjęcia tutaj(III) wprowadź opis zdjęcia tutaj(II) wprowadź opis zdjęcia tutaj(I)

Rezultat: prawda Objaśnienie: Białe chcą przyłączyć się do swojej królowej, aby bronić króla, ale jego rycerz blokuje ścieżkę.

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

    wprowadź opis zdjęcia tutaj(III) wprowadź opis zdjęcia tutaj(II) wprowadź opis zdjęcia tutaj(I)

Wyjście: prawda Objaśnienie: Białe nie mogą zabrać królowej ze swoim rycerzem, ponieważ wtedy wieża będzie sprawdzać króla Białych.

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

    wprowadź opis zdjęcia tutaj(II) wprowadź opis zdjęcia tutaj(I)

Wyjście: fałsz Objaśnienie: Białe mogą schwytać królową ze swoim królem.

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

    wprowadź opis zdjęcia tutaj(II) wprowadź opis zdjęcia tutaj(I)

Wynik: prawda Objaśnienie: Tym razem wieża się strzeże, więc król nie może schwytać królowej.

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

    wprowadź opis zdjęcia tutaj(III) wprowadź opis zdjęcia tutaj(II) wprowadź opis zdjęcia tutaj(I)

Wyjście: fałsz Objaśnienie: Biały król może uciec, chwytając rycerza.

geokavel
źródło
Tylko szczegół, ale czy nie cell.className = (i + j)%2 == 0 ? "black" : "white"byłby lepszy we fragmencie?
Arnauld,
@Arnauld lol, zapomniałem naprawić najbardziej oczywistą rzecz.
geokavel
Jaki jest największy rozmiar płyty, który musimy wesprzeć?
Weijun Zhou
1
@WeijunZhou Zasadniczo powinieneś być w stanie wykonać przypadki testowe w rozsądnym czasie, aby sprawdzić, czy Twój kod działa. W przypadku większych liczb wystarczy teoretycznie pracować, biorąc pod uwagę nieskończony czas i pamięć.
geokavel

Odpowiedzi:

5

Rubinowy , 412 413 bajtów

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

Wypróbuj online! Teraz sprawdzane we wszystkich przypadkach testowych. Zwiększono kod o 1 bajt, aby naprawić błąd w przypadku 5 (przypadek impasu).

Funkcja Llambda wymagająca wprowadzania jako ciąg znaków w formacie pokazanym poniżej. Można podać opcjonalny drugi parametr, wskazujący, która grupa 32 kodów ASCII ma być wzięta pod uwagę przy następnym ruchu (domyślnie to 2 odpowiada wielkich / białych znaków, ale funkcja wywołuje się rekurencyjnie, używając 3 odpowiadających małym / czarnym znakom. )

Poziom rekurencji 1: Próbuje wszystkich możliwych ruchów białych (z dowolnej kostki do dowolnej kostki) i przechodzi przez wszystkie legalne. Poziom rekurencji 2: W każdym przypadku następnie wzywa się do przejścia przez wszystkie możliwe ruchy czarnych. Zwraca to prawdę, jeśli biały król przetrwał wszystkie możliwe czarne ruchy. Poziom rekurencji 1: Jeśli wszystkie możliwe białe ruchy doprowadzą do sytuacji, w której biały król NIE przeżyje wszystkich możliwych czarnych ruchów, wówczas zwraca wartość true (w przeciwnym razie false).

Ogólnie rzecz biorąc, pionek nie może przejść na pole zajmowane przez pionek przyjazny. Aby rozważyć przypadek, w którym biały w ogóle się nie porusza (stąd mat nie jest impasem), dozwolony jest również przypadek, w którym król „przesuwa się” na pole, na którym już jest. Z powodu krótkiego kodu pozostałe białe pionki mogą również przenieść się na pole zajmowane przez białego króla. Jest to nonsensowny ruch, ale pozwolenie na to nie wpływa na wynik, więc nie stanowi problemu.

Poniższe testy służą do sprawdzenia, czy ruch jest prawidłowy dla każdego elementu. x,y,zsą kwadratami odległości przebytych w każdej osi. ejest ich sumą (stąd kwadrat odległości euklidesowej) i djest wartością maksymalną. Typ elementu jest AND z 95, aby przekonwertować małe wartości ASCII na wielkie.

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

Skomentowany kod

->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
źródło
Czy nie możesz zagrać w golfa przy użyciu 1-cyfrowych wartości ascii? Czy miałeś również na myśli „impas, a nie mat” w trzecim akapicie?
geokavel
@geokavel Najkrótsza reprezentacja pojedynczej wartości ascii w Ruby to ?A(jest w kodzie przykład), więc nadal 2 bajty. Nadal lepsze niż niektóre języki, które wymagają "A". Były pewne manipulacje, które szły lepiej z wartościami ASCII niż z postaciami (w szczególności o^k>31zapewnia to, że pionek może przenieść się na niezajęty plac lub obszar zajmowany przez kawałek przyjazny, ale nie wrogi).
Level River St
Mam na myśli mat, a nie impas. Stalemate to sytuacja, w której król jest zagrożony, jeśli gracz się poruszy. Szach to sytuacja, w której król jest zagrożony, jeśli gracz poruszy się, a także jeśli nie.
Level River St
Co jeśli użyjesz wartości int zamiast wartości ascii (tj. Tablica liczb int zamiast łańcucha)?
geokavel
@geokavel ints prawdopodobnie byłby krótszy i mogę go później zmienić, ponieważ jest to wyraźnie dozwolone przez specyfikację. Ale wybrałem ten format częściowo dlatego, że był bardziej czytelny dla człowieka (a więc łatwiejszy do opracowania), a częściowo dlatego, że zainspirowała mnie moja odpowiedź, która mocno wpłynęła na moje myślenie: codegolf.stackexchange.com/a/45544/15599
Poziom River St