In Progress
Unit 1, Lesson 21
In Progress

Transpose

Video transcript & code

In the previous episode, we were generating a graph representation of a grid of cells, in order to experiment with maze generation algorithms. We used the #each_cons and #flat_map methods to help us convert an array of grid rows into a list of two-element graph edges. Each edge represents the wall between two cells on the same row of the board. We're calling these the "longitudinal walls".

require "./board"

BOARD
# => [[a, b, c, d, e],
#     [f, g, h, i, j],
#     [k, l, m, n, o],
#     [p, q, r, s, t],
#     [u, v, w, x, y]]

longitude_walls = BOARD.flat_map{|row| row.each_cons(2).to_a}.to_a
# => [[a, b],
#     [b, c],
#     [c, d],
#     [d, e],
#     [f, g],
#     [g, h],
#     [h, i],
#     [i, j],
#     [k, l],
#     [l, m],
#     [m, n],
#     [n, o],
#     [p, q],
#     [q, r],
#     [r, s],
#     [s, t],
#     [u, v],
#     [v, w],
#     [w, x],
#     [x, y]]

But we're supposed to be representing a grid here. And in a grid, cells have walls connecting them to other cells both to the east and west, and to the north and south.

We have an elegant and effective means for generating the edges for the east/west rows. But for the vertical rows, it seems like we need a completely different technique.

Or maybe not. What if we could just turn the whole array on its side, and then generate latitudinal edges the same way we generated longitudinal ones?

It turns out that we can. Ruby arrays have a method called #transpose which exists for precisely this purpose. When we send the #transpose message, we get back a new array of arrays. Where we once had horizontal rows, we now have vertical columns. And where we once had columns, we now have rows.

require "./board"

BOARD
# => [[a, b, c, d, e],
#     [f, g, h, i, j],
#     [k, l, m, n, o],
#     [p, q, r, s, t],
#     [u, v, w, x, y]]

BOARD.transpose
# => [[a, f, k, p, u],
#     [b, g, l, q, v],
#     [c, h, m, r, w],
#     [d, i, n, s, x],
#     [e, j, o, t, y]]

Now that we have this transposed board, we can simply apply the same edge-generation algorithm we used before.

require "./board"

latitude_walls = BOARD.transpose.flat_map{|row| row.each_cons(2).to_a}.to_a
# => [[a, f],
#     [f, k],
#     [k, p],
#     [p, u],
#     [b, g],
#     [g, l],
#     [l, q],
#     [q, v],
#     [c, h],
#     [h, m],
#     [m, r],
#     [r, w],
#     [d, i],
#     [i, n],
#     [n, s],
#     [s, x],
#     [e, j],
#     [j, o],
#     [o, t],
#     [t, y]]

We now have a set of latitudinal walls which we can combine with our longitudinal rows to have a complete set of potential cell connections. And we've accomplished it in just a few lines of code. Happy hacking!

Responses