Lesson 2
Analyzing 2D Matrix Traversals with Ruby
Introduction

Hello, aspiring Ruby programmer! Are you ready to journey into the world of matrices? Today, we will explore the realm of 2D matrices with a unique traversal order that promises excitement and intrigue. Fasten your seatbelt and let's dive in!

Task Statement

Imagine we have a 2D matrix where each cell contains a distinct symbol or integer. Our task is to decode this matrix by reading the cells in a particular pattern.

The decoding begins from the top-left cell of the matrix. We move in a diagonal direction toward the bottom-left until we reach the left boundary. Upon hitting the left boundary, we move one cell down (unless we're at the bottom-left corner, in which case we move one cell to the right) and begin moving diagonally upward toward the upper-right.

While moving diagonally upward, if we hit the top boundary, we move one cell to the right and start going downwards diagonally. If we hit the right boundary while moving upwards, we move one cell down and resume a bottom-left diagonal path. In essence, we zigzag across the matrix diagonally until every cell is traversed.

Once we finish this zigzag traversal, we'll process the list of visited cell values to uncover the indices of perfect square numbers. The diagonal_traverse_and_squares(matrix) function should implement this traversal and return a list of 1-indexed positions of perfect squares in the traversed sequence.

Take a 3x4 matrix, for example:

Plain text
1[ 2 [1, 2, 3, 4], 3 [5, 6, 7, 8], 4 [9, 10, 11, 12] 5]

Following the diagonal traversal, we get the list: [1, 5, 2, 3, 6, 9, 10, 7, 4, 8, 11, 12]. From this list, 1, 9, and 4 are the perfect squares found at the 1st, 6th, and 9th positions (1-indexed). Thus, our function returns: [1, 6, 9].

Solution Building: Step 1

Firstly, let's explore the dimensions of the 2D matrix using Ruby's length method. We need to establish the landscape of our matrix by determining the number of rows and columns. Next, we initialize two arrays: traversal and results. The traversal array holds the values from the matrix captured during our distinctive diagonal zigzag path. Later, the results array is filled with the 1-indexed positions of the perfect square numbers found in the traversal array.

Ruby
1def diagonal_traverse(matrix) 2 rows = matrix.length 3 cols = matrix[0].length 4 traversal = [] 5 results = []
Solution Building: Step 2

The next step involves executing the diagonal traversal of the 2D matrix. We begin at the top-left corner (cell [0][0]) and navigate through the matrix using two variables, row and col, to track the cell indices. An additional dir variable is set to 1, indicating that the starting direction is downward-left.

However, transitioning diagonally isn't straightforward; matching the matrix boundaries requires us to adjust our direction. In Ruby, a times loop iterates for the total number of cells, and we use conditional statements to control the direction and ensure we respect the matrix edges.

Ruby
1 row = col = 0 2 dir = 1 3 (rows * cols).times do 4 traversal << matrix[row][col] 5 6 if dir == 1 # Moving down-left 7 if row == rows - 1 8 col += 1 9 dir = -1 10 elsif col == 0 11 row += 1 12 dir = -1 13 else 14 row += 1 15 col -= 1 16 end 17 else # Moving up-right 18 if col == cols - 1 19 row += 1 20 dir = 1 21 elsif row == 0 22 col += 1 23 dir = 1 24 else 25 row -= 1 26 col += 1 27 end 28 end 29 end

Moving Down-Left (dir == 1)

  • If at the last row:
    • Move right (col += 1)
    • Change direction to up-right (dir = -1)
  • If at the first column:
    • Move down (row += 1)
    • Change direction to up-right (dir = -1)
  • Otherwise:
    • Move diagonally down-left (row += 1, col -= 1)

Moving Up-Right (else)

  • If at the last column:
    • Move down (row += 1)
    • Change direction to down-left (dir = 1)
  • If at the first row:
    • Move right (col += 1)
    • Change direction to down-left (dir = 1)
  • Otherwise:
    • Move diagonally up-right (row -= 1, col += 1)
Solution Building: Step 3

With the traversal complete, we possess a list of integers. Our task now is to identify perfect squares — integers that are squares of other integers. For each perfect square discovered, we append its 1-indexed position in the traversal list to results. Using Ruby's Math.sqrt, we determine if a number is a perfect square by checking if it equals the square of its integer square root.

Ruby
1 traversal.each_with_index do |val, idx| 2 if (Math.sqrt(val) % 1).zero? # Check if the value is a perfect square 3 results << idx + 1 4 end 5 end 6 7 results 8end
Lesson Summary

Congratulations! You've adeptly navigated a challenging task involving a unique matrix traversal pattern. You've demonstrated solid skills in Ruby programming, focusing on array manipulation and the complexities of working with 2D arrays.

Now, take what you've learned and apply it to tackle more complex matrices and diverse values to solidify your understanding. Keep experimenting, and soon you'll master the art of matrix traversals. Happy coding!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.