Fork me on GitHub

Project Notes

#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:

  • placeScarecrows takes 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"

Credits and References

About LCK#385 Haskellcassidoo

This page is a web-friendly rendering of my project notes shared in the LittleCodingKata GitHub repository.

Project Source on GitHub Return to the LittleCodingKata Catalog
About LittleCodingKata

LittleCodingKata is my collection of programming exercises, research and code toys broadly spanning things that relate to programming and software development (languages, frameworks and tools).

These range from the trivial to the complex and serious. Many are inspired by existing work and I'll note credits and references where applicable. The focus is quite scattered, as I variously work on things new and important in the moment, or go back to revisit things from the past.

This is primarily a personal collection for my own edification and learning, but anyone who stumbles by is welcome to borrow, steal or reference the work here. And if you spot errors or issues I'd really appreciate some feedback - create an issue, send me an email or even send a pull-request.

Follow the Blog follow projects and notes as they are published in your favourite feed reader