aoc_rb_helpers 0.0.4 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab9f12989f97afbeb704d8439ba020351f1288f8519683aaca95cae2cadb5d47
4
- data.tar.gz: ddfc599e4d027bb4b55e2b6d83b02c3ce19146d01a37345ac59487ea9272ec6c
3
+ metadata.gz: be89f829468b5e0144844944ec0bd8a96973e45d9200cf32b8b23de30f3a0a4b
4
+ data.tar.gz: 2619c91954216ba37620673a97bdd3f27b74e47e8094a418444fa317363b5270
5
5
  SHA512:
6
- metadata.gz: 788dc4890a2955752e00e9071363f973396c3f4b1a89d3340d59bd382bdc38158d13677568f400c8b2ad84124b1bb1620ba8a187426c018ad2d7edc5903f7ba6
7
- data.tar.gz: e3e73b45faf9044fd73c74289d5bdaa1e9d09c28cd42d913f6c47ffe577b69379827f88bf867b044a90db1cda39fb47c9f15f08d00b4ad7e9d547b67f37bfc7e
6
+ metadata.gz: dd7f615183ca42cd9bc8fcc2febe8a2d688c781dde3cdff9819aae9cd2157e22ac0943c1076c647750ceb1cdd6aee303d80aa86abdf446f7bcc74fdddd3ef9c8
7
+ data.tar.gz: c0d45da087522c0a1ce92c43b946674c36e79bf1c2cc6d6e1aa65679b5c32b8141235b3dfe663f8c849ef065936725ccbb288fd3745557e432efa09b2087278d
data/CHANGELOG.md CHANGED
@@ -7,6 +7,26 @@ 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.6]
11
+ ### Added
12
+ - AocInput#single_line - Strips newline characters from single line puzzle inputs
13
+
14
+ ## [0.0.5]
15
+ ### Added
16
+ - AocInput#process_each_line - Processes each line of the input data using the provided block
17
+ - Grid#includes_coords? - Returns `true` if the provided coordinates exist within the bounds of the grid
18
+ - Grid#beyond_grid? - Returns `true` if the provided coordinates exceed the bounds of the grid
19
+ - Grid#locate(value) - Returns the first coordinates within the grid containing the given value
20
+ - Grid#locate_all(value) - Returns an array of coordinates for any location within the grid containing the given value
21
+ - Grid#each_cell - Iterates over each cell in the grid
22
+
23
+ ### Changed
24
+ - Grid#cell now returns `nil` if the provided coordinates to not exist within the grid
25
+ - Grid#set_cell nwo returns `nil` if the provided coordinates to not exist within the grid
26
+
27
+ ### Fixed
28
+ - Grid#dup previously returned a new `Grid` instance with the same instance of the `@grid` array within it. Now `@grid` is a unique copy.
29
+
10
30
  ## [0.0.4]
11
31
  ### Added
12
32
  - Grid class for working with two-dimensional arrays of data
@@ -29,6 +49,10 @@ Initial release.
29
49
  ### Added
30
50
  - Created `AocInput` class with initial helper methods
31
51
 
32
- [Unreleased]: https://github.com/pacso/aoc_rb_helpers/compare/v0.0.2...HEAD
52
+ [Unreleased]: https://github.com/pacso/aoc_rb_helpers/compare/v0.0.6...HEAD
53
+ [0.0.6]: https://github.com/pacso/aoc_rb_helpers/compare/v0.0.5...v0.0.6
54
+ [0.0.5]: https://github.com/pacso/aoc_rb_helpers/compare/v0.0.4...v0.0.5
55
+ [0.0.4]: https://github.com/pacso/aoc_rb_helpers/compare/v0.0.3...v0.0.4
56
+ [0.0.3]: https://github.com/pacso/aoc_rb_helpers/compare/v0.0.2...v0.0.3
33
57
  [0.0.2]: https://github.com/pacso/aoc_rb_helpers/compare/v0.0.1...v0.0.2
34
58
  [0.0.1]: https://github.com/pacso/aoc_rb_helpers
@@ -22,6 +22,17 @@ class AocInput
22
22
  @data ||= @raw_input
23
23
  end
24
24
 
25
+ # Strips newline characters from the data, leaving a single line of input.
26
+ #
27
+ # @return [AocInput] self
28
+ def single_line
29
+ can_call?(:single_line)
30
+ @data = data.chomp('')
31
+ revoke(:multiple_lines)
32
+ revoke(:single_line)
33
+ self
34
+ end
35
+
25
36
  # Splits the input string into an array of lines.
26
37
  #
27
38
  # This method processes +@data+ by splitting the input string into multiple lines,
@@ -30,9 +41,33 @@ class AocInput
30
41
  #
31
42
  # @return [AocInput] self
32
43
  def multiple_lines
44
+ can_call?(:multiple_lines)
33
45
  @data = data.lines(chomp: true)
34
46
  allow(:columns_of_numbers)
47
+ allow(:process_each_line)
35
48
  revoke(:multiple_lines)
49
+ revoke(:single_line)
50
+ self
51
+ end
52
+
53
+ # Processes each line of the data using the provided block.
54
+ #
55
+ # This method applies the given block to each line in the +@data+ array,
56
+ # replacing the original +@data+ with the results of the block. The method
57
+ # returns +self+ to allow method chaining.
58
+ #
59
+ # Returns an enumerator if no block is given.
60
+ #
61
+ # @yieldparam line [Object, Array<Object>] a single line of the data being processed
62
+ # @yieldreturn [Object, Array<Object>] the result of processing the line
63
+ # @return [self] the instance itself, for method chaining
64
+ # @return [Enumerator] if no block is given
65
+ def process_each_line
66
+ can_call?(:process_each_line, "call .multiple_lines first")
67
+ return to_enum(__callee__) unless block_given?
68
+ @data = @data.map do |line|
69
+ yield line
70
+ end
36
71
  self
37
72
  end
38
73
 
@@ -98,6 +133,8 @@ class AocInput
98
133
  @can_call = {
99
134
  columns_of_numbers: false,
100
135
  multiple_lines: true,
136
+ process_each_line: false,
137
+ single_line: true,
101
138
  sort_arrays: false,
102
139
  transpose: false
103
140
  }
@@ -16,23 +16,55 @@ class Grid
16
16
  @grid = grid
17
17
  end
18
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
+
19
40
  # Returns the value stored at coordinates +(row, column)+ within the grid.
20
41
  #
42
+ # Returns +nil+ if the provided coordinates do not exist within the grid.
43
+ #
21
44
  # Row and column numbers are zero-indexed.
22
45
  #
23
46
  # @param row [Integer] the row index of the desired cell
24
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
25
51
  def cell(row, column)
52
+ return nil unless includes_coords?(row, column)
26
53
  @grid[row][column]
27
54
  end
28
55
 
29
56
  # Updates the cell at coordinates +(row, column)+ with the object provided in +value+; returns the given object.
30
57
  #
58
+ # Returns +nil+ if the provided coordinates do not exist within the grid.
59
+ #
31
60
  # @param row [Integer] the row index of the cell you wish to update
32
61
  # @param column [Integer] the column index of the cell you wish to update
33
62
  # @param value [Object] the object to assign to the selected grid cell
34
63
  # @return [Object] the given +value+
64
+ # @return [nil] if the provided coordinates do not exist within the grid
65
+ # @see #cell
35
66
  def set_cell(row, column, value)
67
+ return nil unless includes_coords?(row, column)
36
68
  @grid[row][column] = value
37
69
  end
38
70
 
@@ -80,7 +112,7 @@ class Grid
80
112
  # Returns a new {Grid} as a copy of self.
81
113
  # @return [Grid] a copy of +self+
82
114
  def dup
83
- Grid.new(@grid)
115
+ self.class.new(@grid.map { |row| row.map { |cell| cell } })
84
116
  end
85
117
 
86
118
  # Updates +self+ with a rotated grid and returns +self+.
@@ -126,4 +158,109 @@ class Grid
126
158
  raise ArgumentError unless columns.is_a?(Integer) && columns > 0 && columns <= @grid.first.length
127
159
  each_subgrid(rows, columns).to_a
128
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
129
266
  end
@@ -1,3 +1,3 @@
1
1
  module AocRbHelpers
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.6"
3
3
  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
4
+ version: 0.0.6
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-05 00:00:00.000000000 Z
11
+ date: 2024-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aoc_rb