greyhawkweather 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +12 -0
- data/Manifest.txt +39 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +52 -0
- data/Rakefile +26 -0
- data/bin/greyweathergen +22 -0
- data/data/baselinedata.yml +120 -0
- data/data/precipitationoccurance.yml +112 -0
- data/lib/baselinedata.rb +28 -0
- data/lib/greyhawkweather.rb +6 -0
- data/lib/greyhawkweathergenerator.rb +15 -0
- data/lib/month.rb +25 -0
- data/lib/precipitation.rb +16 -0
- data/lib/precipitationinfo.rb +32 -0
- data/lib/precipitationoccurance.rb +83 -0
- data/lib/singledayweather.rb +29 -0
- data/lib/skyconditions.rb +15 -0
- data/lib/temperaturerange.rb +26 -0
- data/lib/util/dieroller.rb +11 -0
- data/lib/weathergenerator.rb +44 -0
- data/lib/wind.rb +11 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/rollers/avgroller.rb +7 -0
- data/test/rollers/riggedroller.rb +11 -0
- data/test/test_acceptance.rb +36 -0
- data/test/test_dieroller.rb +30 -0
- data/test/test_greyhawkweather.rb +11 -0
- data/test/test_helper.rb +3 -0
- data/test/test_month.rb +36 -0
- data/test/test_precipitation.rb +26 -0
- data/test/test_precipitation_occurance.rb +93 -0
- data/test/test_singledayweather.rb +61 -0
- data/test/test_sky_conditions.rb +23 -0
- data/test/test_temperature_range.rb +30 -0
- data/test/test_weather_generator.rb +59 -0
- data/test/test_wind.rb +11 -0
- data/todo.org +48 -0
- data.tar.gz.sig +0 -0
- metadata +210 -0
- metadata.gz.sig +1 -0
data/lib/month.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'skyconditions'
|
2
|
+
require 'temperaturerange'
|
3
|
+
|
4
|
+
class Month
|
5
|
+
def initialize(temp_range = TemperatureRange.new(0, [0, 0], [0, 0]),
|
6
|
+
conditions = SkyConditions.new((0..100), (100..100), (100..100)),
|
7
|
+
precipitation_chance = 0)
|
8
|
+
@temp_range = temp_range
|
9
|
+
@sky_condition = conditions
|
10
|
+
@precipitation_chance = precipitation_chance
|
11
|
+
end
|
12
|
+
|
13
|
+
def sky_conditions (dieroller)
|
14
|
+
@sky_condition.condition(dieroller)
|
15
|
+
end
|
16
|
+
|
17
|
+
def temp_range (dieroller, record_temp=nil)
|
18
|
+
@temp_range.range(dieroller, record_temp)
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_precipitation (dieroller)
|
22
|
+
@precipitation_chance >= dieroller.roll(100)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Precipitation
|
2
|
+
attr_reader :name
|
3
|
+
def initialize(info, dieroller)
|
4
|
+
@name = info.name
|
5
|
+
@chance_for_rainbow = info.chance_of_rainbow
|
6
|
+
@roller = dieroller
|
7
|
+
end
|
8
|
+
|
9
|
+
def rainbow?
|
10
|
+
@chance_for_rainbow > 0 && @roller.roll(100) <= @chance_for_rainbow
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
"[#{@name}; rainbow: #{rainbow?}]"
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class PrecipitationInfo
|
2
|
+
attr_reader :name
|
3
|
+
attr_reader :min_temp
|
4
|
+
attr_reader :max_temp
|
5
|
+
attr_reader :chance_to_continue
|
6
|
+
attr_reader :chance_of_rainbow
|
7
|
+
attr_reader :not_allowed_in
|
8
|
+
|
9
|
+
def self.create_from_data(arg_hash)
|
10
|
+
PrecipitationInfo.new(arg_hash[:name],
|
11
|
+
arg_hash[:min_temp],
|
12
|
+
arg_hash[:max_temp],
|
13
|
+
arg_hash[:chance_to_continue],
|
14
|
+
arg_hash[:chance_of_rainbow],
|
15
|
+
arg_hash[:not_allowed_in])
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(name, min_temp=nil, max_temp=nil, chance_to_continue=0, chance_of_rainbow=0, not_allowed_in=[])
|
19
|
+
@name = name
|
20
|
+
@min_temp = min_temp
|
21
|
+
@max_temp = max_temp
|
22
|
+
@chance_to_continue = chance_to_continue || 0
|
23
|
+
@chance_of_rainbow = chance_of_rainbow || 0
|
24
|
+
@not_allowed_in = not_allowed_in || []
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class NullPrecipitationInfo < PrecipitationInfo
|
29
|
+
def initialize()
|
30
|
+
super "No Precipitation"
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'YAML'
|
2
|
+
|
3
|
+
require 'rangehash'
|
4
|
+
|
5
|
+
require 'precipitationinfo'
|
6
|
+
require 'precipitation'
|
7
|
+
|
8
|
+
class PrecipitationOccurance < RangeHash
|
9
|
+
def self.load(file)
|
10
|
+
data = YAML.load_file(file)
|
11
|
+
data.each_pair { |k, v| data[k] = PrecipitationInfo.create_from_data(v)}
|
12
|
+
PrecipitationOccurance.new(data)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(args = nil)
|
16
|
+
super args, NullPrecipitationInfo.new()
|
17
|
+
end
|
18
|
+
|
19
|
+
def type(dieroller, temp_range = nil, terrain = :plains)
|
20
|
+
get_all_precip initial_precip(dieroller, temp_range, terrain), dieroller, temp_range, terrain
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def invalid_precip?(precip_info, temp_range, terrain)
|
25
|
+
(temp_range and
|
26
|
+
((precip_info.min_temp and !(precip_info.min_temp <= temp_range.last)) or
|
27
|
+
(precip_info.max_temp and !(precip_info.max_temp >= temp_range.first)))) or
|
28
|
+
(terrain and precip_info.not_allowed_in.include?(terrain))
|
29
|
+
end
|
30
|
+
|
31
|
+
def initial_precip (dieroller, temp_range, terrain)
|
32
|
+
precip_info = self[dieroller.roll(100)]
|
33
|
+
|
34
|
+
if invalid_precip?(precip_info, temp_range, terrain)
|
35
|
+
precip_info = self[dieroller.roll(100)]
|
36
|
+
|
37
|
+
if invalid_precip?(precip_info, temp_range, terrain)
|
38
|
+
precip_info = NullPrecipitationInfo.new()
|
39
|
+
end
|
40
|
+
end
|
41
|
+
precip_info
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_all_precip (precip_info, dieroller, temp_range, terrain)
|
45
|
+
all_precip = Array.new().push(Precipitation.new(precip_info, dieroller))
|
46
|
+
|
47
|
+
while precip_continues?(dieroller, precip_info)
|
48
|
+
next_precip_info = next_precip_info(dieroller, precip_info)
|
49
|
+
precip_info = next_precip_info unless invalid_precip?(next_precip_info, temp_range, terrain)
|
50
|
+
all_precip.push(Precipitation.new(precip_info, dieroller))
|
51
|
+
end
|
52
|
+
|
53
|
+
all_precip
|
54
|
+
end
|
55
|
+
|
56
|
+
def precip_continues?(dieroller, precip_info)
|
57
|
+
precip_info.chance_to_continue > 0 &&
|
58
|
+
dieroller.roll(100) <= precip_info.chance_to_continue
|
59
|
+
end
|
60
|
+
|
61
|
+
def next_precip_info(dieroller, precip_info)
|
62
|
+
continue_roll = dieroller.roll(10)
|
63
|
+
return line_above(precip_info) if continue_roll == 1
|
64
|
+
return line_below(precip_info) if continue_roll == 10
|
65
|
+
precip_info
|
66
|
+
end
|
67
|
+
|
68
|
+
def line_above(precip_info)
|
69
|
+
prev_key = sorted_keys[[0,index_of_precip(precip_info)-1].max]
|
70
|
+
@key_value_hash[prev_key]
|
71
|
+
end
|
72
|
+
|
73
|
+
def line_below(precip_info)
|
74
|
+
next_key = sorted_keys[[sorted_keys.length,index_of_precip(precip_info)+1].min]
|
75
|
+
@key_value_hash[next_key]
|
76
|
+
end
|
77
|
+
|
78
|
+
def index_of_precip(precip_info)
|
79
|
+
key = @key_value_hash.index(precip_info)
|
80
|
+
index_of_key = sorted_keys.index(key)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'month'
|
2
|
+
require 'precipitationoccurance'
|
3
|
+
require 'precipitationinfo'
|
4
|
+
require 'wind'
|
5
|
+
|
6
|
+
class SingleDayWeather
|
7
|
+
attr_reader :temperature_range
|
8
|
+
attr_reader :sky_conditions
|
9
|
+
attr_reader :precipitation
|
10
|
+
attr_reader :wind
|
11
|
+
|
12
|
+
def initialize (month, dieroller,
|
13
|
+
precipitation_occurance_chart=PrecipitationOccurance.new({ 0..100 => NullPrecipitationInfo.new() }),
|
14
|
+
record_temp=nil,
|
15
|
+
terrain = :plains)
|
16
|
+
@temperature_range = month.temp_range(dieroller, record_temp)
|
17
|
+
@sky_conditions = month.sky_conditions(dieroller)
|
18
|
+
@record_temp = record_temp
|
19
|
+
@precipitation =
|
20
|
+
precipitation_occurance_chart.type(month.has_precipitation(dieroller) ? dieroller : NullDieRoller.new(),
|
21
|
+
@temperature_range, terrain)
|
22
|
+
@wind = Wind.new(dieroller)
|
23
|
+
end
|
24
|
+
|
25
|
+
def inspect
|
26
|
+
"#{@record_temp} #{@temperature_range} #{@sky_conditions} #{@precipitation} #{@wind}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rangehash'
|
2
|
+
|
3
|
+
class SkyConditions
|
4
|
+
def initialize (clear_range, partly_range, cloudy_range)
|
5
|
+
hash = { clear_range => :clear, partly_range => :partly_cloudy, cloudy_range => :cloudy}
|
6
|
+
@condition_ranges = RangeHash.new(hash , :none)
|
7
|
+
end
|
8
|
+
|
9
|
+
def condition(roller)
|
10
|
+
roll = roller.roll(100)
|
11
|
+
roll = 100 if roll == 0
|
12
|
+
@condition_ranges[roll]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class TemperatureRange
|
2
|
+
def initialize (base, high_adj, low_adj)
|
3
|
+
@base = base
|
4
|
+
@high_adj = high_adj
|
5
|
+
@low_adj = low_adj
|
6
|
+
end
|
7
|
+
|
8
|
+
def range (roller, record=nil)
|
9
|
+
base = calculate_todays_base(record)
|
10
|
+
(base - roller.roll(@low_adj[0], @low_adj[1])..base+ roller.roll(@high_adj[0], @high_adj[1]))
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
def calculate_todays_base(record)
|
15
|
+
record = make_record_array record
|
16
|
+
|
17
|
+
base = @base
|
18
|
+
base = base + (record.find_all{ |r| r == :high}.length * (@high_adj[0] + @high_adj[1]))
|
19
|
+
base = base - (record.find_all{ |r| r == :low}.length * (@low_adj[0] + @low_adj[1]))
|
20
|
+
base
|
21
|
+
end
|
22
|
+
|
23
|
+
def make_record_array(record)
|
24
|
+
((record.class == Array) ? record : [record])
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'singledayweather'
|
2
|
+
|
3
|
+
class WeatherGenerator
|
4
|
+
attr_reader :days
|
5
|
+
|
6
|
+
def initialize (baselinedata, precipitation_occurance_chart, month_index, num_days, dieroller, terrain = :plains)
|
7
|
+
month_for_each_day = make_months_for_days_array(baselinedata, month_index, num_days)
|
8
|
+
@days = month_for_each_day.map { |month| make_weather month, dieroller, precipitation_occurance_chart, terrain}
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def make_months_for_days_array(baselinedata, month_index, num_days)
|
13
|
+
months = Array.new
|
14
|
+
while num_days > 0
|
15
|
+
if (num_days > 28)
|
16
|
+
28.times { months.push baselinedata.month(month_index) }
|
17
|
+
num_days -= 28
|
18
|
+
month_index += 1
|
19
|
+
if month_index > baselinedata.num_months
|
20
|
+
month_index = 1
|
21
|
+
end
|
22
|
+
else
|
23
|
+
num_days.times { months.push baselinedata.month(month_index) }
|
24
|
+
num_days = 0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
months
|
28
|
+
end
|
29
|
+
|
30
|
+
def make_weather(month, dieroller, precipitation_occurance_chart, terrain)
|
31
|
+
SingleDayWeather.new(month, dieroller, precipitation_occurance_chart, check_record_high_low(dieroller), terrain)
|
32
|
+
end
|
33
|
+
|
34
|
+
def check_record_high_low(dieroller)
|
35
|
+
record_high_low_range = RangeHash.new({ 1 => [:low, :low, :low],
|
36
|
+
2 => [:low, :low],
|
37
|
+
3..4 => :low,
|
38
|
+
97..98 => :high,
|
39
|
+
99 => [:high, :high],
|
40
|
+
100 => [:high, :high, :high]},
|
41
|
+
:normal)
|
42
|
+
record_high_low_range[dieroller.roll(100)]
|
43
|
+
end
|
44
|
+
end
|
data/lib/wind.rb
ADDED
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/greyhawkweather.rb'}"
|
9
|
+
puts "Loading greyhawkweather gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rollers/avgroller'
|
4
|
+
require 'rollers/riggedroller'
|
5
|
+
|
6
|
+
require 'greyhawkweathergenerator'
|
7
|
+
|
8
|
+
class TestAcceptanceTests < Test::Unit::TestCase
|
9
|
+
def test_generate_weather_for_three_days_in_planting
|
10
|
+
weather_generator = GreyhawkWeatherGenerator.create_weather_generator(4, 3, AvgRoller.new)
|
11
|
+
assert_equal(3, weather_generator.days.length, "should have generated 3 days")
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_generate_weather_for_planting
|
15
|
+
weather_generator = GreyhawkWeatherGenerator.create_weather_generator(4, 1, AvgRoller.new)
|
16
|
+
weather = weather_generator.days[0]
|
17
|
+
assert_equal(44..63, weather.temperature_range)
|
18
|
+
assert_equal(:partly_cloudy, weather.sky_conditions)
|
19
|
+
assert_equal(NullPrecipitationInfo.new().name, weather.precipitation[0].name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_generate_weather_for_goodmonth
|
23
|
+
weather_generator = GreyhawkWeatherGenerator.create_weather_generator(8, 1, AvgRoller.new)
|
24
|
+
weather = weather_generator.days[0]
|
25
|
+
assert_equal(66..83, weather.temperature_range)
|
26
|
+
assert_equal(:partly_cloudy, weather.sky_conditions)
|
27
|
+
assert_equal(NullPrecipitationInfo.new().name, weather.precipitation[0].name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_generate_weather_with_terrain
|
31
|
+
weather_generator = GreyhawkWeatherGenerator.create_weather_generator(1, 1, RiggedRoller.new(30), :desert)
|
32
|
+
weather = weather_generator.days[0]
|
33
|
+
# without terrain the above would generate "Fog, Heavy" for precipitation
|
34
|
+
assert_equal(NullPrecipitationInfo.new().name, weather.precipitation[0].name)
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'util/dieroller'
|
4
|
+
|
5
|
+
$next_defined_random_number = 0
|
6
|
+
$max_arg_to_rand = -1
|
7
|
+
|
8
|
+
def rand (max=0)
|
9
|
+
$max_arg_to_rand = max
|
10
|
+
$next_defined_random_number
|
11
|
+
end
|
12
|
+
|
13
|
+
class TestDieRoller < Test::Unit::TestCase
|
14
|
+
def test_D6
|
15
|
+
$next_defined_random_number = 3
|
16
|
+
assert_equal(4, DieRoller.new.roll(6), "should return random number (+1)")
|
17
|
+
assert_equal(6, $max_arg_to_rand, "should have defined 6 as maximum number to rand")
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_is_1_to_N_range
|
21
|
+
$next_defined_random_number = 0
|
22
|
+
assert_equal(1, DieRoller.new.roll(6), "should use 1..N range")
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_applies_modifier_if_given
|
26
|
+
$next_defined_random_number = 1
|
27
|
+
assert_equal(4, DieRoller.new.roll(6, +2), "Should have added the +2")
|
28
|
+
assert_equal(-1, DieRoller.new.roll(6, -3), "Should have added the -3")
|
29
|
+
end
|
30
|
+
end
|