greyhawkweather 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|