Skip to content
This repository has been archived by the owner on Nov 26, 2020. It is now read-only.

Commit

Permalink
Clear market price based on supply and demand of fuel.
Browse files Browse the repository at this point in the history
Fixed #72.
  • Loading branch information
Christopher Peplin committed Oct 26, 2010
1 parent 2c12ffb commit a239837
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 48 deletions.
25 changes: 22 additions & 3 deletions app/models/fuel_market.rb
@@ -1,5 +1,15 @@
class FuelMarket < ActiveRecord::Base
has_many :market_prices
has_many :market_prices do
def find_current(game)
price = find(:all, :conditions => {:game_id => game},
:order => "created_at DESC", :limit => 1)
if price
price.first
else
nil
end
end
end
has_many :games, :through => :market_prices
has_many :generator_types
has_many :generators, :through => :generator_types do
Expand All @@ -20,7 +30,11 @@ def find_by_game game

def average_demand game, time=nil
generators.find_by_game(game).inject(0) {|demand, generator|
demand + generator.average_fuel_burn_rate(time)
if time and generator.created_at >= time
demand
else
demand + generator.average_fuel_burn_rate(time)
end
}
end

Expand All @@ -31,10 +45,15 @@ def demand game
end

def clear game
last_price = market_prices.find_current(game)
old_demand = average_demand(game, last_price.created_at)
new_demand = average_demand(game)
new_price = last_price.price + (supply_slope * (new_demand - old_demand))
market_prices.create :price => new_price, :game => game
end

def current_price game
market_price = market_prices.order("created_at DESC").find_by_game_id(game)
market_price = market_prices.find_current(game)
if market_price
market_price.price
else
Expand Down
119 changes: 74 additions & 45 deletions spec/models/fuel_market_spec.rb
Expand Up @@ -30,79 +30,108 @@
@game = @price.game
@state = Factory :state, :game => @game
@city = Factory :city, :state => @state
@generator_type = Factory :generator_type, :fuel_market => @market
@generator = Factory :generator, :city => @city,
:generator_type => @generator_type
@another_price = Factory :market_price
@another_game = @another_price.game
@another_state = Factory :another_state, :game => @another_game
@another_city = Factory :another_city, :state => @another_state
end

it { @market.friendly_id.should eq(@market.name.downcase) }
context "with stubbed time" do
before do
stub_time
end

it "should know the instantaneous demand in a game" do
demand = @game.generators(@market).inject(0) {|demand, gen|
demand + gen.fuel_burn_rate
}
@market.demand(@game).should eq(demand)
end
it { @market.friendly_id.should eq(@market.name.downcase) }

it "should know the average demand for the fuel now in a game" do
average = @game.generators(@market).inject(0) {|demand, gen|
demand + gen.average_fuel_burn_rate
}
@market.average_demand(@game).should eq(average)
end
it "should know the instantaneous demand in a game" do
demand = @game.generators(@market).inject(0) {|demand, gen|
demand + gen.fuel_burn_rate
}
@market.demand(@game).should eq(demand)
end

it "should know the avg demand for the fuel on an arbitrary day in game" do
average = @game.generators(@market).inject(0) {|demand, gen|
demand + gen.average_fuel_burn_rate(1.day.ago)
}
@market.average_demand(@game, 1.day.ago).should eq(average)
end
it "should know the average demand for the fuel now in a game" do
average = @game.generators(@market).inject(0) {|demand, gen|
demand + gen.average_fuel_burn_rate
}
@market.average_demand(@game).should eq(average)
end

it "should have a current price for the overall market in a game" do
(@market.current_price(@game)).should eq(
@game.market_prices.find_by_fuel_market_id(@market,
:order => "created_at DESC").price)
end
it "should have a current price for the overall market in a game" do
(@market.current_price(@game)).should eq(
@game.market_prices.find_by_fuel_market_id(@market,
:order => "created_at DESC").price)
end

it "should have a current price a specific city" do
(@market.current_local_price(@city)).should eq(
@game.market_prices.find_by_fuel_market_id(@market,
:order => "created_at DESC").price)
# TODO multiple by city factors
end
it "should have a current price a specific city" do
(@market.current_local_price(@city)).should eq(
@game.market_prices.find_by_fuel_market_id(@market,
:order => "created_at DESC").price)
# TODO multiple by city factors
end

it "should grab the most recent price for current price" do
new_price = 42
@market.market_prices.create(:price => new_price, :game => @game)
@market.current_price(@game).should eq(new_price)
end
it "should grab the most recent price for current price" do
new_price = 42
@market.market_prices.create(:price => new_price, :game => @game)
@market.current_price(@game).should eq(new_price)
end

it "should have a lower coal price in a city with coal"
it "should have a lower coal price in a city with coal"

it "should average the price over all games" do
sum = @market.games.inject(0) {|sum, game|
sum + @market.current_price(game)
}
@market.average_price.should eq(sum / @market.games.length)
end
end

it "should average the price over all games" do
sum = @market.games.inject(0) {|sum, game|
sum + @market.current_price(game)
it "should know the avg demand for the fuel on an arbitrary day in game" do
@generator = Factory :generator, :city => @city,
:generator_type => @generator_type, :created_at => 2.days.ago
time = 1.day.ago
average = @game.generators(@market).inject(0) {|demand, gen|
if gen.created_at >= time
demand
else
demand + gen.average_fuel_burn_rate(time)
end
}
@market.average_price.should eq(sum / @market.games.length)
stub_time
@market.average_demand(@game, time).should eq(average)
end

it "should only count generators that exist in the average demand" do
@market.average_demand(@game, 1.day.ago).should eq(0)
end

context "clearing market" do
before do
@market.clear @game
@original_price = @market.current_price @game
@another_market = Factory :fuel_market, :supply_slope => 2
@another_price = Factory :market_price, :fuel_market => @another_market,
:price => @price.price, :game => @game
@another_generator_type = Factory :generator_type,
:fuel_market => @another_market
@another_generator = Factory :generator, :city => @city,
:generator_type => @another_generator_type
end

it "should recalculate prices based on supply of fuel" do
@market.supply_slope *= 2
@market.clear(@game)
@market.current_price(@game).should be > @original_price
@another_market.clear(@game)
@another_market.current_price(@game).should be > @original_price
end

it "should recalculate prices based on demand" do
FuelMarket.any_instance.stubs(:average_demand).returns(0)
another_generator = Factory :generator, :city => @city,
:generator_type => @generator_type
@market.reload
@market.clear(@game)
@market.current_price(@game).should be < @original_price
@market.current_price(@game).should be > @original_price
end
end
end
Expand Down
4 changes: 4 additions & 0 deletions spec/support/time_stubber.rb
@@ -0,0 +1,4 @@
def stub_time
time = Time.now
Time.stubs(:now).returns(time)
end

0 comments on commit a239837

Please sign in to comment.