#385 placeScarecrows
Using Haskell to place scarecrows in a field; cassidoo’s interview question of the week (2025-10-27).
Notes
The interview question of the week (2025-10-27) call for some evaluation across neighboring elements in an array:
Given a field represented as an array of 0s and 1s, where 1 means that position needs protection, you can place a scarecrow at any index, and each scarecrow protects up to k consecutive positions centered around itself (for example, for k = 3, a scarecrow at i protects i-1, i, and i+1). Return the minimum set of indices where scarecrows should be placed so that all the positions with 1 are protected. You can assume k is an odd number (or make up what happens if it’s even).
Examples: let field = [1, 1, 0, 1, 1, 0, 1]; let k = 3; placeScarecrows(field, k); > [1, 4, 6] placeScarecrows([1, 0, 1, 1, 0, 1], k) > [1, 4] placeScarecrows([1, 1, 1, 1, 1], 1) > [0, 1, 2, 3, 4]
Thinking About the Problem
Scarecrows need to cover all unprotected parts of the field, so intuitively it seems that we could just scan the field in a single direction (say, left to right). Every time we encounter an unprotected cell, we just place a scarecrow as far to the right as possible, and continue scanning beyond the scarecrow’s coverage.
I can’t see any obvious ways to improve the technique. Let’s give it a go!
An Initial Implementation
I’m going to try some Haskell this week.
The base algorithm:
placeScarecrowstakes field (array of int) and k (int)- uses a recursive worker
go- if empty, return empty
- if the current position is already covered, skip it and continue with the rest of the field.
- if this position doesn’t need protection, skip it and move one step right.
- if the position needs protection, place the scarecrow and skip forward to the next uncovered position
placeScarecrows :: [Int] -> Int -> [Int]
placeScarecrows field k = go 0 indexed
where
n = length field
half = k `div` 2
indexed = zip [0..] field
go _ [] = []
go i xs@((j, val):rest)
| j < i = go i rest
| val == 0 = go (j + 1) rest
| otherwise =
let place = min (n - 1) (j + half)
right = min (n - 1) (place + half)
in place : go (right + 1) rest
Let’s test it with the given examples:
$ runhaskell scarecrows.hs "1 1 0 1 1 0 1" 3
Scarecrows: [1,4,6]
$ runhaskell scarecrows.hs "1 0 1 1 0 1" 3
Scarecrows: [1,4]
$ runhaskell scarecrows.hs "1 1 1 1 1" 1
Scarecrows: [0,1,2,3,4]
All OK!
Compiling to an Executable
Let’s compile to an executable:
$ ghc scarecrows.hs
[1 of 2] Compiling Main ( scarecrows.hs, scarecrows.o ) [Missing object file]
[2 of 2] Linking scarecrows
Can now use the executable scarecrows:
$ ./scarecrows "0 1 0 1 1 0" 3
Scarecrows: [2,5]
Example Code
Final code is in scarecrows.hs:
import System.Environment (getArgs)
-- solver
placeScarecrows :: [Int] -> Int -> [Int]
placeScarecrows field k = go 0 indexed
where
n = length field
half = k `div` 2
indexed = zip [0..] field
go _ [] = []
go i xs@((j, val):rest)
| j < i = go i rest
| val == 0 = go (j + 1) rest
| otherwise =
let place = min (n - 1) (j + half)
right = min (n - 1) (place + half)
in place : go (right + 1) rest
-- main program
main :: IO ()
main = do
args <- getArgs
case args of
[fieldStr, kStr] -> do
let field = map read (words fieldStr) :: [Int]
k = read kStr :: Int
result = placeScarecrows field k
putStrLn $ "Scarecrows: " ++ show result
_ -> putStrLn "Usage: runhaskell scarecrows.hs \"0 1 0 1 1 0\" 3"