三维象棋


26

为了捍卫某人的莫名其妙的决定,人们经常说那个人在每个人的头顶上方,下着“ 3D国际象棋”。现在,您就有机会下3D象棋!

规则

3D Chess有很多变种,但是对于这个挑战,我已经做好了自己的准备。我的版本与常规国际象棋一样,除了棋子位于立方体而不是正方形内,并且现在具有更大的运动尺寸。为了使这一挑战变得简单,没有典当没有铸造

件运动

(指南针方向是指在标准棋盘上发生的移动,“向上”和“向下”是指在3D棋盘上垂直移动)。

  • 国王 -在给定的回合上可以移动26个正方形:N,NE,E,SE,S,SW,W,NW; 以及上,下和上/下+指南针方向之一。
  • 女王 -可以朝国王的方向移动,但只要她想朝这些方向移动即可。
  • 车鸦 -可以在6个方向上移动:N,E,S,W,向上和向下,
  • 毕晓普 -有旅行的8个triagonal方向:NE +上/下,SE +上/下,SW +上/下,NW +向上/向下
  • 骑士 -一个轴移动2个空间,然后再移动1个空间。就像普通的国际象棋一样,骑士是唯一可以超越其他棋子的棋子。

零件测试仪

使用此代码段查看不同块在3D板上的移动方式(提示*Test只需根据距块的绝对距离,即可查看JS中的功能,以快速确定正方形是否为有效移动。):

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>

挑战

给定一个n x n x n的棋盘,确定白王是否将死。

输入项

  • (可选)ñ ≥2 -电路板的尺寸
  • 游戏板
    • 可以采用1d-2d或3d-阵列或其他类似格式的形式。表示法可以是任何简单格式。例如,带有#的KQRBN(白色)和kqrbn(黑色)表示空的多维数据集。或者,将数字用于不同的值。
    • 将3D国际象棋棋盘想象成是多个棋盘互相堆叠并从上到下列出。然后,从左到右,从前到后(黑边到白边)标记每个单独的板。
    • 想象一下,将这种2x2x2情况作为3D数组给出:
 [
[[bq] [##]]
[[bn] [KQ]]
]

“顶部”板:在此处输入图片说明“底部”板:在此处输入图片说明

输出量

  • 布尔值(真值/伪造值)-如果白王在将军中,则为true,否则为false。

将军

白王正在检查黑棋是否威胁要在黑棋的下一回合中将其捕获。为了摆脱困境,怀特需要将他的国王转移到安全地带,用另外一块保卫它,或者夺取威胁的一块。如果怀特没有办法摆脱困境,那么怀特国王就是将军。请记住,如果怀特没有处于控制状态,但是如果没有进入控制状态就无法移动,则它是一个僵局,而不是一个将军。

规格

  • 您将不会获得黑人国王试图“检查”白人国王的董事会,也不会得到两位国王都在检查中的董事会(不可能的情况)。

测试用例

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

    在此处输入图片说明(三)在此处输入图片说明(二)在此处输入图片说明(一)

    输出:

    说明:国王从顶层的车厢收到支票。白车无法阻止攻击或捕获威胁的车,因此国王必须设法移开。让我们考虑国王的举动选择:

    1. c2(I)-由主教在b3(II)守卫
    2. b2(I)-由骑士在a2(III)守卫
    3. c1(II)-由车队在c1(III)守卫
    4. b1(II)-由车队在b1(III)守卫
    5. c2(II)-由骑士在a2(III)守卫
    6. b2(II)-由主教在a1(I)守卫

由于国王无法逃脱支票,因此将成为将军!

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

    在此处输入图片说明(三)在此处输入图片说明(二)在此处输入图片说明(一)

    输出:false说明:国王正在从女王那里收到一张支票,并且没有任何逃脱或阻碍的动作。但是,骑士可以俘获女王。

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

    在此处输入图片说明(三)在此处输入图片说明(二)在此处输入图片说明(一)

输出:false说明:白人无法捕获威胁女王或将他的国王移交给安全。但是,通过将他的主教移至b2(II),怀特可以阻止女王的威胁。

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

    在此处输入图片说明(四)在此处输入图片说明(三)在此处输入图片说明(二)在此处输入图片说明(一)

    输出:true说明:在这种情况下,国王从骑士和皇后中的一位接受支票。即使怀特可以捕获/阻止其中一个检查块,但他不能捕获/阻止两个检查块。因此,怀特必须设法使他的国王摆脱困境,但他别无选择。

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

    在此处输入图片说明(三)在此处输入图片说明(二)在此处输入图片说明(一)

输出:false说明:白色不在检查范围之内,但是如果没有检查就无法移动。因此,这是一个僵局,而不是一个将军。

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

    在此处输入图片说明(三)在此处输入图片说明(二)在此处输入图片说明(一)

输出:true说明:怀特想与他的女王一起捍卫他的国王,但他的骑士挡住了道路。

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

    在此处输入图片说明(三)在此处输入图片说明(二)在此处输入图片说明(一)

输出:true说明:怀特不能将皇后与他的骑士团并肩作战,因为这时车队将检查怀特的国王。

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

    在此处输入图片说明(二)在此处输入图片说明(一)

输出:false说明:White可以用他的国王占领女王。

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

    在此处输入图片说明(二)在此处输入图片说明(一)

输出:true说明:这次菜鸟在守卫,因此国王无法捕获女王。

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

    在此处输入图片说明(三)在此处输入图片说明(二)在此处输入图片说明(一)

输出:false说明:白色国王可以通过俘获骑士逃脱。


只是一个细节,但是cell.className = (i + j)%2 == 0 ? "black" : "white"片段中会更好吗?
Arnauld,

@Arnauld哈哈,忘了修理最明显的东西。
geokavel

我们需要支持的最大电路板尺寸是多少?

1
@WeijunZhou基本上,您应该能够在合理的时间内完成测试用例,以查看您的代码是否有效。对于更大的数字,理论上只需要在无限的时间和内存下工作即可。
geokavel

Answers:


5

红宝石412个 413字节

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

在线尝试!现在检查所有测试用例。代码增加了1个字节,以解决案例5(僵持的情况)的错误。

Llambda函数需要以如下所示的格式作为字符串输入。可以给出一个可选的第二个参数,指示下一步将考虑使用32组ASCII码的组(默认情况下,这2个对应于大写/白色字符,但是该函数使用3个对应于小写/黑色字符的方式递归调用自身。 )

递归级别1:尝试白色的所有可能移动(任何多维数据集到任意多维数据集),并逐步通过所有合法步骤。递归级别2:然后在每种情况下,它都会调用自己逐步执行黑色的所有可能动作。如果白国王在所有可能的黑棋中幸存下来,则返回true。递归级别1:如果所有可能的白色举动导致白王不能幸免于所有可能的黑色举动的情况,则返回true(否则为false)。

通常,一个棋子不能移动到一个友好棋子占据的正方形。为了考虑白色根本不移动的情况(因此将死状态不僵持),还允许国王“移动”到他已经在的正方形上的情况。出于短代码的原因,其他白色棋子也被允许移动到由白色国王占领的广场。这是胡说八道,但允许这样做不会影响结果,因此这不是问题。

以下测试用于检查移动是否对每块有效。 x,y,z是每个轴上行进距离的平方。e是这些值的总和(因此是欧几里德距离的平方),并且d是最大值。片段类型与95进行“与”运算,将小写ASCII值转换为大写的ASCII值。

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

注释代码

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

您不能使用1位数的ascii值来打高尔夫球吗?另外,您在第三段中的意思是“僵局而不是将军”吗?
geokavel

@geokavel在Ruby中,单个ascii值的最短表示形式是 ?A(代码中有一个示例),因此它仍然是2个字节。仍然比一些需要的语言更好"A"。在某些操作中,使用ASCII值而不是使用字符会更好(特别是o^k>31可以确保一个棋子可以移动到一个空置的正方形或被一个友善的棋子占据的地方,而不是敌对的棋子。)
Level River St

我的意思是将死不僵持。当玩家移动时,国王将受到威胁。如果玩家移动,国王也不会移动,则国王将受到威胁。
水平河

如果您使用int值而不是ascii值(即,使用int数组而不是字符串)怎么办?
geokavel

@geokavel int可能会更短,我可能会在以后修改它,因为规范特别允许。但是我选择了所选择的格式,部分是因为它更易于阅读(因此更易于开发),部分是因为我的答案对我的思想产生了深远的影响:codegolf.stackexchange.com/a/45544/15599
Level圣河
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.