| Bytes | Lang | Time | Link |
|---|---|---|---|
| 935 | Python3 | 220310T182137Z | Ajax1234 |
| 141 | Charcoal | 220310T005921Z | Neil |
Python3, 935 bytes:
E=enumerate
S=lambda b,x:(x+1==len(b)or x==0)*[1,-1][x>0]
def F(b,C,v,x,y,q,w,c=0):
if int==type(b[x][y])and c:b[x][y]=[v,'R'][C==(x,y)];return
if b[x][y]=='O':b[C[0]][C[1]]='H';return
T=[]
for i in[1,-1]:
X=x+(i*(q==0)+(q!=0)*q);Y=y+(i*(w==0)+(w!=0)*w)
if X>=0 and Y>=0:
try:T+=[i]*(b[X][Y]=='O')
except:1
T*=b[x+q][y+w]=='.'
if not c and T:b[C[0]][C[1]]='R';return
if T:
Q,W=0,0
if len(T)==2:Q=q-1*(q!=0)*q;W=w-1*(w!=0)*w
else:Q=(q==0)*T[0]*-1;W=(w==0)*T[0]*-1
F(b,C,v,x,y,Q,W,c+1);return
F(b,C,v,x+q,y+w,q,w,c+1)
def g(b):
for x,j in E(b):
for y,k in E(j):
if k and type(k)==int:F(b,t:=(x,y),b[x][y],*t,S(b,x),S(b[0],y))
return b
K=lambda b:'\n'.join(''.join(map(str,[[j,' '][y in[0,len(a)-1]]for y,j in E(a)]if i in[0,len(b)-1]else[[' ',j][y in[0,len(a)-1]]for y,j in E(a)]))for i,a in E(b))
f=lambda b,c=0:K(g((A:=[[0]+[(c:=c+1)for _ in b[0]]+[0]])+[[(M:=(c:=c+1))]+i+[M]for i in b]+eval(str(A))))
Charcoal, 171 141 bytes
≔⁺⁺ψ⭆θ ψη⊞υηWS⊞υ⪫ ιυη≔⁰ζF⊕LυFLη«Jκι¿⁼ KK«≔⁻⁶⊗⌕KVωδM✳δW⁼KK.«≔⊗E²№KD²✳⁺δ⁺²×⁴μOε≧⁺⊗⌈εδM✳δ≧⁻↨ε±¹δ»≡KKO≔Hδ¿∧⁼ⅈκ⁼ⅉι≔Rδ«≔Iζδδ≦⊕ζ»Jκιδ»»J¹¦¹UOLθ⊖Lυ
Try it online! Link is to verbose version of code. Takes input as a list of newline-terminated strings. Explanation:
≔⁺⁺ψ⭆θ ψη⊞υη
Create a header row.
WS⊞υ⪫ ι
Read the grid and pad the sides.
υη
Output the grid and a footer.
≔⁰ζ
Start with no rays.
F⊕LυFLη«
Loop over all of the squares.
Jκι¿⁼ KK«
Is this an entry point?
≔⁻⁶⊗⌕KVωδ
Work out which direction the ray leaves this entry point.
M✳δ
Move onto the grid.
W⁼KK.«
Repeat while the current cell is empty.
≔⊗E²№KD²✳⁺δ⁺²×⁴μOε
Check the neighbours for Os.
≧⁺⊗⌈εδ
If there are any then reverse direction so that the next move takes a step back. (This also handles the case of an O at the edge of the grid.)
M✳δ
Take one step.
≧⁻↨ε±¹δ
Adjust the direction if there was only one adjacent O.
»≡KKO≔Hδ
Did we hit an atom?
¿∧⁼ⅈκ⁼ⅉι≔Rδ
Were we reflected?
«≔Iζδδ≦⊕ζ»
Otherwise, output the next ray number at the exit point we just reached.
Jκιδ
Output the result of the ray at its entry point.
»»J¹¦¹UOLθ⊖Lυ
Clear out the grid.