Проверьте загадку королев


16

Если вы не знаете, что такое королева в шахматах, это не имеет большого значения; это просто имя :)

Ваш ввод будет квадратом произвольной ширины и высоты, содержащим некоторое количество королев. Плата ввода будет выглядеть так (эта доска имеет ширину и высоту 8):

...Q....
......Q.
..Q.....
.......Q
.Q......
....Q...
Q.......
.....Q..

На этой доске 8 королев. Если бы здесь было, скажем, 7, 1 или 10, доска не была бы действительной.

Здесь мы используем .для пустого пространства, а Qдля королевы. Вместо этого вы можете использовать любой непробельный символ, какой пожелаете.

Этот ввод может быть проверен как действительный, и вы должны напечатать (или вернуть) истинное значение (если оно недопустимо, вы должны напечатать (или вернуть) ложное значение). Он действителен, потому что ни одна королева не находится в той же строке, столбце, диагонали или антидиагонале, что и другая .

Примеры (не выводите вещи в скобках):

...Q....
......Q.
..Q.....
.......Q
.Q......
....Q...
Q.......
.....Q..

1

...Q.
Q....
.Q...
....Q
..Q..

0

Q.
Q.

0

..Q
...
.Q.

0 (this is 0 because there are only 2 queens on a 3x3 board)


..Q.
Q...
...Q
.Q..

1

Q

1 (this is valid, because the board is only 1x1, so there's no queen that can take another)

Позвольте мне подчеркнуть, что вход действителен только в том случае, если ни одна ферзя не находится в той же строке, столбце, диагонали или антидиагональности, что и другая .

правила

  • Вы никогда не получите пустой ввод
  • Если вход содержит меньше ферзей, чем квадратный корень области платы, он недействителен.
  • Обратите внимание, что для доски 2x2 или 3x3 нет действительных решений, но есть решение для любой другой квадратной доски, где ширина и высота - это натуральное число.
  • Ввод может быть в любом разумном формате, согласно правилам PPCG
  • Вход всегда будет квадратным
  • Я использовал 1 и 0 в примерах, но вы можете использовать любые истинные или ложные значения (такие как Why yes, sir, that is indeed the caseи Why no, sir, that is not the case)

Поскольку это , выигрывает самый короткий код!



1
Будет ли {(x, y, v)}с vв [., Q]быть допустимым форматом ввода?
PidgeyUsedGust

@DuctrTape Я не думаю, что это имеет большой смысл.
Okx

2
@Okx Другими словами, они спрашивают о получении списка координат и значений в качестве входных данных. Например: (0, 0, Q), (0, 1, .), (1, 0, Q), (1, 1, .)будет третий контрольный пример.
Мего

Могу ли я взять строку без разрывов строки?
Титус

Ответы:


7

Улитки , 14 байт

&
o.,\Q!(z.,\Q

Попробуйте онлайн!

Ничего похожего на язык соответствия 2D-моделей для решения 2D-задач. :)

объяснение

&На первой линии является вариантом режима матч , который требует узора на второй линии , чтобы соответствовать из любой возможной позиции на входе. Если это так, программа печатает 1, в противном случае она печатает 0.

Что касается самого шаблона, обратите внимание, что )в конце есть неявное .

o       ,, Move in any orthogonal direction (up, down, left or right).
.,\Q    ,, Make sure that there's a Q somewhere in that direction from the
        ,, starting position of the match.
!(      ,, After finding the Q, make sure that the following part _doesn't_ match:
  z     ,,   Move in any orthogonal or diagonal direction.
  .,\Q  ,,   Try to find another Q in a straight line.
)

Почему это работает легче всего понять, начав с негативного взгляда: убедившись, что нет Qпрямой линии от другой, которую Qмы уже нашли, мы удостоверимся, что существует не более N королев (в противном случае быть двумя в одном ряду, и было бы невозможно найти этих королев, не найдя другую). Затем первая часть, убедившись в том, что королева достижима в ортогональном направлении из любой позиции, гарантирует, что существует ровно N королев. Если бы кто-то отсутствовал, там была бы строка и столбец без королевы. Начиная с их пересечения, невозможно найти королеву, если идти только в ортогональном направлении.


6

Желе , 17 или 15 байт

ỴµUŒD;ŒD;ZVṀ;V=1Ṃ

Попробуйте онлайн!

Использует для королевы и ¹для пустого пространства. (Это в основном является следствием запрета на использование входных данных в качестве массива, поскольку он заставляет входные данные быть строками; преобразование строк в целые числа затруднено в Jelly, причем самым простым методом является оценка, и получается, что вместо 1 и 0, используя «add 1» ( ) и «add 0» ( ¹), можно опустить несколько команд суммирования и отображения, потому что мы можем подсчитать королев в списке, оценивая его.) Значения truey и falsey являются нормальными для Jelly 1и 0,

РЕДАКТИРОВАТЬ: вопрос изменился, так как я написал этот ответ, чтобы позволить принимать входные данные в качестве матрицы. Это позволяет отбрасывать ведущий Ỵµ, экономя 2 байта. Это также, вероятно, позволяет изменить формат ввода на что-то более нормальное, используя Sдля суммирования, а не Vдля оценки, но я не думаю, что это экономит байты, и мне нравится этот классный формат.

объяснение

ỴµUŒD;ŒD;ZVṀ;V=1Ṃ
Ỵ                    Split on newlines.
 µ                   Set this value as the default for missing arguments.
     ;  ;            Concatenate the following three values:
  UŒD                - the antidiagonals;
      ŒD             - the diagonals;
         Z           - and the columns.
          V          Evaluate (i.e. count the queens on) all of those.
           Ṁ         Take the largest value among the results.
            ;V       Append the evaluation (i.e. queen count) of {each row}.
              =1     Compare each value to 1.
                Ṃ    Take the minimum (i.e. most falsey) result.

Итак, основная идея заключается в том, что мы гарантируем, что в каждой антидиагонали, диагонали и столбце есть не более одной ферзя; и ровно одна королева в каждом ряду. Этих условий достаточно для того, чтобы на каждом из четырех видов линий было не более одной ферзя, а количество ферзей равнялось длине стороны доски.

Между прочим, Jelly, вероятно, мог бы сделать со встроенным антидиагоналом, но AFAICT, похоже, его не имеет, поэтому мне нужно согласиться на отражение доски и затем взять диагонали.

Еще одно интересное примечание: изменение =1Ṃна E(все равно) дает обобщенную проверку n- королев, которая также будет принимать доску n × n, где каждая строка, столбец, диагональ и антидиагональ содержит не более k ферзей, а доска содержит ровно кн королев. Ограничение k равным 1 фактически стоит два байта.


Правила были обновлены, теперь «Ввод может быть в любом разумном формате, в соответствии с правилами PPCG», что должно сделать его короче :) РЕДАКТИРОВАТЬ - я вижу, вы заметили это.
Джонатан Аллан

5

Октава, 57 70 67 51 52 байта

Сохранено 1 байт с использованием flipвместо rot90@LuisMendo, но обнаружена ошибка в случае 1x1

@(A)all(sum([A A' (d=@spdiags)(A) d(flip(A))],1)==1)

Принимает ввод как двоичную матрицу с 1, представляющим Королеву, и 0, представляющим пустое пространство.

Создает анонимную функцию, которая сначала объединяет матрицу ввода и ее транспонирование.

spdiags создает матрицу с тем же числом строк, что и аргумент, с диагоналами, превращенными в столбцы (с добавлением нуля по мере необходимости), поэтому объединяются spdiags входной матрицы для получения диагоналей и spdiagsматрицы переворачивается горизонтально для получения антидиагоналей.

Теперь возьмите сумму каждого столбца каскадной матрицы и убедитесь, что каждый столбец точно равен 1.

Пробный прогон на идеоне .


Я думаю, что вы можете использовать flipвместоrot90
Луис Мендо

@ LuisMendo Да, это тоже сработает. Благодарность!
стакан

Кроме того, вы не можете избежать all()?
Луис Мендо

@LuisMendo Тьфу ... наверное ... но придется подождать до обеда;)
мензурка

4

MATL , 38 34 байта

4 байта, благодаря @beaker !

sG!sGt&n_w&:&XdsGP5M&Xdsv2<GnGzU=*

Входные данные представляют собой двумерный массив нулей и единиц, использующий точки с запятой в качестве разделителей строк.

Это выводит вектор столбца единиц как истинный, и вектор столбца, содержащий по крайней мере один ноль как ложный.

Попробуйте онлайн! Код ifнижнего колонтитула - это ветка, демонстрирующая правду или ложь.

Или проверьте все тестовые случаи .

объяснение

s      % Input binary matrix implicitly. Sum of columns. Gives a row vector
G!     % Paste input again. Transpose
s      % Sum of columns (rows in the original matrix). Gives a row vector
G      % Paste input again
t&n    % Duplicate. Push number of rows and number of columns (will be equal)
_w     % Negate, flip
&:     % Binary range. Gives [-n -n+1 ... n] for input of size n×n
&Xd    % Get diagonals -n through n. This gives all diagonals as colums
s      % Sum of each column (diagonals of original matrix). Gives a row vector
GP     % Paste input again. Flip vertically
5M     % Push [-n -n+1 ... n] again
&Xd    % Get diagonals -n through n (anti-diagonals of original matrix)
s      % Sum of each column. Gives a row vector
v      % Concatenate everything into a column vector
2<     % True for elements that are less than 2
Gn     % Paste input again. Number of elements
Gz     % Paste input again. Number of nonzeros (i.e. of queens)
U      % Square
=      % True if equal
*      % Mutiply, element-wise

Теперь вы можете сохранить 2 байта, так как вы можете использовать двоичную матрицу в качестве входных данных
стакан

2

J 37 байт

(+/&,=#)*1=[:>./+//.,+//.&|.,+/,+/&|:

Поезд анонимной функции, который принимает в качестве аргумента булеву матрицу.

Попробуйте онлайн!

( +/сумма &из ,в Равель =равна #бирки строк)

* и (лит. раз)

1один =равняется [:на >./максимум

+/суммы по /.диагонали ,и (буквально)

+/суммы по /.диагонали &на |.обратной стороне ,и

+/суммы по ,и

+/суммы &из |:транспонированной


2

SnakeEx , 67 байт

m:({q<>}({q<R>}[{q<RF>}{n<RF>}].)*{e<>}<R>)%{4}
e:.$
q:_*Q_*$
n:_+$

Использует _вместо. ввода. Возвращает 1 или более совпадений для truey, 0 совпадений для falsey. Вы можете найти онлайн переводчика по ссылке в шапке.

объяснение

SnakeEx - это язык из задачи 2-D Pattern Matching . Он определяет «змей», которые перемещаются по сетке, сопоставляя вещи. Змеи могут порождать других змей, что делает язык довольно мощным.

Давайте посмотрим на эту программу снизу вверх.

n:_+$

Это определяет змею, nкоторая соответствует 1 или более подчеркиваниям, а затем краю сетки. Обратите внимание, что это может быть в любом из 8 основных направлений - направление определяется, когда появляется змея.

q:_*Q_*$

Как и nвыше, это определяет qзмею, которая соответствует любому числу подчеркиваний, одиночному Q, любому числу подчеркиваний и краю сетки. Другими словами, строка / столбец / диагональ, в которой есть только одна королева.

e:.$

e это змея, которая соответствует одному персонажу и краю сетки.

m:({q<>}({q<R>}[{q<RF>}{n<RF>}].)*{e<>}<R>)%{4}

Главная змея m использует эти строительные блоки, чтобы проверить всю доску. Концептуально, он проходит по внешним краям сетки, порождая других змей, чтобы проверить, что все столбцы и строки имеют ровно одну королеву, а все диагонали имеют не более одной королевы. Если какая-либо из порожденных змей не соответствует, все совпадение не выполняется. Давайте разберемся с этим.

  • ( )%{4}выполняет то, что внутри скобок 4 раза, по одному для каждой стороны. (В дальнейшем полезно изобразить определенную сторону - скажем, верхний край сетки, начиная с верхнего левого угла и двигаясь вправо.)
  • {q<>}порождает qзмею в том же направлении, в котором движется главная змея. Это подтверждает, что текущий фронт соответствует правилу «ровно одна королева». Обратите внимание, что порожденные змеи не перемещают указатель соответствия главной змеи, поэтому мы все еще в начале края.
  • ( )* соответствует 0 или более из того, что внутри скобок.
  • {q<R>}порождает qзмею, повернутую направо от направления главной змеи. (Например, если главная змея движется вправо вдоль верхнего края, эта змея движется вниз.) Это проверяет каждый столбец / строку.
  • [ ] соответствует одному из вариантов в скобках:
    • {q<RF>}порождает qзмею, повернутую на 45 градусов вправо (т.е. вправо Rи Fвлево) от направления главной змеи. qЗмея соответствует , если диагональ содержит ровно одну королеву.
    • {n<RF>}порождает nзмею вместо этого. nЗмея совпадает , если диагональ не содержит маток.
  • . соответствует любому символу, перемещая указатель соответствия вперед.
  • После проверки как можно большего количества горизонталей и диагоналей, мы проверяем, что мы находимся на краю, порождая {e<>} .
  • Наконец, <R>поворачивается главная змея вправо, готовая соответствовать следующему краю.

Странные вещи

  • В программе нет ничего, чтобы гарантировать, что сопоставление начинается с внешнего угла. Фактически, правдивые тестовые примеры дают несколько совпадений, некоторые из которых начинаются где-то внутри. Несмотря на это, ни один из фальшивых случаев, которые я пробовал, не дал ложных срабатываний.
  • Если я правильно читаю спецификацию языка , я должен был бы использовать X(разветвить во всех диагональных направлениях) вместо RF. К сожалению, онлайн-переводчик сказал, что это синтаксическая ошибка. Я тоже пытался *(ответвление во всех направлениях), но это повесил переводчик.
  • Теоретически, что-то вроде _*Q?_*$должно работать для сопоставления "не более одной королевы" в диагонали, но это также повесил интерпретатор. Я предполагаю, что возможность пустых матчей вызывает проблемы.

2

Рубин, 120 байт

Лямбда-функция основана на оригинальной спецификации, которая требует ввода в виде строки.

->s{t=k=0
a=[]
s.bytes{|i|i>65&&(a.map{|j|t&&=((k-j)**4).imag!=0};a<<k)
k=i<11?k.real+1:k+?i.to_c}
t&&~a.size**2>s.size}

преобразует Q в комплексные числа и вычитает их друг от друга. Если разница между координатами любых двух королев является горизонтальной, вертикальной или диагональной, увеличение ее до 4-й степени даст действительное число, и расположение будет недействительным.

Неуправляемый в тестовой программе

f=->s{                                 #Take input as string argument.
  t=k=0                                #k=coordinate of character. t=0 (truthy in ruby.)
  a=[]                                 #Empty array for storing coordinates.
  s.bytes{                             #Iterate through all characters as bytes.
    |i|i>65&&(                         #If alphabetical, compare the current value of k to the contents of a
      a.map{|j|t&&=((k-j)**4).imag!=0} #If k-j is horizontal, vertical or diagonal, (k-j)**4 will be real and t will be false
      a<<k)                            #Add the new value of k to the end of a.
    k=i<11?k.real+1:k+?i.to_c          #If not a newline, increment the imaginary part of k. If a newline, set imaginary to 0 and increment real
  }                                    #s.size should be a*a + a newlines. ~a.size = -1-a.size, so ~a.size**2 = (a.size+1)**2
t&&~a.size**2>s.size}                  #compare a.size with s.size and AND the result with t. Return value. 


p f["...Q....
......Q.
..Q.....
.......Q
.Q......
....Q...
Q.......
.....Q.."]

p f["...Q.
Q....
.Q...
....Q
..Q.."]

p f["Q.
Q."]

p f["..Q
...
.Q."]

p f["..Q.
Q...
...Q
.Q.."]

p f["Q"]

2

Python 3 , 232 200 155 байтов

d=1
f=input()
Q=[]
for i in f:d=[0,d][i.count('Q')==1];Q+=[(len(Q),i.index('Q'))]
print[0,d][sum(k[1]==i[1]or sum(k)==sum(i)for k in Q for i in Q)==len(Q)]

Попробуйте онлайн!

-32 байта благодаря @beaker, заметившему изменение в спецификациях ввода; Я изменил язык с Python 3 на 2, что позволило мне использовать inputвходные данные как массив строк или массив символьных массивов.

-45 байтов благодаря @Leaky Nun


Требования к вводу были смягчены, если это поможет вам.
стакан

@ beaker Хорошо, спасибо. Вместо этого я возьму ввод как массив строк. Спасибо что подметил это!
HyperNeutrino


1

JavaScript (ES6), 115 байт

a=>!a.some((b,i)=>b.some((q,j)=>q&&h[i]|v[j]|d[i+j]|e[i-j]|!(h[i]=v[j]=d[i+j]=e[i-j]=1))|!h[i],h=[],v=[],d=[],e=[])

Ungolfed:

function queens(arr) {
    horiz = [];
    vert = [];
    diag = [];
    anti = [];
    for (i = 0; i < arr.length; i++) {
        for (j = 0; j < arr.length; j++) {
            if (arr[i][j]) { // if there is a queen...
                if (horiz[i]) return false; // not already on the same row
                if (vert[j]) return false; // or column
                if (diag[i + j]) return false; // or diagonal
                if (anti[i - j]) return false; // or antidiagonal
                horiz[i] = vert[j] = diag[i + j] = anti[i - j] = true; // mark it
            }
        }
        if (!horiz[i]) return false; // fail if no queen in this row
    }
    return true;
}

0

Рубин, 155 байт

->x{(y=x.map{|r|(i=r.index ?Q)==r.rindex(?Q)?i:p or-2}).zip(y.rotate).map.with_index{|n,i|n.max-n.min==1&&i<y.size-1?-2:n[0]}.inject(:+)*2==(s=x.size)*~-s}

Это ужасно читать, поэтому у меня есть чуть менее гольф версия ниже

->x{
    (y=x.map{|r|(i=r.index ?Q)==r.rindex(?Q)?i:p or-2})
    .zip(y.rotate)
    .map.with_index{|n,i|n.max-n.min==1&&i<y.size-1?-2:n[0]}
    .inject(:+)*2==(s=x.size)*~-s
}

Это тот же код, но с некоторыми новыми строками, чтобы выделить то, что происходит.

Сам код является анонимной лямбда-функцией, которая принимает массив строк (x ) в формате ["..Q", "Q..", ".Q."].

Первая строка отображает каждую строку на индекс символа Q в этой строке. Если символа Q нет, он заменяется на -2 1 . Этот новый массив индексов присваивается переменнойy .

Следующая строка упаковывает этот массив индексов, смещая его на единицу (повернуто). Это приводит к массиву пар последовательных индексов.

Следующая строка особенно сложна. Он проходит через каждую из пар индексов и вычитает меньшее из большего. Если это 1 (а мы не на последней паре 2 ), то есть две королевы, которые находятся на одной диагонали, и вставляется значение -2, в противном случае вставляется исходный индекс ферзя в строке ,

Последняя строка суммирует все индексы для каждого и проверяет, является ли это число треугольника для n-1, где n - ширина (или высота) квадрата.

1: -1 было бы моим ходом, но это 1, кроме 0, так что мешало бы проверять диагонали. Отрицательность этого важна, чтобы сделать окончательную сумму неправильной. Я думал о большом числе (с одной цифрой), например, 9, но я не уверен, что это не приведет к неправильной проверке.
2: доска не переворачивается, в rotateотличие от функции массива ruby , и если последняя пара отличается на одну, это не имеет значения - это не диагональ.


0

PHP, 137 143 байта

вдохновленный решением Нейла

for($n=1+strlen($s=$argv[1])**.5|0;($c=$s[$p])&&!(Q==$c&&$v[$x=$p%$n]++|$h[$x=$p/$n]++|$d[$y-$x]++|$a[$y+$x]++);$p++);echo$n-1==count($a)&&!$c;

принимает входные данные из первого аргумента командной строки; беги с -r. Требуется разрыв строки в один байт.
На самом деле вы можете использовать любой символ, но 0для разрыва строки.
печатает true ( 1) или false (пустая строка).

сломать

for($n=1+strlen($s=$argv[1])**.5|0; // copy input to $s, $n=size+1 (for the linebreak)
    ($c=$s[$p])&&!(                 // loop through characters
        Q==$c&&                         // if queen: test and increment lines
            $v[$x=$p%$n]++|$h[$x=$p/$n]++|$d[$y-$x]++|$a[$y+$x]++
    );                                  // break if a line had been marked before
    $p++);
echo$n-1==count($a)             // print result: true for $n-1(=size) marks
    &&!$c;                      // and loop has finished

0

Python 3 , 185 176 175 172 171 байт

lambda x,c=lambda x:x.count("Q")==1:all([*map(c,x+[[l[i]for l in x]for i in range(len(x[0]))])])*~any(map(lambda s:"Q%sQ"%(s*".")in"".join(x),[len(x[0]),len(x[0])-2]))==-1

Анонимная функция, принимающая список строк в качестве входных данных.

Python 2 , 175 байт

lambda x:all([a.count("Q")==1for a in x]+[[l[i]for l in x].count("Q")==1for i in range(len(x[0]))]+[all(map(lambda s:"Q%sQ"%(s*".")not in"".join(x),[len(x[0]),len(x[0])-2]))])
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.