Skip to content

Commit

Permalink
Merge pull request #5 from matthewstyler/tm/roads
Browse files Browse the repository at this point in the history
Roads
  • Loading branch information
matthewstyler committed Aug 8, 2023
2 parents 0f31912 + 76ece5e commit a06db4f
Show file tree
Hide file tree
Showing 20 changed files with 735 additions and 76 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
*.a
mkmf.log
Gemfile.lock
.irb_history
8 changes: 8 additions & 0 deletions .irbrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

def require_all_files(directory)
Dir["#{directory}/**/*.rb"].each { |file| require file }
end

# Require all files in the project_root directory and its subdirectories
require_all_files(File.expand_path(__dir__))
6 changes: 5 additions & 1 deletion .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ Metrics/AbcSize:
Metrics/ClassLength:
Exclude:
- 'lib/CLI/command.rb'
Max: 197
- 'lib/biome.rb'
- 'test/**/*'
Max: 150

# Offense count: 2
# Configuration parameters: AllowedMethods, AllowedPatterns.
Expand All @@ -45,6 +47,8 @@ Metrics/MethodLength:
# Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
Metrics/ParameterLists:
Max: 6
Exclude:
- 'lib/tile.rb'

# Offense count: 2
# Configuration parameters: AllowedMethods, AllowedPatterns.
Expand Down
124 changes: 85 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
![CodeQL](https://github.com/matthewstyler/ruby-perlin-2D-map-generator/workflows/CodeQL/badge.svg)
[![Downloads](https://img.shields.io/gem/dt/ruby-perlin-2D-map-generator.svg?style=flat)](https://rubygems.org/gems/ruby-perlin-2D-map-generator)

A gem that procedurally generates seeded and customizable 2D map using perlin noise.
A gem that procedurally generates seeded and customizable 2D map with optional roads using perlin noise.

Include the gem in your project, or use the executable from the command line.

Expand Down Expand Up @@ -34,6 +34,7 @@ gem install ruby-perlin-2D-map-generator
See Command line Usage for full customization, below are some examples. Alter the temperature, moisture or elevation seeds to alter these maps:

- Plains with random terrain evens: `ruby-perlin-2D-map-generator render`
- Plains with random terrain events and two roads: `ruby-perlin-2D-map-generator render --roads=2`
- Desert (increase temperature, decrease moisture): `ruby-perlin-2D-map-generator render --temp=100 --moisture=-100`
- Mountainous with lakes (increase elevation, increase moisture) `ruby-perlin-2D-map-generator render --elevation=25 --moisture=25`
- Islands (decreaes elevation, increase moisture): `ruby-perlin-2D-map-generator render --elevation=-40 --moisture=25`
Expand All @@ -44,21 +45,39 @@ See Command line Usage for full customization, below are some examples. Alter th
--width=int The width of the generated map (default 128)
--height=int The height of the generated map (default 128)

--roads=int Add this many roads through the map,
starting and ending at edges
(default 0)

--hs=int The seed for a terrains height perlin generation
(default 10)
--ms=int The seed for a terrains moist perlin generation
(default 300)
--ts=int The seed for a terrains temperature perlin generation
(default 3000)
--rs=int The seed for generating roads
(default 100)

--elevation=float Adjust each generated elevation by this percent (0 -
--elevation=float Adjust each generated elevation by this percent (-100 -
100) (default 0.0)
--moisture=float Adjust each generated moisture by this percent (0 -
--moisture=float Adjust each generated moisture by this percent (-100 -
100) (default 0.0)
--temp=float Adjust each generated temperature by this percent (0
--temp=float Adjust each generated temperature by this percent (-100
- 100) (default 0.0)
```

## Roads and the heuristic
Roads can be generated by providing a positive integer to the `roads=` argument. Roads are randomly seeded to begin
and start at an axis (but not the same axis).

A* pathfinding is used to generate the roads with a heuristic that uses manhattan distance, favours existing roads and similar elevations in adjacent tiles.

Roads can be configured to include/exclude generating paths thorugh water, mountains and flora.

Tiles containing roads are of type `road`, those without are of type `terrain`.

The `--roads_to_make` option allows you to specify multiple pairs of coordinates to attempt to build paths, subject to the heuristic and other option constraints. Expects a a single list, but must be sets of 4, example of two roads: `--roads_to_make=0,0,50,50,0,0,75,75`

# Generate without rendering

```irb
Expand Down Expand Up @@ -112,7 +131,7 @@ $ ruby-perlin-2D-map-generator --help
```bash
Usage: ruby-perlin-2D-map-generator [OPTIONS] (DESCRIBE | RENDER)

Generate a seeded customizable procedurally generated 2D map.
Generate a seeded customizable procedurally generated 2D map with optional roads.
Rendered in the console using ansi colours, or described as a 2D array of
hashes with each tiles information.

Expand All @@ -128,47 +147,74 @@ Keywords:
coordinate tile details

Options:
--elevation=float Adjust each generated elevation by this percent (0 -
100) (default 0.0)
--fhx=float The frequency for height generation across the x-axis
(default 2.5)
--fhy=float The frequency for height generation across the y-axis
(default 2.5)
--fmx=float The frequency for moist generation across the x-axis
(default 2.5)
--fmy=float The frequency for moist generation across the y-axis
(default 2.5)
--ftx=float The frequency for temp generation across the x-axis
(default 2.5)
--fty=float The frequency for temp generation across the y-axis
(default 2.5)
--gf=bool Generate flora, significantly affects performance
--height=int The height of the generated map (default 128)
-h, --help Print usage
--hs=int The seed for a terrains height perlin generation
(default 10)
--moisture=float Adjust each generated moisture by this percent (0 -
100) (default 0.0)
--ms=int The seed for a terrains moist perlin generation
(default 300)
--oh=int Octaves for height generation (default 3)
--om=int Octaves for moist generation (default 3)
--ot=int Octaves for temp generation (default 3)
--ph=float Persistance for height generation (default 1.0)
--pm=float Persistance for moist generation (default 1.0)
--pt=float Persistance for temp generation (default 1.0)
--temp=float Adjust each generated temperature by this percent (0
- 100) (default 0.0)
--ts=int The seed for a terrains temperature perlin generation
(default 3000)
--width=int The width of the generated map (default 128)
--elevation=float Adjust each generated elevation by
this percent (-100 - 100) (default 0.0)
--fhx=float The frequency for height generation
across the x-axis (default 2.5)
--fhy=float The frequency for height generation
across the y-axis (default 2.5)
--fmx=float The frequency for moist generation
across the x-axis (default 2.5)
--fmy=float The frequency for moist generation
across the y-axis (default 2.5)
--ftx=float The frequency for temp generation
across the x-axis (default 2.5)
--fty=float The frequency for temp generation
across the y-axis (default 2.5)
--gf=bool Generate flora, significantly affects
performance
--height=int The height of the generated map
(default 128)
-h, --help Print usage
--hs=int The seed for a terrains height perlin
generation (default 10)
--moisture=float Adjust each generated moisture by
this percent (-100 - 100) (default 0.0)
--ms=int The seed for a terrains moist perlin
generation (default 300)
--oh=int Octaves for height generation
(default 3)
--om=int Octaves for moist generation (default
3)
--ot=int Octaves for temp generation (default
3)
--ph=float Persistance for height generation
(default 1.0)
--pm=float Persistance for moist generation
(default 1.0)
--pt=float Persistance for temp generation
(default 1.0)
--road_exclude_flora_path=bool Controls if roads will run tiles
containing flora
--road_exclude_mountain_path=bool Controls if roads will run through
high mountains
--road_exclude_water_path=bool Controls if roads will run through
water
--roads=int Add this many roads through the map,
starting and ending at edges (default
0)
--roads_to_make ints Attempt to create a road from a start
and end point (4 integers), can be
supplied multiple paths
(default [])
--rs=int The seed for generating roads
(default 100)
--temp=float Adjust each generated temperature by
this percent (-100 - 100) (default 0.0)
--ts=int The seed for a terrains temperature
perlin generation (default 3000)
--width=int The width of the generated map
(default 128)

Examples:
Render with defaults
$ ruby-perlin-2D-map-generator render

Render with options
$ ruby-perlin-2D-map-generator render --elevation=-40 --moisture=25 --hs=1

Render with roads
$ ruby-perlin-2D-map-generator render --roads=2

Describe tile [1, 1]
$ ruby-perlin-2D-map-generator describe coordinates=1,1
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Minitest::TestTask.create(:test) do |t|
end

task :irb do
exec 'irb -I lib -r ./lib/**/*'
exec 'irb -I lib'
end

task :lint do
Expand Down
73 changes: 65 additions & 8 deletions lib/CLI/command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Command

no_command

desc 'Generate a seeded customizable procedurally generated 2D map. Rendered in the console ' \
desc 'Generate a seeded customizable procedurally generated 2D map with optional roads. Rendered in the console ' \
' using ansi colours, or described as a 2D array of hashes with each tiles information.'

example 'Render with defaults',
Expand All @@ -21,6 +21,9 @@ class Command
example 'Render with options',
' $ ruby-perlin-2D-map-generator render --elevation=-40 --moisture=25 --hs=1'

example 'Render with roads',
' $ ruby-perlin-2D-map-generator render --roads=2'

example 'Describe tile [1, 1]',
' $ ruby-perlin-2D-map-generator describe coordinates=1,1'
end
Expand All @@ -41,6 +44,15 @@ class Command
desc 'Used with the describe command, only returns the given coordinate tile details'
end

option :roads_to_make do
arity one
long '--roads_to_make ints'
convert :int_list
validate ->(v) { v >= 0 }
desc 'Attempt to create a road from a start and end point (4 integers), can be supplied multiple paths'
default MapConfig::DEFAULT_ROADS_TO_MAKE
end

option :height_seed do
long '--hs int'
# or
Expand Down Expand Up @@ -210,7 +222,7 @@ class Command
long '--temp float'
long '--temp=float'

desc 'Adjust each generated temperature by this percent (0 - 100)'
desc 'Adjust each generated temperature by this percent (-100 - 100)'
convert ->(val) { val.to_f / 100.0 }
validate ->(val) { val >= -1.0 && val <= 1.0 }
default MapConfig::DEFAULT_TEMP_ADJUSTMENT
Expand All @@ -220,7 +232,7 @@ class Command
long '--elevation float'
long '--elevation=float'

desc 'Adjust each generated elevation by this percent (0 - 100)'
desc 'Adjust each generated elevation by this percent (-100 - 100)'
convert ->(val) { val.to_f / 100.0 }
validate ->(val) { val >= -1.0 && val <= 1.0 }
default MapConfig::DEFAULT_HEIGHT_ADJUSTMENT
Expand All @@ -230,12 +242,58 @@ class Command
long '--moisture float'
long '--moisture=float'

desc 'Adjust each generated moisture by this percent (0 - 100)'
desc 'Adjust each generated moisture by this percent (-100 - 100)'
convert ->(val) { val.to_f / 100.0 }
validate ->(val) { val >= -1.0 && val <= 1.0 }
default MapConfig::DEFAULT_MOIST_ADJUSTMENT
end

option :roads do
long '--roads int'
long '--roads=int'

desc 'Add this many roads through the map, starting and ending at edges'
convert Integer
validate ->(val) { val >= 0 }
default MapConfig::DEFAULT_NUM_OF_ROADS
end

option :road_seed do
long '--rs int'
long '--rs=int'

desc 'The seed for generating roads'
convert Integer
default MapConfig::DEFAULT_ROAD_SEED
end

option :road_exclude_water_path do
long '--road_exclude_water_path bool'
long '--road_exclude_water_path=bool'

desc 'Controls if roads will run through water'
convert :bool
default MapConfig::DEFAULT_ROAD_EXCLUDE_WATER_PATH
end

option :road_exclude_mountain_path do
long '--road_exclude_mountain_path bool'
long '--road_exclude_mountain_path=bool'

desc 'Controls if roads will run through high mountains'
convert :bool
default MapConfig::DEFAULT_ROAD_EXCLUDE_MOUNTAIN_PATH
end

option :road_exclude_flora_path do
long '--road_exclude_flora_path bool'
long '--road_exclude_flora_path=bool'

desc 'Controls if roads will run tiles containing flora'
convert :bool
default MapConfig::DEFAULT_ROAD_EXCLUDE_FLORA_PATH
end

flag :help do
short '-h'
long '--help'
Expand All @@ -259,10 +317,9 @@ def execute_command
map = Map.new(map_config: MapConfig.new(
width: params[:width],
height: params[:height],
perlin_height_config: perlin_height_config,
perlin_moist_config: perlin_moist_config,
perlin_temp_config: perlin_temp_config,
generate_flora: params[:generate_flora]
all_perlin_configs: MapConfig::AllPerlinConfigs.new(perlin_height_config, perlin_moist_config, perlin_temp_config),
generate_flora: params[:generate_flora],
road_config: MapConfig::RoadConfig.new(*params.to_h.slice(:road_seed, :roads, :road_exclude_water_path, :road_exclude_mountain_path, :road_exclude_flora_path, :roads_to_make).values)
))
case params[:command]
when 'render' then map.render
Expand Down
3 changes: 3 additions & 0 deletions lib/ansi_colours.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ module Background
TAIGA_HIGHLAND = "\e[48;5;65m"
TAIGA_COAST = "\e[48;5;17m"
ICE = "\e[48;5;159m"
LOW_ROAD_BLACK = "\e[48;5;241m"
ROAD_BLACK = "\e[48;5;239m"
HIGH_ROAD_BLACK = "\e[48;5;236m"
ANSI_RESET = "\033[0m"
end
end
10 changes: 10 additions & 0 deletions lib/biome.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ def taiga?
TAIGA_TERRAIN.include?(self)
end

def high_mountain?
HIGH_MOUNTAIN.include?(self)
end

def flora_available
!flora_range.nil?
end
Expand Down Expand Up @@ -132,6 +136,12 @@ def self.from(elevation, moist, temp)
TAIGA_COAST
].freeze

HIGH_MOUNTAIN = [
SNOW,
ROCKS,
MOUNTAIN
].freeze

LAND_TERRAIN = (ALL_TERRAIN - WATER_TERRAIN).freeze

class << self
Expand Down
Loading

0 comments on commit a06db4f

Please sign in to comment.