slippy_tiles_scorer 0.0.1 → 0.0.2

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: 3535ebc0ef81b4b9096043ac739f65877a793c82e9f115f4faa16339184c359c
4
- data.tar.gz: f0375a478ee6603038e12fc15f55ecf320c161d2764d30fbd362908bfaf763b9
3
+ metadata.gz: 95be9f898e6231b3595f43b3b35baf834e5eba161e78db33b2eb14c7baa19975
4
+ data.tar.gz: 785f9286455947d79581de9cef5ffc2cde4ecd8b1860f7ab0494c6ae47386ff9
5
5
  SHA512:
6
- metadata.gz: 0df4fbebb75b3f9b3a4019490695d6ae81e9d59498a1479f72f63f92de17ad756b1e1776787025e06cebeff2770aab067faff79aa6f6a2053757daf7972d5a34
7
- data.tar.gz: 1c5b8bc92a68023c2fb8fbd84f9bba559eeb1b5eec26b757b7310c22a0aacbf316700736f4c814b31e2871a57b279f26d951d576d8861104c5b2460e10771a6e
6
+ metadata.gz: f9af7b7e325f515220925b5361cb5c20aefc00add5742539d2b0dfd42a5b9f1d996b880a6d739180ac84d9a8715a68b08325ebcf34008a52a311a9cbe5b51899
7
+ data.tar.gz: 85ffe608074ddf335004e48dee35feef330bea221de5fdd6f4deab9213df1d266cf29c5edf9d45d07316c588f4d3a62d19e0bd3e7689809cf328375f595a53d2
data/README.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # SlippyTilesScorer
2
2
 
3
+ > [!NOTE]
4
+ > This gem's API is not considered stable yet.
5
+ > Things might change in the future.
6
+
7
+ [![Gem Version](https://badge.fury.io/rb/slippy_tiles_scorer.svg)](https://badge.fury.io/rb/slippy_tiles_scorer) \
8
+ [![Ruby](https://github.com/simonneutert/slippy_tiles_scorer/actions/workflows/main.yml/badge.svg)](https://github.com/simonneutert/slippy_tiles_scorer/actions/workflows/main.yml)
9
+
3
10
  Calculate scores of map tiles (x, y) on a map. The scores are total, (max)
4
11
  clusters, and max squares.
5
12
 
@@ -7,18 +14,16 @@ To experiment with that code, run `bin/console` for an interactive prompt.
7
14
 
8
15
  ## Installation
9
16
 
10
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
11
-
12
17
  Install the gem and add to the application's Gemfile by executing:
13
18
 
14
19
  ```bash
15
- bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
20
+ bundle add slippy_tiles_scorer
16
21
  ```
17
22
 
18
23
  If bundler is not being used to manage dependencies, install the gem by executing:
19
24
 
20
25
  ```bash
21
- gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
26
+ gem install slippy_tiles_scorer
22
27
  ```
23
28
 
24
29
  ## Usage
@@ -43,7 +48,7 @@ collection_of_tiles.add([2, 0])
43
48
  collection_of_tiles.add([2, 1])
44
49
  collection_of_tiles.add([2, 2])
45
50
 
46
- tile_scorer = SlippyTilesScorer::Scorer.new(tiles_x_y: collection_of_tiles)
51
+ tile_scorer = SlippyTilesScorer::Score.new(tiles_x_y: collection_of_tiles)
47
52
  tile_scorer.valid? # => true
48
53
 
49
54
  # the collection_of_tiles is a 3x3 map and will be used to calculate scores,
@@ -55,15 +60,17 @@ tile_scorer.visited # => 9
55
60
  tile_scorer.clusters # =>
56
61
  # {
57
62
  # :clusters=>[
58
- # <Set: {[0, 0], [1, 0], [0, 1], [1, 1], [0, 2], [1, 2], [2, 2], [2, 1], [2, 0]}>
63
+ # [
64
+ # [0, 0], [1, 0], [0, 1], [1, 1], [0, 2], [1, 2], [2, 2], [2, 1], [2, 0]
65
+ # ]
59
66
  # ],
60
67
  # :cluster_tiles=>#<Set: {[1, 1]}>,
61
- # :clusters_of_cluster_tiles=>[]
68
+ # :clusters_of_cluster_tiles=>[[[1, 1]]]
62
69
  # }
63
70
 
64
71
  # calculate max squares
65
- tile_scorer.max_squares # => {:size=>3, top_left_tile_x_y=>#<Set: {[0, 0]}>}
66
- tile_scorer.max_squares(min_size: 4) # => {:size=>4, top_left_tile_x_y=>#<Set: {}>}
72
+ tile_scorer.max_squares # => {:size=>0, top_left_tile_x_y=>#<Set: {[0, 0]}>}
73
+ tile_scorer.max_squares(min_size: 4) # => {:size=>0, top_left_tile_x_y=>#<Set: {}>}
67
74
  ```
68
75
 
69
76
  ### Optimized
@@ -72,7 +79,7 @@ An more computationally optimized example of how to use the `TileScorer` class,
72
79
 
73
80
  ```ruby
74
81
  ### OPTIMIZE COMPUTATION ###
75
- tile_scorer = SlippyTilesScorer::Scorer.new(tiles_x_y: collection_of_tiles)
82
+ tile_scorer = SlippyTilesScorer::Score.new(tiles_x_y: collection_of_tiles)
76
83
  # Optimize computation by calculating clusters first,
77
84
  result_clusters = tile_scorer.clusters
78
85
  clusters = result_clusters[:clusters]
@@ -6,18 +6,17 @@ module SlippyTilesScorer
6
6
  attr_accessor :tiles_x_y
7
7
 
8
8
  def initialize(tiles_x_y: Set.new)
9
- @tiles_x_y = Marshal.load(Marshal.dump(tiles_x_y))
9
+ @tiles_x_y = tiles_x_y
10
10
  @cluster_tiles = Set.new
11
- @visited = Set.new
11
+ @visited = {}
12
12
  @clusters = []
13
13
  end
14
14
 
15
15
  def clusters
16
- while @tiles_x_y.any?
17
- start = @tiles_x_y.first
18
- @tiles_x_y.delete(start)
19
- @visited.add(start)
20
- find_cluster_around(start)
16
+ @tiles_x_y.each do |i|
17
+ next if visited?(i[0], i[1])
18
+ visit!(i[0], i[1])
19
+ find_cluster_around(i)
21
20
  end
22
21
  { clusters: @clusters, cluster_tiles: @cluster_tiles }
23
22
  end
@@ -25,44 +24,43 @@ module SlippyTilesScorer
25
24
  private
26
25
 
27
26
  def find_cluster_around(start)
28
- cluster = Set.new
29
- cluster.add(start)
27
+ cluster = []
28
+ cluster.push(start)
30
29
  todo = [start]
30
+ broad_search!(todo, cluster)
31
31
 
32
- cluster = broad_search(todo, cluster)
33
-
34
- @clusters.push(cluster) if cluster.size > 1
32
+ @clusters.push(cluster) if cluster.size > 0
35
33
  cluster
36
34
  end
37
35
 
38
36
  def neighbors_up_down_left_right?(neighbors)
39
- neighbors.all? { |n| @tiles_x_y.include?(n) || @visited.include?(n) }
37
+ neighbors.all? { |n| @tiles_x_y.include?(n) }
40
38
  end
41
39
 
42
- def broad_search(todo, cluster) # rubocop:disable Metrics/MethodLength
40
+ def broad_search!(todo, cluster) # rubocop:disable Metrics/MethodLength
43
41
  until todo.empty?
44
42
  point = todo.pop
45
43
  neighbors = neighbor_points(*point)
46
-
47
- next if neighbors.empty?
48
-
49
- @cluster_tiles.add(point) if neighbors_up_down_left_right?(neighbors)
44
+ neighbors_up_down_left_right?(neighbors) && @cluster_tiles.add(point)
50
45
  neighbors.each do |neighbor|
46
+ next if visited?(neighbor[0], neighbor[1])
51
47
  next unless @tiles_x_y.include?(neighbor)
52
- next if @visited.include?(neighbor)
53
-
54
- @visited.add(neighbor)
55
- cluster.add(neighbor)
56
- todo.push(neighbor)
48
+ visit!(*neighbor) && todo.push(neighbor) && cluster.push(neighbor)
57
49
  end
58
50
  end
59
- cluster
60
51
  end
61
52
 
62
- def neighbor_points(x, y) # rubocop:disable Naming/MethodParameterName
63
- res = Set.new
64
- [[x - 1, y], [x + 1, y], [x, y + 1], [x, y - 1]].each { |point| res.add(point) }
65
- res
53
+ def visit!(x, y)
54
+ @visited[x] ||= {}
55
+ @visited[x][y] = true
56
+ end
57
+
58
+ def visited?(x, y)
59
+ @visited.dig(x, y)
60
+ end
61
+
62
+ def neighbor_points(x, y)
63
+ [[x - 1, y], [x + 1, y], [x, y + 1], [x, y - 1]]
66
64
  end
67
65
  end
68
66
  end
@@ -6,22 +6,33 @@ module SlippyTilesScorer
6
6
  attr_accessor :tiles_x_y
7
7
 
8
8
  def initialize(tiles_x_y: Set.new)
9
- @tiles_x_y = Marshal.load(Marshal.dump(tiles_x_y))
9
+ @tiles_x_y = tiles_x_y
10
+ @tiles_lut = nil
10
11
  end
11
12
 
12
13
  # @param min_size [Integer] The minimum size of the square, should be 3 or greater.
13
14
  # As the smallest square is 3x3 and therefor a cluster tile needs to be the center.
14
15
  # @return [Hash] The size of the square and the points of the square.
15
16
  def max_squares(min_size: 3)
17
+ @max_size_found = 0
16
18
  raise ArgumentError, 'min_size must be 2 or greater' if min_size < 2
17
19
 
18
- result = { size: min_size, top_left_tile_x_y: Set.new }
20
+ result = { size: @max_size_found, top_left_tile_x_y: Set.new }
19
21
  @tiles_x_y.each do |(x, y)|
20
22
  raise ArgumentError, 'x and y must be greater than or equal to 0' if x.negative? || y.negative?
21
23
 
22
24
  steps = max_square(x: x, y: y)
23
- track_result(result: result, steps: steps, x: x, y: y) if steps >= min_size
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
24
34
  end
35
+ @tiles_lut = nil
25
36
  result
26
37
  end
27
38
 
@@ -32,23 +43,29 @@ module SlippyTilesScorer
32
43
  end
33
44
 
34
45
  def steps_fulfilled?(x:, y:, steps:) # rubocop:disable Naming/MethodParameterName
35
- @tiles_x_y.include?([x + steps, y + steps]) &&
36
- (0...steps).all? do |i|
37
- @tiles_x_y.include?([x + steps, y + i]) &&
38
- @tiles_x_y.include?([x + i, y + steps])
39
- end
46
+ 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
40
51
  end
41
52
 
42
53
  private
43
54
 
44
- def track_result(result:, steps:, x:, y:) # rubocop:disable Naming/MethodParameterName
45
- if steps > result[:size]
46
- result[:size] = steps
47
- result[:top_left_tile_x_y] = Set.new
48
- result[:top_left_tile_x_y] << [x, y]
49
- elsif steps == result[:size]
50
- result[:top_left_tile_x_y] << [x, y]
55
+ def in_lut?(x:, y:)
56
+ unless @tiles_lut
57
+ @tiles_lut = {}
58
+ @tiles_x_y.each do |(x, y)|
59
+ @tiles_lut[x] ||= {}
60
+ @tiles_lut[x][y] = true
61
+ end
51
62
  end
63
+ @tiles_lut.dig(x, y)
64
+ end
65
+
66
+ def track_result(result:, steps:, x:, y:) # rubocop:disable Naming/MethodParameterName
67
+ result[:size] = steps
68
+ result[:top_left_tile_x_y] << [x, y]
52
69
  result
53
70
  end
54
71
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SlippyTilesScorer
4
- VERSION = "0.0.1"
4
+ VERSION = "0.0.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slippy_tiles_scorer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Neutert
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-25 00:00:00.000000000 Z
11
+ date: 2024-11-26 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: For a given set of slippy tiles, this gem calculates the score of the
14
14
  tiles, like total tiles, clusters and max squares.