Üç Boyutlu Satranç


26

Birinin şaşırtıcı kararını savunmak için insanlar genellikle o kişinin herkesin başına geçtiğini ve “3 boyutlu satranç” oynadığını söyler. Şimdi 3 boyutlu satranç oynama şansın!

kurallar

3D Satranç'ın birçok çeşidi var , ama bu meydan okuma için kendimi uydurdum. Benim versiyonum da normal satranç taşları gibidir, ancak parçalar kareler yerine küplerin içindedir ve artık ek bir hareket boyutu vardır. Orada bu meydan basit hale getirmek için hiçbir piyonlar ve Rok .

Parça Hareketi

(Pusula yönleri, standart bir satranç tahtasında gerçekleşecek hareketi, Yukarı ve Aşağı 3D satranç tahtasında dikey olarak hareket etmeyi belirtir).

  • King - verilen bir dönüşte gidebileceği 26 kareye sahip: N, NE, E, SE, S, SW, W, NW; yanı sıra yukarı, aşağı ve yukarı / aşağı + pusula yönlerinden birini.
  • Kraliçe - Kral ile aynı yönde hareket edebilir, ancak istediği kadarıyla bu yönde hareket edebilir.
  • Kale - 6 yönde hareket edebilir: N, E, S, W, Yukarı ve Aşağı,
  • Piskopos - 8 üçgensel hareket yönü var: NE + Yukarı / Aşağı, SE + Yukarı / Aşağı, SW + Yukarı / Aşağı, NW + Yukarı / Aşağı
  • Şövalye - bir eksende 2 boşluk, ardından bir boşlukta 1 boşluk. Tıpkı normal satranç taşları gibi, şövalye diğer parçalara atlayabilecek tek parça.

Parça Test Cihazı

Farklı parçaların 3B panosunda nasıl hareket ettiğini görmek için bu pasajı kullanın ( ipucu : *Testbir karenin geçerli bir hareket olup olmadığını belirlemek için JS'deki fonksiyonlara hızlıca bakın.

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>

Meydan okuma

Bir n x n x n levha verildiğinde , beyaz kralın eş arkadaşı olup olmadığını belirleyin.

Giriş

  • (İsteğe bağlı) n ≥ 2 - tahta boyutu
  • Oyun tahtası
    • 1d - 2d veya 3d dizi veya benzeri bir formatta olabilir. Gösterim, herhangi bir basit biçimde olabilir. Örneğin, boş küpler için # ile KQRBN (Beyaz) ve kqrbn (Siyah). Veya farklı değerler için sayılar kullanın.
    • 3D satranç tahtasını, üst üste yığılmış ve yukarıdan aşağıya doğru listelenmiş çoklu panolar olarak düşünün. Daha sonra, her bir tahta soldan sağa, arkadan öne (Siyah taraftan Beyaz tarafa) not edilir.
    • 3B dizi olarak verilen bu 2x2x2 vakasını hayal edin:
 [
[[Bq] [##]]
[[Bn] [KQ]]
]

"üst" tahta: görüntü tanımını buraya girin"alt" tahta:görüntü tanımını buraya girin

Çıktı

  • boolean (truthy / falsy value) - beyaz kralın eş arkadaşı olması durumunda doğru, aksi takdirde yanlış.

Şah Mat

Beyaz kral, bir siyah parçanın bir sonraki dönüşünde onu ele geçirme tehdidi altında olup olmadığını kontrol ediyor. Kontrolden çıkmak için White'ın kralı güvenliğe götürmesi, başka bir taşla savunması veya tehdit edici parçayı ele geçirmesi gerekiyor. White'ın kontrolden çıkmanın bir yolu yoksa, o zaman beyaz kral eşdedir . Unutmayın, Beyaz kontrol altında değilse de kontrol edilmeden hareket edemiyorsa , bu bir kontrol arkadaşı olmayan bir çıkmazdır .

Şartname

  • Kara kralın beyaz kralı "kontrol etmeye" çalıştığı bir tahta veya her iki kralın da kontrol altında olduğu bir tahta (imkansız senaryolar) verilmez.

Test Kılıfları

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

    görüntü tanımını buraya girin(III) görüntü tanımını buraya girin(II) görüntü tanımını buraya girin(I)

    Çıktı: doğru

    Açıklama: Kral, üst kattaki kaleden bir çek alıyor. Beyaz kale saldırıyı engelleyemiyor veya tehdit edici rotayı yakalayamıyor, bu yüzden kral yoldan çekilmeye çalışmalı. Kralın hareket seçeneklerini düşünelim:

    1. c2 (I) - b3 (II) 'de piskopos tarafından korunmaktadır
    2. b2 (I) - a2 (III) 'deki şövalye tarafından korunan
    3. c1 (II) - c1 (III) deki kale tarafından korunmaktadır
    4. b1 (II) - b1 (III) deki kale tarafından korunmaktadır
    5. c2 (II) - a2 (III) de şövalye tarafından korunmaktadır
    6. b2 (II) - a1 (I) 'de piskopos tarafından korunan

Kral çeklerden kaçamayacağından, bu bir çek arkadaşı!

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

    görüntü tanımını buraya girin(III) görüntü tanımını buraya girin(II) görüntü tanımını buraya girin(I)

    Çıktı: yanlış Açıklama: Kral kraliçeden bir çek alıyor ve kaçmak veya engellemek için hamle yapmıyor. Ancak, şövalye kraliçeyi ele geçirebilir.

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

    görüntü tanımını buraya girin(III) görüntü tanımını buraya girin(II) görüntü tanımını buraya girin(I)

Çıktı: yanlış Açıklama: Beyaz, tehdit altındaki kraliçeyi ele geçirme veya kralı güvenli hale getirme yoluna sahip değildir. Ancak, piskoposunu b2'ye (II) getirerek, Beyaz kraliçenin tehdidini engelleyebilir.

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

    görüntü tanımını buraya girin(IV) görüntü tanımını buraya girin(III) görüntü tanımını buraya girin(II) görüntü tanımını buraya girin(I)

    Çıktı: doğru Açıklama: Bu durumda kral, şövalyelerden birinden ve bir kraliçeden bir çek alıyor. Beyaz kontrol parçalarından birini yakalayabilse / engelleyebilse de, ikisini birden yakalayamaz / engelleyemez. Bu nedenle, Beyaz kralını kontrolden çıkarmaya çalışmalı, ancak başka seçeneği yok.

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

    görüntü tanımını buraya girin(III) görüntü tanımını buraya girin(II) görüntü tanımını buraya girin(I)

Çıktı: yanlış Açıklama: Beyaz kontrol altında değil, kontrol edilmeden hareket etmenin bir yolu yok. Bu nedenle, bir çıkmaz, ancak bir çek arkadaşı değil.

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

    görüntü tanımını buraya girin(III) görüntü tanımını buraya girin(II) görüntü tanımını buraya girin(I)

Çıktı: doğru Açıklama: Beyaz, kralını savunmak için kraliçesi ile dokunmak istiyor, ancak şövalyesi yolu tıkıyor.

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

    görüntü tanımını buraya girin(III) görüntü tanımını buraya girin(II) görüntü tanımını buraya girin(I)

Çıktı: doğru Açıklama: Beyaz, şövalyeyle kraliçeyi alamaz, çünkü o zaman kale Beyazın kralını kontrol eder.

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

    görüntü tanımını buraya girin(II) görüntü tanımını buraya girin(I)

Çıktı: yanlış Açıklama: Beyaz kraliçeyi kralıyla birlikte yakalayabilir.

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

    görüntü tanımını buraya girin(II) görüntü tanımını buraya girin(I)

Çıktı: doğru Açıklama: Bu sefer kale koruyor, böylece kral kraliçeyi ele geçiremiyor.

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

    görüntü tanımını buraya girin(III) görüntü tanımını buraya girin(II) görüntü tanımını buraya girin(I)

Çıktı: yanlış Açıklama: Beyaz kral şövalyeyi ele geçirerek kaçabilir.


Sadece bir detay, ama cell.className = (i + j)%2 == 0 ? "black" : "white"pasajda daha iyi olmaz mıydı ?
Arnauld

@Arnauld lol, en bariz şeyi düzeltmeyi unuttu.
geokavel

Desteklememiz gereken en büyük tahta boyutu nedir?
Weijun Zhou

1
@WeijunZhou Temel olarak, kodunuzun işe yarayıp yaramadığını görmek için test durumlarını makul bir süre içinde yapabilmelisiniz. Daha büyük sayılar için sadece sonsuz zaman ve hafıza verilen teorik olarak çalışması gerekir.
geokavel

Yanıtlar:


5

Ruby , 412 413 bayt

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

Çevrimiçi deneyin! Şimdi tüm test durumlarında kontrol edildi. Kod, durum 5'teki bir hatayı düzeltmek için 1 bayt artırıldı (genel durum durumu).

Llambda işlevi aşağıda gösterilen biçimde bir dize girişi gerektiren işlevdir. Bir sonraki hamlede hangi ASCII kod grubunun (32) seçileceğini belirten isteğe bağlı bir ikinci parametre verilebilir (varsayılan olarak bu 2, büyük / beyaz karakterlere karşılık gelir, ancak işlev küçük harf / siyah karakterlere karşılık gelen 3 kullanarak tekrarlı olarak çağırır. )

Özyineleme seviyesi 1: Beyaz için olası tüm hareketleri (herhangi bir küpün küpü) tüm yasal hareketlerin içinden geçmeye çalışır. Özyineleme seviyesi 2: Her durumda, siyahın tüm olası hareketlerini ilerletmek için kendisini çağırır. Beyaz kral tüm olası siyah hamleleri yaşadıysa bu gerçek olur. Özyineleme seviyesi 1: Tüm olası beyaz hareketler, beyaz kralın tüm olası siyah hareketlere dayanamadığı bir duruma yol açarsa, doğru olarak geri dönün (aksi takdirde yanlış).

Genel olarak, bir parça, dost bir parça tarafından işgal edilen bir kareye hareket edemez. Beyazın hiç hareket etmediği durumu (dolayısıyla kontrol arkadaşı çıkmaz değil) dikkate almak için, kralın üzerinde bulunduğu kareye "hareket ettiği" duruma de izin verilir. Kısa kod nedeniyle, diğer beyaz parçaların da beyaz kralın işgal ettiği kareye gitmesine izin verilir. Bu saçma bir hareket, ancak sonucu etkilememesine izin vermek bir sorun değil.

Her parça için bir hareketin geçerli olup olmadığını kontrol etmek için aşağıdaki testler kullanılır. x,y,zher eksende kat edilen mesafelerin kareleridir. ebunların toplamıdır (dolayısıyla öklid mesafesinin karesi) ve dmaksimumdur. Küçük ASCII değerlerini büyük harflere dönüştürmek için parça türü 95 ile ANDed'dir.

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

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

Bunu 1 basamaklı ascii değerlerini kullanarak golf alamaz mıydınız? Ayrıca, üçüncü paragrafta "çıkmaz çek değil" derken mi demek istediniz?
geokavel

@geokavel Ruby'deki tek bir ascii değerinin en kısa gösterimi ( ?Akodda bir örnek var) yani 2 bayt. Hala gerektiren bazı dillerden daha iyi "A". Karakterlerden ziyade ASCII değerleri ile daha iyi giden bazı manipülasyonlar vardı (özellikle o^k>31, bir parçanın boş bir kareye ya da dostça bir parça tarafından işgal edilen fakat düşmanca olmayan bir kareye hareket etmesini sağlar)
Level River St

Yani, kontrol arkadaşı çıkmaz değil. Çıkmaz, oyuncu hareket ederse kralın tehdit altında olduğu durumdur. Şah mat, oyuncu hareket ederse ve o oynamazsa, kralın tehdit altında olduğu durumdur.
Seviye Nehri St

Ascii değerleri yerine int değerleri kullandıysanız (dize yerine ints dizisi gibi)?
geokavel

@geokavel ints muhtemelen daha kısa olacaktır ve spesifik olarak spesifik olarak izin verildiği için daha sonra revize edebilirim. Ancak seçilen forma kısmen gittim, çünkü daha okunabilirdi (bu yüzden geliştirmesi daha kolaydı) ve kısmen de düşüncelerimi çok fazla etkileyen bu cevabımdan
Level Nehir St
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.