| Bytes | Lang | Time | Link |
|---|---|---|---|
| 081 | Uiua | 250703T235210Z | ErikDaPa |
| 065 | Vyxal j | 250627T195452Z | pacman25 |
| 114 | BQN | 220128T164747Z | ovs |
| 8783 | 05AB1E | 220128T155403Z | Kevin Cr |
| 166 | Ruby 1.9 | 110810T203837Z | Lowjacke |
| 649 | Scala | 110811T070344Z | user unk |
| 342 | JavaScript | 110809T181701Z | Briguy37 |
| 230 | Perl | 110810T154400Z | DCharnes |
Uiua, 81 bytes
≡₀⨬⋅@ ∘↥⤚⊃(/↥⊂≡⍉∩⌟˜≡◇⦷⊸⍉□|↥∩≡↘₁∩⌟₂⍜(⍉≡↻|/↥˜≡◇⦷□)⊸¯°⊏≡(⊂@ )):⊂⊸⍚⇌∩°□°⊟⊜(□⍣⊜∘⊜□¬⊸⦷@\n)¬⊸⦷˙⊂@\n
Explanation:
≡₀⨬⋅@ ∘↥⤚⊃(RC|DA):⊂⊸⍚⇌GD
GD => (get data), splits data into grid and list of words
:⊂⊸⍚⇌ => reverse each word and include it in the list of words
⤚⊃(RC|DA) => (word search)
≡₀⨬⋅@ ∘↥ => OR all searches, and keep letters at truthy indices
otherwise fill with spaces
GD: (get data)
∩°□°⊟⊜(□⍣⊜∘⊜□¬⊸⦷@\n)¬⊸⦷˙⊂@\n
⊜( )¬⊸⦷˙⊂@\n => splits by double newline (word list & grid)
□⍣⊜∘⊜□¬⊸⦷@\n => for each result split by newline and box each row if needed
∩°□°⊟ => put elements of the list onto the stack and unbox both elements
RC: (row & col search)
/↥⊂≡⍉∩⌟˜≡◇⦷⊸⍉□
∩⌟˜≡◇⦷⊸⍉□ => generate bool masks for all matches in rows and cols
/↥⊂≡⍉ => transpose back col bool masks, then OR them
DA: (diag & anti-diag search)
↥∩≡↘₁∩⌟₂⍜(⍉≡↻|/↥˜≡◇⦷□)⊸¯°⊏≡(⊂@ )
⍜(⍉≡↻| )⊸¯°⊏≡(⊂@ ) => rotate each row prepended with spaces by its idx in both directions
& transpose (gives both diag & anti-diag)
∩⌟₂ /↥˜≡◇⦷□ => search (basically the same logic as RC)
↥∩≡↘₁ => drop prepended space and OR both bool masks
Vyxal j, 73 69 68 65 bytes
¤€÷$:RJ£D₍Þ√Þ`ṅ∇∩"Jvƛ¥ve:[¨vƒrꜝfUsn$⁽ɽ¢]ƛaßð;ṅ;ɾ÷∩^Þ„‟Þ‟W∩4/ƛ∩vGṅ
this took me several hours and a lot of annoyances with regex but I did it will explain later today
-8 from basic optimization
explanation (old):
¤€÷$:RJ£D₍Þ√Þ`ṅ∇∩"Jvƛ¥ve:a[¨vƒrꜝfUsn$⁽ɽ¢|n]ƛaßð;ṅ;ɾ÷∩^Þ„‟Þ‟W∩4/ƛ∩vG;ṅ
¤€÷$ # parse input
:RJ£ # set register to the wordlist plus all words reversed
D # push the grid 3x
₍Þ√Þ`ṅ∇∩"J # list of diagonals, antidiagonals, rows and columns
vƛ ṅ; # map over each slice and concat
¥ve # first and last index for all regex matches for words
:a[ | ] # if any has a match
¨vƒr # convert those indices to a range
ꜝfUs # sort all unique values across all ranges
n$⁽ɽ¢ # apply lowercase to items at those indices
# This now has the words all lowercased in each slice of uppercase
n # otherwise just push the slice
ƛaßð; # convert any uppercase letters to spaces
ɾ # uppercase everything
÷ # push all the slice lists
∩^ # transpose the first one to get columns, then reverse the stack
Þ„‟Þ‟ # list from diagonals and antidiagonals with a stack rotate in between
W∩4/ # wrap the stack, transpose it and split into four equal parts
# this gives each row in a solved grid for rows columns diags and antidiags
ƛ∩vG;ṅ # get any uppercase letters in any row, spaces for the rest
💎
Created with the help of Luminespire.
BQN, 126 114 bytesSBCS
{S←-++`׬⋄{w𝕊g:g⊑∘↑˜¨¯2+∨´⥊w{H←⊒˜∊·⥊(↕≠𝕨)+⌜·/𝕨⊸⍷⋄(H˘∨1↓˘⊒˜⌽⁼˘·H˘⌾⍉⊒˜⌽˘' '⊸∾˘)⌾(⌽∘⍉⍟𝕩)g}⌜↕4}⟜>´(S⟨⟩⊸≡¨)⊸⊔𝕩⊔˜S𝕩='
'}
One third of the code is parsing the input, the more interesting parts are outlined below:
{w𝕊g:g⊑∘↑˜¨¯2+∨´⥊w{H←⊒˜∊·⥊(↕≠𝕨)+⌜·/𝕨⊸⍷⋄(H˘∨1↓˘⊒˜⌽⁼˘·H˘⌾⍉⊒˜⌽˘' '⊸∾˘)⌾(⌽∘⍉⍟𝕩)g}⌜↕4}
{w𝕊g:g⊑∘↑˜¨¯2+∨´⥊w{ ... }⌜↕4}
w𝕊g: # A dyadic function taking:
# - left argument w: word list
# - right argument g: grid
↕4 # 0 1 2 3
{ ... }⌜ # For each of those numbers on the right (specifying rotation) and ...
w # each word on the left, call the inner function.
# The inner function returns boolean matrices of the same shape of the input
∨´⥊ # Boolean OR of all the matrices
g⊑∘↑˜¨¯2+ # For 1's in the matrix take a character from the grid, for 0's take a space.
The inner function rotates the grid (as many times as its right argument specifies: ⌽∘⍉⍟𝕩), checks for words from left to right and on diagonals and then rotates the result back.
How to get get diagonals:
This method is mostly taken from BQNcrate. First a space is prepended to each row. Then each row is rotated by its index. Now words previously in the diagonals are in the columns, by transposing we get them in the rows. After marking the words, all the steps can be reversed: Try with step-by-step results!
05AB1E, 87 (or 83?) bytes
||UεVX8FD»YåiY1:AuSð:1Y:}D€g©ËiεSÐ0:«NFÁ}}øíJ0δKõKë®à©FD®£€нJRsεN®‹i¦}}¦}\)]€Søε{θ}J®ä»
With the actual I/O as mentioned in the challenge description.
Try it online. (For some reason, the Á is very slow on an inner list of characters instead of a string in this program, so εSÐ0:«NFÁ}} has been replaced with εÐS0:«NFÁ}S} (rotate first; then convert it to a list of characters) to speed things up substantially - it'll now output on TIO in roughly a second, instead of timing out without any output after 60 seconds.)
With less strict I/O (first words-input as a list, second grid-input as a list of lines; output-grid as a list of lines as well), this would be 83 bytes instead:
εVI8FD»YåiY1:AuSð:1Y:}D€g©ËiεSÐ0:«NFÁ}}øíJ0δKõKë®à©FD®£€нJRsεN®‹i¦}}¦}\)]€Søε{θ}J®ä
Try it online (with the same modification as above so it won't time out).
Explanation:
In pseudo-code, I do the following steps:
Map over the list of words:
Push the input-grid
Loop 8 times:
If the word is present horizontally left-to-right:
Replace everything else with a space
Rotate the grid 45 degrees counterclockwise
Reduce/combine all grids of spaces and words
As for the actual code, of which most (50 bytes) is used to rotate the grid 45 degrees:
| # Get all inputs until an empty line is encountered,
# resulting in the list of words
| # Do it again, resulting in the grid
U # Pop and store the grid in variable `X`
ε # Map over each of the words:
V # Pop and store the word in variable `Y`
X # Push grid `X`
8F # Loop 8 times:
D»Yå # Check if the word is in the grid:
D # Duplicate the grid
» # Join the lines with newline delimiter
Yå # Check that this contains the word `Y`
i # If this is truthy:
Y1: # Replace the word temporarily with a 1
AuSð: # Replace all uppercase letters with a space
1Y: # Replace the 1 back to the word
} # Close the if-statement
D€g©ËiεSÐ0:«NFÁ}}øíJ0δKõKë®à©FD®£€нJRsεN®‹i¦}}¦}\)
# Rotate the grid 45 degrees counterclockwise:
D€g©Ë # Check if the grid is a rectangle:
D # Duplicate the grid
€g # Get the length of each row
© # Save this list of lengths in variable `®` (without popping)
Ë # Check whether these lengths are all equal
i # If this is truthy:
ε # Map over each row:
S # Convert it to a list of characters
Ð0:« # Append the row-length amount of 0s to the row
Ð # Triplicate the row
0: # Pop two, and replace all characters to 0s
« # Merge this list of 0s to the row
NF # Loop the 0-based map-index amount of times:
Á # Rotate the row once towards the right
} # Close the loop
} # Close the map
øí # Now rotate 90 degrees clockwise:
ø # Zip/transpose; swapping rows/columns
í # Reverse each row
J # Join the inner list of characters back to a string
δ # Map over each row:
0 K # Remove all 0s from the row
õK # Remove any empty rows
ë # Else (it's a diamond-shape instead):
® # Push the list of lengths
à # Pop and push its maximum
© # Store this maximum as new variable `®` (without popping)
F # Loop this maximum amount of times:
D # Duplicate the list
®£ # Only leave the first max amount of values
€н # Only leave the first character of each row
J # Join these characters together to a string
R # Reverse it
s # Swap so the list is at the top again
ε # Map over each row:
N®‹i # If the map-index is smaller than max `®`:
¦ # Remove the first character
} # Close the if-statement
} # Close the map
¦ # Remove the first (now empty) row
} # Close the loop
\ # Discard the now empty list
) # Wrap all rows on the stack into a list
] # Close the open if-statement; loop; and map
# (we now have a list space-grids, except for the found words)
€S # Convert each inner grid to a flattened list of characters
ø # Zip/transpose; swapping rows/columns
ε # Map over each inner list:
{ # Sort; spaces at the front, potential letter(s) at the end
θ # Pop and leave the last character
} # Close the map
J # Join everything together to one huge string
® # Push the last maximum `®`
ä # Split the string into that many equal-sized parts
» # Join the list of rows with newline delimiter
# (after which it is output implicitly as result)
Ruby 1.9, 214 210 206 182 177 173 172 166
s,G=$<.read.split$/*2
O=G.tr'^
',' '
(s+$/+s.reverse).split.map{|w|[0,l=G=~/$/,l+1,l-1].map{|d|(k=G=~/#{[*w.chars].*?.*d}/m)&&w.size.times{|i|O[k+d*i+i]=w[i]}}}
$><<O
Scala 697, 666 649
val(z,n)=io.Source.fromFile("F").getLines.toList.span(_.length>0)
val m=n.tail
val(w,h)=(m.head.length,m.size)
def g(d:Int,e:Int,k:Int,g:Int,h:Int,i:Int,s:String)={
def f(x:Int,y:Int):Seq[(Int,Int)]={
val q=for(c<-(0 to s.size-1))
yield (y+c*i,x+c*k)
if((q.map(p=>m(p._1)(p._2))).mkString==s)q else Nil}
val t=for(x<-(d to e);
y<-(g to h))yield f(x,y)
t.flatten}
def i(s:String)={val l=s.size
g(0,w-l,1,0,h-1,0,s)++ g(0,w-1,0,0,h-l,1,s)++ g(0,w-l,1,l-1,h-1,-1,s)++ g(0,w-l,1,0,h-l,1,s)}
def j(s: String)=i(s)++ i(s.reverse)
val k=z.map(j).flatten
(0 to h-1).map(r=>{(0 to w-1).map(c=>if(k.contains(r,c))print(""+m(r)(c))else print(" "));println()})
degolfed:
object Golf {
def main (args: Array[String]) = {
val (words, matrix) = io.Source.fromFile ("./wordsearch.data").getLines.toList.span (_.length > 0)
val m = matrix.tail
val (w,h) = (m.head.length, m.size)
// xi: x-increment, yi: y-increment
def find (x: Int, y: Int, xi: Int, yi: Int, s: String): Seq [(Int, Int)] = {
val points = for (c <- (0 to s.length-1))
yield (y + c*yi, x + c * xi)
if ((points.map (p => m (p._1)(p._2))).mkString == s) points else Nil
}
def findInScope (xS: Int, xD: Int, xi: Int, yS: Int, yD: Int, yi: Int, s: String): Seq [(Int, Int)] = {
val ppoints = for (x <- (xS to xD);
y <- (yS to yD)) yield find (x, y, xi, yi, s)
ppoints.flatten
}
def findRowColFallingClimbing (s: String) = {
val l=s.length
// horizontal:
findInScope (0, w-l, 1, 0, h-1, 0, s) ++
// vertical:
findInScope (0, w-1, 0, 0, h-l, 1, s) ++
// climbing /:
findInScope (0, w-l, 1, l-1, h-1, -1, s) ++
// falling \:
findInScope (0, w-l, 1, 0, h-l, 1, s)
}
def findBoth (s: String) = findRowColFallingClimbing (s) ++ findRowColFallingClimbing (s.reverse)
val coords = words.map (findBoth).flatten
(0 to h-1).map ( r => {
(0 to w-1).map (c =>
if (coords.contains (r, c))
print ("" + m(r)(c))
else print (" ")
)
println ()
})
}
}
JavaScript: 342 characters
function a(b){c='\n';d=b.split(c+c);e=d[1].split(c);for(f=-1,g=[];h=e[++f];)for(i=-1,g[f]=[];h[++i];)for(j=-2,g[f][i]=' ';2>++j;)for(l=-2;2>++l;)for(k=0;m=d[0].split(c)[k++];)for(n=-1;o=m[++n];)for(p=f-n*j-j,q=i-n*l-l,r=0;(s=m[r++])&&(t=e[p+=j])&&(u=t[q+=l])&&s==u;)if(r==m.length)g[f][i]=o;for(i=0;v=g[i];)g[i++]=v.join('');return g.join(c)}
function solveWordsearch(input){
var lineBreak = '\n';
var solver = input.split(lineBreak+lineBreak);
var board = solver[1].split(lineBreak);
for(row=-1,output=[]; line=board[++row];){
for(col=-1,output[row]=[]; line[++col];){
for(rowIncrement=-2,output[row][col]=' ';2>++rowIncrement;){
for(colIncrement=-2;2>++colIncrement;){
for(k=0; word=solver[0].split(lineBreak)[k++];){
for(charPosition=-1; wordChar=word[++charPosition];){
var startRowIndex=row-charPosition*rowIncrement-rowIncrement;
var startColIndex=col-charPosition*colIncrement-colIncrement;
for(wordIndex=0;(compareWordChar=word[wordIndex++])&&(compareBoardRow=board[startRowIndex+=rowIncrement])&&(compareBoardChar=compareBoardRow[startColIndex+=colIncrement])&&compareWordChar==compareBoardChar;){
if(wordIndex == word.length){
output[row][col]=wordChar;
}
}
}
}
}
}
}
}
for(i=0;outLine=output[i];){
output[i++]=outLine.join('');
}
return output.join('\n');
}
The concept behind this solution is to iterate over all positions on the board, initialize a 2D-array's values to ' ' for each position, and then consider all potential word directions and word offsets. If a matching word is found, the array's value for that position is updated to the correct letter. Finally, the array is converted to a string and returned.
Perl - 230 chars
Count includes 4 for "-ln " command-line options.
if(1../^$/){push@w,$_,''.reverse if$_}else{$a.="$_\n"}END{$_=$a;/.+/;$W=$+[0];y/A-Z/ /;chomp;for$w(@w){for$n(0,$W-1..$W+1){$r=join".{$n}",map"($_)",(@l=split//,$w);if($i=$a=~/$r/s){substr($_,$-[$i++],1,shift@l)while@l}}}print}
Ungolfed:
# -n: implicitly loop over input lines
# -l: strip the newlines
if ( 1 .. /^$/ ) { # from first line to empty line
push @w, # record in @w
$_, # the word
''.reverse # and its reverse
if $_ # if it's not the empty line
}
else {
$a .= "$_\n" # otherwise, add to the search array
}
END {
$_ = $a; # make a copy for the output
/.+/; $W = $+[0]; # compute array width
y/A-Z/ /; # blank the output board
chomp; # and remove the trailing newline,
# because -l will add it back for us
for $w (@w) { # for each word
for $n (0, $W-1 .. $W+1) { # for each direction in E, SW, S, SE
$r = join ".{$n}", # form a regexp with an appropriate
# number of characters skipped between letters
# (0 -> adjacent, so E; $W -> next line, so S;
# off by one from $W for the diagonals),
map "($_)", # capturing the letters of the word (for their offsets),
(@l=split//,$w); # which we split up here
if ( $i = $a =~ /$r/s ) { # if the word matches in this orientation
substr( $_, # set the substring of the output
$-[$i++], # at the offset this letter matched
1, # length 1
shift @l ) # to the corresponding letter
while @l # (for each letter)
}
}
}
print # and print the output
}