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 ) ));
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).
- 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.
- Patrick2788Jul 23, 2023Silver Contributor
I thought it would be interesting to re-visit this task with a fresh set of eyes. I scrapped my solution from 2022 and made things more interesting.
Functionality added:
- Diagonals are now supported
- Multiple dictionary support
There's a bit of calculation crunch when using the dictionary with 9,500+ words. I was going to add an Oxford dictionary that contained 100,000 words but the CSV needed extensive cleanup (Probably for the best as larger word lists contain a lot of made-up words).
=LET( height, ROWS(Puzzle), width, COLUMNS(Puzzle), AccumulateText, LAMBDA(a, letter, a & letter), Letter2Array, LAMBDA(arr, SCAN("", arr, AccumulateText)), WordsReversed, MAP(dictionary, LAMBDA(e, Reverse(e))), results, REDUCE( "", Puzzle, LAMBDA(a, letter, LET( r, ROW(letter), c, COLUMN(letter), across, INDEX(Puzzle, r, SEQUENCE(, width - c + 1, c, 1)), down, INDEX(Puzzle, SEQUENCE(height - r + 1, , r), c), diagonal_c, SEQUENCE(width - c + 1, , c), diagonal_r, SEQUENCE(width - c + 1, , r), diagonal, INDEX(Puzzle, diagonal_r, diagonal_c), neg_diagonal_c, SEQUENCE(c, , c, -1), neg_diagonal_r, SEQUENCE(width - c, , r), neg_diagonal, INDEX(Puzzle, neg_diagonal_r, neg_diagonal_c), arrAcross, TOCOL(Letter2Array(across)), arrDown, Letter2Array(down), arrDiagonal, Letter2Array(diagonal), arrDiagonalNeg, TOCOL(Letter2Array(neg_diagonal)), WordStack, IF( c = width, VSTACK(arrDown, arrDiagonalNeg), IF( r = height, VSTACK(arrAcross, arrDiagonal, arrDiagonalNeg), IF( c = 1, VSTACK(arrAcross, arrDown, arrDiagonal), VSTACK(arrAcross, arrDown, arrDiagonal, arrDiagonalNeg) ) ) ), WordBank, VSTACK(dictionary, WordsReversed), FoundWords, VSTACK(dictionary, dictionary), GetWords, TOCOL(XLOOKUP(WordStack, WordBank, FoundWords, ""), 2), VSTACK(a, GetWords) ) ) ), SORT(FILTER(results, results <> "", "no words found")) )- mtarlerJul 31, 2023Silver Contributor
Patrick2788 so I finally got back to this and did my version. Love to hear about the performance testing you do on them ....
=LET( h, ROWS(puzzleRange), w, COLUMNS(puzzleRange), space, " ", spaceLine, EXPAND(space, 1, w, space), PuzzleReverseH, CHOOSECOLS(puzzleRange, SEQUENCE(, w, w, -1)), PuzzleStack1, VSTACK(puzzleRange, spaceLine, PuzzleReverseH), PuzzleReverseV, CHOOSEROWS(PuzzleStack1, SEQUENCE(, 2 * h + 1, 2 * h + 1, -1)), PuzzleStack2, HSTACK(TRANSPOSE(puzzleRange), TRANSPOSE(TAKE(PuzzleReverseV, -h - 1, ))), PuzzleDiags, LAMBDA(stack, LET( nr, ROWS(stack), nc, COLUMNS(stack), REDUCE( EXPAND(INDEX(stack, , 1), nr + nc - 1, 1, space), SEQUENCE(nc - 1), LAMBDA(p, q, HSTACK( p, EXPAND( VSTACK(EXPAND(space, q, 1, space), INDEX(stack, , q + 1)), nr + nc - 1, 1, space ) ) ) ) ) ), PuzzleStacksHalf1, VSTACK( PuzzleStack1, spaceLine, PuzzleDiags(VSTACK(PuzzleStack1, spaceLine, PuzzleReverseV)) ), PuzzleStacksHalf2, PuzzleStack2, findWord, LAMBDA(puzzlestack, REDUCE( "", SEQUENCE(ROWS(puzzlestack)), LAMBDA(p, r, VSTACK( p, FILTER( dictionary, ISNUMBER(SEARCH(dictionary, CONCAT(INDEX(puzzlestack, r, )))), "" ) ) ) ) ), findWords, VSTACK(findWord(PuzzleStacksHalf1), findWord(PuzzleStacksHalf2)), out, SORT(FILTER(findWords, findWords <> "")), out )ok so I did a quick test and mine seems to fair pretty well. (*** note I have made a few edits as I found my diagonals were not as I thought and needed to adjust my sets to get all 4 diagonals correctly. Note, I also found that your solution is also missing some)
btw my concept was to take the puzzle and create a stack of:
orig puzzle,
puzzle reversed by rows, columns, and both
the above 2 shifted by 1 row for each column (i.e. creating the diagonals)
and then find any words found in any row
and repeat for the transpose of the orig and rev by rows to get vertical up/down words.
so I originally output the UNIQUE list but noted you showed all. As noted above I orig had some issues with missing 1 or 2 diagonals so my list had some you didn't you had some i didn't. I fixed it and now have every word in your list but when I removed UNIQUE i notice you have more copies in a couple cases. I don't know why that is the case but submit this as is for now)