greedy packing
Keep adding words until the next word won't fit. Count each word's length plus one mandatory space between words. When the total exceeds the line width, stop and format.
Book typography justified text long before computers existed. This algorithm packs as many words as possible onto each line, then distributes the remaining whitespace evenly across the gaps — leftmost gaps absorb any remainder. The final line stays left-aligned, exactly like a paragraph's closing sentence.
Every line follows exactly one of three spacing rules depending on its word count and position.
Keep adding words until the next word won't fit. Count each word's length plus one mandatory space between words. When the total exceeds the line width, stop and format.
An interior line has totalSpaces = maxWidth − letters to spread across its gaps. Divide evenly: base = totalSpaces ÷ gaps, remainder extra = totalSpaces mod gaps. The leftmost gaps each absorb one extra space.
The final line uses single spaces between words and pads the remaining width on the right — just like natural paragraph endings. A single-word line follows the same trailing-pad rule.
Two phases per line. One greedy scan, one formatting pass.
Starting from the current word, accumulate words onto the line. A word fits if letters + word.length + gapCount ≤ maxWidth. Stop when the next word would overflow.
If only one word occupies the line, or this is the last line, use left-justification with trailing padding. Otherwise, use full justification with distributed spaces.
For interior lines: compute base = (maxWidth − letters) ÷ gaps and extra = (maxWidth − letters) mod gaps. Place base + 1 spaces in the first extra gaps, base in the rest.
Append the formatted line to the output. Move the word pointer past the line's last word. Repeat until all words are consumed.
Three scenarios test whether you apply the right rule at the right time.
A word so long it fills the line alone. There are zero gaps — you cannot divide by zero. The word is left-justified with trailing spaces, exactly like a last line.
When totalSpaces mod gaps ≠ 0, the leftmost gaps absorb the extras. For "one··two·six·ten": 4 spaces across 3 gaps gives base 1, extra 1. The first gap gets 2 spaces, the rest get 1.
Even if there's room to distribute spaces evenly, the last line must use single spaces and pad the right. Treating it like an interior line would stretch words apart unnaturally.