Forum Discussion
A LAMBDA Word Search Puzzle
- Jul 16, 2022
Here is one more variant
//------ variant without TEXTJOIN() reverseColumns= LAMBDA( data, LET( n, COLUMNS( data ), CHOOSECOLS( data, SEQUENCE(n,,n,-1) ) )); reversedText= LAMBDA( str, LET( head, LEFT(str), tail, RIGHT(str, LEN(str) - 1), IF(str = "", "", reversedText(tail) & head) )); isPolindrom= LAMBDA( text, text = reversedText( text ) ); checkSingleWord= LAMBDA( str, vector, LET( getWord, REDUCE("", vector, LAMBDA( a,v, IF( LEFT(str, LEN(a&v)) = a&v, a&v, IF( LEFT(str) = a, v, IF( a = str, a, "" ) ) ) ) ), IF( getWord = str, str, "") )); checkListOfWords= LAMBDA( wordsVector, vector, LET( getWords, REDUCE("", wordsVector, LAMBDA(a,v, VSTACK(a, checkSingleWord( v, vector) ) ) ), IFERROR( FILTER( getWords, getWords <> ""), "" ) )); wordsInMatrix= LAMBDA( data, wordsVector, LET( k, SEQUENCE( ROWS(data) ), scanData, REDUCE(1, k, LAMBDA(a,v, CHOOSECOLS( IF( v < SEQUENCE(,v,v,-1), a, VSTACK(a, checkListOfWords( Words, CHOOSEROWS(data,v) ) ) ), 1 ) )), removeFirst, DROP( scanData, 1 ), FILTER( removeFirst, removeFirst <> "") )); wordsInPuzzle= LAMBDA( data, wordsVector, LET( allWords, SORT( VSTACK( wordsInMatrix( data, wordsVector ), wordsInMatrix( reverseColumns( data ), wordsVector ), wordsInMatrix( TRANSPOSE( data ), wordsVector ), wordsInMatrix( reverseColumns( TRANSPOSE( data ) ), wordsVector ) )), ifPolindroms, MAP(allWords, LAMBDA(v, isPolindrom(v) ) ), polindroms, UNIQUE( FILTER(allWords, ifPolindroms)), notPolindroms, FILTER(allWords, ifPolindroms -1), stack, IF( ISERR(polindroms), notPolindroms, VSTACK( polindroms, notPolindroms ) ), SORT( stack ) ));
Here is one more variant
//------ variant without TEXTJOIN()
reverseColumns=
LAMBDA( data,
LET(
n, COLUMNS( data ),
CHOOSECOLS( data, SEQUENCE(n,,n,-1) )
));
reversedText=
LAMBDA( str,
LET(
head, LEFT(str),
tail, RIGHT(str, LEN(str) - 1),
IF(str = "", "", reversedText(tail) & head)
));
isPolindrom=
LAMBDA( text, text = reversedText( text ) );
checkSingleWord=
LAMBDA( str, vector,
LET(
getWord, REDUCE("", vector,
LAMBDA( a,v,
IF( LEFT(str, LEN(a&v)) = a&v, a&v,
IF( LEFT(str) = a, v,
IF( a = str, a, "" )
) ) ) ),
IF( getWord = str, str, "")
));
checkListOfWords=
LAMBDA( wordsVector, vector,
LET(
getWords,
REDUCE("", wordsVector,
LAMBDA(a,v, VSTACK(a, checkSingleWord( v, vector) ) )
),
IFERROR( FILTER( getWords, getWords <> ""), "" )
));
wordsInMatrix=
LAMBDA( data, wordsVector,
LET(
k, SEQUENCE( ROWS(data) ),
scanData, REDUCE(1, k,
LAMBDA(a,v,
CHOOSECOLS(
IF( v < SEQUENCE(,v,v,-1),
a,
VSTACK(a, checkListOfWords( Words, CHOOSEROWS(data,v) ) ) ),
1 )
)),
removeFirst, DROP( scanData, 1 ),
FILTER( removeFirst, removeFirst <> "")
));
wordsInPuzzle=
LAMBDA( data, wordsVector,
LET(
allWords, SORT( VSTACK(
wordsInMatrix( data, wordsVector ),
wordsInMatrix( reverseColumns( data ), wordsVector ),
wordsInMatrix( TRANSPOSE( data ), wordsVector ),
wordsInMatrix( reverseColumns( TRANSPOSE( data ) ), wordsVector )
)),
ifPolindroms, MAP(allWords, LAMBDA(v, isPolindrom(v) ) ),
polindroms, UNIQUE( FILTER(allWords, ifPolindroms)),
notPolindroms, FILTER(allWords, ifPolindroms -1),
stack, IF( ISERR(polindroms), notPolindroms, VSTACK( polindroms, notPolindroms ) ),
SORT( stack )
));
I'm wondering if it's possible (or even sensible) to use recursion with SCAN to check an element in the array to see if it contains a word from the word list when the element LEN is at least 3. The word would be returned and the excess letters would be discarded. I'm messing around with recursion and SUBSTITUTE and receiving memory errors.
Ideally, the SCAN results would be like this:
- mtarlerJul 24, 2022Silver Contributor
Patrick2788 I haven't evaluated the actual functions developed here (but duly impressed). but I noticed this proposed method:
Ideally, the SCAN results would be like this:
and wanted to mention that in word search you can often have overlapping words. So you could have WAVE and VENUS overlapping so after finding WAVE you shouldn't reset the search array to the next letter D but should start with AVE (maybe the next word is AVENUE).
- Patrick2788Jul 24, 2022Silver ContributorFor this exercise, I didn't do overlapping words or diagonals (Things might really get out of hand if those were included!). I think SCAN can locate the words, but it seems easier to go by the row (Less letters to discard and no need to account for the row changing) or convert the matrix to a vector to pull the words.
- mtarlerJul 25, 2022Silver Contributoryes I saw the no diagonals but didn't see any exclusion for overlap. Besides, I don't think overlap adds a lot of complexity, just prevents some tricks that make it more efficient.
- SergeiBaklanJul 19, 2022MVP
Not sure I understood your idea correctly. If we scan only one row (one by one) and expected result is like
when it could be
///--- SCAN row on Words getWord= LAMBDA( str, words, XLOOKUP( str, words, words, 0) ); getWordOnRight= LAMBDA( str, words, IFNA( INDEX( Words, XMATCH( TRUE, RIGHT(str, LEN(Words) )= Words ) ), 0 ) ); getReversedWordOnRight= LAMBDA( str, words, IFNA( INDEX( Words, XMATCH( TRUE, LEFT( reversedText(str), LEN(Words) )= Words ) ), 0 ) ); scanVector= LAMBDA( vector, words, SCAN("", vector, LAMBDA(a,v, IF( getWord( a, Words ) <> 0, v, IF( getWordOnRight( a&v, Words ) <> 0, getWordOnRight( a&v, Words ), IF( getReversedWordOnRight( a&v, Words ) <> 0, getReversedWordOnRight( a&v, Words ), a&v ) ) ) ) ) );
I guess could could be more compact, just first iteration.
- Patrick2788Jul 19, 2022Silver ContributorThat's exactly it. My idea involved scanning the entire target array, but it looks like going by row is much better. No need to account for the change in row and less text to discard.
- PeterBartholomew1Jul 20, 2022Silver ContributorI have been trying something different with some success. I reduce the entire puzzle to a single string, padded with "|" between source rows and, rather than reversing the puzzle, I reverse the search words and append them to the original set. The location of the matches within the string is related to the position within the puzzle grid. So far, I have 0 and 1 to show where the matches are, but by combining that with the original grid, I could display the words in their original setting.