A query that lands on the start of a word or path segment feels like a much better hit than one landing mid-word. Today you reward matches that fall on a boundary.
Add a bonus for a matched character that begins a word - the character right after a separator.
Where a match sits within a word matters as much as how tight it is. Typing main and landing on the m that begins the main segment of src/main.go is a far better hit than landing on an m in the middle of some word. A boundary is the position right after a separator - a space, slash, underscore, hyphen, or dot - the spots where a new word or path segment starts. A matched character on a boundary earns +8.
This bonus stacks with everything from the earlier lessons; it is added per matched position, independent of the gap logic. One deliberate choice: index 0 is not treated as a boundary here - a match at the very start already benefits from a zero leading gap, so rewarding it again would double-count. Keeping start-of-string out of the boundary rule is what lets the earlier leading-gap lesson and this one compose cleanly, each owning its own effect.
// A boundary is a matched char preceded by a separator. Add the bonus// for every matched position that qualifies, regardless of gap.const scoreBoundary = 8func isBoundary(candidate string, p int) bool {if p == 0 { return false } // start-of-string handled by leading gapreturn isSeparator(candidate[p-1]) // space / _ - .}// after adding the per-char reward, for every k:if isBoundary(candidate, p) { s += scoreBoundary }