slippy_tiles_scorer 0.0.2 → 0.0.3

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: 95be9f898e6231b3595f43b3b35baf834e5eba161e78db33b2eb14c7baa19975
4
- data.tar.gz: 785f9286455947d79581de9cef5ffc2cde4ecd8b1860f7ab0494c6ae47386ff9
3
+ metadata.gz: ce623fd11c56fc5615043d62fd196810c7c0caccd5f9d9789dfaa864954ed2ee
4
+ data.tar.gz: 0b7296978405915b2ee53d79da2a8e8c0cc15445f2b71ce5e396ca5fc7af5a39
5
5
  SHA512:
6
- metadata.gz: f9af7b7e325f515220925b5361cb5c20aefc00add5742539d2b0dfd42a5b9f1d996b880a6d739180ac84d9a8715a68b08325ebcf34008a52a311a9cbe5b51899
7
- data.tar.gz: 85ffe608074ddf335004e48dee35feef330bea221de5fdd6f4deab9213df1d266cf29c5edf9d45d07316c588f4d3a62d19e0bd3e7689809cf328375f595a53d2
6
+ metadata.gz: 746ffc5f6d06857aec00c471b3c671612debe31c22a2cdb1d73b1da3583ba253008cbea5e886addf44961019cd2435db6eccb7f70086f182e3cfa3440247a88a
7
+ data.tar.gz: 7e6bacaaab5a06b40d0fee46a3494f436a96b04e042a90bae45ae567ab1860b99499999e66089a372be84d733ae4f15683316748ee1835604c3358acdb3b2da8
data/.rubocop.yml CHANGED
@@ -1,10 +1,19 @@
1
+ require:
2
+ - rubocop-rake
3
+ - rubocop-performance
4
+
1
5
  AllCops:
2
6
  TargetRubyVersion: 3.0
7
+ NewCops: enable
3
8
  Exclude:
4
- '*.gemspec'
9
+ - "*.gemspec"
10
+ - "./vendor/bundle/**/*"
5
11
 
6
12
  Style/StringLiterals:
7
13
  EnforcedStyle: double_quotes
8
14
 
9
15
  Style/StringLiteralsInInterpolation:
10
16
  EnforcedStyle: double_quotes
17
+
18
+ Naming/MethodParameterName:
19
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2024-11-25
3
+ ## [0.0.3] - 2024-11-26
4
+
5
+ - More tests, like a json file with test data.
6
+ - The `Rakefile` can be used to run the tests and check the code style.
7
+ - A CI pipeline runs the test suite and checks the code style for multiple Ruby versions >= v3.
8
+ - Rubocop was configured and some plugins were added to the `.rubocop.yml` file.
9
+
10
+ ## [0.0.2] - 2024-11-26
11
+
12
+ - The result `Hash` of `#clusters` under the key `:clusters` is now an array of `[x, y]` and `x` and `y` being integer values.
13
+
14
+ ## [0.0.1] - 2024-11-25
4
15
 
5
16
  - Initial release
data/Rakefile CHANGED
@@ -6,4 +6,7 @@ RuboCop::RakeTask.new
6
6
 
7
7
  task default: %i[test rubocop]
8
8
 
9
- # TODO: add more tasks here
9
+ desc "Run tests"
10
+ task :test do
11
+ sh "ruby test_runner.rb"
12
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "set"
4
+
3
5
  module SlippyTilesScorer
4
6
  # finds clusters in a collection/tiles_x_y of points (x, y)
5
7
  class Cluster
@@ -12,9 +14,11 @@ module SlippyTilesScorer
12
14
  @clusters = []
13
15
  end
14
16
 
17
+ # @return [Hash] The clusters and the tiles in the clusters.
15
18
  def clusters
16
19
  @tiles_x_y.each do |i|
17
20
  next if visited?(i[0], i[1])
21
+
18
22
  visit!(i[0], i[1])
19
23
  find_cluster_around(i)
20
24
  end
@@ -23,21 +27,21 @@ module SlippyTilesScorer
23
27
 
24
28
  private
25
29
 
30
+ # @param start [Array] The x and y coordinate of the start point.
31
+ # @return [Array<Array<Integer, Integer>>] The cluster of points.
26
32
  def find_cluster_around(start)
27
33
  cluster = []
28
34
  cluster.push(start)
29
35
  todo = [start]
30
36
  broad_search!(todo, cluster)
31
37
 
32
- @clusters.push(cluster) if cluster.size > 0
38
+ @clusters.push(cluster) if cluster.size.positive?
33
39
  cluster
34
40
  end
35
41
 
36
- def neighbors_up_down_left_right?(neighbors)
37
- neighbors.all? { |n| @tiles_x_y.include?(n) }
38
- end
39
-
40
- def broad_search!(todo, cluster) # rubocop:disable Metrics/MethodLength
42
+ # @param todo [Array] The points to visit.
43
+ # @param cluster [Array] The cluster of points.
44
+ def broad_search!(todo, cluster) # rubocop:disable Metrics/CyclomaticComplexity
41
45
  until todo.empty?
42
46
  point = todo.pop
43
47
  neighbors = neighbor_points(*point)
@@ -45,20 +49,36 @@ module SlippyTilesScorer
45
49
  neighbors.each do |neighbor|
46
50
  next if visited?(neighbor[0], neighbor[1])
47
51
  next unless @tiles_x_y.include?(neighbor)
52
+
48
53
  visit!(*neighbor) && todo.push(neighbor) && cluster.push(neighbor)
49
54
  end
50
55
  end
51
56
  end
52
57
 
58
+ # @param x [Integer] The x coordinate of the point.
59
+ # @param y [Integer] The y coordinate of the point.
60
+ # @return [Boolean] True if the point is visited.
53
61
  def visit!(x, y)
54
62
  @visited[x] ||= {}
55
63
  @visited[x][y] = true
56
64
  end
57
65
 
66
+ # @param x [Integer] The x coordinate of the point.
67
+ # @param y [Integer] The y coordinate of the point.
68
+ # @return [Boolean|Nil] True if the point is visited.
58
69
  def visited?(x, y)
59
70
  @visited.dig(x, y)
60
71
  end
61
72
 
73
+ # @param neighbors [Array] The neighbors of the point.
74
+ # @return [Boolean] True if all neighbors are in the tiles_x_y.
75
+ def neighbors_up_down_left_right?(neighbors)
76
+ neighbors.all? { |n| @tiles_x_y.include?(n) }
77
+ end
78
+
79
+ # @param x [Integer] The x coordinate of the point.
80
+ # @param y [Integer] The y coordinate of the point.
81
+ # @return [Array<Array<Integer, Integer>>] The neighbors of the point.
62
82
  def neighbor_points(x, y)
63
83
  [[x - 1, y], [x + 1, y], [x, y + 1], [x, y - 1]]
64
84
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "set"
4
+
3
5
  module SlippyTilesScorer
4
6
  # finds the maximum square in a collection/tiles_x_y of points (x, y)
5
7
  class MaxSquare
@@ -15,43 +17,55 @@ module SlippyTilesScorer
15
17
  # @return [Hash] The size of the square and the points of the square.
16
18
  def max_squares(min_size: 3)
17
19
  @max_size_found = 0
18
- raise ArgumentError, 'min_size must be 2 or greater' if min_size < 2
20
+ raise ArgumentError, "min_size must be 2 or greater" if min_size < 2
21
+
22
+ result = max_square_result(min_size: min_size)
23
+ @max_size_found = 0
24
+ @tiles_lut = nil
25
+ result
26
+ end
19
27
 
28
+ # @param min_size [Integer] The minimum size of the square, should be 3 or greater.
29
+ # @return [Hash] The size of the square and the points of the square.
30
+ def max_square_result(min_size: 3)
20
31
  result = { size: @max_size_found, top_left_tile_x_y: Set.new }
21
32
  @tiles_x_y.each do |(x, y)|
22
- raise ArgumentError, 'x and y must be greater than or equal to 0' if x.negative? || y.negative?
33
+ raise ArgumentError, "x and y must be greater than or equal to 0" if x.negative? || y.negative?
23
34
 
24
35
  steps = max_square(x: x, y: y)
25
- next if steps < min_size
26
- if steps > @max_size_found
27
- @max_size_found = steps
28
- result = { size: @max_size_found, top_left_tile_x_y: Set.new }
29
- track_result(result: result, steps: steps, x: x, y: y)
30
- elsif steps == @max_size_found
31
- result ||= { size: @max_size_found, top_left_tile_x_y: Set.new }
32
- track_result(result: result, steps: steps, x: x, y: y)
33
- end
36
+ result = track_result(result: result, steps: steps, x: x, y: y) if steps >= min_size
34
37
  end
35
- @tiles_lut = nil
36
38
  result
37
39
  end
38
40
 
39
- def max_square(x:, y:) # rubocop:disable Naming/MethodParameterName
41
+ # @param x [Integer] The x coordinate of the top left tile.
42
+ # @param y [Integer] The y coordinate of the top left tile.
43
+ # @return [Integer] The size of the square.
44
+ def max_square(x:, y:)
40
45
  steps = 1
41
46
  steps += 1 while steps_fulfilled?(x: x, y: y, steps: steps)
42
47
  steps
43
48
  end
44
49
 
45
- def steps_fulfilled?(x:, y:, steps:) # rubocop:disable Naming/MethodParameterName
50
+ # @param x [Integer] The x coordinate of the top left tile.
51
+ # @param y [Integer] The y coordinate of the top left tile.
52
+ # @param steps [Integer] The size of the square.
53
+ # @return [Boolean] True if all steps are fulfilled.
54
+ def steps_fulfilled?(x:, y:, steps:)
46
55
  in_lut?(x: x + steps, y: y + steps) &&
47
- (0...steps).all? do |i|
48
- in_lut?(x: x + steps, y: y + i) &&
49
- in_lut?(x: x + i, y: y + steps)
50
- end
56
+ (0...steps).all? do |i|
57
+ in_lut?(x: x + steps, y: y + i) &&
58
+ in_lut?(x: x + i, y: y + steps)
59
+ end
51
60
  end
52
61
 
53
62
  private
54
63
 
64
+ # This is as fast as it gets! Do not implement `#nil?
65
+ #
66
+ # @param x [Integer] The x coordinate of the top left tile.
67
+ # @param y [Integer] The y coordinate of the top left tile.
68
+ # @return [Boolean|Nil] True if the tile is in the tiles_lut.
55
69
  def in_lut?(x:, y:)
56
70
  unless @tiles_lut
57
71
  @tiles_lut = {}
@@ -63,7 +77,28 @@ module SlippyTilesScorer
63
77
  @tiles_lut.dig(x, y)
64
78
  end
65
79
 
66
- def track_result(result:, steps:, x:, y:) # rubocop:disable Naming/MethodParameterName
80
+ # @param result [Hash] The result hash.
81
+ # @param steps [Integer] The size of the square.
82
+ # @param x [Integer] The x coordinate of the top left tile.
83
+ # @param y [Integer] The y coordinate of the top left tile.
84
+ # @return [Hash] The updated result hash.
85
+ def track_result(result:, steps:, x:, y:)
86
+ if steps > @max_size_found
87
+ @max_size_found = steps
88
+ result = { size: @max_size_found, top_left_tile_x_y: Set.new }
89
+ update_result!(result: result, steps: steps, x: x, y: y)
90
+ elsif steps == @max_size_found
91
+ update_result!(result: result, steps: steps, x: x, y: y)
92
+ end
93
+ result
94
+ end
95
+
96
+ # @param result [Hash] The result hash.
97
+ # @param steps [Integer] The size of the square.
98
+ # @param x [Integer] The x coordinate of the top left tile.
99
+ # @param y [Integer] The y coordinate of the top left tile.
100
+ # @return [Hash] The updated result hash.
101
+ def update_result!(result:, steps:, x:, y:)
67
102
  result[:size] = steps
68
103
  result[:top_left_tile_x_y] << [x, y]
69
104
  result
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SlippyTilesScorer
4
- VERSION = "0.0.2"
4
+ VERSION = "0.0.3"
5
5
  end
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "set"
3
4
  require_relative "slippy_tiles_scorer/version"
4
- require_relative "./slippy_tiles_scorer/cluster"
5
- require_relative "./slippy_tiles_scorer/max_square"
5
+ require_relative "slippy_tiles_scorer/cluster"
6
+ require_relative "slippy_tiles_scorer/max_square"
6
7
 
7
8
  module SlippyTilesScorer
8
9
  class Error < StandardError; end
@@ -17,11 +18,9 @@ module SlippyTilesScorer
17
18
 
18
19
  def valid?
19
20
  return true if @tiles_x_y.empty?
20
-
21
21
  raise ArgumentError, "@tiles_x_y must be a Set" unless @tiles_x_y.is_a?(Set)
22
22
 
23
- set_of_arrays?
24
- set_of_arrays_of_integers?
23
+ set_of_arrays? && set_of_arrays_of_integers?
25
24
  end
26
25
 
27
26
  def clusters(tiles_x_y: @tiles_x_y)
@@ -32,7 +31,7 @@ module SlippyTilesScorer
32
31
  result
33
32
  end
34
33
 
35
- def max_square(x:, y:, tiles_x_y: @tiles_x_y) # rubocop:disable Naming/MethodParameterName
34
+ def max_square(x:, y:, tiles_x_y: @tiles_x_y)
36
35
  SlippyTilesScorer::MaxSquare.new(tiles_x_y: tiles_x_y).max_square(x: x, y: y)
37
36
  end
38
37
 
@@ -40,7 +39,7 @@ module SlippyTilesScorer
40
39
  SlippyTilesScorer::MaxSquare.new(tiles_x_y: tiles_x_y).max_squares(min_size: min_size)
41
40
  end
42
41
 
43
- def steps_fulfilled?(x:, y:, steps:) # rubocop:disable Naming/MethodParameterName
42
+ def steps_fulfilled?(x:, y:, steps:)
44
43
  SlippyTilesScorer::MaxSquare.new(tiles_x_y: @tiles_x_y).steps_fulfilled?(x: x, y: y, steps: steps)
45
44
  end
46
45
 
@@ -51,13 +50,13 @@ module SlippyTilesScorer
51
50
  private
52
51
 
53
52
  def set_of_arrays?
54
- return if @tiles_x_y.all? { |point| point.is_a?(Array) && point.size == 2 }
53
+ return true if @tiles_x_y.all? { |point| point.is_a?(Array) && point.size == 2 }
55
54
 
56
55
  raise ArgumentError, "each point must be an array with two elements"
57
56
  end
58
57
 
59
58
  def set_of_arrays_of_integers?
60
- return if @tiles_x_y.all? { |point| point.all? { |coord| coord.is_a?(Integer) } }
59
+ return true if @tiles_x_y.all? { |point| point.all?(Integer) }
61
60
 
62
61
  raise ArgumentError, "each point must be an array with two integers"
63
62
  end
data/test_helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SlippyTilesScorer
4
+ # TestHelper class to help with testing
5
+ class TestHelper
6
+ class << self
7
+ def stub_tiles_x_y(service:, size: 50)
8
+ service.tiles_x_y = Set.new
9
+ (0...size).each do |i|
10
+ (0...size).each do |j|
11
+ service.tiles_x_y.add([i, j])
12
+ end
13
+ end
14
+ service
15
+ end
16
+ end
17
+ end
18
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slippy_tiles_scorer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Neutert
@@ -9,7 +9,21 @@ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
11
  date: 2024-11-26 00:00:00.000000000 Z
12
- dependencies: []
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: set
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
13
27
  description: For a given set of slippy tiles, this gem calculates the score of the
14
28
  tiles, like total tiles, clusters and max squares.
15
29
  email:
@@ -27,6 +41,7 @@ files:
27
41
  - lib/slippy_tiles_scorer/max_square.rb
28
42
  - lib/slippy_tiles_scorer/version.rb
29
43
  - sig/slippy_tiles_scorer.rbs
44
+ - test_helper.rb
30
45
  homepage: https://github.com/simonneutert/slippy_tiles_scorer
31
46
  licenses: []
32
47
  metadata: