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 ) ));
Thank you for your reply. I spent a couple days on it on and off then dropped it for a few days because I couldn't resolve it with SCAN. I did go through the paces with TOCOL and reducing the letters to a scalar. I didn't feel good about where I was headed. I revisited the task when I thought of how the new Text functions may be helpful by using delimiters, so I played with feeding TEXTSPLIT/TEXTBEFORE/TEXTAFTER a stack of words to delimit on. SergeiBaklan - I need to take some time to study this solution. I've been looking at this puzzle too much lately but will come back to it soon.
The part I couldn't get around with SCAN was achieving something like this (A sample of the first two rows done manually):
The closest I came was getting WAVE and AES (placed in row 2) but the rest that followed was not accurate.
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 )
));
- Patrick2788Jul 19, 2022Silver Contributor
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.
- 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.
- Patrick2788Jul 16, 2022Silver ContributorThank you for the examples. I really need to improve on recursion. I've been doing some things the long way and can refine my methods much more!