[Question]
  [
Imagine you have a grid where some squares are walls, some are empty, and some are lights that shine for arbitrary distances in the four cardinal directions until they meet walls:
```
####.####
##..L....
####.##.#
####.##L.
##......L
```
In the above grid, the lights cover all the tiles. But in some cases, they may not be:
```
###
.#L
###
```
Your challenge is, given a grid like the one above, determine whether all empty tiles are lit up. You may take input as a matrix of characters or integers, a list of lines, newline-separated lines (as above) with any three distinct characters, etc.
An input may contain none of a type of cell.
You may output truthy and falsy with any of the following:
* Values your language considers truthy or falsy (if applicable), or inverted
* One truthy value and everything else is falsy, or vice versa
* Two consistent values representing truthy and falsy
# Testcases (Given in above format)
Truthy:
```
L
L.
.L
L....
..#L.
....L
.L...
#
L...L...L
#####.###
#L...L...
##.####L.
#.L..####
```
Falsey:
```
.
.#
L#.
.#.
.L.
.#.
L...
L...
L.#.
L...
L.
..
```
  
[Answer]
# [Vyxal](https://github.com/Vyxal/Vyxal), ~~29~~ ~~27~~ ~~25~~ 23 bytes
```
2(⌈ƛƛ:×c[¶1V];Ṅ;∩vṅ)∑¶↔
```
Split on wall, check if any spilt contain light, replace it with 1, transpose, do it again, check sum.
outputs empty string for false, dots otherwise.
-2 by @lyxal (pog)
-2 by @lyxal again (1 minute after first one)
-2 by ... yep still @lyxal
[Try it Online!](https://vyxal.pythonanywhere.com/#WyIiLCIiLCIyKOKMiMabxps6w5djW8K2MVZdO+G5hDviiKl24bmFKeKIkcK24oaUIiwiIiwiWycgICAgIFxcbiAgICcsICcgKlxcblxcblxcbipcXG5cXG5cXG4nLCAnICBcXG4gICAgKlxcbicsICcgXFxuKlxcblxcbiAgICAnXSJd)
[translate the input](https://vyxal.pythonanywhere.com/#WyIiLCIiLCLilqHGm1xcI1xcIFZcXExcXCpWXFwuwrZWO2Z3XFwlJCUiLCIiLCIjIyMjIy4jIyNcbiNMLi4uTC4uLlxuIyMuIyMjI0wuXG4jLkwuLiMjIyMiXQ==)
[Answer]
# JavaScript (ES6), 112 bytes
Expects a matrix with \$0\$ for walls, \$3\$ for lights and \$4\$ for empty squares. Returns *false* if the lights cover all the tiles, or *true* otherwise.
```
f=m=>m<(m=m.map((r,y)=>r.map((v,x)=>v&&[1,2,1,2].map((b,d)=>v|=(m[y+--d%2]||0)[x+~-d%2]&b)|v)))?f(m):/4/.test(m)
```
[Try it online!](https://tio.run/##RY7BbsIwDIbveYqIaDQWxTDGqVvYaTv1xrFwKG3KOjUtS7IKRNmrd0krhCXH///FTvydtqnJdHmy87rJZd8XQomNeuNKKFTpiXMdXkBs9Gja8OxMO50mz@EqdLkf@SHMPe8EV8llNp/nT6t91y0hOc/@BjM9QNcCwHvBFUSL9QKtNNbpXsuf31JLHhQmANQyzT/LSm4vdcaXgLbZWl3WRw5oTlVp@WRX7@oJYNHojzT74oaKDb0SSitpqaKCmkeja/Pbad@SIKIet82859cAg2gd0iAOohdXWBAtb5Bke4BX91zW1KapJFbNkfudHbxBHxMSI8GhuCCIzHsXsaOeEDbeDemcD3RJ2J2SEfhB5oHXhLhJ9KNsEP4PHOrw2P1go/oH "JavaScript (Node.js) – Try It Online")
[Answer]
# [JavaScript (Node.js)](https://nodejs.org), 89 bytes
```
f=(a,n=4)=>n?f(a[0].map((_,x)=>a.map(c=>(t=c.at(~x))>1?p=t:t|p>>2,p=0)),n-1):!/0/.test(a)
```
[Try it online!](https://tio.run/##VZHBbtswDEDP1Vew9cES6ipu0VMyudhhtwzbPSlW1ZESFw5tyHTXIMl@PaXsdFsJyCQfSVMiX@yr7cpQtXSDzcqdfjy/uJL0yvkK3c/QtC7QTn4Nwe50GxpqaNe6DK4sXWWwh1db924KvseSqgbBkkQFe3GBYOC7pY2mwLEIDwfIZ@Ki8iARvkCuAOHaAG2qTtcO17T5PxrTEYpPcQXBUR8Qehzvt@KKM4ppC3yciWMGv0NF9rnme3FzvqzDfuvCSLytO0Zlg75a9@FfGhzVTAhvTt5Im6G5V6bABy/tIn/UW9tK@St7Y2YHpzSFJFNqfu@fN6WK24fW0JQObVHcZa3Jlcrw5lZNLyf5RJPrSFp1irq0net4Nk9iLsRcCz0oFqF1En2WOdNIRDLGhsNeFM1HJB9UjCAWJhFEWwiu1LE0GYzYQw96@NnHJzlbT7yhaiuV7tq6IjlZ4hKvJ2p4JYEpgM6RdInpiEPECy4O42Qw@nIPqU6nkGeQzlnfs05Y38GR96JYeLx/J6B9E77ZcjO24G10Te103ayllxRzT@8 "JavaScript (Node.js) – Try It Online")
Input matrix where 0 = empty, 2 = wall, 4 = light. Output true vs. false.
Rotate the matrix 90deg 4 times, fill empty cell if there is a light on its left side. Finally test if there are any empty cell left.
This function use ES2022 feature `Array#at` which requires a newer version of NodeJs than current TIO available. A Polyfill for `Array#at` is included in the header of TIO code. So it may be tested on it. You may execute it on a more recent version NodeJs without the header.
```
f=
  (a, // input matrix
  n=4 // rotate 4 times
)=>n?
f(
a[0].map((_,x)=>a.map(c=>(t=c.at(~x)) // rotate
/* t */>1?p=t:t|p>>2,p=0) // fill empty cell if there is a light left side
),n-1):
!/0/.test(a) // no empty cells left
```
---
# [JavaScript (Node.js)](https://nodejs.org), 95 bytes
```
a=>w=>a.every((c,i)=>c|[-2,-1,1,2].some(s=>a.some(_=>t=a[j+=s%2?(j%w-~s)%-~w&&s:s*w/2],j=i)&t))
```
[Try it online!](https://tio.run/##PVDLboMwELz7KyyhBLsxS@CYyPTUG1I/gKDGIiYFJSbCVmjVNr9O107TlXZndvZluVdXZZuxu7jEDAc9t3JWsphkoUBf9fjJWCM6Lovmu0pykWQiE3kNdjhrZn1TYG@ycFJV/UraRf7M@sWU3CxfJLdpubQb@zSleS162fGl43x22rpGWW2ppHtSElICgQBoBCDyOVqJqldIdK8Fx8wboJPooZK74AcjL3hOCE6CH40C8TcgYFj2CNEf24MbuzPjYC@nzrF0Z3ZmlXI4qwtzVBa0cshd887SCl9Yp8d7zfga@6IxxBu6FjQuETPECDGnP5WpORfUQWcO@uO1ZfHOxLzmW0L@/wHaYXxRuDocagZjh5OG03BkLXPVuuYYM1zDt/Mv "JavaScript (Node.js) – Try It Online")
Input flatten matrix with 0 = empty, 1 = light, 2 = wall, and its width. Output true vs. false.
```
a=> // the matrix; 0 = empty, 1 = light, 2 = wall
w=> // width of matrix
a.every(   // if every cell is
  (c,i)=>c| // either cell is not empty
  // or cell is lighted
  [-2,-1,1,2] // four directions; up, left, right, down
  .some(s=>   // any direction that
    a.some(_=>  // repeat enough times (we use `a` only because it is long enough)
      t=a[ // repeat move until current cell is non empty
        j+=s%2? // -2, 2 are left / right, while -1, 1 are up / down
          (j%w-~s)%-~w&&s: // if we reached end of current row, stop move
          s*w/2 // move up or down (may out of bound but we don't care)
      ],
      j=i // starting from cell `i`
    )&t // if non-empty cell exists and the cell is light
  )
)
```
[Answer]
# JavaScript (ES6), 254 bytes
```
d=>!(f=i=>i?f(i-1,d=d.replace(/(?<=a|b)[ c]|[ c](?=a|b)/g,x=>"ab"[+ 
(x<"!")]),d=(t=s=>[...s.split`
`[0]].map((_,i)=>s.split`
`.map(x=>x[i]).join``).join`
`)(t(d).replace(/(?<=a|c)[ b]|[ b](?=a|c)/g,x=>"ac"[+(x<"!")]))):d) 
(d.length+d[0].length).includes` `
```
Uses  for empty spaces, `a` for lights, and any non-alphabetical and non-space character for walls.
[Answer]
# [C (gcc)](https://gcc.gnu.org/), ~~274~~ \$\cdots\$ ~~195~~ 191 bytes
```
#define F for(y=0,i=r*c;i--;
#define J(A,B,C,D)for(y=A c;--y+B&&~-m[C*c+D];)m[C*c+D]|=m[i]*2&4;
i;y;f(m,r,c)int*m;{F){J(-i%,c,i/c,-y)J(i%,1,i/c,y)J(-i/,r,-y,i%c)J(i/,1,y,i%c)}F)y|=!m[i];i=y;}
```
[Try it online!](https://tio.run/##bZTdjtowEIXveYppViAn2CUE9gK5qbTLlgvUNwBUoYmzNS0BJalKyqaPXurEcf7YyBCPz2fPmUkUZK@It9tDIEIZCVhBeIpJ5rtU@rGDXDLGB0Zckyf6TJf0xdbQEyBnLBs/j0Z/2XGzdHD8suO2mb35x43cOd5ozgeSZzwkRxpTtGWUOkd@XdnXNWFySJHKCVKW2WuiomkZFQGTE8WzjMohFtpEaTrIV3b25n8ojufSz3h@U2fCcS8jYsN1AOoqFlKRpNPNDny4TinUw23Np7ReU8Mzk3K8u8dt9vQUr9nj3g0v5x1bXteWW51QxT14pmG3tzy/L61b3bRbkdcvrduIuoA22ui95N9inf2RwqwE5n0ANbAwwKIBnJJINFA@Jaq7om8zfWufKC5ngakIqk7UxVYInqIkBfy@jx31L/CHqOxZ28sXb3tZLNXv0aLQjmdWtVu9zUCKLDIKxEVtc3k1/QSJ/CNOITH57Um14NQrHMbjkjavXlOkOkoXWuo73pYhrlTVyfdkNDLeyY3fyqvyGZc22hY65EGTB0ViQR76pEkbFGk30kEYw6GV01znWFEhsYZYdPPjw1drE@zsLpd3ovOvNCGW1WLyTqGJyhiStPw0dFsglFI/@H4TjBFgn2EYwDDZRspRQuvnn/i@aDvTPvz6Mo7yQX77h@HP/WtyY7//Aw "C (gcc) – Try It Online")
*Saved a whopping ~~45~~ \$\cdots\$ ~~55~~ 59 bytes and got below 200 thanks to [ceilingcat](https://codegolf.stackexchange.com/users/52904/ceilingcat)!!!*
Inputs a pointer to an array of integers along with the room dimensions (since pointers in C carry no length info).  
These integers represent a room with \$0\$ -> `.`, \$1\$ -> `#`, and \$2\$ -> `L`.  
Returns \$0\$ if the room is lit up or \$1\$ otherwise.
[Answer]
# [Jelly](https://github.com/DennisMitchell/jellylanguage), 19 bytes
```
,Z»×¥@\Ṛ$2¡€Z»¥/F’Ạ
```
[Try It Online!](https://jht.hyper-neutrino.xyz/tio#WyIiLCIsWsK7w5fCpUBcXOG5miQywqHigqxawrvCpS9G4oCZ4bqgIiwidOKAnMK24oCdxZPhuaPigJzCtsK24oCdwrXhu7RpQOKCrOKCrOKAnC5M4oCdw4fCteKCrCIsIiIsWyJcIlwiXCJcbkxcblxuTC5cbi5MXG5cbkwuLi4uXG4uLiNMLlxuLi4uLkxcbi5MLi4uXG5cbiNcblxuTC4uLkwuLi5MXG5cbiMjIyMjLiMjI1xuI0wuLi5MLi4uXG4jIy4jIyMjTC5cbiMuTC4uIyMjI1xuXG4uXG5cbi4jXG5cbkwjLlxuXG4uIy5cbi5MLlxuLiMuXG5cbkwuLi5cbkwuLi5cbkwuIy5cbkwuLi5cblwiXCJcIiJdXQ==)
"Borrowing" the multiplication idea from Unrelated String (i.e. stealing lol). 0 for `#`, 1 for `.`, 2 for `L`.
[Answer]
# [J](http://jsoftware.com/), 43 bytes
```
*-:g&.|:>.g=.**[:}:@;"1<@(#$2&e.);.2"1@,.&0
```
[Try it online!](https://tio.run/##fVDLCsIwELzvVyyNNKboUHtMrRQETzmJNw8i0vpAFHyBoN9eu1o9mS5MstmZzC67qwLokjPLmnscs63RB4@nblJFfbsO8bAjrDNE0dw@bZ4Gg2HeVZ0kLGBSJMEg7yGMK0O0Oh5uxemSgbWC0@EWKRYJUbHaHFnPTtfL5q6bZ8mNWlrGpBzI/KeclwChhayDADGW1NVaqZj/7X02SgI1ZEJ8LD4FMVZSkLxtijd@Aj1Z7s@@LXh3AH8H1fJJFoT33TLf91BNZqh6AQ "J – Try It Online")
Based on [okie's "split on walls and check if each section contains a light" idea](https://codegolf.stackexchange.com/a/239863/15469).
[Answer]
# [05AB1E (legacy)](https://github.com/Adriandmen/05AB1E/tree/fb4a2ce2bce6660e1a680a74dd61b72c945e6c3b), 21 [bytes](https://github.com/Adriandmen/05AB1E/wiki/Codepage)
```
3xŸvTyT+:yT*y∞:ζí}SßĀ
```
Input as a list of lines, where `.L#` are `012` respectively.
Uses the legacy version of 05AB1E where the `ζ` and `:` builtin works on list of strings, which would have been `€SζJ` and required a map over the lines in the new 05AB1E (ending up [6 bytes longer](https://tio.run/##yy9OTMpM/f/fuOLojrLK0HNbQyJCtK0iQrQiDu2yCq49t83r8Nra4MPzjzT8/x@tZGhgYKCkg6CM4LxYAA)).
[Try it online](https://tio.run/##MzBNTDJM/f/fuOLojrKQyhBtq8oQrcpHHfOszm07vLY2@PD8Iw3//0erGxoYGKjrKCDRRgh@LAA) or [verify all test cases](https://tio.run/##MzBNTDJM/V@mFFCUWlJSqVtQlJlXkpqikJlXUFpipaCkU6nDpeSYXFKamAMXs688tO3QwnNbHzUs0/NRNjA0etSwsPbQjtNzbP8bVxzdURZSGaJtVRmiVfmoY57VuW2H19YGH55/pOG/kn9pCdQEnUPb7P9HKykDgR6IiMkDMvR89IAAxASL6inDmT56EAUg4KOkowTECkogQQgPok1PD6wOrAYkA6SBkspQBT5QrcowO4EmwsTBhoPEwfaAhEAckB0gE/TARihDmGA7QQSYD9EMI5WhbLBCcjwWCwA).
**Explanation:**
```
3          # Push a 3
 x         # Double it (without popping): 6
  Ÿ        # Pop both and push a list in this range: [3,4,5,6]
   v       # Loop over each of these digits `y`:
        :  #  Replace all:
    T      #   "10"
     yT+   #   with "1y", where `y` is the current digit
           #  (which use the implicit input-list in the first iteration)
         : #  Then infinitely replace all:
    yT*    #   "y0"
       y∞  #   with "yy", where the `y` are again the current digit
    ζí     #  Then rotate once clockwise:
    ζ      #   Zip/transpose; swapping rows/columns
     í     #   Reverse each row
   }       # After the loop, we want to check if any empty spots remain:
    S      # Convert the list of strings to a flattened list of characters
     ß     # Pop and push its minimum
      Ā    # Check if this is NOT 0
           # (after which the result is output implicitly)
```
[Answer]
Brev, 159, no, 156 bytes:
```
(define (l row) (strse row "[g_]*L+[g_]*" (strse (m 0) "_" "g")))
(print (apply any (compose (strse? "_") l string) (map (o string->list l) (read-lines))))
```
Uses \_ instead of . (shaves four bytes) and prints #f for lit up, #t for dark.
Update: remove a redundant partial applicator
[Answer]
# [SnakeEx](http://www.brianmacintosh.com/snakeex/spec.html), 34 bytes
```
m:{d<>}{d<R>}{d<L>}{d<B>}
d:,+[#$]
```
Uses `,` instead of `.`; to take inputs formatted as in the question, replace `,` on the second line with `\.`. Outputs one or more matches (truthy) for a room that is not fully lit, no matches (falsey) for a room that is lit. [Try it here!](http://www.brianmacintosh.com/snakeex/)
### Explanation
Core idea: find a `,` which can't "see" an `L` in any of the four directions. If no such `,` exists, the room is fully lit; if such a `,` exists, it is not fully lit.
```
d:        Define a helper snake d to match
  ,+      1 or more commas
    [#$]  followed by a pound sign or the edge of the grid
m:                         Define the main snake m to match
  {d<>}                    d in the default direction (left-to-right)
       {d<R>}              and also in the direction 90 degrees clockwise (top-to-bottom)
             {d<L>}        and the direction 90 degrees counterclockwise (bottom-to-top)
                   {d<B>}  and the reverse direction (right-to-left)
```
[Answer]
## Txr Lisp, 109 bytes
```
(do let((l(op mapcar(op regsub #/[. ]*L[. ]*/(op regsub #/\./" ")))))(find #\.(cat-str[l(transpose[l @1])])))
```
## 103 bytes
```
(op find #\.(cat-str[#1=(op mapcar(op regsub #/[. ]*L[. ]*/(op regsub #/\./" ")))(transpose[#1# @1])]))
```
## 97 bytes
Drop `(cat-str X)`, use quasiliteral ``@x``.
```
(op find #\.`@[#1=(op mapcar(op regsub #/[. ]*L[. ]*/(op regsub #/\./" ")))(transpose[#1# @1])]`)
```
This is an expression that evaluate so to a function which operates on sequence of strings, those being the lines of the grid.
The function returns `#\.`, the dot character, to indicate that unlit areas remain. Otherwise it returns `nil`. A character is truthy, and `nil` is the only false value.
The logic is just regex. The `regsub` function matches regular expressions. If the replacement argument is a function, the matched text is passed to it and replaced with what the function returns. For the substitution we use another partially applied `regsub` which replaces dots with spaces.
So, in every string of dots or spaces that contains an `L`, we replace the dots with spaces, doing this in every string. Then we transpose the vector of strings and do it again.
Truthy example:
```
#####.###        #####.###        ####       ####
#L...L...  -->   #L   L      -->  #L#   -->  #L#
##.####L.        ##.####L         # .L       #  L
#.L..####        # L  ####        # #        # #
                                  # #        # #
                                  .L##        L##
                                  # ##       # ##
                                  # L#       # L#
                                  #  #       #  #
```
No dots remain, so everything is lit.
This main list-of-string processing action for replacing the `L`s is a function. In the 109 byte version, it bound to the lexical variable `l`, which we then refer to twice separated by a `transpose` call.
In the 103 byte version, we get rid of the local variable and just repeat the code in two places using the Lisp circle notation. `#1=OBJ` means "`OBJ`, also associated with label 1". And `#1#` then means "reproduce the object from label 1, `OBJ` here". With this we can make a piece of data (i.e. piece of source code, of code is data) appear in two or more places.
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), ~~17~~ 16 bytes
```
»×¥@\Ṛ$⁺
Ç€»ÇF1e
```
[Try it online!](https://tio.run/##NY4xDsIwDEV3H6NmrCzKCTox5QisHUAdWdgKSwZGBiRUJsTWkSKVbok4SHKRYLvUiuP/X2Inu6quDym50V/ds9yE4baIxw94G08dQ7suqrSPTevesbl/L2F4qFHr@jC@tiXflNW0BhmG8bzKl3nhresZp5RlGRgAQ0BaOIAIxXMYpkIApzNNdhLECThTmIA0ogDRANxJ0ooq5A3SqsPmDf9KhgH/5wc "Jelly – Try It Online")
*Fixed by borrowing back from hyper-neutrino lmao*
*-1 replacing the double transpose with a map by replacing the map with implicit vectorization*
Takes a matrix of 0 for `#`, 1 for `.`, and 2 for `L`.
```
»×¥@\Ṛ$⁺    Monadic helper link: light up all columns or a row
    \       Scan by
»  @        (vectorizing) max of right and
 ×¥         (vectorizing) product,
     Ṛ      then reverse.
      $⁺    Do it again.
Ç€»ÇF1e    Monadic main link: is there anything unlit?
Ç          Light up
 €         each row,
   Ç       light up the columns,
  »        and take the maximum at each position.
    F      Flatten the result.
     1e    Does it contain 1?
```
[Answer]
# [Charcoal](https://github.com/somebody1234/Charcoal), 47 bytes
```
ＷＳ⊞υιυＦＬυＦ⌕Ａ§υιLＦ⁴«ＪκιＭ✳⊗λＷ﹪℅ＫＫ³⁵✳⊗λ_»≔№ＫＡ.θ⎚¬θ
```
[Try it online!](https://tio.run/##bU/BTgMhED2XryDby5CsXNSTp00bkxqqm@jdrAvukiLTslBNjN@Ow7b15DsMw7w3j0c/dqHHzuX8OVpnOGz8PsXnGKwfQAjepmmEVHMr7lhLwwiJuncMHJTxQySSVPP93nrdOAdN3Hhtvk5bNa9UdVHcCP7NFg/pY/@CsDuZLrZ4NLC2wfTRooc1pjdnNDghCntOtUWdHMJT0NZ3DlpjdpSu5te3JeOc618Lev61Ip8f1kyTHTysMJG27JeohZcV1QNpVs50Af7@@YgRDpQh5yVBlsLolEoS2Hkml5dOyZktUCxfHd0v "Charcoal – Try It Online") Link is to verbose version of code. Takes input as a list of newline-terminated strings and outputs a Charcoal boolean, i.e. `-` if the room is fully lit, nothing if not. Explanation:
```
ＷＳ⊞υιυ
```
Input the map and print it to the canvas.
```
ＦＬυＦ⌕Ａ§υιLＦ⁴«
```
Loop over the lights in all directions.
```
ＪκιＭ✳⊗λ
```
Move to a tile adjacent to a light.
```
Ｗ﹪℅ＫＫ³⁵
```
While this tile is not wall, ...
```
✳⊗λ_
```
... mark it as lit and move to the next tile. (Note: If there are two lamps, they'll light each other, but the loop above checks the original lamps, so it doesn't matter that they get removed from the canvas.)
```
»≔№ＫＡ.θ
```
Count the number of remaining unlit tiles.
```
⎚¬θ
```
Clear the canvas and output the result.
[Answer]
# [Retina 0.8.2](https://github.com/m-ender/retina/wiki/The-Language/a950ad7d925ec9316e3e2fb2cf5d49fd15d23e3d), ~~94~~ 91 bytes
```
(?!_+L|((?<=(.)*)_.*¶(?<-2>.)*(?(2)^))+L)_(?<!L_+|L((?<=(?<!.)(?(4)$)(?<-4>.)*.).*¶(.)*_)+)
```
[Try it online!](https://tio.run/##NUu5DcJAEMyvC8sOdnzyBJZD4BrYEhArAgISAkTouiiAxo45GybYnfd5e90f13pmimqli@yrWTkcjRgRHD9vqWk@SVqxGRcgO0Jm55FX38tShPIFA1p/aX1im4sFMmrtBbaT9OkU0s9j/2fOLW3wLw "Retina 0.8.2 – Try It Online") Takes input using `_` as a floor tile instead of `.` but header converts `.` to `_` for you for convenience. Outputs the number of unlit floor tiles, so a falsy value if the room is lit. Explanation:
```
(?!_+L|
```
Don't match a floor tile that is to the left of a light, or...
```
((?<=(.)*)_.*¶(?<-2>.)*(?(2)^))+L)
```
... that is above a light.
```
_
```
Match an unlit floor tile.
```
(?<!L_+|
```
Don't match a floor tile that is to the right of a light, or...
```
L((?<=(?<!.)(?(4)$)(?<-4>.)*.).*¶(.)*_)+)
```
... that is below a light.
.NET balancing groups are used to ensure that the light is in the same column as the tile.
[Answer]
# Python3, 205 bytes:
```
import re
m=lambda x:re.sub('(?:\.+)*L(?:\.+)*',lambda j:'L'*len(j.group()),x)
f=lambda x:all(all(n!=('.','.')for n in zip(m(i),j)if n!=('#','#'))for i,j in zip(x,[*zip(*[m(''.join(c))for c in zip(*x)])]))
```
[Try it online!](https://tio.run/##hZBdTsQgEMef5RS4PDBUnBh9MU02XqDxArvG7AddaSgQ2k2ql6/QbWNiVhwyMGF@M/wZ/9l/OPv07MM46ta70NOgSLs2u3Z/3NGhDAq78x44vJRbvBNFtQRczkxT8ooXRllo8BTc2YMQchCk/mmyMwaS29s1cOQyuqhdoJZqS7@0hxa0kI3QNZ0QFhHGxcRo2SzUIDdFOotNC5xj47SFw4U6LEwxiLe4xHhUNe3d@ynoI3SiJDdB9edgqdFdD7U2vQrw6qyStMPOG90D39r4piDEB20jA0v5arVi0TBtJJ5YYTQy3yFbogqnbLIq1qRe11sRZFUq@hvK1MdXMJtO2hCTmkkJmeRm9OR7Vf/@5jIZwhaazKNK40gX7PdP@T0vHh@utsvoxJxQli1ME4uegybh88Yu0QyP3w)
[Answer]
# [Perl 5](https://www.perl.org/), 103 bytes
```
sub{$_=pop;while(!$h{$_}++){s/(Ll*)\./$1l/;$r=@l=();map/\s/?$r=0:$l[$r++]=~s/^/$_/,/./gs;$_="@l"}!/\./}
```
[Try it online!](https://tio.run/##dZDBbsIwDIbvfgpozNKuKIHDLoQM7qvGZTdgiEktoAWoGtCEUPfqnVNaiQKz1MT5fruJ/zTOzEuBiS7s8euMC53uU/Wz3pjYb@OaQB6GwdlKPzLPwUxI7BupMNNjo/1AbZepnFk5ItAboJliFoZz/Wvlp8SF7EohV1bRT72x8fK2pP68UADJPvOhRTEdDjnXr/15FyK4IwLEI0oBQjAnU0RU5MhtHXvYWX4A13UUwi2UXXRRM8HqLBKlKhrdPeoWzRNrHCN2K7uJRLk36tyd1cKqDIJz@f7tycdNF@NAj3GhKoQr/YQJCcGFpNlmd0i8jm117GznUbnWuBrx/Tcf8PfJR2vyxgmO@CE7HtYngsnS2PjEFeRQ0ESV1f96y@DaPVZ7BqymUJnojHKgNNS54ywpfWgM/2DiPw "Perl 5 – Try It Online")
[Answer]
# [C (gcc)](https://gcc.gnu.org/), ~~146~~ 141 bytes
```
#define F(d)for(i=r*c;i--;F&=m[i])for(j=i;m[i]>3&1u*j<r*c&m[j]<8&&j/c!=i/c^d*d;j+=d)m[j]|=1;
i;j;F;f(m,r,c)int*m;{F(1)F(-1)F(c)F=1;F(-c)i=F;}
```
[Try it online!](https://tio.run/##dVLbbuIwEH33VwxEBYfctX0omPQxT/wBTaWs7YDTJCAnEVp1@fVlxwl0gS0j2Z45c@Zij7m34fx0soTMVS0hocLOd5qqWM84U57HkklcrVXao0WsmDFef0yiblYskTOp1kW6fJlMioCPYhXwdzETrHBiYRvP7zhiRLGCJSynlatdbqu6nVXsM6GRnVDPbNxOkIYGOuOEHU9BACHIat/@Iqg@Q6k22xaaXae5NMgcDllZEkvVvOyEhGXTCrXzt68Ek0Mrm3Y9R0lZb1eZqqkNnwRQDKDj0AVltoL14GGrSgnY0Jl0IXKIYSNbvs00tV0Q7MvbHBTCgK1fhfCskeBFC9Cy7XQNIbt1TVfTxdCdcpwUcz8z@Kll9nHP8@944QOedcebP@C91dPFF2TEcTS7AcT1TW9dKgeK7hii8PqyFwmCvca3yun4ScCTeKvHOGV1l2MgDl8oZMUyCpnjFPZV5NjtL1KkNtt3bUPH429S/OObMjAa5dREuaBxnoG2H1bFYTM1VFXfVFXXVR@XP491@E@37iPIEl/6/@fpavOsVLhg/mh9H0ZutSM5nlaErHzi9wcK8X3L2CgrRA1CrMHXL7SM@LiIdUHJAJhAywBGJwQjfRNq9Yqp4fdnn@yyWWetbwKPPzwvs01z8g5/AQ "C (gcc) – Try It Online")
Thank ceilingcat for -3 bytes
Not quite sure what Noodle9 did, and not sure why I can't `F(1)(-1)...` here
]