aoc_rb_helpers 0.0.3 → 0.0.4

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: e9049a2637e249afd1d2670f1b4ca3616aa21ef94ae10efb271178693ff16f63
4
- data.tar.gz: 485a04d7594ef25fbec3fb2ca19060c8f5699a30fb0845ec9c985a899aae5be4
3
+ metadata.gz: ab9f12989f97afbeb704d8439ba020351f1288f8519683aaca95cae2cadb5d47
4
+ data.tar.gz: ddfc599e4d027bb4b55e2b6d83b02c3ce19146d01a37345ac59487ea9272ec6c
5
5
  SHA512:
6
- metadata.gz: 6343e8180d5ab30baecad403c7765b4a666562a713154541c70ee6a602ecaa3253c08a25f89db76d36e4e86371901564b34eb7ba779fbbaa2e011cb543edf10a
7
- data.tar.gz: dade32999ee76bbda52f4615cad719ab2dc4ab2209dccf88b6756b0f63d125d7dfe40b76d61e85245c599b472b29e426c5dd110b91c5c3eb46bd8ffd1ab96f84
6
+ metadata.gz: 788dc4890a2955752e00e9071363f973396c3f4b1a89d3340d59bd382bdc38158d13677568f400c8b2ad84124b1bb1620ba8a187426c018ad2d7edc5903f7ba6
7
+ data.tar.gz: e3e73b45faf9044fd73c74289d5bdaa1e9d09c28cd42d913f6c47ffe577b69379827f88bf867b044a90db1cda39fb47c9f15f08d00b4ad7e9d547b67f37bfc7e
data/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ 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.4]
11
+ ### Added
12
+ - Grid class for working with two-dimensional arrays of data
13
+ - AocInput updated with convenience method for creating a Grid from input
14
+ - AocInput#sections added, for splitting input into multiple sections
15
+
10
16
  ## [0.0.3]
11
17
  ### Added
12
18
  - Characters `I` and `T` now supported by DotMatrix
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 methdos can be used to format the puzzle input:
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 @data instance variable.
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 from #data
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 `@data` by splitting the input string into multiple lines,
28
- # removing trailing newline characters. It modifies `@data` directly and returns `self`
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
@@ -38,11 +38,11 @@ class AocInput
38
38
 
39
39
  # Splits each string in the data array into an array of numbers.
40
40
  #
41
- # This method processes `@data` by splitting each string in the array using the specified delimiter,
42
- # then converting each resulting element to an integer. It modifies `@data` directly and enables
43
- # chaining by returning `self`.
41
+ # This method processes +@data+ by splitting each string in the array using the specified delimiter,
42
+ # then converting each resulting element to an integer. It modifies +@data+ directly and enables
43
+ # chaining by returning +self+.
44
44
  #
45
- # @param delimiter [String, nil] the delimiter to be passed to `String#split`
45
+ # @param delimiter [String, nil] the delimiter to be passed to +String#split+
46
46
  # @raise [RuntimeError] if {#multiple_lines} has not been called
47
47
  # @return [AocInput] self
48
48
  def columns_of_numbers(delimiter = nil)
@@ -57,7 +57,7 @@ class AocInput
57
57
  # Transposes the data array.
58
58
  #
59
59
  # This method can only be called after {columns_of_numbers}.
60
- # It directly modifies `@data` by transposing it and returns `self` to allow method chaining.
60
+ # It directly modifies +@data+ by transposing it and returns +self+ to allow method chaining.
61
61
  #
62
62
  # @raise [RuntimeError] if {columns_of_numbers} has not been called.
63
63
  # @return [AocInput] self
@@ -67,10 +67,10 @@ class AocInput
67
67
  self
68
68
  end
69
69
 
70
- # Sorts each array within the `@data` array.
70
+ # Sorts each array within the +@data+ array.
71
71
  #
72
- # This method processes `@data` by sorting each nested array in ascending order.
73
- # It directly modifies `@data` and returns `self` to enable method chaining.
72
+ # This method processes +@data+ by sorting each nested array in ascending order.
73
+ # It directly modifies +@data+ and returns +self+ to enable method chaining.
74
74
  #
75
75
  # @raise [RuntimeError] if {#columns_of_numbers} has not been called
76
76
  # @return [AocInput] self
@@ -80,6 +80,19 @@ class AocInput
80
80
  self
81
81
  end
82
82
 
83
+ # Returns a new +Grid+ object from the parsed input
84
+ # @return [Grid] the new grid
85
+ def to_grid
86
+ Grid.from_input(@raw_input)
87
+ end
88
+
89
+ # Returns a new +AocInput+ for each section of the raw input, split by the given delimiter.
90
+ # @param delimiter [String] the string used to split sections
91
+ # @return [Array<AocInput>] an array of new AocInput instances initialised with each section of the raw input from +self+
92
+ def sections(delimiter = "\n\n")
93
+ @sections = @raw_input.split(delimiter).map { |section_input| AocInput.new(section_input) }
94
+ end
95
+
83
96
  private
84
97
  def configure_method_access
85
98
  @can_call = {
@@ -0,0 +1,129 @@
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 the value stored at coordinates +(row, column)+ within the grid.
20
+ #
21
+ # Row and column numbers are zero-indexed.
22
+ #
23
+ # @param row [Integer] the row index of the desired cell
24
+ # @param column [Integer] the column index of the desired cell
25
+ def cell(row, column)
26
+ @grid[row][column]
27
+ end
28
+
29
+ # Updates the cell at coordinates +(row, column)+ with the object provided in +value+; returns the given object.
30
+ #
31
+ # @param row [Integer] the row index of the cell you wish to update
32
+ # @param column [Integer] the column index of the cell you wish to update
33
+ # @param value [Object] the object to assign to the selected grid cell
34
+ # @return [Object] the given +value+
35
+ def set_cell(row, column, value)
36
+ @grid[row][column] = value
37
+ end
38
+
39
+ # Returns +true+ if the other grid has the same content in the same orientation, +false+ otherwise.
40
+ #
41
+ # grid = Grid.new([1, 2], [3, 4])
42
+ # grid == Grid.new([1, 2], [3, 4]) # => true
43
+ # grid == Grid.new([0, 1], [2, 3]) # => false
44
+ # grid == "non-grid object" # => false
45
+ #
46
+ # @param other [Grid] the grid you wish to compare with
47
+ # @return [Boolean]
48
+ def ==(other)
49
+ return false unless other.is_a?(self.class)
50
+ @grid == other.instance_variable_get(:@grid)
51
+ end
52
+
53
+ # Returns +true+ if the other grid can be rotated into an orientation where it is equal to +self+, +false+ otherwise.
54
+ #
55
+ # grid = Grid.new([1, 2], [3, 4])
56
+ # grid == Grid.new([1, 2], [3, 4]) # => true
57
+ # grid == Grid.new([3, 1], [4, 2]) # => true
58
+ # grid == Grid.new([1, 2], [4, 3]) # => false
59
+ # grid == "non-grid object" # => false
60
+ #
61
+ # @param other [Grid] the grid you wish to compare with
62
+ def matches_with_rotations?(other)
63
+ other.all_rotations.any? { |rotated| self == rotated }
64
+ end
65
+
66
+ # Returns an array of {Grid} objects in all possible rotations, copied from +self+.
67
+ # @return [Array<Grid>] an array containing four {Grid} objects, one in each possible rotation
68
+ def all_rotations
69
+ rotations = []
70
+ current_grid = self.dup
71
+
72
+ 4.times do
73
+ rotations << current_grid.dup
74
+ current_grid.rotate!
75
+ end
76
+
77
+ rotations
78
+ end
79
+
80
+ # Returns a new {Grid} as a copy of self.
81
+ # @return [Grid] a copy of +self+
82
+ def dup
83
+ Grid.new(@grid)
84
+ end
85
+
86
+ # Updates +self+ with a rotated grid and returns +self+.
87
+ #
88
+ # Will rotate in a clockwise direction by default. Will rotate in an anticlockwise direction if passed
89
+ # a param which is not +:clockwise+.
90
+ #
91
+ # @param direction [Symbol]
92
+ # @return [self]
93
+ def rotate!(direction = :clockwise)
94
+ @grid = direction == :clockwise ? @grid.transpose.map(&:reverse) : @grid.map(&:reverse).transpose
95
+ self
96
+ end
97
+
98
+ # Calls the given block with each subgrid from +self+ with the size constraints provided; returns +self+.
99
+ #
100
+ # Returns an enumerator if no block is given
101
+ #
102
+ # @return [Enumerator] if no block is given.
103
+ # @return [self] after processing the provided block
104
+ # @yield [subgrid] calls the provided block with each subgrid as a new {Grid} object
105
+ # @yieldparam subgrid [Grid] a new {Grid} object containing a subgrid from the main grid
106
+ def each_subgrid(rows, columns)
107
+ return to_enum(__callee__, rows, columns) unless block_given?
108
+ @grid.each_cons(rows) do |rows|
109
+ rows[0].each_cons(columns).with_index do |_, col_index|
110
+ yield Grid.new(rows.map { |row| row[col_index, columns] })
111
+ end
112
+ end
113
+
114
+ self
115
+ end
116
+
117
+ # Returns an array containing all of the subgrids of the specified dimensions.
118
+ # @param rows [Integer] the number of rows each subgrid should contain.
119
+ # Must be greater than zero and less than or equal to the number of rows in the grid.
120
+ # @param columns [Integer] the number of columns each subgrid should contain.
121
+ # Must be greater than zero and less than or equal to the number of columns in the grid.
122
+ # @raise [ArgumentError] if the specified rows or columns are not {Integer} values, or exceed the grid's dimensions.
123
+ # @return [Array<Grid>]
124
+ def subgrids(rows, columns)
125
+ raise ArgumentError unless rows.is_a?(Integer) && rows > 0 && rows <= @grid.length
126
+ raise ArgumentError unless columns.is_a?(Integer) && columns > 0 && columns <= @grid.first.length
127
+ each_subgrid(rows, columns).to_a
128
+ end
129
+ end
@@ -1,3 +1,3 @@
1
1
  module AocRbHelpers
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
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.3
4
+ version: 0.0.4
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-02 00:00:00.000000000 Z
11
+ date: 2024-12-05 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