Catur Tiga Dimensi

26

Untuk membela keputusan seseorang yang membingungkan, orang sering mengatakan bahwa orang itu menguasai pikiran semua orang dan bermain “catur 3 dimensi”. Sekarang kesempatan Anda untuk bermain catur 3 dimensi!

Aturan

Ada banyak varian Catur 3D , tetapi untuk tantangan ini saya telah membuat sendiri. Versi saya hanya seperti catur biasa kecuali bahwa potongan-potongan itu berada di dalam kubus bukannya kotak, dan sekarang memiliki dimensi gerakan tambahan. Untuk membuat tantangan ini sederhana, tidak ada pion dan tidak ada casting .

Gerakan Sepotong

(Arah kompas mengacu pada gerakan yang akan terjadi pada papan catur standar, Naik dan Turun mengacu pada bergerak secara vertikal di papan catur 3D).

  • King - memiliki 26 kotak yang bisa dituju secara bergantian: N, NE, E, SE, S, SW, W, NW; juga atas, bawah, dan atas / bawah + salah satu arah kompas.
  • Ratu - dapat bergerak ke arah yang sama dengan Raja, tetapi sejauh yang dia inginkan ke arah itu.
  • Benteng - dapat bergerak dalam 6 arah: N, E, S, W, Atas, dan Bawah,
  • Bishop - memiliki 8 arah perjalanan segitiga: NE + Atas / Bawah, SE + Atas / Bawah, SW + Atas / Bawah, NW + Atas / Bawah
  • Ksatria - bergerak 2 spasi satu sumbu, lalu 1 ruang pada yang lain. Sama seperti catur biasa, ksatria adalah satu-satunya bidak yang bisa melompati bidak lainnya.

Sepotong Tester

Gunakan potongan ini untuk melihat bagaimana bagian-bagian yang berbeda bergerak di papan 3D ( tip : periksa *Testfungsi di JS untuk cara cepat untuk menentukan apakah kotak adalah langkah yang valid, cukup berdasarkan jarak absolutnya dari potongan.):

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>

Tantangan

Diberi papan n x n x n , tentukan apakah raja putih ada di skakmat.

Memasukkan

  • (Opsional) n ≥ 2 - ukuran papan
  • Papan permainan
    • Bisa dalam bentuk 1d- 2d- atau 3d- array, atau format serupa lainnya. Notasi dapat dalam format sederhana apa pun. Misalnya, KQRBN (Putih) dan kqrbn (Hitam) dengan # untuk kubus kosong. Atau, gunakan angka untuk nilai yang berbeda.
    • Pikirkan papan catur 3D karena banyak papan yang saling bertumpuk dan terdaftar dari atas ke bawah. Kemudian, masing-masing papan dinotasikan dari kiri ke kanan, kembali ke depan (sisi Hitam ke sisi Putih).
    • Bayangkan case 2x2x2 ini diberikan sebagai array 3D:
 [
[[bq] [##]]
[[bn] [KQ]]
]

papan "atas": papan masukkan deskripsi gambar di sini"bawah":masukkan deskripsi gambar di sini

Keluaran

  • boolean (nilai true / falsy) - benar jika raja kulit putih dalam skakmat, salah sebaliknya.

Sekakmat

Raja putih di cek jika sepotong hitam mengancam untuk menangkapnya pada giliran berikutnya Black. Untuk keluar dari kendali, White perlu memindahkan rajanya ke tempat yang aman, mempertahankannya dengan bagian lain, atau menangkap bagian yang mengancam. Jika White tidak memiliki cara untuk keluar dari cek, maka raja putih berada di skakmat . Ingat, jika Putih tidak di cek, tetapi tidak bisa bergerak tanpa masuk ke cek, maka itu adalah jalan buntu , yang bukan skakmat.

Spesifikasi

  • Anda tidak akan diberikan papan tempat raja hitam berusaha "memeriksa" raja putih, atau papan tempat kedua raja berada di bawah kendali (skenario yang mustahil).

Uji Kasus

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

    masukkan deskripsi gambar di sini(III) masukkan deskripsi gambar di sini(II) masukkan deskripsi gambar di sini(I)

    Output: benar

    Penjelasan: Raja menerima cek dari benteng di lantai atas. Benteng putih tidak dapat memblokir serangan atau menangkap benteng yang mengancam, sehingga raja harus mencoba untuk bergerak keluar dari jalan. Mari kita pertimbangkan opsi langkah raja:

    1. c2 (I) - dijaga oleh uskup di b3 (II)
    2. b2 (I) - dijaga oleh knight di a2 (III)
    3. c1 (II) - dijaga oleh benteng di c1 (III)
    4. b1 (II) - dijaga oleh benteng di b1 (III)
    5. c2 (II) - dijaga oleh knight di a2 (III)
    6. b2 (II) - dijaga oleh uskup di a1 (I)

Karena raja tidak bisa lolos dari pemeriksaan, itu adalah sekakmat!

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

    masukkan deskripsi gambar di sini(III) masukkan deskripsi gambar di sini(II) masukkan deskripsi gambar di sini(I)

    Keluaran: false Penjelasan: Raja menerima cek dari ratu, dan tidak memiliki gerakan untuk melarikan diri atau memblokir. Namun, sang ksatria bisa menangkap sang ratu.

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

    masukkan deskripsi gambar di sini(III) masukkan deskripsi gambar di sini(II) masukkan deskripsi gambar di sini(I)

Keluaran: false Penjelasan: Putih tidak memiliki cara untuk menangkap ratu yang mengancam atau memindahkan rajanya ke tempat yang aman. Namun, dengan memindahkan uskupnya ke b2 (II), White dapat memblokir ancaman ratu.

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

    masukkan deskripsi gambar di sini(IV) masukkan deskripsi gambar di sini(III) masukkan deskripsi gambar di sini(II) masukkan deskripsi gambar di sini(I)

    Keluaran: Penjelasan benar : Dalam hal ini raja menerima cek dari salah satu ksatria dan ratu. Meskipun Putih dapat menangkap / memblokir salah satu dari barang yang diperiksa, ia tidak dapat menangkap / memblokir keduanya. Oleh karena itu, Putih harus mencoba untuk memindahkan rajanya dari cek, tetapi ia tidak memiliki pilihan.

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

    masukkan deskripsi gambar di sini(III) masukkan deskripsi gambar di sini(II) masukkan deskripsi gambar di sini(I)

Output: false Penjelasan: Putih tidak di periksa, tetapi tidak memiliki cara untuk bergerak tanpa memeriksa. Oleh karena itu, ini adalah jalan buntu, tetapi bukan skakmat.

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

    masukkan deskripsi gambar di sini(III) masukkan deskripsi gambar di sini(II) masukkan deskripsi gambar di sini(I)

Keluaran: benar Penjelasan: Putih ingin menukik dengan ratu untuk membela rajanya, tetapi kesatria itu menghalangi jalan.

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

    masukkan deskripsi gambar di sini(III) masukkan deskripsi gambar di sini(II) masukkan deskripsi gambar di sini(I)

Output: true Penjelasan: Putih tidak dapat mengambil ratu dengan ksatrianya, karena kemudian benteng akan memeriksa raja White.

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

    masukkan deskripsi gambar di sini(II) masukkan deskripsi gambar di sini(I)

Output: false Penjelasan: Putih dapat menangkap ratu dengan rajanya.

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

    masukkan deskripsi gambar di sini(II) masukkan deskripsi gambar di sini(I)

Output: true Penjelasan: Kali ini benteng itu menjaga, jadi raja tidak bisa menangkap ratu.

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

    masukkan deskripsi gambar di sini(III) masukkan deskripsi gambar di sini(II) masukkan deskripsi gambar di sini(I)

Output: false Penjelasan: Raja putih dapat melarikan diri dengan menangkap ksatria.

geokavel
sumber
Hanya detail, tetapi tidak cell.className = (i + j)%2 == 0 ? "black" : "white"akan lebih baik di cuplikan?
Arnauld
@Arnauld lol, lupa untuk memperbaiki hal yang paling jelas.
geokavel
Berapa ukuran papan terbesar yang perlu kita dukung?
Weijun Zhou
1
@ WeijunZhou Pada dasarnya Anda harus dapat melakukan uji kasus dalam jumlah waktu yang wajar untuk melihat apakah kode Anda berfungsi. Untuk angka yang lebih besar itu hanya perlu secara teoritis bekerja mengingat waktu dan memori yang tak terbatas.
geokavel

Jawaban:

5

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

Cobalah online! Sekarang periksa semua test case. Kode bertambah 1 byte untuk memperbaiki bug pada case 5 (case stalemate.)

Fungsi Llambda membutuhkan input sebagai string dalam format yang ditunjukkan di bawah ini. Parameter opsional kedua dapat diberikan, menunjukkan kelompok mana dari 32 kode ASCII yang harus dipertimbangkan pada langkah berikutnya (secara default 2 ini sesuai dengan karakter huruf besar / putih, tetapi fungsi menyebut dirinya secara rekursif menggunakan 3 yang sesuai dengan huruf kecil / karakter hitam. )

Level rekursi 1: Mencoba semua gerakan yang mungkin untuk putih (kubus apa pun ke kubus mana pun) dan melangkah melalui semua langkah hukum. Level rekursi 2: Dalam setiap kasus kemudian memanggil dirinya sendiri untuk melangkah melalui semua kemungkinan gerakan untuk hitam. Ini mengembalikan true jika raja putih telah selamat dari semua kemungkinan pergerakan hitam. Level rekursi 1: Jika semua gerakan putih yang mungkin mengarah pada situasi di mana raja putih TIDAK bertahan dari semua gerakan hitam yang mungkin, maka kembalikan benar (jika tidak palsu.)

Secara umum, sepotong tidak bisa bergerak ke kotak yang ditempati oleh sepotong ramah. Untuk mempertimbangkan kasus di mana putih tidak bergerak sama sekali (maka skakmat tidak kebuntuan), kasus di mana raja "pindah" ke alun-alun dia sudah di juga diperbolehkan. Untuk alasan kode pendek, potongan putih lainnya juga diperbolehkan untuk pindah ke alun-alun yang ditempati oleh raja putih. Ini adalah langkah yang tidak masuk akal, tetapi membiarkannya tidak mempengaruhi hasilnya sehingga tidak menjadi masalah.

Tes berikut digunakan untuk memeriksa apakah suatu gerakan valid untuk masing-masing bagian. x,y,zadalah kuadrat jarak yang ditempuh di setiap sumbu. eadalah jumlah dari ini (maka kuadrat dari jarak euclidean) dan dmerupakan maksimum. Jenis potongan ANDed dengan 95 untuk mengkonversi nilai ASCII huruf kecil menjadi huruf besar.

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

Kode yang dikomentari

->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
sumber
Tidak bisakah Anda golf ini dengan menggunakan nilai ascii 1-digit? Juga, apakah maksud Anda "jalan buntu bukan skakmat" di paragraf ketiga?
geokavel
@geokavel Representasi terpendek dari nilai ascii tunggal di Ruby adalah ?A(ada contoh dalam kode) jadi masih 2 byte. Masih lebih baik daripada beberapa bahasa yang membutuhkan "A". Ada manipulasi tertentu yang berjalan lebih baik dengan nilai-nilai ASCII daripada karakter (khususnya o^k>31yang memastikan bahwa sepotong dapat pindah ke kotak kosong atau ditempati oleh sepotong ramah tetapi tidak bermusuhan.)
Level River St
Maksud saya sekakmat tidak jalan buntu. Kebuntuan adalah situasi di mana raja terancam jika pemain bergerak. Skakmat adalah situasi di mana raja terancam jika pemain bergerak, dan juga jika dia tidak.
Level River St
Bagaimana jika Anda menggunakan nilai int bukan nilai ascii (yaitu array int bukan string)?
geokavel
@geokavel ints mungkin akan lebih pendek, dan saya dapat merevisinya nanti karena secara khusus diizinkan oleh spec. Tetapi saya pergi dengan format yang dipilih sebagian karena lebih mudah dibaca manusia (karena itu lebih mudah untuk dikembangkan) dan sebagian karena saya terinspirasi oleh jawaban saya yang sangat memengaruhi pemikiran saya: codegolf.stackexchange.com/a/45544/15599
Level Sungai St.