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/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,11 @@
1
+ class DieRoller
2
+ def roll(nSides, modifier=0)
3
+ rand(nSides) + 1 + modifier
4
+ end
5
+ end
6
+
7
+ class NullDieRoller
8
+ def roll(nSides, modifier=0)
9
+ -1
10
+ end
11
+ 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
@@ -0,0 +1,11 @@
1
+
2
+ class Wind
3
+ def initialize(dieroller)
4
+ @speed = dieroller.roll(20, -1)
5
+ @direction = [:N, :NE, :E, :SE, :S, :SW, :W, :NW][dieroller.roll(8, -1)]
6
+ end
7
+
8
+ def to_s
9
+ @speed.to_s + @direction.to_s
10
+ end
11
+ end
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,7 @@
1
+ require 'util/dieroller'
2
+
3
+ class AvgRoller < DieRoller
4
+ def roll(nsides, modifier=0)
5
+ return nsides/2 + modifier
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ require 'util/dieroller'
2
+
3
+ class RiggedRoller < DieRoller
4
+ def initialize(*rolls)
5
+ @last_roll = rolls.pop
6
+ @rolls = rolls.reverse
7
+ end
8
+ def roll(nSides, modifier=0)
9
+ (@rolls.pop || @last_roll) + modifier
10
+ end
11
+ end
@@ -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