| Bytes | Lang | Time | Link |
|---|---|---|---|
| 054 | Google Sheets | 250815T102449Z | doubleun |
| 162 | Python | 250815T125721Z | Cloudfer |
| 072 | JavaScript ES6 | 250815T161618Z | Arnauld |
| 090 | Retina 0.8.2 | 250815T225125Z | Neil |
| 024 | MATL | 250815T145018Z | Luis Men |
| 099 | Maple | 250815T213436Z | dharr |
| 012 | Jelly | 250815T182520Z | Jonathan |
| 034 | Pip | 250815T193419Z | DLosc |
| 047 | Dyalog APL | 250815T165728Z | Aaron |
| 028 | 05AB1E | 250815T123949Z | Kevin Cr |
| 025 | Uiua | 250815T085609Z | mousetai |
| 082 | JavaScript Node.js | 250815T093534Z | l4m2 |
Google Sheets, 54 bytes
=index(ifs(B2:D4,1,len(A1:C3&C1:E3&A3:C5&C3:E5),2,1,))
Expects 1 instead of X, and blanks, i.e., empty values, instead of 0. Outputs the whole grid in one go as 1s, 2s and blanks.
To output x and * (58 bytes):
=index(ifs(B2:D4,"x",len(A1:C3&C1:E3&A3:C5&C3:E5),"*",1,))

To change output grid size, use Insert > Cells within the input grid.
Python, 162 bytes
- -2 bytes thanks to @Kevin Cruijssen
The input is given as a 2d grid of characters g.
def f(g):
for _ in[0]*4:
for r,o in zip(g,g[1:]):
for j in range(len(r)-1):
if'W'<r[j]and'X'!=o[j+1]:o[j+1]='*'
g=[*map(list,zip(*g[::-1]))]
return g
JavaScript (ES6), 72 bytes
Expects a string made of 0's and 1's for O and X. Returns another string with additional 2's for *.
s=>s.replace(/0/g,(_,i)=>s[i-=w=s.search`
`]|s[i-2]|s[i+=w*2]|s[i+2]&&2)
Try it online! (with post-processing for readability)
Commented
s => // s = input string
s.replace( // replace in s
/0/g, // each 0
(_, i) => // at index i:
s[ //
i -= // subtract from i
w = s.search`\n` // the width w of the matrix
] | // to test the top-right neighbor
s[i - 2] | // subtract 2 to test the top-left neighbor
s[i += w * 2] | // add 2w to test the bottom-left neighbor
s[i + 2] // add 2 to test the bottom-right neighbor
&& 2 // replace with 2 if any of them is 1
// (or leave it to 0 otherwise)
) // end of replace()
Retina 0.8.2, 90 bytes
(?<=(.)*)O(?=.*¶(?<-1>.)*(?(1)^)(.X|(?<=X)))|O(?=(.)*)(?<=(X.|(?=X))(?(3)$)(?<-3>.)*¶.*)
*
Try it online! Link is to test suite that accepts double-spaced test cases. Explanation: The regex has two sets of two alternations; the first pair detect Os diagonally to the left or right above Xs while the second pair detect Os diagonally to the right or left below Xs.
Unless there's some other feature of Retina 1 that I'm forgetting that would make this shorter, this would actually be longer in Retina 1 as that requires * to be quoted with $ in the replacement string.
MATL, 24 bytes
'*XO'5Y"i79>2Y6~o6 5(Z+)
Try it online! Or verify all test cases.
How it works
'*XO' % Push this string
5Y" % Have each entry appear 5 times. Gives '*****XXXXXOOOOO'
i % Push input: 2D char array
79> % Is each entry greater than 79 (code point of 'O')?
2Y6 % Push predefined literal [FTF; TTT; FTF]
~o % Negate, convert to number. Gives [1 0 1; 0 0 0; 1 0 1]
6 5( % Write 6 at the 5th entry. Gives [1 0 1; 0 6 0; 1 0 1]
Z+ % 2D convolution, without enlarging the array
) % Index into the string. Gives a 2D char array
% Implicitly display
Maple, 99 bytes
proc(M)for j in op(2,M)do for i,c in M do if add((i-lhs(j))^~2)=2and c=0then M[i]:=2fi od od;M end;
proc(M) # accepts matrix of 0=sky, 1=star
for j in op(2,M) do # lhs(j) has coords of stars
for i,c in M do # i = coords, c = contents
# if squared distance to star is 2 and c = sky then shine (set = 2)
if add((i-lhs(j))^~2)=2 and c=0 then M[i]:=2 fi
od
od;
M
end;
Jelly, 12 bytes
ŒĠạċØ1ɗƇ/ŒṬ^
A monadic Link that accepts a list of lists of OX character codepoints (where O is sky, and X is a star), containing both character codepoints, and yields a list of lists of NOX character codepoints (where N is the shine).
How?
ŒĠạċØ1ɗƇ/ŒṬ^ - Link: 2d-array of OX characters, Map (both O and X present)
ŒĠ - group multidimensional indices by their values
/ - reduce this pair of lists of pairs by:
Ƈ - keep those for which:
ɗ - last three links as a dyad
- f([SkyR,SkyC], [[Star1R,Star1C],[Star2R,Star2C],...]):
ạ - {[SkyR,SkyC]} absolute difference {[[Star1R,Star1C],[Star2R,Star2C],...]}
ċ - count occurrences of...
Ø1 - ...literal [1,1]
ŒṬ - multidimensional array with 1 at {those} indices & 0 elsewhere
^ - XOR {Map}
Pip, 34 bytes
L$+Ya@?s+:[vo];R:aR:0.XXX*y.2o.S_a
Input and output via strings, rows separated by spaces, OX* -> 021.
Explanation
This is a less-cryptic 35-byte version.
L2*Ya@?s;R:aR:0.XXX*[y-1y+1].2o.S_a
a Command-line argument
@?s Index of first space (= length of first row)
Y Yank (save as y)
2* Twice that amount
L ; Loop that many times:
R:a Reverse a and assign back to a
R: Replace and assign back to a...
Find this pattern:
[y-1y+1] List of y plus or minus 1
XX* Make two regexes matching that many chars
X Combine into one regex matching either option
0. Concatenate 0 on the front
.2 Concatenate 2 on the end
This regex matches a 0 on one line with a
diagonally adjacent 2 on the next line
Replace with:
S_ All but the first character of the match
o. Concatenate 1 to the front
The loop runs enough times to catch all the
replacements
a Afterwards, output the final value of a
To get to the 34-byte version, observe that the sum of the plus-or-minus 1 array is exactly two times the length of the first row, which is the number we need for our loop count. [vo] is [-1;1].
Dyalog APL, 47 chars
{{⍵⌷'O*X'}¨1+(q×2)⌈∨⌿2=(⍸q←'X'=⍵)∘.(+/2*⍨-)⍳⍴⍵}
⍳⍴⍵ # Get coordinates of every point of this input matrix
(⍸q←'X'=⍵) # Find bitmask of stars, store in q, and then get list of their coordinates
∘. # Outer product
(+/2*⍨-) # Sum of the square of their difference to find the square of the distance
2= # Every diagonal connection to a star has a distance of exactly 2
∨⌿ # Or-Over the multiple matrices generated (one for each star) to get full map of shine positions
⌈ # Maximum with
(q×2) # The original star mask multiplied by two, so stars always win over any shine
1+ # Add 1 for indexing purposes
{⍵⌷'O*X'}¨ # Index each element of the map into this string
💎
Created with the help of Luminespire.
05AB1E, 35 33 28 bytes
4F¬ašøí}2Fø€ü3}εε˜ιнDÅssài_>
I/O as a matrix of digits, with 012 for OX* respectively.
It feels way too long.. :/
Try it online or verify all test cases.
Explanation:
4F¬ašøí} # Add a border (of 0s) around the (implicit) input-matrix:
4F } # Loop 4 times:
¬ # Get the first row (without popping the matrix)
# (which will use the implicit input in the first iteration)
a # Convert each 1 to a 0 with an isLetter check
š # Prepend that list of 0s to the matrix
øí # Rotate once 90 degrees clockwise:
ø # Zip/transpose; swapping rows/columns
í # Reverse each inner list
2Fø€ü3} # Then convert it to a matrix of overlapping 3x3 blocks:
2F } # Loop 2 times:
ø # Zip/transpose; swapping rows/columns
€ # Map over each inner list:
ü3 # Convert it to overlapping triplets
εε # Nested map over each 3x3 blocks:
˜ # Flatten it to a list of nine items
ι # Uninterleave it into two parts: [corners+center,edges]
н # Pop and leave just the first item with the corners+center
D # Duplicate it
Ås # Pop the copy and push its center
s # Swap so the corners+center are at the top again
ài # If the max of these corners+center is 1
# (aka, it includes an "X"):
_ # ==0 check on the center that's on the stack
> # +1
# (aka, 1/"X" remains 1/"X", but 0/"O" becomes 2/"*")
# (after which the modified matrix is output implicitly as result)
Uiua, 25 glyphs
- -17 bytes thanks to @RubenVerg
- -2 bytes eliminating the pointless flatten
⨬∘⋅@*↧⊃(≠@X|/↥=@X⬚@O↻C₂).
I'm starting a stopwatch till someone who actually understands Uiua halves my score.
Edit: Stopwatch stopped after 1 hour and 2 minutes.
Uiua, 11 glyphs
Takes input as an array of numbers. Uses 0 for "O", 1 for "*", 2 for "X":
↥/↥-₁⬚0↻C₂.
JavaScript (Node.js), 82 bytes
A=>A.map((r,y)=>r.map((c,x)=>c||(g=(a,b)=>(A[y+a]||0)[x+b]?2:a>b?0:g(-b,a))(1,1)))