Manipulate grid like structure in Ruby.
Add this line to your application's Gemfile:
gem 'grid_struct'
And then execute:
$ bundle
Or install it yourself as:
$ gem install grid_struct
In order to create a grid, you have to pass a 2 arguments:
rows
: the number of rows your grid has (the height of the grid)columns
: the number columns your grid has (the width of the grid)
rows = 9
columns = 5
# Create a grid of size 5x9
grid = GridStruct.new(rows, columns)
grid.size # => 45
grid.columns # => 5
grid.rows # => 9
It is possible to initialize the array with pre-set values. The 3rd argument must be an array.
If we want to initialize the following grid:
+---+---+---+
| X | O | O |
+---+---+---+
| X | x | O |
+---+---+---+
| O | X | O |
+---+---+---+
Use the following array structure:
# +-----------+-----------+-----------+
# | ROW 0 | ROW 1 | ROW 2 |
# +---------+-----------+-----------+-----------+
# | COLUMNS | 0 | 1 | 2 | 0 | 1 | 2 | 0 | 1 | 2 |
grid_data = ['X','O','O','X','X','O','O','X','O']
tic_tac_toe = GridStruct.new(3, 3, grid_data)
GridStruct
actually store your values extactly the same way, in a 1-dimentional array.
Now you know how to create grids, it's time to learn how to use our new data structure.
As mentionned above, your data are stored in a 1-dimentional array.
tic_tac_toe.store # => ["X","O","O","X","X","O","O","X","O"]
GridStruct.new(9,9).store # => []
As you can see, the store
always starts as an empty array unless you decide to pre-fill the grid.
To set a value, pass the row and column you want to fill, and a block that will return the value
GridStruct#set(row, column) { value }
sudoku_grid = GridStruct.new(9,9)
sudoku_grid.set(0,0) { 'Hello World' }
sudoku_grid.store # => ["Hello World"]
sudoku_grid.set(1,0) { 'Row: 1, Col: 0' }
sudoku_grid.store # => ["Hello World",nil,nil,nil,nil,nil,nil,nil,"Row: 1, Col: 0"]
To get a value at a specific coordinate, use th get
method.
GridStruct#get(row, column) # => value
sudoku_grid.get(1,0) # => "Row: 1, Col: 0"
You can iterate through the grid using the each method
GridStruct#each { |value, row, column| # Do something }
Incase you need to update each element within the grid, use the map!
method
GridStruct#map! { |value, row, column| # Return new value }
grid = GridStruct.new(3,3)
grid.map! { |value, row, column| (row * grid.columns) + column }
grid.store # => [0,1,2,3,4,5,6,7,8]
You can update a specific row if needed, for example, if we want to update the middle row
GridStruct#map_row! { |value, column| # Return new value }
+---+---+---+
| 0 | 1 | 2 |
+---+---+---+
Update this row → | 3 | 4 | 5 |
+---+---+---+
| 6 | 7 | 8 |
+---+---+---+
grid.map_row!(1) { |value| value * 10 }
grid.store # => [0,1,2,30,40,50,6,7,8]
You can update a specific row if needed, for example, if we want to update the middle row
GridStruct#map_column! { |value, row| # Return new value }
Update this columns
↓
+---+---+---+
| 0 | 1 | 2 |
+---+---+---+
| 3 | 4 | 5 |
+---+---+---+
| 6 | 7 | 8 |
+---+---+---+
grid.map_column!(2) { |value| value * 10 }
grid.store # => [0,1,20,3,4,50,6,7,80]
Selector gives you access to line of values within the grid, and allows you to only act on that line. Each selector return a (or an array of) GridStruct::Selector.
A selector has the following instances:
grid
: The grid it is selecting fromindexes
: An array of indexes mapping to the selected values in the grid store
grid = GridStruct.new(3,3)
grid.map! do |value, row, column|
(row * grid.columns + column) * 10
end
grid.row(0) # => #<GridStruct::Selector:0x007fb3d11decf0 @grid=#<GridStruct:0x007fb3d15541f0 @columns=3, @rows=3, @store=[0, 10, 20, 30, 40, 50, 60, 70, 80]>, @indexes=[0, 1, 2]>
You can retrieve and update values using []
. It will map the action to the grid.
first_row = grid.row(0)
first_row.to_a # => [0,10,20]
first_row[0] # => 0
first_row[1] # => 10
first_row[2] # => 20
first_row[0] = -100
grid.to_a # => [-100,10,20,30,40,50,60,70,80]
To select a specific row, use the method row
GridStruct#row(row_number)
rows = []
# Fetch selector for every rows
grid.rows.times.each do |row_index|
rows[row_index] = grid.row(row_index)
end
To select a specific column, use the method column
GridStruct#column(column_number)
columns = []
# Fetch selector for every columns
grid.columns.times.each do |column_index|
columns[column_index] = grid.column(column_index)
end
The diagonals retrieval works slightly differently from the two previous methods. In order to retrieve diagonals, you must provide the coordinates of a cell in the grid. This will retrieve the diagonals that cross through that specific cell. The returned array can be of size 0 (no diagonals found, for example, in a grid of size 1), 1 (when retrieving diagonals from the corners of the grid) or 2.
GridStruct#diagonals(1,1) # => [#<GridStruct::Selector ...>, #<GridStruct::Selector ...>]
diagonals = grid.diagonals(1,1)
diagonals.first.to_a # => [0,40,80]
diagonals.last.to_a # => [30,40,60]
corner_diagonal = grid.diagonals(0,0) # fetch diagonals from top left corner
corner_diagonal.size # => 1
corner_diagonal.first.to_a # => [0,40,80]
Imagine a slice as a projection of a section of your grid.
Use the slice
method to access a single slice.
GridStruct#slice(slice_index, rows: slice_rows, columns: slice_columns) # => #<GridStruct::Selector ...>
In the following example, we are manipulating a sudoku grid, and we want to access the middle 3x3 square
sudoku_grid = GridStruct.new(9,9)
sudoku_grid.map! do |v, r, c|
(r * sudoku_grid.columns) + c + 1
end
sudoku_grid.slice(4, rows: 3, columns: 3) # => #<GridStruct:0x007fb3d16e4e70 @columns=3, @rows=3, @store=[31, 32, 33, 40, 41, 42, 49, 50, 51]>
Use the each_slice
method to go through each slices
GridStruct#each_slice(slice_rows,slice_columns) { |slice, slice_index| # Do something }
sudoku_grid.each_slice(3,3) do |slice, index|
# Do something
end
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request