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 +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
|