Mars Rovers VII: The Grid Viz Design

This is part of the Mars Rovers series.

Have you solved The Grid Viz Problem yourself?
Spoilers no longer an issue?
Satisfied with your solution(s)?

Good! So I can now show you what I did.

The Design

I created The Grid Viz Problem based only on how I wanted to visualize it. How to solve it was a problem for you, and for future-me, neither of which had anything to do with problem-designing–me.

But soon enough future-me became present-me — and then had a problem to solve.

The Grid

How can we represent and modify such rover-populated grid?

It helps to think of its smallest unit. Since there can be no rover-movement representation in 0×0, the smallest would be the 1×1:

Empty

·   ·

·   ·

Rovered

·───E
│
1   ·

Although this is a 1×1 grid, we see that there’re 2×2 dots.
And although there’re 2×2 dots, there’re 3×3 places to put stuff on:

        • · •
• •  →  · · ·
• •     • · •

So we have:

  • The 4 corners. These can be either:
    • Grid points (:p)
    • Rover number (say, “1”)
    • Rover heading (one of :N, :E, :S, :W).
  • The middle. This could in theory be modified; but in our problem here, it’s constant (:m) and blank.
  • The 4 sides:
    • 2 verticals: either blank (:v) or a vertical rover track (:V).
    • 2 horizontals: either blank (:z) or a horizontal rover track (:Z).

Each of these keywords would point to a specific string for final display. In the exact form stated by the problem, these ones:

:p → "·"
:V → "│"
:v → " "
:Z → "───"
:z → "   "
:m → "   "

Yet note that these are an incidental implementation of the general abstraction. Like color schemes, we could change them with whatever we want, and the underlying representation would remain the same.

(A possible additional restriction: for it to look good for you and me in a monospaced display, the widths of variables in the same column should match. Likewise the heights of those in the same row, since these variables’ values could have a \n, thereby increasing row height.)

So our empty 1×1 is this:

:p :z :p
:v :m :v
:p :z :p

And the rovered one from above is this:

:p  :Z :E
:V  :m :v
"1" :z :p

(Numbers could, in theory, also be customized — but, to simplify, I won’t: they’ll be just “1”..“9”.)

But how do we map this spatial arrangement to code?

The Mapping

Since the midpoints are of interest, we could stretch the xy representation of the grid:
(x,y) → (2x,2y)

Now every unit in either axis is a “slot”. Predictably:

y odd :v :V :m
y even :p [NESW] [1-9] :z :Z
  x even y odd

So depending on the x,y combination:

even,odd
a vertical (empty or not),
odd,even
a horizontal (empty or not),
odd,odd
an always-empty middle, or
even,even
a grid point (which could be replaced by either a heading or a rover number).

This looks a lot like a matrix now, doesn’t it?
Or a list of lists (lol).
Or a vector of vectors (vov).
Or a seq of seqs (sos).
Or rows and columns in a spreadsheet.
Same thing.

So we could map the grid onto one of these — but not directly, because while we get our grid’s xy coordinates by going right and then up, we get our Lisp’s vov’s coordinates by going down and then right. Which means that if we use the (now doubled) coordinates for plugging things into a vov, things will look clockwise-rotated by 90°:

 y                 0 1 2 y
2|  •1,2       0 [[_ _ _]
1|         ↔   1  [_ _ •]]
0|_ _ x        x
  0 1

This means we could use the doubled values directly, and then, at the end, rotate it 90° counterclockwise to match the grid’s visual positions:

(vov-counterclockwise '[[a b c]  ; 'f = (1,2) ↔ (-> it (nth 1) (nth 2))
                        [d e f]])         |
                     y   ,----------------+
=> '[[c f]    ;     2|c f
     [b e]    ;  ↔  1|b e
     [a d]]   ;     0|a d _x
;;                    0 1

at which point it’d be a simple matter of map-reducing each vector to string and then joining them with newlines.

The Filling

So now we’d need to find ways to:

  1. create a vector of vectors (vov) representing an empty grid
  2. collect rover-induced modifications (its number, start point, end point, end heading, and segments from path)
  3. translate these modifications into vov coordinates
  4. merge these into the empty one
  5. replace these keywords with display strings
  6. counterclockwise-rotate it
  7. and merge it into a final string

Briefly, these would be, respectively:

  1. a function of the given maximum coordinates, interlacing the odds and evens as shown above
  2. we already have a function for all maps of a rover, so from these come the points, whose midpoints define horizontal and vertical segments
  3. just need to double them and check whether they’re odd,even (horizontal) or even,odd (vertical)
  4. simple-enough map merging: coordinates as keys (some vector: [x y]) and modification keywords (e.g., :V) as values, showing where the modification happened
  5. simple map lookup
  6. map across indices
  7. reduce twice

All these would be mapped over each rover’s initial map.

The Separations

At the end, rover grids must be wrapped and interposed with the same separator. Its length depends on the given maximum x coordinate.

So it makes sense to start with each rover’s initial map (parsed from input string) and keep mapping over them until we get to each rover’s grid string — and then reduce that by wrapping and interposing separators.

See next

As with the original problem, my first solution was in Clojure.

Mars Rovers VIII: The Grid Viz Solutions — Clojure

📆 2026-W16-7📆 2026-04-19