greyhawkweather 0.0.3

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