Тривимірні шахи


26

Для того, щоб захистити чиєсь неприємне рішення, люди часто кажуть, що ця людина перебирає голову всіх і грає у «тривимірні шахи». Тепер ваш шанс грати в тривимірні шахи!

Правила

Існує багато варіантів 3D-шахів , але для цього завдання я склав свій власний. Моя версія подібна до звичайних шахів, за винятком того, що шматки знаходяться всередині кубів замість квадратів, і тепер мають додатковий вимір руху. Щоб зробити цей виклик простим, немає пішаків і жодної ролі .

Шматок руху

(Вказівки компаса стосуються руху, який відбуватиметься на стандартній шаховій дошці; вгору та вниз - вертикальне переміщення на шахівниці 3D).

  • Кінг - має 26 квадратів, на які він може перейти в даний момент: N, NE, E, SE, S, SW, W, NW; а також вгору, вниз та вгору / вниз + один із напрямків компаса.
  • Королева - може рухатися в тих же напрямках, що і Король, але наскільки вона хоче в цих напрямках.
  • Ладья - може рухатися в 6 напрямках: N, E, S, W, вгору та вниз,
  • Bishop - має 8 трикутних напрямків руху: 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 дошку, визначте, чи є білий король у матчі.

Вхідні дані

  • (Необов’язково) n ≥ 2 - розмір дошки
  • Ігрова дошка
    • Може мати форму 1d- 2d- або 3d- масив або інший подібний формат. Повідомлення можуть бути в будь-якому простому форматі. Наприклад, KQRBN (білий) і kqrbn (чорний) з # для порожніх кубів. Або використовувати числа для різних значень.
    • Подумайте про 3D-шахову дошку як про декілька дощок, складених одна над одною та перелічених зверху вниз. Потім кожна окрема дошка помічається зліва направо, назад вперед (чорна сторона до білої сторони).
    • Уявіть цей випадок 2x2x2, поданий у вигляді 3D-масиву:
 [
[[bq] [##]]
[[bn] [KQ]]
]

Дошка "верх": введіть тут опис зображення"нижня" дошка:введіть тут опис зображення

Вихідні дані

  • boolean (truthy / falesy value) - вірно, якщо білий король у мат, а в іншому випадку помилковий.

Матч

Білий король перевіряє, чи чорний шматок загрожує захопленням його в наступному ході Блек. Щоб вийти з перевірки, Білому потрібно перевести свого короля в безпеку, захистити його іншим твором або захопити загрозливий шматок. Якщо у Білого немає ніякого способу вийти з чека, то білий король знаходиться в мат . Пам’ятайте, якщо Білий не перебуває під контролем, але не може рухатись, не потрапляючи на чек, то це тупик , який не є мат.

Специфікація

  • Вам не дадуть дошку, де чорний король намагається "перевірити" білого короля, або дошку, де обидва королі знаходяться під контролем (неможливі сценарії).

Випробування

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

    введіть тут опис зображення(III) введіть тут опис зображення(II) введіть тут опис зображення(I)

    Вихід: вірно

    Пояснення: Король отримує чек із грака на останньому поверсі. Білий грак не в змозі перекрити атаку або захопити загрозливий грак, тому король повинен спробувати рухатися з шляху. Розглянемо варіанти переходу короля:

    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#]

    введіть тут опис зображення(III) введіть тут опис зображення(II) введіть тут опис зображення(I)

    Висновок: помилкове Пояснення: Король отримує чек від королеви, і не має жодних кроків для втечі чи блокування. Однак лицар може захопити королеву.

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

    введіть тут опис зображення(III) введіть тут опис зображення(II) введіть тут опис зображення(I)

Вихід: помилкове Пояснення: Білий не має можливості захопити царицю, що загрожує, або перенести свого короля в безпеку. Однак, перемістивши свого єпископа до b2 (II), Білий може блокувати загрозу королеви.

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

    введіть тут опис зображення(IV) введіть тут опис зображення(III) введіть тут опис зображення(II) введіть тут опис зображення(I)

    Вихід: істинне Пояснення: У цьому випадку король отримує чек від одного з лицарів і королеви. Хоча Білий може захопити / заблокувати одну з контрольних деталей, він не може захопити / заблокувати обидва. Тому Білий повинен спробувати вивести свого короля з-під перевірки, але у нього немає варіантів.

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

    введіть тут опис зображення(III) введіть тут опис зображення(II) введіть тут опис зображення(I)

Вихід: помилкове Пояснення: Білий не перебуває під контролем, але не має можливості пересуватися, не потрапляючи на перевірку. Тому це тупик, але не мат.

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

    введіть тут опис зображення(III) введіть тут опис зображення(II) введіть тут опис зображення(I)

Вихід: справжнє Пояснення: Білий хотів би пролізти з королевою, щоб захистити свого короля, але його лицар перекриває шлях.

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

    введіть тут опис зображення(III) введіть тут опис зображення(II) введіть тут опис зображення(I)

Вихід: справжнє Пояснення: Білий не може взяти королеву зі своїм лицарем, бо тоді грак буде перевіряти царя Білого.

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

    введіть тут опис зображення(II) введіть тут опис зображення(I)

Вихід: помилкове Пояснення: Білий може захопити королеву зі своїм королем.

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

    введіть тут опис зображення(II) введіть тут опис зображення(I)

Вихід: вірно Пояснення: Цього разу грак охороняє, тому король не може захопити королеву.

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

    введіть тут опис зображення(III) введіть тут опис зображення(II) введіть тут опис зображення(I)

Вихід: помилкове Пояснення: Білий король може втекти, захопивши лицаря.


Просто деталь, але чи не cell.className = (i + j)%2 == 0 ? "black" : "white"буде краще у фрагменті?
Арнольд

@Arnauld lol, забув виправити найочевидніше.
геокавель

Який найбільший розмір плати, який нам потрібно підтримувати?
Вейджун Чжоу

1
@WeijunZhou В основному ви повинні мати можливість робити тестові справи за розумну кількість часу, щоб побачити, чи працює ваш код. Для більшої кількості потрібно просто теоретично працювати, враховуючи нескінченний час і пам'ять.
геокавель

Відповіді:


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: У кожному випадку він закликає себе перейти всі можливі кроки для чорного. Це повертається правдою, якщо білий цар пережив усі можливі чорні кроки. Рівень рекурсії 1: Якщо всі можливі білі рухи призводять до ситуації, коли білий король НЕ пережив усіх можливих чорних рухів, тоді поверніться істинним (інакше помилковим.)

Загалом, п'єса не може переміститися до площі, зайнятої дружнім твором. Для того, щоб розглянути випадок, коли білий взагалі не рухається (отже, мат не манить), також допускається випадок, коли король "рухається" до площі, на якій він вже знаходиться. З причини короткого коду іншим білим шматочкам також дозволяється переміщатися на площу, яку займає білий король. Це нісенітниця, але дозволити це не впливає на результат, тому це не проблема.

Наступні тести використовуються для перевірки, чи дійсний хід для кожного твору. x,y,z- квадрати пройдених відстаней у кожній осі. e- сума цих (звідси квадрат евклідової відстані) і dє максимальною. Тип шматка ANDed з 95, щоб перетворити невеликі значення 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}

Не могли б ви переграти це за допомогою однозначних значень ascii? Крім того, ви мали на увазі "патова ситуація не мат" в третьому абзаці?
геокавель

@geokavel Найкоротше представлення одного значення ascii в Ruby є ?A(є приклад у коді), тому це ще 2 байти. Ще краще, ніж деякі мови, які вимагають "A". Були певні маніпуляції, які краще йшли зі значеннями ASCII, а не з персонажами (зокрема, o^k>31це забезпечує те, що шматок може переміститися до незайнятої площі чи тієї, яку займає дружній шматок, але не ворожий.)
рівень річки Св.

Я маю на увазі, що мат не матовий. Тупик - це ситуація, коли королю загрожує, якщо гравець рухається. Команда - це ситуація, коли королю загрожує, якщо гравець рухається, а також якщо він цього не робить.
Річка рівня Св.

Що робити, якщо ви використовували значення int замість значень ascii (тобто масив ints замість рядка)?
geokavel

Вклади @geokavel, ймовірно, будуть коротшими, і я можу переглянути його пізніше, оскільки це спеціально дозволено специфікацією. Але я пішов із обраним форматом частково тому, що він був більш читабельним для людини (отже, легше розвиватись), а почасти тому, що мене надихнула ця моя відповідь, яка сильно вплинула на моє мислення: codegolf.stackexchange.com/a/45544/15599
Рівень Річка Св.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.