Это слово на изумленной доске?

38

Введение

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

Твое задание

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

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

Пример ввода:

AJNES
TNFTR
LSAIL
UDNEX
EQGMM
DAFTER

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

Пример вывода для вышеуказанного ввода:

1

Руководство по вводу / выводу

  • Входные данные могут быть прочитаны из стандартного ввода, а выходные данные - в стандартный вывод.

Или

  • Входные данные могут быть одним строковым аргументом функции, а answer - возвращаемым значением этой функции.

Богдл Правила

  • Слово «на доске», если вы можете построить слово по пути последовательных, смежных, неповторяющихся плиток на доске.
  • Плитка считается смежной с восемью плитками, которые ее окружают (разрешены диагональные пути). Плитки на краю доски примыкают только к пяти плиткам. Плитка в углу соседствует только с тремя.
  • Последовательные буквы в слове должны быть смежными, iбуква th в слове должна быть смежной с буквой i-1th и i+1th.
  • Буква может появиться в слове более одного раза, но вы не можете использовать один и тот же квадрат на доске для сообщений более одного раза за слово.
  • Онлайновый сайт WordPlay.net может быть полезен, если вы никогда раньше не играли в boggle, но хотите ознакомиться с этими правилами.

В отличие от обычной болтовни:

  • Вам не нужно беспокоиться о том, что это слово является действительным английским словом.
  • Там не будет ни Quодной плитки.
  • Слово может быть любой длины> 0

пример

На доске

AJNES
TNFTR
LSAIL
UDNEX
EQGMM

Эти слова должны возвращать Истину: СУДЬБА, ЗНАКОМСТВА, СТЕНДЫ, ЛИФТЫ.

Эти слова должны возвращать False: SADDEN, SULTANS, EXIST, SUEDE, QUEST

Это испытание для игры в гольф, поэтому выигрывает самый короткий код!

turbulencetoo
источник
Доска оборачивается? Я не могу вспомнить
Клавдиу
Нет, это не оборачивается, я обновил разъяснение о смежности, чтобы отразить это.
турбулентность
Может ли путь пересечь себя (по диагонали)?
Мартин Эндер
@ m.buettner Да
турбулентность
Боггл - это обычно доска 4х4.
mbomb007

Ответы:

11

GolfScript, 74 символа

:^n%5>)]){{^@==}+29,\,{{+}+1$/}%\;}/{:s$..&=[s{.@-\}*;]1567`{7&.~)}%-!&},,

Ввод должен быть дан на STDIN. Печатает количество допустимых путей на плате, то есть 0ни для одного, и положительное число (true) в остальном.

Вы можете проверить пример онлайн .

Код с некоторыми комментариями:

:^              # assign the input to variable ^
n%              # split at newlines
5>              # truncate array such that [WORD] remains
)])             # prepares [[]] and WORD on the stack

# the following loop generates all possible paths (valid and invalid ones)
# by looking up all index combinations which yield the correct word
{               # loop over all characters
  {^@==}+29,\,  # get all indices of current character in the board
  {{+}+1$/}%\;  # append any index to all lists in the result set
}/              # end loop

# filter the results list for valid paths
{               # {...}, -> apply filter
  :s            # save path to variable s
  $..&=         # check if all numbers in path are unique
  [s{.@-\}*;]   # calculate differences along the path
  1567`{7&.~)}% # generate the array [1 -1 5 -5 6 -6 7 -7] of valid
                # differences
  -!            # check if all differences were valid
  &             # are both conditions fulfilled?
},              # end of filter block

,               # count the number of remaining paths
Говард
источник
12

Javascript (E6) 137 160 175 190

Менее 2 * Golfscript. Моральная победа ...

F=a=>[...a].some((e,p,b)=>(Q=(p,n)=>p>29||b[p]!=b[n]||(b.r|=!b[++n])||(b[p]=b[n+~[1,5,6,7].map(q=>Q(p+q,n)|Q(p-q,n),b[p]=0)]))(p,30)&b.r)

Редактировать Гольф-код реорганизации. Опять и опять

Ungolfed Последняя версия, немного сложная для подражания

F = a => 
  [...a] // input string to array, 30 chars of board then the target word
  .some ( // use some to scan the board, return true when found
      (e,p,b)=> // params to callback: element, position, complete array 
      (         // NB array b has no .r property, so use it for return value (it's undefined at start) 
        Q = (p,n) =>         // Scan function, p=position in board, n=nth char of target word
          p > 29 ||          // Chaek if going outside the board to the target word
          b[p] != b[n] ||    // if invalid char at current position, return
          (b.r |= !b[++n]) ||  // if at end of target, set r to 1 and return (also increment n )
          (                  // else... (NB next tree lines are coalesced in golfed code)
            b[p] = 0,        // remove current char (to avoid reusing) 
            [1,5,6,7].map( q => Q(p+q,n)|Q(p-q,n)), // recursive call for + - 1,5,6,7
            b[p] = b[n-1]    // put current char into array again 
          )
      )(p,30) & b.r // initial position 0 in target word is 30 in the array
  ) 

Ungolfed Первая версия, должно быть яснее

F = a => (
  b = a.split('\n'),
  w = b.pop(),
  r = 0,
  Q = (p, n) => 
    (r |= !w[n]) || 
    (
      b[p] = 0,
      [1,5,6,7,-1,-5,-6,-7].map( q => b[q+=p]==w[n] && Q(q,n+1)),
      b[p] = w[n-1]
    ),
  b = [...b+''],
  b.map((e, p) => e==w[0] && Q(p,1)),
  r
)

использование

F("AJNES\nTNFTR\nLSAIL\nUDNEX\nEQGMM\nLIFTS\nDAFTER")

Тест

['DAFTER', 'STANDS', 'LIFTS', 'FATE', 'DATING' ,
 'SADDEN','SULTANS', 'EXIST', 'SUEDE', 'QUEST']
.map(w => [w, F("AJNES\nTNFTR\nLSAIL\nUDNEX\nEQGMM\n" +w)])

Выход:

[["DAFTER", true], ["STANDS", true], ["LIFTS", true], ["FATE", true], ["DATING", true], 
["SADDEN", false], ["SULTANS", false], ["EXIST", false], ["SUEDE", false], ["QUEST", false]]
edc65
источник
1
Небольшая оптимизация:F=a=>(b=a.split('\n'),w=b.pop(Q=(p,n)=>((R|=!w[n])||(b[p]=0)||[1,5,6,7,-1,-5,-6,-7].map(q=>b[q+=p]==w[n]&&Q(q,n+1,b[q]=w[n])))),[Q(~~p,1)for(p in b=[...b.join(R=0)])if(b[p]==w[0])],R)
nderscore
Это должно быть w = a.pop()(игра в гольф) или w = b.pop()(без игры в гольф, линия 2)? (вероятно, последнее, я думаю)
Hlt
@androyd После реорганизации я оставил старый код без кода для ясности. Но это не на 100% в синхронизации. Я постараюсь уточнить
edc65
Боже мой, не видел, чтобы вы изменили его a=a.pop()вместо b=a.pop()...
Hlt
4

Питон, 207 204 203

g=raw_input
r=range
b=''.join(g()for _ in r(5))
w=g()
s=lambda b,w,i:0<=i<25and(not w or(b[i]==w[0])*any(s(b[:i]+'_'+b[i+1:],w[1:],i+j+k*5-6)for j in r(3)for k in r(3)))
print any(s(b,w,i)for i in r(25))

Замена ... (b[i]==w[0])*any ...на ... b[i]==w[0]and any ...дает гораздо лучшую производительность за счет 2 символов.

картонная коробка
источник
1
Вы можете сбрить пробелы между числами и командами; 0<=i<25and
Seequ
3

J - 75 символов

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

+/@([:*/"1^:2(2(=*)@-/\>@~.)S:1)@{@(((<@#:i.)5 5)<@#~&,"2{:=/&:>}:)@(<;._2)

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

  • (<;._2)- Это разбивает строки на символы новой строки / разделителя. Он использует символ в конце строки как символ для разделения. Мы помещаем все в box ( <), потому что если мы не получим некоторые проблемы с заполнением, когда J возвращает нам результат.

  • (((<@#:i.)5 5)<@#~&,"2{:=/&:>}:) - Для каждой буквы в проверяемом слове создайте список индексов на доске Boggle, где можно найти эту букву.

    • {:последний разделенный фрагмент (слово для проверки) и }:все, кроме последнего (доска Boggle).

    • &:>открывает поля, которые мы сделали ранее, с полезным побочным продуктом превращения }:в двумерный массив символов. =/затем делает копию этой доски Boggle для каждой буквы в слове и превращает позиции в логические значения в зависимости от того, соответствует ли буква на доске этой букве в слове.

    • ((<@#:i.)5 5)это короткий способ выражения массива индексов 5x5. x#:yis преобразуется yв массив базового xпредставления. (Ну, почти. Правда сложнее, но это работает для наших целей.)

    • <@#~&,"2- Для полученной логической матрицы каждой буквы соберите все соответственно истинные индексы. "2заставляет все работать с правильными результатами, #~&,делает выбор и <@собирает каждый результат в поле для подготовки к следующему шагу.

  • {- Этот глагол, используемый монадически, называется Каталогом, и в качестве аргумента он принимает список полей. Он сочетает в себе каждую коробку всеми возможными способами. Так, например, каталог в некоторых полях, содержащий строки «AB» и «abc», даст результаты «Aa», «Ab», «Ac», «Ba», «Bb», «Bc».

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

  • ([:*/"1^:2(2(=*)@-/\>@~.)S:1) - Здесь мы проверяем каждый путь, чтобы увидеть, если он действителен.

    • (...)S:1применяет (...)к каждому пути и собирает результаты в плоский список. Это очень важно, потому что в результате {получается многомерный массив, и нам не важна структура этого массива, только его содержимое в каждом блоке.

    • 2(=*)@-/\>дает 1, если каждая координата каждого индекса находится на расстоянии не более одной от следующей за ним, и 0 в противном случае. 2И /\несут ответственность за выполнение этой парно.

    • */"1^:2логические И это все вместе в конце. [:Часть является структурной вещью в J, не беспокойтесь об этом.

    • Добавление @~.на >самом деле является умным способом исключить пути с повторяющимися записями. ~.берет уникальные элементы списка, поэтому список укорачивается, если он самопересекается, и более короткие списки автоматически заполняются нулями при их объединении, как способ объединения результатов по мере их появления S:. Это в конечном итоге короче, чем явное исключение самопересекающихся путей.

  • +/- Наконец, мы просто складываем все вместе в конце. Результатом является количество допустимых путей, которые составляют слово на доске, где 0 означает отсутствие путей, т.е. это слово отсутствует на доске. +./Вместо стоимости одного символа мы можем вместо этого написать (логическое ИЛИ все), что в явном виде даст логическое значение 1 или 0.

Вот несколько примеров выполнения. Вы можете получить интерпретатор J на jsoftware.com или попробовать его в Интернете по адресу tryj.tk .

   NB. the  0 : 0 ... )  thing is how you do multiline strings in J
   +/@([:*/"1^:2(2(=*)@-/\>@~.)S:1)@{@(((<@#:i.)5 5)<@#~&,"2{:=/&:>}:)@(<;._2) 0 : 0
AJNES
TNFTR
LSAIL
UDNEX
EQGMM
DAFTER
)
1
   b =: +/@([:*/"1^:2(2(=*)@-/\>@~.)S:1)@{@(((<@#:i.)5 5)<@#~&,"2{:=/&:>}:)@(<;._2)
   b 'AJNES TNFTR LSAIL UDNEX EQGMM FATE '    NB. any separator will do
1
   b 'AJNES TNFTR LSAIL UDNEX EQGMM SADDEN '  NB. not on the board
0
   b 'AJNES TNFTR LSAIL UDNEX EQGMM SANDS '   NB. self-intersecting path
0
   b 'AJNES TNFTR LSAIL UDNEX EQGMM MEND '    NB. multiple paths
2
algorithmshark
источник
1
+1 за подробности. Я хотел бы видеть больше ответа, как это!
edc65
2

Пролог - 315

r(L):-get_char(C),(C='\n',!,L=[];r(T),L=[C|T]).
b(0,[]):-!.
b(N,[R|T]):-M is N-1,r(R),b(M,T).
d(-1). d(0). d(1).
d([A,B],[C,D]):-d(X),C is A+X,d(Y),D is B+Y.
f([L|W],B,P,U):-P=[X,Y],nth(Y,B,R),nth(X,R,L),\+member(P,U),(W=[];d(P,Q),f(W,B,Q,[P|U])).
m:-b(5,B),r(W),f(W,B,_,[]),write(t);write(f).
:-initialization(m).

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

Протестировано с GNU Prolog; должен соответствовать стандарту ISO Prolog.

Ungolfed:

get_line(Line) :-
    get_char(C),
    (   C='\n', !, Line=[]
    ;   get_line(Tail), Line=[C|Tail]
    ).

% The cut prevents recursion to help_get_board(-1, MoreRows)
% (and golfs one character shorter than putting N>0 in the second rule).
help_get_board(0, []) :- !.
help_get_board(N, [Row|Tail]) :-
    M is N-1, get_line(Row), help_get_board(M, Tail).

% The golfed version doesn't define an equivalent to get_board/1.
% help_get_board(5,Board) is used directly instead.
get_board(Board) :- help_get_board(5,Board).

small(-1). small(0). small(1).
step([X1,Y1],[X2,Y2]) :-
    small(DX), X2 is X1+DX,
    small(DY), Y2 is Y1+DY.

% The golfed version doesn't define an equivalent to letter_at/3.
% See find_word/4.
letter_at([X,Y], Letter, Board) :-
    nth(Y, Board, Row),
    nth(X, Row, Letter).

find_word([Letter|Word], Board, Pos1, Used) :-
%    letter_at(Pos1, Letter, Board),  % "inlined" to next three lines:
    ( Pos1 = [X,Y],
      nth(Y, Board, Row),
      nth(X, Row, Letter) ),
    \+member(Pos1, Used),
    (   Word=[]
    ;
        step(Pos1, Pos2),
        find_word(Word, Board, Pos2, [Pos1|Used])
    ).

main :-
    get_board(Board),
    get_line(Word),
    % Begin at any position. Initially no positions are "Used".
    find_word(Word, Board, _, []).
aschepler
источник