aoc_rb_helpers 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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