aoc_rb_helpers 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -1
- data/README.md +17 -1
- data/lib/aoc_rb_helpers/aoc_input.rb +45 -12
- data/lib/aoc_rb_helpers/grid.rb +266 -0
- data/lib/aoc_rb_helpers/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1990cde2622df33946ce6131918c215ac548d3b013ed36b57fd980fd0ba7c0ab
|
4
|
+
data.tar.gz: 7070a8add7b5f3bf0b4fa033959ce30624edeac87329a95964e2bade9dbb5741
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 402844433642a9dcfd4bcded006ec9eca2d3cc8b18a0016b7d3cc45631b24e54e37315af3cff1d895c511233a167b9cc82ed21f7f942f721cafe016f8ea552d6
|
7
|
+
data.tar.gz: 34f664b1de9a6fd751241afc34445c46cc16ab6cce24f246476799d7915ce4f519f4ac67d22a42b72780c673d5c21fe693c19c42786a23f6b529c19beffa53f8
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
## [Unreleased]
|
8
8
|
- No unreleased changes!
|
9
9
|
|
10
|
+
## [0.0.5]
|
11
|
+
### Added
|
12
|
+
- AocInput#process_each_line - Processes each line of the input data using the provided block
|
13
|
+
- Grid#includes_coords? - Returns `true` if the provided coordinates exist within the bounds of the grid
|
14
|
+
- Grid#beyond_grid? - Returns `true` if the provided coordinates exceed the bounds of the grid
|
15
|
+
- Grid#locate(value) - Returns the first coordinates within the grid containing the given value
|
16
|
+
- Grid#locate_all(value) - Returns an array of coordinates for any location within the grid containing the given value
|
17
|
+
- Grid#each_cell - Iterates over each cell in the grid
|
18
|
+
|
19
|
+
### Changed
|
20
|
+
- Grid#cell now returns `nil` if the provided coordinates to not exist within the grid
|
21
|
+
- Grid#set_cell nwo returns `nil` if the provided coordinates to not exist within the grid
|
22
|
+
|
23
|
+
### Fixed
|
24
|
+
- Grid#dup previously returned a new `Grid` instance with the same instance of the `@grid` array within it. Now `@grid` is a unique copy.
|
25
|
+
|
26
|
+
## [0.0.4]
|
27
|
+
### Added
|
28
|
+
- Grid class for working with two-dimensional arrays of data
|
29
|
+
- AocInput updated with convenience method for creating a Grid from input
|
30
|
+
- AocInput#sections added, for splitting input into multiple sections
|
31
|
+
|
10
32
|
## [0.0.3]
|
11
33
|
### Added
|
12
34
|
- Characters `I` and `T` now supported by DotMatrix
|
@@ -23,6 +45,9 @@ Initial release.
|
|
23
45
|
### Added
|
24
46
|
- Created `AocInput` class with initial helper methods
|
25
47
|
|
26
|
-
[Unreleased]: https://github.com/pacso/aoc_rb_helpers/compare/v0.0.
|
48
|
+
[Unreleased]: https://github.com/pacso/aoc_rb_helpers/compare/v0.0.5...HEAD
|
49
|
+
[0.0.5]: https://github.com/pacso/aoc_rb_helpers/compare/v0.0.4...v0.0.5
|
50
|
+
[0.0.4]: https://github.com/pacso/aoc_rb_helpers/compare/v0.0.3...v0.0.4
|
51
|
+
[0.0.3]: https://github.com/pacso/aoc_rb_helpers/compare/v0.0.2...v0.0.3
|
27
52
|
[0.0.2]: https://github.com/pacso/aoc_rb_helpers/compare/v0.0.1...v0.0.2
|
28
53
|
[0.0.1]: https://github.com/pacso/aoc_rb_helpers
|
data/README.md
CHANGED
@@ -58,13 +58,21 @@ X X X X X X X X X X X X X
|
|
58
58
|
```
|
59
59
|
Into the string `CFLELOYFCS`.
|
60
60
|
|
61
|
+
### [Grid](https://rubydoc.info/github/pacso/aoc_rb_helpers/Grid)
|
62
|
+
Provides helper methods for manipulating end querying two-dimensional grids.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
grid = Grid.new([[0, 1], [2, 3]])
|
66
|
+
grid.rotate! # => #<Grid:0x0000ffff8f42f8f8 @grid=[[2, 0], [3, 1]]>
|
67
|
+
```
|
68
|
+
|
61
69
|
## Examples
|
62
70
|
|
63
71
|
Below are some examples of how you can use the features of this gem.
|
64
72
|
|
65
73
|
### Input manipulation
|
66
74
|
|
67
|
-
This example solution for 2024 Day 1 shows how the convenience
|
75
|
+
This example solution for 2024 Day 1 shows how the convenience methods can be used to format the puzzle input:
|
68
76
|
|
69
77
|
```ruby
|
70
78
|
# frozen_string_literal: true
|
@@ -95,6 +103,14 @@ module Year2024
|
|
95
103
|
end
|
96
104
|
```
|
97
105
|
|
106
|
+
Where you have different sections of input which need to be handled differently, you can quickly split them into independent instances of `AocInput`, such as with the pussle from 2024, Day 5:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
page_rules, page_updates = aoc_input.sections
|
110
|
+
page_rules_data = page_rules.multiple_lines.columns_of_numbers("|").data
|
111
|
+
page_updates_data = page_updates.multiple_lines.columns_of_numbers(",").data
|
112
|
+
```
|
113
|
+
|
98
114
|
### Decoding printed text
|
99
115
|
|
100
116
|
```ruby
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Provides input manipulation helper methods.
|
4
|
-
# Methods are chainable, and directly modify the parsed view of the input data within the
|
4
|
+
# Methods are chainable, and directly modify the parsed view of the input data within the +@data+ instance variable.
|
5
5
|
#
|
6
|
-
# Once manipulated as required, the input is accessable
|
6
|
+
# Once manipulated as required, the input is accessable using the {#data} method.
|
7
7
|
class AocInput
|
8
8
|
# Returns a new AocInput initialized with the given puzzle input.
|
9
9
|
#
|
@@ -24,8 +24,8 @@ class AocInput
|
|
24
24
|
|
25
25
|
# Splits the input string into an array of lines.
|
26
26
|
#
|
27
|
-
# This method processes
|
28
|
-
# removing trailing newline characters. It modifies
|
27
|
+
# This method processes +@data+ by splitting the input string into multiple lines,
|
28
|
+
# removing trailing newline characters. It modifies +@data+ directly and returns +self+
|
29
29
|
# to enable method chaining.
|
30
30
|
#
|
31
31
|
# @return [AocInput] self
|
@@ -36,13 +36,33 @@ class AocInput
|
|
36
36
|
self
|
37
37
|
end
|
38
38
|
|
39
|
+
# Processes each line of the data using the provided block.
|
40
|
+
#
|
41
|
+
# This method applies the given block to each line in the +@data+ array,
|
42
|
+
# replacing the original +@data+ with the results of the block. The method
|
43
|
+
# returns +self+ to allow method chaining.
|
44
|
+
#
|
45
|
+
# Returns an enumerator if no block is given.
|
46
|
+
#
|
47
|
+
# @yieldparam line [Object, Array<Object>] a single line of the data being processed
|
48
|
+
# @yieldreturn [Object, Array<Object>] the result of processing the line
|
49
|
+
# @return [self] the instance itself, for method chaining
|
50
|
+
# @return [Enumerator] if no block is given
|
51
|
+
def process_each_line
|
52
|
+
return to_enum(__callee__) unless block_given?
|
53
|
+
@data = @data.map do |line|
|
54
|
+
yield line
|
55
|
+
end
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
39
59
|
# Splits each string in the data array into an array of numbers.
|
40
60
|
#
|
41
|
-
# This method processes
|
42
|
-
# then converting each resulting element to an integer. It modifies
|
43
|
-
# chaining by returning
|
61
|
+
# This method processes +@data+ by splitting each string in the array using the specified delimiter,
|
62
|
+
# then converting each resulting element to an integer. It modifies +@data+ directly and enables
|
63
|
+
# chaining by returning +self+.
|
44
64
|
#
|
45
|
-
# @param delimiter [String, nil] the delimiter to be passed to
|
65
|
+
# @param delimiter [String, nil] the delimiter to be passed to +String#split+
|
46
66
|
# @raise [RuntimeError] if {#multiple_lines} has not been called
|
47
67
|
# @return [AocInput] self
|
48
68
|
def columns_of_numbers(delimiter = nil)
|
@@ -57,7 +77,7 @@ class AocInput
|
|
57
77
|
# Transposes the data array.
|
58
78
|
#
|
59
79
|
# This method can only be called after {columns_of_numbers}.
|
60
|
-
# It directly modifies
|
80
|
+
# It directly modifies +@data+ by transposing it and returns +self+ to allow method chaining.
|
61
81
|
#
|
62
82
|
# @raise [RuntimeError] if {columns_of_numbers} has not been called.
|
63
83
|
# @return [AocInput] self
|
@@ -67,10 +87,10 @@ class AocInput
|
|
67
87
|
self
|
68
88
|
end
|
69
89
|
|
70
|
-
# Sorts each array within the
|
90
|
+
# Sorts each array within the +@data+ array.
|
71
91
|
#
|
72
|
-
# This method processes
|
73
|
-
# It directly modifies
|
92
|
+
# This method processes +@data+ by sorting each nested array in ascending order.
|
93
|
+
# It directly modifies +@data+ and returns +self+ to enable method chaining.
|
74
94
|
#
|
75
95
|
# @raise [RuntimeError] if {#columns_of_numbers} has not been called
|
76
96
|
# @return [AocInput] self
|
@@ -80,6 +100,19 @@ class AocInput
|
|
80
100
|
self
|
81
101
|
end
|
82
102
|
|
103
|
+
# Returns a new +Grid+ object from the parsed input
|
104
|
+
# @return [Grid] the new grid
|
105
|
+
def to_grid
|
106
|
+
Grid.from_input(@raw_input)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns a new +AocInput+ for each section of the raw input, split by the given delimiter.
|
110
|
+
# @param delimiter [String] the string used to split sections
|
111
|
+
# @return [Array<AocInput>] an array of new AocInput instances initialised with each section of the raw input from +self+
|
112
|
+
def sections(delimiter = "\n\n")
|
113
|
+
@sections = @raw_input.split(delimiter).map { |section_input| AocInput.new(section_input) }
|
114
|
+
end
|
115
|
+
|
83
116
|
private
|
84
117
|
def configure_method_access
|
85
118
|
@can_call = {
|
@@ -0,0 +1,266 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Provides helper methods for manipulating end querying two-dimensional grids.
|
4
|
+
class Grid
|
5
|
+
# Returns a new {Grid} initialized with the given input.
|
6
|
+
#
|
7
|
+
# @param input [String] the unprocessed input text containing the grid
|
8
|
+
def self.from_input(input)
|
9
|
+
self.new(input.lines(chomp: true).map(&:chars))
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns a new {Grid} initialized with the provided two-dimensional array.
|
13
|
+
#
|
14
|
+
# @param grid [Array<Array<Object>>] the grid in a two-dimensional array
|
15
|
+
def initialize(grid)
|
16
|
+
@grid = grid
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns +true+ if the provided coordinates exceed the bounds of the grid; +false+ otherwise.
|
20
|
+
#
|
21
|
+
# @param row [Integer] the row index to test
|
22
|
+
# @param column [Integer] the column index to test
|
23
|
+
# @return [Boolean]
|
24
|
+
# @see #includes_coords?
|
25
|
+
def beyond_grid?(row, column)
|
26
|
+
!includes_coords?(row, column)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns +true+ if the provided coordinates exist within the bounds of the grid; +false+ otherwise.
|
30
|
+
#
|
31
|
+
# @param row [Integer] the row index to test
|
32
|
+
# @param column [Integer] the column index to test
|
33
|
+
# @return [Boolean]
|
34
|
+
# @see #beyond_grid?
|
35
|
+
def includes_coords?(row, column)
|
36
|
+
row >= 0 && column >= 0 && row < @grid.length && column < @grid.first.length
|
37
|
+
end
|
38
|
+
alias_method(:within_grid?, :includes_coords?)
|
39
|
+
|
40
|
+
# Returns the value stored at coordinates +(row, column)+ within the grid.
|
41
|
+
#
|
42
|
+
# Returns +nil+ if the provided coordinates do not exist within the grid.
|
43
|
+
#
|
44
|
+
# Row and column numbers are zero-indexed.
|
45
|
+
#
|
46
|
+
# @param row [Integer] the row index of the desired cell
|
47
|
+
# @param column [Integer] the column index of the desired cell
|
48
|
+
# @return [Object] the value at the given coordinates within the grid
|
49
|
+
# @return [nil] if the given coordinates do not exist within the grid
|
50
|
+
# @see #set_cell
|
51
|
+
def cell(row, column)
|
52
|
+
return nil unless includes_coords?(row, column)
|
53
|
+
@grid[row][column]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Updates the cell at coordinates +(row, column)+ with the object provided in +value+; returns the given object.
|
57
|
+
#
|
58
|
+
# Returns +nil+ if the provided coordinates do not exist within the grid.
|
59
|
+
#
|
60
|
+
# @param row [Integer] the row index of the cell you wish to update
|
61
|
+
# @param column [Integer] the column index of the cell you wish to update
|
62
|
+
# @param value [Object] the object to assign to the selected grid cell
|
63
|
+
# @return [Object] the given +value+
|
64
|
+
# @return [nil] if the provided coordinates do not exist within the grid
|
65
|
+
# @see #cell
|
66
|
+
def set_cell(row, column, value)
|
67
|
+
return nil unless includes_coords?(row, column)
|
68
|
+
@grid[row][column] = value
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns +true+ if the other grid has the same content in the same orientation, +false+ otherwise.
|
72
|
+
#
|
73
|
+
# grid = Grid.new([1, 2], [3, 4])
|
74
|
+
# grid == Grid.new([1, 2], [3, 4]) # => true
|
75
|
+
# grid == Grid.new([0, 1], [2, 3]) # => false
|
76
|
+
# grid == "non-grid object" # => false
|
77
|
+
#
|
78
|
+
# @param other [Grid] the grid you wish to compare with
|
79
|
+
# @return [Boolean]
|
80
|
+
def ==(other)
|
81
|
+
return false unless other.is_a?(self.class)
|
82
|
+
@grid == other.instance_variable_get(:@grid)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Returns +true+ if the other grid can be rotated into an orientation where it is equal to +self+, +false+ otherwise.
|
86
|
+
#
|
87
|
+
# grid = Grid.new([1, 2], [3, 4])
|
88
|
+
# grid == Grid.new([1, 2], [3, 4]) # => true
|
89
|
+
# grid == Grid.new([3, 1], [4, 2]) # => true
|
90
|
+
# grid == Grid.new([1, 2], [4, 3]) # => false
|
91
|
+
# grid == "non-grid object" # => false
|
92
|
+
#
|
93
|
+
# @param other [Grid] the grid you wish to compare with
|
94
|
+
def matches_with_rotations?(other)
|
95
|
+
other.all_rotations.any? { |rotated| self == rotated }
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns an array of {Grid} objects in all possible rotations, copied from +self+.
|
99
|
+
# @return [Array<Grid>] an array containing four {Grid} objects, one in each possible rotation
|
100
|
+
def all_rotations
|
101
|
+
rotations = []
|
102
|
+
current_grid = self.dup
|
103
|
+
|
104
|
+
4.times do
|
105
|
+
rotations << current_grid.dup
|
106
|
+
current_grid.rotate!
|
107
|
+
end
|
108
|
+
|
109
|
+
rotations
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns a new {Grid} as a copy of self.
|
113
|
+
# @return [Grid] a copy of +self+
|
114
|
+
def dup
|
115
|
+
self.class.new(@grid.map { |row| row.map { |cell| cell } })
|
116
|
+
end
|
117
|
+
|
118
|
+
# Updates +self+ with a rotated grid and returns +self+.
|
119
|
+
#
|
120
|
+
# Will rotate in a clockwise direction by default. Will rotate in an anticlockwise direction if passed
|
121
|
+
# a param which is not +:clockwise+.
|
122
|
+
#
|
123
|
+
# @param direction [Symbol]
|
124
|
+
# @return [self]
|
125
|
+
def rotate!(direction = :clockwise)
|
126
|
+
@grid = direction == :clockwise ? @grid.transpose.map(&:reverse) : @grid.map(&:reverse).transpose
|
127
|
+
self
|
128
|
+
end
|
129
|
+
|
130
|
+
# Calls the given block with each subgrid from +self+ with the size constraints provided; returns +self+.
|
131
|
+
#
|
132
|
+
# Returns an enumerator if no block is given
|
133
|
+
#
|
134
|
+
# @return [Enumerator] if no block is given.
|
135
|
+
# @return [self] after processing the provided block
|
136
|
+
# @yield [subgrid] calls the provided block with each subgrid as a new {Grid} object
|
137
|
+
# @yieldparam subgrid [Grid] a new {Grid} object containing a subgrid from the main grid
|
138
|
+
def each_subgrid(rows, columns)
|
139
|
+
return to_enum(__callee__, rows, columns) unless block_given?
|
140
|
+
@grid.each_cons(rows) do |rows|
|
141
|
+
rows[0].each_cons(columns).with_index do |_, col_index|
|
142
|
+
yield Grid.new(rows.map { |row| row[col_index, columns] })
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns an array containing all of the subgrids of the specified dimensions.
|
150
|
+
# @param rows [Integer] the number of rows each subgrid should contain.
|
151
|
+
# Must be greater than zero and less than or equal to the number of rows in the grid.
|
152
|
+
# @param columns [Integer] the number of columns each subgrid should contain.
|
153
|
+
# Must be greater than zero and less than or equal to the number of columns in the grid.
|
154
|
+
# @raise [ArgumentError] if the specified rows or columns are not {Integer} values, or exceed the grid's dimensions.
|
155
|
+
# @return [Array<Grid>]
|
156
|
+
def subgrids(rows, columns)
|
157
|
+
raise ArgumentError unless rows.is_a?(Integer) && rows > 0 && rows <= @grid.length
|
158
|
+
raise ArgumentError unless columns.is_a?(Integer) && columns > 0 && columns <= @grid.first.length
|
159
|
+
each_subgrid(rows, columns).to_a
|
160
|
+
end
|
161
|
+
|
162
|
+
# Returns the first coordinates within the grid containing the given value. Returns +nil+ if not found.
|
163
|
+
#
|
164
|
+
# If given an array of values, the first coordinate matching any of the given values will be returned.
|
165
|
+
#
|
166
|
+
# Searches the grid from top left (+[0, 0]+) to bottom right, by scanning each row.
|
167
|
+
#
|
168
|
+
# @param value [Object, Array<Object>] the value, or array of values, to search for.
|
169
|
+
# @return [Array<Integer>] if the value was located, its coordinates are returned in a 2-item array where:
|
170
|
+
# - The first item is the row index.
|
171
|
+
# - The second item is the column index.
|
172
|
+
# @return [nil] if the value was not located
|
173
|
+
def locate(value)
|
174
|
+
result = nil
|
175
|
+
if value.is_a? Array
|
176
|
+
value.each do |e|
|
177
|
+
result = locate(e)
|
178
|
+
break unless result.nil?
|
179
|
+
end
|
180
|
+
else
|
181
|
+
result = locate_value value
|
182
|
+
end
|
183
|
+
result
|
184
|
+
end
|
185
|
+
|
186
|
+
# Returns an array of coordinates for any location within the grid containing the given value.
|
187
|
+
#
|
188
|
+
# If given an array of values, the coordinates of any cell matching any of the given values will be returned.
|
189
|
+
#
|
190
|
+
# @param value [Object, Array<Object>] the value, or array of values, to search for.
|
191
|
+
# @return [Array<Array<Integer>>] an array of coordinates. Each coordinate is a 2-item array where:
|
192
|
+
# - The first item is the row index.
|
193
|
+
# - The second item is the column index.
|
194
|
+
def locate_all(value)
|
195
|
+
locations = []
|
196
|
+
|
197
|
+
if value.is_a? Array
|
198
|
+
@grid.each_with_index.select { |row, _r_index| value.any? { |el| row.include?(el) } }.each do |row, r_index|
|
199
|
+
row.each_with_index do |cell, c_index|
|
200
|
+
locations << [r_index, c_index] if value.include?(cell)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
else
|
204
|
+
@grid.each_with_index.select { |row, _r_index| row.include?(value) }.each do |row, r_index|
|
205
|
+
row.each_with_index do |cell, c_index|
|
206
|
+
locations << [r_index, c_index] if cell == value
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
locations
|
212
|
+
end
|
213
|
+
|
214
|
+
# Iterates over each cell in the grid.
|
215
|
+
#
|
216
|
+
# When a block is given, passes the coordinates and value of each cell to the block; returns +self+:
|
217
|
+
# g = Grid.new([
|
218
|
+
# ["a", "b"],
|
219
|
+
# ["c", "d"]
|
220
|
+
# ])
|
221
|
+
# g.each_cell { |coords, value| puts "#{coords.inspect} => #{value}" }
|
222
|
+
#
|
223
|
+
# Output:
|
224
|
+
# [0, 0] => a
|
225
|
+
# [0, 1] => b
|
226
|
+
# [1, 0] => c
|
227
|
+
# [1, 1] => d
|
228
|
+
#
|
229
|
+
# When no block is given, returns a new Enumerator:
|
230
|
+
# g = Grid.new([
|
231
|
+
# [:a, "b"],
|
232
|
+
# [3, true]
|
233
|
+
# ])
|
234
|
+
# e = g.each_cell
|
235
|
+
# e # => #<Enumerator: #<Grid: @grid=[[\"a\", \"b\"], [\"c\", \"d\"]]>:each_cell>
|
236
|
+
# g1 = e.each { |coords, value| puts "#{coords.inspect} => #{value.class}: #{value}" }
|
237
|
+
#
|
238
|
+
# Output:
|
239
|
+
# [0, 0] => Symbol: a
|
240
|
+
# [0, 1] => String: b
|
241
|
+
# [1, 0] => Integer: 3
|
242
|
+
# [1, 1] => TrueClass: true
|
243
|
+
# @yieldparam coords [Array<Integer>] the coordinates of the cell in a 2-item array where:
|
244
|
+
# # - The first item is the row index.
|
245
|
+
# # - The second item is the column index.
|
246
|
+
# @yieldparam value [Object] the value stored within the cell
|
247
|
+
# @return [self]
|
248
|
+
def each_cell
|
249
|
+
return to_enum(__callee__) unless block_given?
|
250
|
+
@grid.each_with_index do |row, r_index|
|
251
|
+
row.each_with_index do |cell, c_index|
|
252
|
+
yield [[r_index, c_index], cell]
|
253
|
+
end
|
254
|
+
end
|
255
|
+
self
|
256
|
+
end
|
257
|
+
|
258
|
+
private
|
259
|
+
|
260
|
+
def locate_value(element)
|
261
|
+
row = @grid.index { |row| row.include?(element) }
|
262
|
+
return nil if row.nil?
|
263
|
+
column = @grid[row].index(element)
|
264
|
+
[row, column]
|
265
|
+
end
|
266
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aoc_rb_helpers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Pascoe
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-12-
|
11
|
+
date: 2024-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aoc_rb
|
@@ -70,6 +70,7 @@ files:
|
|
70
70
|
- lib/aoc_rb_helpers.rb
|
71
71
|
- lib/aoc_rb_helpers/aoc_input.rb
|
72
72
|
- lib/aoc_rb_helpers/dot_matrix.rb
|
73
|
+
- lib/aoc_rb_helpers/grid.rb
|
73
74
|
- lib/aoc_rb_helpers/solution/input_handling.rb
|
74
75
|
- lib/aoc_rb_helpers/version.rb
|
75
76
|
homepage: https://github.com/pacso/aoc_rb_helpers
|