README.md
# Ruby Perlin 2D Map Generator
[![Gem Version](https://badge.fury.io/rb/ruby-perlin-2D-map-generator.svg)](https://badge.fury.io/rb/ruby-perlin-2D-map-generator)
![CI Status](https://github.com/matthewstyler/ruby-perlin-2D-map-generator/actions/workflows/main.yml/badge.svg)
![CodeQL](https://github.com/matthewstyler/ruby-perlin-2D-map-generator/workflows/CodeQL/badge.svg)
<a href="https://codeclimate.com/github/matthewstyler/ruby-perlin-2D-map-generator/test_coverage"><img src="https://api.codeclimate.com/v1/badges/b99aae29d02b7a8a4cc6/test_coverage" /></a>
<a href="https://codeclimate.com/github/matthewstyler/ruby-perlin-2D-map-generator/maintainability"><img src="https://api.codeclimate.com/v1/badges/b99aae29d02b7a8a4cc6/maintainability" /></a>
[![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 with optional roads and towns using perlin noise.
Include the gem in your project, or use the executable from the command line.
Map can be rendered in console using ansi colors or returned as 2D array of hashes describing each tile and binome. Completely customizable, use the --help option for full usage details.
![2D-maps](https://github.com/matthewstyler/ruby-perlin-2D-map-generator/assets/4560901/6234ebc1-f3bd-48b5-9b78-4d286d2c8d6e)
# Installation
### Bundler
```ruby
gem 'ruby-perlin-2D-map-generator'
```
### Manual
```sh
gem install ruby-perlin-2D-map-generator
```
# Customization examples
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`
- Taiga map (decrease temperature, increase moisture): `ruby-perlin-2D-map-generator render --temp=-60 --moisture=30 `
## Common customization
```bash
--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)
--towns=int Add this randomly sized towns
(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 (-100 -
100) (default 0.0)
--moisture=float Adjust each generated moisture by this percent (-100 -
100) (default 0.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 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.
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`
## Towns
With Poisson Disk Sampling, towns can be generated randomly or with a provided x,y coordinate used as a centroid with radius. The result will be tiles that contain `Building` `items`. Buildings in a town are connected by roads, and additionally towns are connected to other towns by roads.
# Generate without rendering
```irb
irb(main):001:0> map = Map.new
```
Map can then be manipulated via traditional x,y lookup
```irb
map[x, y].to_h
=>
{:x=>0,
:y=>1,
:height=>0.29251394359649563,
:moist=>0.29100678755603004,
:temp=>0.6034041566100443,
:biome=>{:name=>"deep_valley", :flora_range=>1, :colour=>"\e[48;5;47m"},
:items=>[]}
```
or the less intuitative multidimensional lookup (reversed axis):
```irb
map.tiles[y][x].to_h
=>
{:x=>0,
:y=>1,
:height=>0.29251394359649563,
:moist=>0.29100678755603004,
:temp=>0.6034041566100443,
:biome=>{:name=>"deep_valley", :flora_range=>1, :colour=>"\e[48;5;47m"},
:items=>[]}
```
or from the command line:
```bash
$ ruby-perlin-2D-map-generator describe coordinates=0,1
{:x=>0,
:y=>1,
:height=>0.29251394359649563,
:moist=>0.29100678755603004,
:temp=>0.6034041566100443,
:biome=>{:name=>"deep_valley", :flora_range=>1, :colour=>"\e[48;5;47m"},
:items=>[]}
```
# Full Command line Usage
```bash
$ ruby-perlin-2D-map-generator --help
```
```bash
Usage: ruby-perlin-2D-map-generator [OPTIONS] (DESCRIBE | RENDER)
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.
Arguments:
(DESCRIBE | RENDER) command to run: render prints the map to standard
output using ansi colors. describe prints each tiles
bionome information in the map, can be combined with the
coordinates keyword to print a specific tile.
(permitted: describe, render)
Keywords:
COORDINATES=INT_LIST Used with the describe command, only returns the given
coordinate tile details
Options:
--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)
--town_seed=int The seed for generating towns
(default 500)
--towns=int Add this many randomly sized towns
throughout the map
(default 0)
--towns_to_make ints Attempt to create a town at given x,y
coordinate, with z points and v radius
(4 integers). Can be supplied multiple
towns.
(default [])
--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
Render with 5 roads, 1 provided road, 10 random towns and 1 provided town
$ ruby-perlin-2D-map-generator render --roads=5 --roads_to_make=0,0,50,50 --towns=10 --towns_to_make=5,5,10,3
Describe tile [1, 1]
$ ruby-perlin-2D-map-generator describe coordinates=1,1
```