The .flow file format
The plain-text format the solver opens and exports, with the exact rules the browser checks and the extensions the Python toolkit adds.
A .flow file is a plain-text drawing of a board, one character per cell. The browser solver opens and exports it, every puzzle page offers one for download, and the project's Python toolkit reads an extended version.
A first example
# type: square
# fill: true
...A.
.B.C.
..D..
.B.AD
.C...
This 5 × 5 board has four colors. The first two lines are directives, and the other five are the rows from top to bottom. Blue (A) has its dots at row 1, column 4 and row 4, column 4.
Cells
| Character | Meaning |
|---|---|
A to Z |
A dot. Each letter must appear exactly twice, once for each end of its path. |
. |
An empty cell that a path can pass through. |
# |
A hole. The cell isn't part of the board, and no path can enter it. |
Letters are labels. The solver gives each letter a fixed color, starting with A Blue, B Orange, C Green, D Red and E Purple. Any letters in any order work, up to 26 colors.
Every row must be the same length, and the board can be rectangular. The browser takes 2 to 20 rows and 2 to 20 columns. Blank lines and spaces at either end of a line are ignored. The browser doesn't allow spaces inside a row.
Directive lines
A line of the form # key: value is a directive. The key is letters, digits, underscores or hyphens, followed directly by a colon. The browser solver understands two keys.
typegives the board geometry. The browser accepts onlysquare, which covers rectangular boards too.fillistruewhen every cell must be filled andfalsewhen cells may stay empty. The default istrue.
The browser ignores any other key, so # title: My board is fine. It refuses walls, warps, edge_overrides and core, which describe features it doesn't have.
A line is a directive only when a key and a colon follow the #. #A..# has no colon, so it is a row whose first and last cells are holes.
Comments
The browser has no free-text comments. A line such as # made on the train has no key and colon, so it is read as a row and rejected. Write notes as a directive with an unused key, such as # note: made on the train. That works in both tools.
How the browser checks a file
When you open a file or tap Apply in Edit as text, the solver checks these rules. Each is followed by the message shown when it fails.
- The file is smaller than 10 KB (opening files only). Puzzle files must be smaller than 10 KB.
type, if present, issquare. The local prototype supports square boards only.fill, if present, istrueorfalse. Fill must be true or false.- No
walls,warps,edge_overridesorcoredirective. The local prototype does not support walls. (with the key's name) - Every other non-blank line contains only
A–Z,.and#. Use A–Z for endpoints, . for empty cells, and # for holes. Bridges and graph JSON are not supported yet. - The board is between 2 × 2 and 20 × 20. Use a board between 2 × 2 and 20 × 20.
- All rows are the same length. Every board row must have the same length.
- There is at least one letter. Add at least one endpoint pair.
- Every letter appears exactly twice. B has 3 endpoints; each letter needs exactly two. (with the letter and count)
A file that fails only rule 3, 8 or 9 still opens in the editor, so you can fix it there. Colors with the wrong number of dots are circled, and Solve puzzle stays disabled until the board passes every rule.
Files from puzzle pages
The Download .flow button on each puzzle page gives you a file shaped like this:
# type: square
# fill: true
# title: Puzzle name
# source: https://flowpuzzlesolver.net/puzzles/1-puzzle-name/
...A.
.B.C.
..D..
.B.AD
.C...
The title and source lines record where the file came from. The browser ignores them as unknown directives, and the Python toolkit keeps them as metadata. Files exported from the solver normally hold just the type and fill lines and the rows.
Board links
The Solve it in the solver button on a puzzle page puts the board in the address, as /solve/?board= followed by the rows joined with hyphens. A 3 × 3 board with a hole in the center reads /solve/?board=A.B-.%23.-A.B, because a web address writes # as %23. The link holds 2 to 20 rows of 2 to 20 cells, at most 1,000 characters, and no directives, so the board must be filled. Once the board is open, the solver removes it from the address, so a reload doesn't bring it back.
Extensions in the Python toolkit
The Python toolkit reads .flow files with from_flow_text in flow_solver/puzzle.py. It accepts everything above and adds the extensions below, none of which open in the browser solver.
Whitespace-separated tokens. If a row contains spaces, the toolkit splits it on whitespace instead of reading one character per cell. A . B and A.B describe the same row.
Bridges. A + is a bridge cell. One path can cross it from left to right while another crosses from top to bottom, and the two don't connect. Neither path can turn inside the bridge.
# type: square
# fill: true
. . A . .
. . . . .
B . + . B
. . . . .
. . A . .
Hexagonal boards. With # type: hex, the 2nd, 4th and every other even row sit half a cell to the right, and each cell has up to six neighbors.
# type: hex
# fill: true
A . B
. . .
. A B
Circular boards. With # type: circle, each row is a ring, innermost first, and each column is a sector. Each ring wraps around, and each cell also connects to the same sector in the neighboring rings. # core: true adds a center cell joined to every cell of the innermost ring.
The toolkit is also more relaxed. A line starting with # and a space but no colon is a comment. fill treats 1, true, yes, y and on as true and anything else as false. Other directives become metadata. The toolkit doesn't read walls or warps from a .flow file. It describes those boards in its JSON format.
For a file that opens in both tools, follow the browser's rules. Use one character per cell, type: square, fill: true or false, and notes written as # note: ....