ruby-perlin-2D-map-generator 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/town_generator.rb +53 -27
  4. metadata +6 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8bef2e8554e39c0e315b940f4a98a8927348ae576a7f12168c86c74f969c241b
4
- data.tar.gz: b3debfe8269979c1f1f0be2a8def6a86de9fcd2a8ad6f548295113068ec04566
3
+ metadata.gz: 25ba5741714e7132250486cdb48c6d0114e858aa272bdb68d90289af12643e3a
4
+ data.tar.gz: cc4ffc80e85167443d92fbf0755c7a70db4e5ef9cb824e86b98ec83792d82715
5
5
  SHA512:
6
- metadata.gz: c91f9810eda61b360e26b31944820b2587ff9e6a10776cdc84347475470573b381853e63b629781fbc0f18eb9fc33299fad31e2a436ef7f7a66d67db8dbb2ea2
7
- data.tar.gz: 8c12388e0e7965165557bc5680f030d6d2da9a42e35cc066fbff2390de0e6076c2318e7d62000d17026fa91206adb1ff631eff0ff6af5d670ef81e3d206e45a0
6
+ metadata.gz: b613588fb06e7bc82af707823e7a1b69b95a3fa670f337577c310bcdcd149b1a58610ae4673ac65b5d7d1415536d9e2c231b9265dbaf3b084060108a45b77e06
7
+ data.tar.gz: 1d7aaf0819fdf911705d0b18dfc480915a2869bbe994db13d9f91d43a861d14b1a9235f0823ff9d0c4cfb5f08f38267dc39ed49f8ef7544136622f8167069ad8
data/README.md CHANGED
@@ -73,7 +73,7 @@ See Command line Usage for full customization, below are some examples. Alter th
73
73
  Roads can be generated by providing a positive integer to the `roads=` argument. Roads are randomly seeded to begin
74
74
  and start at an axis (but not the same axis).
75
75
 
76
- A* pathfinding with a priority queue is used to generate the roads. The heuristic uses manhattan distance, and favours existing roads and similar elevations in adjacent tiles.
76
+ A* pathfinding with a priority queue, along with prim's algorithn and a minimum spanning tree is used to generate the roads. The heuristic uses manhattan distance, and favours existing roads and similar elevations in adjacent tiles.
77
77
 
78
78
  Roads can be configured to include/exclude generating paths thorugh water, mountains and flora.
79
79
 
@@ -8,6 +8,7 @@ require 'map_config'
8
8
  #
9
9
  # Generates building tile items using Poisson Disk Sampling for the given tiles
10
10
  # Roads are generated between the buildings and between towns using A* pathfinding
11
+ # and a minimum tree spanning algorithm
11
12
  #
12
13
  class TownGenerator
13
14
  attr_reader :sample_area, :road_generator
@@ -81,25 +82,66 @@ class TownGenerator
81
82
  end
82
83
 
83
84
  def generate_town_roads(points, town_num, verbose)
84
- # TODO: slow, bad (complete graph) will update to use minimum tree spanning algorithm instead
85
85
  puts "generating town #{town_num} roads..." if verbose
86
86
 
87
+ generate_roads_from_connected_pairs(build_minimum_spanning_tree(points, populate_distances_between_each_point(points)))
88
+ end
89
+
90
+ def generate_roads_from_connected_pairs(connected_pairs)
91
+ connected_pairs.each do |edge|
92
+ road_to_building_one = place_in_front_or_behind(edge.first)
93
+ road_to_building_two = place_in_front_or_behind(edge.last)
94
+
95
+ next if road_to_building_one.nil? || road_to_building_two.nil?
96
+
97
+ road_generator.generate_roads_from_coordinate_list(road_to_building_one.concat(road_to_building_two), false)
98
+ end
99
+ end
100
+
101
+ def build_minimum_spanning_tree(points, distances)
87
102
  connected_pairs = Set.new
103
+ visited = Set.new([points.first]) # Create a set to keep track of visited nodes
104
+ until visited.size == points.size
105
+ edge = find_minimum_edge(distances, visited)
106
+ connected_pairs.add(edge)
107
+ visited.add(edge.last)
108
+ end
109
+ connected_pairs
110
+ end
111
+
112
+ def populate_distances_between_each_point(points)
113
+ distances = {}
88
114
  points.each_with_index do |point_one, idx_one|
89
115
  points[idx_one + 1..].each do |point_two|
90
- next if connected_pairs.include?([point_one, point_two]) || connected_pairs.include?([point_two, point_one])
116
+ distance = calculate_distance(point_one, point_two)
117
+ distances[[point_one, point_two]] = distance
118
+ distances[[point_two, point_one]] = distance
119
+ end
120
+ end
121
+ distances
122
+ end
91
123
 
92
- road_to_building_one = place_in_front_or_behind(point_one)
93
- road_to_building_two = place_in_front_or_behind(point_two)
124
+ def calculate_distance(point1, point2)
125
+ Math.sqrt((point1.y - point2.y)**2 + (point1.x - point2.x)**2)
126
+ end
94
127
 
95
- connected_pairs.add([point_one, point_two])
96
- connected_pairs.add([point_two, point_one])
128
+ def find_minimum_edge(distances, visited)
129
+ # method to find the minimum edge connecting visited and unvisited nodes
130
+ min_edge = nil
131
+ min_distance = Float::INFINITY
97
132
 
98
- next if road_to_building_one.nil? || road_to_building_two.nil?
133
+ visited.each do |visited_node|
134
+ distances.each do |edge, distance|
135
+ next if visited.include?(edge.last) || edge.first != visited_node
99
136
 
100
- road_generator.generate_roads_from_coordinate_list(road_to_building_one.concat(road_to_building_two), false)
137
+ if distance < min_distance
138
+ min_distance = distance
139
+ min_edge = edge
140
+ end
101
141
  end
102
142
  end
143
+
144
+ min_edge
103
145
  end
104
146
 
105
147
  def place_in_front_or_behind(point)
@@ -116,24 +158,8 @@ class TownGenerator
116
158
 
117
159
  puts 'generating roads between towns...' if verbose
118
160
 
119
- connected_pairs = Set.new
120
- town_centroids = {}
121
-
122
- @all_town_points.each_with_index do |town_one, idx_one|
123
- find_town_centroid(town_one)
124
-
125
- @all_town_points[idx_one + 1..].each do |town_two|
126
- next if connected_pairs.include?([town_one, town_two]) || connected_pairs.include?([town_two, town_one])
127
-
128
- town_one_center_x, town_one_center_y = (town_centroids[town_one] ||= find_town_centroid(town_one))
129
- town_two_center_x, town_two_center_y = (town_centroids[town_two] ||= find_town_centroid(town_two))
130
-
131
- road_generator.generate_roads_from_coordinate_list([town_one_center_x, town_one_center_y, town_two_center_x, town_two_center_y], false)
132
-
133
- connected_pairs.add([town_one, town_two])
134
- connected_pairs.add([town_two, town_one])
135
- end
136
- end
161
+ centroids = @all_town_points.map { |town_points| find_town_centroid(town_points) }
162
+ generate_roads_from_connected_pairs(build_minimum_spanning_tree(centroids, populate_distances_between_each_point(centroids)))
137
163
  end
138
164
 
139
165
  def find_town_centroid(points)
@@ -149,6 +175,6 @@ class TownGenerator
149
175
  average_x = total_x / num_coordinates.to_f
150
176
  average_y = total_y / num_coordinates.to_f
151
177
 
152
- [average_x, average_y]
178
+ OpenStruct.new(x: average_x, y: average_y)
153
179
  end
154
180
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-perlin-2D-map-generator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Matthews (matthewstyler)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-15 00:00:00.000000000 Z
11
+ date: 2023-12-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: perlin
@@ -86,28 +86,28 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 13.0.6
89
+ version: 13.1.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 13.0.6
96
+ version: 13.1.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 1.56.0
103
+ version: 1.58.0
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 1.56.0
110
+ version: 1.58.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: simplecov
113
113
  requirement: !ruby/object:Gem::Requirement