Проверьте, могут ли три буквы образовать «куб Годеля-Эшера-Баха»

29

Этот вопрос вдохновлен обложкой книги «Годель, Эшер, Бах»:

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

В этом упражнении вы можете использовать только буквы размером 5 на 5 * 5 пикселей:

Или в двоичном (от А до Я):

01110  11110  01111  11110  11111  11111  11111  10001  11111  11111  10001  10000  10001  10001  01110  11110  01110  11110  01111  11111  10001  10001  10001  10001  10001  11111
10001  10001  10000  10001  10000  10000  10000  10001  00100  00100  10010  10000  11011  11001  10001  10001  10001  10001  10000  00100  10001  10001  10001  01010  01010  00010
10001  11110  10000  10001  11100  11110  10011  11111  00100  00100  11100  10000  10101  10101  10001  10001  10001  11111  01110  00100  10001  01010  10001  00100  00100  00100
11111  10001  10000  10001  10000  10000  10001  10001  00100  10100  10010  10000  10001  10011  10001  11110  10011  10010  00001  00100  10001  01010  10101  01010  00100  01000
10001  11110  01111  11110  11111  10000  11111  10001  11111  11100  10001  11111  10001  10001  01110  10000  01111  10001  11110  00100  01110  00100  01010  10001  00100  11111

Скульптура состоит из трех букв в следующем порядке:

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

Пример:

Ваша функция может принимать в качестве входных данных три заглавные буквы (три символа или три строки одной буквы) и выводить логическое значение (true / false или 0/1), указывающее, может ли существовать соответствующая скульптура.

Пример:

f("B","E","G") // true  (because if you "sculpt out" B on top + E on the left + G on the right, and watch the three sides of the sculpture, you'll see exactly B, E and G as they are defined)
f("B","G","E") // false (because if you "sculpt out" B on top + G on the left + E on the right, and watch the three sides of the sculpture, you won't see a complete G and a complete E. Their shapes bother each other)

NB: вы можете вернуть true, даже если скульптура содержит «летающие пиксели» (кубы или группы кубов, которые ни к чему не прикреплены).

Применяются стандартные лазейки.

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

Самый короткий ответ в символах на любом языке выигрывает!

Повеселись :)

XEM
источник
Да, именно загадка MU заставила меня открыть для себя книгу, и именно обложка книги заставила меня задуматься об этой проблеме. Есть проблема? Это было частью вашей 18-луночной игры?
xem
2
Было бы хорошим вариантом заменить отверстие 1.;) ... Не берите в голову, если я что-то виноват в том, что не поднял что-то раньше. Это действительно достойный вызов, +1!
Мартин Эндер
Можем ли мы получить данные, определяющие форму букв из внешнего файла, или их также необходимо включить в источник?
CesiumLifeJacket
Ваш бинарный B имеет 0 в левом верхнем углу, а не 1.
Увлечения Calvin's

Ответы:

13

Mathematica 423

Я добавил раздел «Как работает блокировка».

Ungolfed

(* Двоичные данные алфавита хранятся в виде одной строки s. varsИмпортирует их и преобразует в массив.)

vars=IntegerDigits[#,10,5]&/@Transpose[ImportString[s,"Table"]];
get[char_]:=(ToCharacterCode[char]-64)[[1]];
cube=Flatten[Table[{i,j,k},{i,5},{j,5},{k,5}],2];

(* character slice along axis *)
slice[char_,layer_,axis_,bit_]:=Insert[(Reverse@#),layer,axis]&/@Position[Reverse@vars[[get[char]]],bit]

(* cuboid assembly  *)
charBlocks[{char_,axis_,bit_}]:=Flatten[Table[slice[char,k,axis,bit],{k,5}],1]

(* letters are those whose HOLES should be sculped out of the full cube *)
sculpturePoints[letters_(*{char_,axis_,bit_}*)]:=Complement[cube,Union[Join@@(charBlocks/@letters(*{char,axis,bit}*))]];

collapse[letters_(*{char_,axis_,bit_}*),axis_]:=Union[Reverse/@(Delete[#,axis]&/@sculpturePoints[letters(*{char,axis,bit}*)])](*/.{x_,y_}\[RuleDelayed] {6-x,y}*)

vQ[l_]:=collapse[l,3]==collapse[{l[[1]]},3]\[And]collapse[l,2]==collapse[{l[[2]]},2]\[And]collapse[l,1]==collapse[{l[[3]]},1]

validQ@l_:= vQ[{{l[[1]],3,0},{l[[2]],2,0},{l[[3]],1,0}}]


perspective[letts_,view_:1]:=
Graphics3D[{AbsolutePointSize[10],Cuboid/@sculpturePoints[letts]},
ImageSize-> 120,
ViewPoint-> Switch[view,1,{0,0,\[Infinity]},2,{0,-\[Infinity],0},3,{\[Infinity],0,0},4,Top,5,Front,6,Right,True,{0,0,\[Infinity]}],
PlotLabel-> Switch[view,1,"top orthogonal view",2,"front orthogonal view",3,"right orthogonal view",4,"top close-up view",5,"front close-up view",6,"right close-up view"],
ImagePadding->10]

пример

Куб {"B", "G", "E"}действителен? (т.е. будут ли три буквы правильно проецироваться на стены?)

validQ[{"B", "G", "E"}]

Ложь

иллюстрации

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

Проблема возникает с буквой "G". Ничто не связывает засечку с остальной частью письма.

pts = {{"B", 3, 0}, {"G", 2, 0}, {"E", 1, 0}}
GraphicsGrid@Partition[Table[perspective[pts, view], {view, 1, 6}], 3]

BGE


BEG, однако, должен работать нормально.

 validQ[{"B", "E", "G"}]

Правда

pts2 = {{"B", 3, 0}, {"E", 2, 0}, {"G", 1, 0}}
GraphicsGrid@Partition[Table[perspective[pts2, view], {view, 1, 6}], 3]

очень прошу


Как работает блокировка?

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

Давайте проследим, что происходит с буквой G в рендеринге куба BGE.

Мы будем уделять особое внимание вокселю (трехмерный пиксель или единичный куб) ниже. Это пиксель, который исчезает в кубе BGE. Это пиксель, соответствующий строке 4, столбцу 5 в массиве битов и на соответствующем графике массива.

блокировка 1


В плоскости xy пиксель соответствует серому диску в точке (5,2). Но поскольку мы собираемся работать в 3D, нам нужно рассмотреть 5 позиций в шахте от (5,1,2) до (5,5,2). Если какой-либо из этих пикселей выживет, создавая буквы B и E, мы сможем увидеть интересующий пиксель в 3D-проекции на стене.

блокировка 2


Буквы мешают, когда пиксели удаляются из сплошного блока. Слева черная стрелка представляет вырезание пикселей, соответствующее биту внизу справа; для буквы B она имеет значение 0. Вырезание удаляет пиксель в точке (5,1,2), а также пиксели, расположенные непосредственно над и под ним. Четыре пикселя еще предстоит учесть.

блокировка 3

Но, как показывает правая панель, буква E выделяет интересующие пиксели (5,2,2) (5,3,2), (5,4,2) и (5,5,2). (Это связано с тем, что буква E имеет биты, равные 0, в четвертом ряду, от столбца 2 до столбца 5.) В результате ни один пиксель не остается среди тех, которые были необходимы для обеспечения затенения в точке (5 , 2) на дальней стене (для буквы G). Вместо этого будет яркое пятно, соответствующее отверстию в букве G! Куб BGE не годится, потому что он неправильно отображает G.

Гольф 423 символа

Функция hвыполняла ту же роль, что и validQв коде unGolfed. Функция рендеринга, perspectiveне включена, потому что она не вносит свой вклад и не является обязательной для задачи.

x=Reverse;q=Flatten;
g@c_:=(ToCharacterCode[c]-64)[[1]];
r[{c_,a_,b_}]:=q[Table[Insert[(x@#),k,a]&/@Position[x@(IntegerDigits[#,10,5]&/@
Transpose[ImportString[s,"Table"]])[[g[c]]],b],{k,5}],1]
p@l_:=Complement[q[Table[{i,j,k},{i,5},{j,5},{k,5}],2],Union[Join@@(r/@l)]];
w[l_,a_]:=Union[x/@(Delete[#,a]&/@p[l])]
v@l_:=w[l,3]==w[{l[[1]]},3]\[And]w[l,2]==w[{l[[2]]},2]\[And]w[l,1]==w[{l[[3]]},1]

h@l_:= v[{{l[[1]],3,0},{l[[2]],2,0},{l[[3]],1,0}}]
DavidC
источник
Вау, эти 3D виды очень аккуратные! Вы уверены, что последний блок кода "UnGolfed"? Кажется, игра в гольф для меня. :)
xem
Ты прав. Последний блок - гольф. Я исправил заголовок. Отличительной особенностью 3D-видов является то, что они интерактивны: вращение и масштабирование можно выполнять с помощью мыши.
DavidC
Кстати, по моим подсчетам, среди 15600 возможных перестановок 564 действительных куба.
DavidC
Это хорошая информация. Сколько времени вам понадобилось, чтобы вычислить это? также 26 * 26 * 26 = 17576, а не 15600. Или я что-то упустил?
xem
Я использовал перестановки, а не кортежи; т.е. нет повторяющихся букв. 26 * 25 * 24 = 15600. Потребовалось 21 секунда, чтобы найти 564 случая.
DavidC
12

Пролог, 440 , 414

:- encoding(utf8).
i(I) :- between(0,4,I).
h(T,L,R,X,Y,Z) :- i(X),i(Y),i(Z),I is 4-X,c(T,Z,I),c(L,Z,Y),c(R,X,Y).
f(T,L,R) :- forall((i(U),i(V),I is 4-V),((\+c(T,U,V);h(T,L,R,I,Y,U)),(\+c(L,U,V);h(T,L,R,X,V,U)),(\+c(R,U,V);h(T,L,R,U,V,Z)))).
c(C,X,Y) :- char_code(C,N),i(X),i(Y),Z is X+5*Y+25*(N-65),I is floor(Z/15),O is (Z mod 15),string_code(I,"䙎㹟䘑߯硁䙏縑ԁࠟя摟䠑䠑ᐑ粤Ⴟ䔅┉ё籁垑䙑曓䗱㩑䙏㡏晑䘞䕟㡞縐Ⴄ䙄㩑⩑䒪噑⩊䕤ᅱ粤ࢨ?",V),1 is (V-32)>>O/\1.

Программа называется так:

?- f('B','E','G').
true.
?- f('B','G','E').
false.

PrologКазалось бы, хороший выбор, так как проблему легко представить в логике первого порядка. Также Prologпредоставляет мощную функциональность для решения такого рода проблем.

Тем не менее, так как в коде нет ничего плохого, думаю, мне следует добавить некоторые пояснения

Мягко играемая в гольф версия

:- encoding(utf8).
i(I) :- between(0,4,I).
t(C,X,Z) :- I is 4-X,c(C,Z,I).
l(C,Y,Z) :- c(C,Z,Y).
r(C,X,Y) :- c(C,X,Y).
h(T,L,R,X,Y,Z) :- i(X),i(Y),i(Z),t(T,X,Z),l(L,Y,Z),r(R,X,Y).
u(T,L,R) :- forall((i(U),i(V),I is 4-V,c(T,U,V)),h(T,L,R,I,Y,U)).
v(T,L,R) :- forall((i(U),i(V),c(L,U,V)),h(T,L,R,X,V,U)).
w(T,L,R) :- forall((i(U),i(V),c(R,U,V)),h(T,L,R,U,V,Z)).
f(T,L,R) :- u(T,L,R),v(T,L,R),w(T,L,R).
c(C,X,Y) :- char_code(C,N),i(X),i(Y),Z is X+5*Y+25*(N-65),I is floor(Z/15),O is (Z mod 15),string_code(I,"䙎㹟䘑߯硁䙏縑ԁࠟя摟䠑䠑ᐑ粤Ⴟ䔅┉ё籁垑䙑曓䗱㩑䙏㡏晑䘞䕟㡞縐Ⴄ䙄㩑⩑䒪噑⩊䕤ᅱ粤ࢨ?",V),1 is (V-32)>>O/\1.

Координаты, соответствующие пикселям на каждой стороне кости, могут быть легко преобразованы в трехмерную систему координат. Я использую T, Lи Rдля верхней части (1), влево (2) и вправо (3) стороны. uи vиспользуются для координат на изображениях:

  • T :(u,v) -> (4-v, ?, u)
  • L :(u,v) -> (?, v, u)
  • R :(u,v) -> (u, v, ?)

Результаты для каждого активного (т.е. черного) пикселя объединяются в набор «3D-пикселей», которые можно активировать, не изменяя внешний вид объекта с этой стороны. Все точки пересечения наборов для каждой стороны - это трехмерные пиксели, которые можно активировать без добавления пикселей, что затруднит вид (т.е. если смотреть по крайней мере с одной стороны, то там будет пиксель, которого не должно быть).

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

Это приводит к предикатам в программе:

  • f : выполняет окончательную проверку; принимает буквы сверху, слева и справа
  • u , v и w : выполнить проверки, если для каждого активного пикселя на стороне есть 3D-пиксель на пересечении, который блокирует вид
  • h : проверяет наличие пикселя в пересечении
  • t , l , r : проверяет, можно ли заблокировать 3D-пиксель сверху, слева и справа.
  • c : проверяет пиксель в изображении буквы. Строка там может выглядеть немного странно, но это только компактный способ хранения данных изображения. Это просто последовательность символов со следующими значениями (шестнадцатеричная запись):

    [464e,3e5f,4611,7ef,7841,464f,7e11,501,81f,44f,645f,4811,4811,1411,7ca4,10bf,4505,2509,451,7c41,5791,4651,66d3,45f1,3a51,464f,384f,6651,461e,455f,385e,7e10,10a4,4644,3a51,2a51,44aa,5651,2a4a,4564,1171,7ca4,8a8,3f]
    

    Каждый из этих символов хранит данные для строк размером 3 пикселя в буквенном изображении (ях) (= 15 пикселей). Пиксели также переупорядочиваются так, что данные хранятся в одном месте и не разделяются на несколько строк, как данные OP.

Математическая формулировка

формула

Входные данные

формула

Преобразование из пикселя в одном символе в набор 3D-пикселей, которые затрудняют вид для этого пикселя

формула

формула

формула

Пиксели, которые можно безопасно добавлять (не мешая обзору в неправильном месте)

формула

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

формула

формула

формула

Комбинат чеков для каждой стороны

формула

Fabian
источник
1
Я .. Эээ ... Что? Я нахожу это непостижимым. (+1)
seequ
Святой ... я иду спать ...
BrunoJ
Впечатляет! Спасибо за этот ответ
xem
1
Ницца. Кстати, я думаю, что процесс начинается с твердого кубического блока. (Вы, кажется, думаете об этом как о добавлении пикселей там, где их раньше не было.) Каждая буква удаляет некоторые трехмерные пиксели из этого блока. Таким образом, помехи возникают, когда соседняя буква удаляет пиксели, которые буква «хотела сохранить». Интерференция возникает из-за «недостающих пикселей», а не из-за дополнительных пикселей.
DavidC
9

J - 223 197 191 символ

Функция, принимающая список из трех символов в качестве аргумента.

(_5#:\".'1b',"#:'fiiifalllvhhhheehhhvhhllvgkkkvnlhhvv444vhhvhhggvhjha44v1111vv848vv248vehhheciiivfjhhedmkkvilll9ggvggu111uo616ou121uha4ahg878ghpljh')((-:0<+/"1,+/"2,:+/)*`(*"1/)/)@:{~_65+3&u:

Этот гольф в значительной степени опирается на мощную особенность J под названием ранга , которая дает нам возможность «ваять» и «наблюдать за» операциями практически бесплатно. Чтобы упростить это немного, ранг относится к размерности существительного или естественных аргументов глагола.

J имеет многомерные массивы, и очевидно, что, скажем, трехмерный массив можно интерпретировать как отдельный трехмерный массив, или как список матриц, или двумерный массив векторов, или трехмерный массив скаляров. Таким образом, каждая операция в J может иметь свое приложение, контролируемое по отношению к аргументу. Ранг 0 означает применение к скалярам, ​​ранг 1 означает применение к векторам и так далее.

   1 + 2 + 3 + 4  NB. add these things together
10
   +/ 1 2 3 4     NB. sum the list by adding its items together
10
   i. 3 4         NB. 2D array, with shape 3-by-4
0 1  2  3
4 5  6  7
8 9 10 11
   +/"2 i. 3 4    NB. add the items of the matrix together
12 15 18 21
   0 1 2 3 + 4 5 6 7 + 8 9 10 11    NB. equivalent
12 15 18 21
   +/"1 i. 3 4    NB. now sum each vector!
6 22 38
   +/"0 i. 3 4    NB. now sum each scalar!
0 1  2  3
4 5  6  7
8 9 10 11

Это становится очень мощным, когда вы вводите двоичные функции (с двумя аргументами), потому что, если формы двух аргументов (после учета ранга) приемлемы, J выполнит неявный цикл:

   10 + 1             NB. scalar addition
11
   10 20 30 + 4 5 6   NB. vector addition, pointwise
14 25 36
   10 + 4 5 6         NB. looping! 
14 15 16
   10 20 + 4 5 6      NB. shapes do not agree...
|length error
|   10 20    +4 5 6

Когда все ваши формы приемлемы и вы можете сами указать ранг, есть много способов объединить аргументы. Здесь мы покажем некоторые способы умножения 2D-матрицы и 3D-массива.

   n =: i. 5 5
   n
 0  1  2  3  4
 5  6  7  8  9
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24
   <"2 n *"2 (5 5 5 $ 1)  NB. multiply by 2-cells
+--------------+--------------+--------------+--------------+--------------+
| 0  1  2  3  4| 0  1  2  3  4| 0  1  2  3  4| 0  1  2  3  4| 0  1  2  3  4|
| 5  6  7  8  9| 5  6  7  8  9| 5  6  7  8  9| 5  6  7  8  9| 5  6  7  8  9|
|10 11 12 13 14|10 11 12 13 14|10 11 12 13 14|10 11 12 13 14|10 11 12 13 14|
|15 16 17 18 19|15 16 17 18 19|15 16 17 18 19|15 16 17 18 19|15 16 17 18 19|
|20 21 22 23 24|20 21 22 23 24|20 21 22 23 24|20 21 22 23 24|20 21 22 23 24|
+--------------+--------------+--------------+--------------+--------------+
   <"2 n *"1 (5 5 5 $ 1)  NB. multiply by vectors
+---------+---------+--------------+--------------+--------------+
|0 1 2 3 4|5 6 7 8 9|10 11 12 13 14|15 16 17 18 19|20 21 22 23 24|
|0 1 2 3 4|5 6 7 8 9|10 11 12 13 14|15 16 17 18 19|20 21 22 23 24|
|0 1 2 3 4|5 6 7 8 9|10 11 12 13 14|15 16 17 18 19|20 21 22 23 24|
|0 1 2 3 4|5 6 7 8 9|10 11 12 13 14|15 16 17 18 19|20 21 22 23 24|
|0 1 2 3 4|5 6 7 8 9|10 11 12 13 14|15 16 17 18 19|20 21 22 23 24|
+---------+---------+--------------+--------------+--------------+
   <"2 n *"0 (5 5 5 $ 1)  NB. multiply by scalars
+---------+---------+--------------+--------------+--------------+
|0 0 0 0 0|5 5 5 5 5|10 10 10 10 10|15 15 15 15 15|20 20 20 20 20|
|1 1 1 1 1|6 6 6 6 6|11 11 11 11 11|16 16 16 16 16|21 21 21 21 21|
|2 2 2 2 2|7 7 7 7 7|12 12 12 12 12|17 17 17 17 17|22 22 22 22 22|
|3 3 3 3 3|8 8 8 8 8|13 13 13 13 13|18 18 18 18 18|23 23 23 23 23|
|4 4 4 4 4|9 9 9 9 9|14 14 14 14 14|19 19 19 19 19|24 24 24 24 24|
+---------+---------+--------------+--------------+--------------+

Вы заметите, что на самом деле это не вписывается в буквы в той ориентации, о которой спрашивает вопрос, а просто записывает их, однако это удобно для логики рангов. Если мы не перевернем или не повернем буквы, прежде чем применить их, это не будет работать правильно. Но для исправления подобных вещей потребовались бы драгоценные символы, поэтому вместо этого мы закодируем буквы так, что, когда J вырезает их естественным образом, некоторая тройка граней будет иметь правильную ориентацию и относительное положение. Оказывается, самое короткое решение - повернуть все буквы на четверть оборота против часовой стрелки. Учитывая, что третье измерение J представляет ось спереди назад, грубая диаграмма ниже показывает, почему эта схема работает.

визуализация куба Рисунок A: Три стороны куба, на которые вырезан J Рисунок B: Три стороны, буквы которых ориентированы так, как задает вопрос.

Этот выбор в кодировке сохраняет 12 символов по сравнению с предыдущим методом и делает все это более аккуратным. Фактический гольф создает куб из"1 и "2вырезает с некоторой причудливой логикой, из-за несвязанной оптимизации.

Тогда мы должны проверить лица. Так как мы закодировать блок как 1 и 0, мы можем просто суммировать вдоль каждой оси , как мы хотим (они являются +/"1, +/"2и+/ битами), приспосабливаются к булевым ( 0<), а затем сравнить их все непосредственно к исходным 90 ° - превратился-буква.

Схема сжатия кодирует каждую строку 5px каждой буквы как представление 32 двоичного числа. Используя ряд синтаксических сахаров и перегрузок операторов,".'1b',"#: это самый короткий способ превратить список символов в базовые 36 чисел. Ну, технически, база 32, но J думает, что это унарно, так кто же считает?

Использование ниже. Обратите внимание, что строки являются символьными массивами в J, поэтому список из трех пунктов 'A','B','C'можно написать 'ABC'для краткости. Кроме того, логические значения равны 1/0.

   NB. can be used inline...
   (_5#:\".'1b',"#:'fiiifalllvhhhheehhhvhhllvgkkkvnlhhvv444vhhvhhggvhjha44v1111vv848vv248vehhheciiivfjhhedmkkvilll9ggvggu111uo616ou121uha4ahg878ghpljh')((-:0<+/"1,+/"2,:+/)*`(*"1/)/)@:{~_65+3&u:'BEG'
1
   NB. or assigned to a name
   geb=:(_5#:\".'1b',"#:'fiiifalllvhhhheehhhvhhllvgkkkvnlhhvv444vhhvhhggvhjha44v1111vv848vv248vehhheciiivfjhhedmkkvilll9ggvggu111uo616ou121uha4ahg878ghpljh')((-:0<+/"1,+/"2,:+/)*`(*"1/)/)@:{~_65+3&u:
   geb 'BGE'
0
algorithmshark
источник
4

Питон, 687 682 671

import itertools as t,bz2
s=range(5)
c=dict([(i,1)for i in t.product(*3*[s])])
z=dict([(chr(i+65),[map(int,bz2.decompress('QlpoOTFBWSZTWXndUmsAATjYAGAQQABgADABGkAlPJU0GACEkjwP0TQlK9lxsG7aomrsbpyyosGdpR6HFVZM8bntihQctsSiOLrWKHHuO7ueAyiR6zRgxbMOLU2IQyhAEAdIJYB0ITlZwUqUlAzEylBsw41g9JyLx6RdFFDQEVJMBTQUcoH0DEPQ8hBhXBIYkXDmCF6E/F3JFOFCQed1Saw='.decode('base64')).split('\n')[j].split()[i])for j in s])for i in range(26)])
def m(a,g):
 for e in c:c[e]&=g[e[a]][e[a-2]]
def f(a):
 g=map(list,[[0]*5]*5)
 for e in c:g[e[a]][e[a-2]]|=c[e]
 return g
r=lambda g:map(list,zip(*g)[::-1])
def v(T,L,R):T,L,R=r(r(z[T])),r(z[L]),z[R];m(1,T);m(2,L);m(0,R);return(T,L,R)==(f(1),f(2),f(0))

Позвонить с v :

v('B','E','G') => True
v('B','G','E') => False

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

import string as s
import itertools as t

az = """01110  11110  01111  11110  11111  11111  11111  10001  11111  11111  10001  10000  10001  10001  01110  11110  01110  11110  01111  11111  10001  10001  10001  10001  10001  11111
10001  10001  10000  10001  10000  10000  10000  10001  00100  00100  10010  10000  11011  11001  10001  10001  10001  10001  10000  00100  10001  10001  10001  01010  01010  00010
10001  11110  10000  10001  11100  11110  10011  11111  00100  00100  11100  10000  10101  10101  10001  10001  10001  11111  01110  00100  10001  01010  10001  00100  00100  00100
11111  10001  10000  10001  10000  10000  10001  10001  00100  10100  10010  10000  10001  10011  10001  11110  10011  10010  00001  00100  10001  01010  10101  01010  00100  01000
10001  11110  01111  11110  11111  10000  11111  10001  11111  11100  10001  11111  10001  10001  01110  10000  01111  10001  11110  00100  01110  00100  01010  10001  00100  11111""".split('\n')

dim = range(len(az))
az = dict([(c, [map(int, az[j].split()[i]) for j in dim]) for i, c in enumerate(s.uppercase)])
cube = dict([(i, 1) for i in t.product(*3*[dim])])

def mask(axis, grid):
    for c in cube:
        if not grid[c[axis]][c[axis - 2]]:
            cube[c] = 0

def face(axis):
    grid = [[0 for j in dim] for i in dim]
    for c in cube:
        if cube[c]:
            grid[c[axis]][c[axis - 2]] = 1
    return grid

def rot(grid):
    return map(list, zip(*grid)[::-1])

def draw(grid, filled='X', empty=' '):
    s = ''
    for y in dim:
        for x in dim:
            s += filled if grid[y][x] else empty
        s += '\n'
    print s

def drawAll():
    print 'TOP:\n'
    draw(rot(rot(face(1))))
    print 'LEFT:\n'
    draw(rot(rot(rot(face(2)))))
    print 'RIGHT:\n'
    draw(face(0))

def valid(top, left, right):
    top, left, right = rot(rot(az[top])), rot(az[left]), az[right]
    mask(1, top)
    mask(2, left)
    mask(0, right)
    return top == face(1)and left == face(2) and right == face(0)

letters = 'BEG'

if valid(*letters):
    print letters, 'is valid.\n'
else:
    print letters, 'is not valid!\n'

drawAll()

Вызов valid чтобы запустить его:

valid('B', 'E', 'G') #returns True
valid('B', 'G', 'E') #returns False

Прямо сейчас код настроен для проверки правильности B E G и распечатки полученных граней:

BEG is valid.

TOP:

XXXX 
X   X
XXXX 
X   X
XXXX 

LEFT:

XXXXX
X    
XXX  
X    
XXXXX

RIGHT:

XXXXX
X    
X  XX
X   X
XXXXX

Запустив его, B G Eмы видим, что G неверен:

BGE is not valid!

TOP:

XXXX 
X   X
XXXX 
X   X
XXXX 

LEFT:

XXXXX
X    
X  XX
X    
XXXXX

RIGHT:

XXXXX
X    
XXX  
X    
XXXXX
Кальвин Хобби
источник
вау, хорошая работа! +1 за ничью и полноту ответа. +1 за использование такого короткого алгоритма. <3 it
xem
@ xem Спасибо! Я наконец играл в гольф. Хотя я не мог понять, как заставить bz2 распаковывать символы юникода.
Увлечения Кэлвина
+1. Хороший ответ. Надеюсь, что все больше людей будут поддерживать гольф, состоящий из небольших гольфов, как это, потому что это действительно требует усилий.
Векторизовано
1
g=[[0 for j in s]for i in s]можно сократить до g=map(list,[[0]*5]*5). Кроме того, вы можете избежать отступы блоков , если они одно заявление: if c[e]:g[e[a]][e[a-2]]=1.
Бакуриу
@Bakuriu и bitpwner, спасибо за предложения и изменения :)
Увлечения Кэлвина
1

Python 3 + NumPy, 327C

from numpy import*
B=hstack([ord(x)>>i&1for x in'옮弟ჹ羂옱쏷)ជ࿂︹缘龌ℿ쓥剴ℌᾄ起츱ꎚㆋឺ௣옮忬⧼ﯠႄ挒⺌ꕆ豈ꪱ袨冊䈑∾Ϣ'for i in range(16)])[:-6].reshape(26,5,5)
T=transpose
def f(*X):
 A=ones((5,5,5));F=list(zip([A,T(A,(1,0,2)),T(fliplr(A),(2,0,1))],[B[ord(x)-65]for x in X]))
 for r,f in F:r[array([f]*5)==0]=0
 return all([all(r.sum(0)>=f)for r,f in F])

Для этого гольф-решения нужна внешняя библиотека numpy, которая довольно популярна, поэтому я думаю, что ее можно использовать.

Строка Unicode состоит из 41 символа, а то же самое в ответе пролога @ fabian - 44.

Здесь самое интересное, что индексация массива numpy. В a[ix], ixможет быть логическим массивом с той же формой, что и a. Это то же самое, что сказатьa[i, j, k] where ix[i, j, k] == True .

Безголовая версия

import numpy as np
table = '옮弟ჹ羂옱쏷)ជ࿂︹缘龌ℿ쓥剴ℌᾄ起츱ꎚㆋឺ௣옮忬⧼ﯠႄ挒⺌ꕆ豈ꪱ袨冊䈑∾Ϣ'

def expand_bits(x):
    return [ord(x) >> i & 1 for i in range(16)]

# B.shape = (26, 5, 5), B[i] is the letter image matrix of the i(th) char
B = np.hstack([expand_bits(x) for x in table])[:-6].reshape(26, 5, 5)

def f(*chars):
    """
    cube:    ----------   axis:           
            /         /|      --------->2  
           /   1     / |     /|            
          /         /  |    / |            
         /         /   |   /  |            
        |---------|  3 |  v   |           
        |         |    /  1   |           
        |    2    |   /       v          
        |         |  /        0         
        |         | /                  
        -----------
    """
    cube = np.ones((5, 5, 5))
    cube_views = [
        cube,
        cube.transpose((1, 0, 2)),  # rotate to make face 2 as face 1
        np.fliplr(cube).transpose(2, 0, 1),  # rotate to make face 3 as face 1
    ]
    faces = [B[ord(char) - ord('A')] for char in chars]
    # mark all white pixels as 0 in cube
    for cube_view, face in zip(cube_views, faces):
        # extrude face to create extractor
        extractor = np.array([face] * 5)
        cube_view[extractor == 0] = 0

    return np.all([
        # cube_view.sum(0): sum along the first axis
        np.all(cube_view.sum(0) >= face)
        for cube_view, face in zip(cube_views, faces)
    ])

Скрипт для сжатия таблицы

import numpy as np

def make_chars():
    s = """
01110  11110  01111  11110  11111  11111  11111  10001  11111  11111  10001  10000  10001  10001  01110  11110  01110  11110  01111  11111  10001  10001  10001  10001  10001  11111
10001  10001  10000  10001  10000  10000  10000  10001  00100  00100  10010  10000  11011  11001  10001  10001  10001  10001  10000  00100  10001  10001  10001  01010  01010  00010
10001  11110  10000  10001  11100  11110  10011  11111  00100  00100  11100  10000  10101  10101  10001  10001  10001  11111  01110  00100  10001  01010  10001  00100  00100  00100
11111  10001  10000  10001  10000  10000  10001  10001  00100  10100  10010  10000  10001  10011  10001  11110  10011  10010  00001  00100  10001  01010  10101  01010  00100  01000
10001  11110  01111  11110  11111  10000  11111  10001  11111  11100  10001  11111  10001  10001  01110  10000  01111  10001  11110  00100  01110  00100  01010  10001  00100  11111
""".strip().split('\n')
    bits = np.zeros((26, 5, 5), dtype=np.bool)
    for c_id in range(26):
        for i in range(5):
            for j in range(5):
                bits[c_id, i, j] = s[i][j + c_id * 7] == '1'
    bits = np.hstack([bits.flat, [0] * 7])
    bytes_ = bytearray()
    for i in range(0, len(bits) - 8, 8):
        x = 0
        for j in range(8):
            x |= bits[i + j] << j
        bytes_.append(x)
    chars = bytes_.decode('utf16')
    return chars
луч
источник