Ciphers

Route transposition

Text in a grid, read along a spiral, a snake or the columns. Decoding reads the path, so a grid copied off a puzzle page goes straight in.
IDroute20 / 55classical · transposition
Cipher / Transposition

Route Transposition

Rows in, a spiral or a snake out.

Keyspace
~20n
Decode
same options back
Works on
all but line breaks, moved
Family
3 in transposition
required 1 / 3

Options

widthnumber
required
Cells per row (2 or more)
cornerstring
default top-left
Corner the path starts from: top-left, top-right, bottom-left, bottom-right
pathstring
default spiral-clockwise
Path through the grid: spiral-clockwise, spiral-counterclockwise, snake-rows, snake-columns, columns

Access

Createcreate("route")
CLIciphers encode route 'ATTACK AT DAWN' --width 4
Tryplayground with the sample above
Kinrail-fence, columnar

Write the text into a grid, row by row. Then walk through it along some path and read what you pass. Nothing gets replaced, every letter just ends up somewhere else. The key is the shape. How wide is the grid, where do you start, which way do you walk?

Which way is decode?

Here it's the one that reads the path. Wikipedia and dCode do it the other way round. There the plaintext fills the rows and the ciphertext is the walk. So why flip it?

Because of how puzzles hand you the grid. You get a picture or a block of rows. The message shows up only once you walk it. That's decoding from where you're sitting. So decode lays the text out in rows and reads the path. encode writes along the path and gives you the rows back.

ts
const route = create("route");
route.decode("ABCDEFGHIJKL", { width: 4 }).text; // "ABCDHLKJIEFG"
route.encode("ABCDHLKJIEFG", { width: 4 }).text; // "ABCDEFGHIJKL"

That's this grid, read clockwise from the top left.

text
A B C D
E F G H
I J K L

The paths

width is the number of cells in a row. It's the one option you have to give. corner picks where the walk starts: top-left (default), top-right, bottom-left or bottom-right. path picks the walk.

pathFrom the top left of the grid above
spiral-clockwise (default)ABCDHLKJIEFG
spiral-counterclockwiseAEIJKLHDCBFG
snake-rowsABCDHGFEIJKL
snake-columnsAEIJFBCGKLHD
columnsAEIBFJCGKDHL

A spiral turns inward until it runs out of cells. From another corner it starts along the edge its direction points to. Clockwise from the top right goes down first. So does counterclockwise from the top left. Columns and snakes start along the column under their corner, snake-rows along the row.

The GSMG.IO opening

The GSMG.IO puzzle opens with a 14 by 14 grid of colored squares. Black and blue are 1, white and yellow are 0. Copy it row by row, then walk it counterclockwise from the top left. Down the left column first.

ts
const grid = "0011010010110011110011101011110111010010010110100001..."; // all 196 cells
route.decode(grid, { width: 14, path: "spiral-counterclockwise" }).text;
// "01100111011100110110110101100111..." as 8-bit ASCII is "gsmg.io/theseedisplanted"

The first 192 bits say gsmg.io/theseedisplanted. The last four are leftovers. Nice opening, right?

Cells

Every character is a cell, spaces and punctuation too. Line breaks aren't, they only lay the grid out. Paste the grid one row per line, it reads the same as one long string.

A short last row just ends in empty cells, and every path skips them. decode(encode(x)) is x for any length. stripNonAlpha and preserveCase work as in every classical cipher. But stripNonAlpha throws digits out too. Leave it off for a grid of bits.

Checked against

The Wikipedia route cipher example. Its grid, read clockwise from the top right, gives EJXCTEDECDAEWRIORFEONALEVSE. And the GSMG.IO opening grid above, which gives the puzzle's first URL. Every path from every corner is pinned on the 3 by 4 grid, both ways.

Errors

No width is a MissingOptionError. A width below 2 or not a whole number is an InvalidOptionError. So is a corner or path that isn't on the lists above.