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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +17 -1
- data/lib/aoc_rb_helpers/aoc_input.rb +25 -12
- data/lib/aoc_rb_helpers/grid.rb +129 -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: ab9f12989f97afbeb704d8439ba020351f1288f8519683aaca95cae2cadb5d47
|
4
|
+
data.tar.gz: ddfc599e4d027bb4b55e2b6d83b02c3ce19146d01a37345ac59487ea9272ec6c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
@@ -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
|
42
|
-
# then converting each resulting element to an integer. It modifies
|
43
|
-
# chaining by returning
|
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
|
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
|
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
|
70
|
+
# Sorts each array within the +@data+ array.
|
71
71
|
#
|
72
|
-
# This method processes
|
73
|
-
# It directly modifies
|
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
|
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.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-
|
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
|