Skip to content

Instantly share code, notes, and snippets.

@patrl
Created January 17, 2023 16:17
Show Gist options
  • Select an option

  • Save patrl/9f013f6ac3270d4fc75dfe9ef25e7df3 to your computer and use it in GitHub Desktop.

Select an option

Save patrl/9f013f6ac3270d4fc75dfe9ef25e7df3 to your computer and use it in GitHub Desktop.

Revisions

  1. patrl created this gist Jan 17, 2023.
    43 changes: 43 additions & 0 deletions shadowcast.hs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,43 @@
    computeQ :: TileMap -> Transform -> Slope -> Slope -> Int -> Visible ()
    computeQ m t s e y = do
    let xmin = roundTiesUp (fromIntegral y * s) -- compute the initial x coordinate bounded by the starting slope
    let xmax = roundTiesDown (fromIntegral y * e) -- compute the ending x coordinate bounded by the ending slope
    let xys = (coord . (,y)) <$> [xmin..xmax] -- create a list of coordinates to recurse through by pairing xs with the depth

    -- a helper function to recurse through a list of coordinates, and potentially create branching row computations
    -- the first argument is a Maybe Bool which tracks whether the previous coordinate was a wall
    -- Nothing indicates that there was no previous coordinate (we're at the beginning of the list)
    -- s indicates the starting slope; this can change as the recursion proceeds.
    -- xys indicates the list of coordinates
    go Nothing s xys where

    -----------------------------------------
    -- definition of row recursion follows --
    -----------------------------------------

    -- if the last tile in the row is visible, then continue onto the next row, otherwise break the recursion
    go final s' [] = unless (final == Just True) $ do
    computeQ m t s' e (y + 1)

    -- case 1: no previous tile.
    -- this indicates that we're at the beginning of a row recursion
    go Nothing s' (c:cs) = do
    let w = isWall m (t c) -- w is a boolean which indicates whether the current focus is a wall (and therefore invisible)
    when (w || isSymmetric s' e c) $ do -- when the current tile is a wall or symmetric...
    addToVis (t c) -- ...add the tranformed coordinate it to the visible coordinates
    go (Just w) s' cs -- now, recurse through the remainder of the wall, setting the Maybe Bool to depend on whether the focus is a wall

    -- case 2: there is a previous tile, whether it was a wall or not is indicated by w'
    go (Just w') s' (c:cs) = do
    let w = isWall m (t c) -- let w indicate the wallhood os te current focus
    when (w || isSymmetric s' e c) $ do -- when the current tile is a wall or symmetric...
    addToVis (t c) -- ...add the transformed coordinate to the visible coordinates
    if -- the next action depends on wallhood of the current and previous tiles
    | (w' && not w) -> -- if the previous tile is a wall, and the current tile isn't a wall...
    go (Just w) (slope c) cs -- continue the recursion through the row, but adjust the start slope to brush the prev tile
    | (not w' && w) -> do -- if the previous tile isn't a wall, but the current tile is a wall
    computeQ m t s' (slope c) (y + 1) -- start a new branching computation on the next row, with an adjusted end slope
    go (Just w) s' cs -- continue recursing through the row
    | otherwise ->
    go (Just w) s' cs -- in other circumstances, continue recursing through the row