Trouble with a while loop

B

Bashka Dooble

Hi,

Please forgive if this forum is not the right one for this post.

I'm writing a small ruby program that implements sale of a plot of land
to 5 investors through English Auction. In an English auction, the
auctioneer begins the auction with the reserve price (lowest acceptable
price) and then takes larger and larger bids from the customers until no
one will increase the bid. The item is then sold to the highest bidder.

The logic that i'm using to decide which investor to bid first is this:
1. Each investor has a maximum willing price that they can't exceed.
2. First find out the difference/margin btw an investor's willing price
and the reserve price
3. The investor that has the lowest margin bids first
4. An investor's first bid = reserve price + half of margin
5. Subsequent bids = first bid + 25% of margin i.e. half of the other
half of margin

The code as it is now is attached.

Thanks,

Bashka

Attachments:
http://www.ruby-forum.com/attachment/1072/engBid42.rb
 
S

Sharon Phillips

Hi Bashka,

I've had a it of a shot at your code, mainly looking at reducing the
repetition and catching a few of the cases that might cause an endless
loop (like if no-one bid higher than the valuation.

It looks from your code like you newish to programming, so there's a
fair chance I've used some constructs not familiar to you. If so, let
us know and someone will help explain. This is only a quick attempt
(I'm supposed to be unpacking boxes - we've just moved house) and a
bit messy.

Here tis:

class Bidder
attr_reader :still_bidding, :num

def initialize num, reserve_price, max_bid
@num= num
@max_bid= max_bid
@margin= @max_bid- reserve_price
@bid= reserve_price+ @margin/2
@still_bidding= @max_bid> reserve_price
end

def current_bid
@bid
end

def raise_bid
@bid+= @margin/4
@still_bidding= @bid<= @max_bid
end
end

@bidders= []

def get_num msg
print "#{msg} >"
gets.to_i
end

#we're only interested in bidders who haven't yet reached their max
def bidders_left
@bidders.select {|bidder| bidder.still_bidding}
end

valuation= get_num "Enter the valuation"
reserve_price= get_num "Enter the reserve price"

#set up the bidders
(1..(get_num "How many bidders?")).each do |index|
max_bid= get_num "How much is invester #{index} willing to spend?"
@bidders << Bidder.new(index, reserve_price, max_bid)
end

#no-one's won yet, and we haven't started
winner= nil
round= 0

while bidders_left.any? && winner.nil?
print "\nRound #{round+=1}: "

#get the current lowest bidder
current_bidder= bidders_left.sort{|a,b| a.current_bid <=>
b.current_bid}.first

bid= current_bidder.current_bid
puts "Investor #{current_bidder.num} is bidding $#{bid}"

#either they won, or they raise their bid
if bid> valuation
winner= current_bidder
else
current_bidder.raise_bid
end
end

if winner.nil?
puts "No one bid high enough. Property passed in"
else
puts "** This property has been sold to Invester
#{current_bidder.num} **"
end
 
B

Bashka Dooble

Hi Sharon,

Many many thanks for your kind response. As you guessed I'm new to
programming. The code works fine. Only it doesn't display messages
asking for user input, for instance "Enter the valuation" message
doesn't appear.

Much appreciated though and God bless.

Best regards,

Bishar
 
S

Sharon Phillips

Hi Sharon,
Everyone says that...
I'm actually Dave, but I use my wife's email :)
Many many thanks for your kind response. As you guessed I'm new to
programming. The code works fine. Only it doesn't display messages
asking for user input, for instance "Enter the valuation" message
doesn't appear.
What sort of environment are you running this on?
Perhaps you could alter get_num to include STDOUT.flush (like your
original)

def get_num msg
print "#{msg} >"
STDOUT.flush
gets.to_i
end


Probably the most important thing I'd like to get across is that
whenever you see yourself writing something like
a_margin = max_price_A - reservePrice
b_margin = max_price_B - reservePrice
c_margin = max_price_C - reservePrice
d_margin = max_price_D - reservePrice
e_margin = max_price_E - reservePrice

you're repeating yourself unnecessarily and making it difficult to
change the programme (what if we had an extra investor? what if we had
100?)
Ruby (unlike a number of other languages) makes it very simple to
manage lists of things.

Here's your original code again, but all I've done is put all the
a_margin (etc) bits into a list and change the bidding section to use
this list

Cheers,
Dave

# set up list (array) to hold our investor information
investors= []

# Change the number of bidders by changing this value
BIDDER_COUNT=5

#Get the valuation price i.e the Auctioneer's expected price of the
property
puts"Enter the valuation: "
STDOUT.flush
valuation = gets.to_i

#Get the Reserve price i.e. the minimum acceptable price of the property
puts "Enter the reserve price: "
STDOUT.flush
reservePrice = gets.to_i

# get the max_price for each investor
for index in (1..BIDDER_COUNT)
# we'll use a hash to keep all the information we need about this
investor
# much tidier than having sperate lists for bids, margins and
max_prices
this_investor= {:index => index}

#Each agent knows the maximun amount it can afford to pay for the
property
puts "How much is invester #{index} willing to spend? "
STDOUT.flush
this_investor[:max_price]= gets.to_i

# add the new investor to our list
investors << this_investor
end

investors.each do |investor|
#Calculate invester bid magins
#i.e. difference btw an agent's max willing price and the reserve
price
investor[:margin] = investor[:max_price] - reservePrice

#Initialize bids for the investers here. First bid is reserve price
plus half of the margin.
#The other half will be incrementally bidded at 50% per round of
bidding
investor[:bid] = reservePrice + investor[:margin]/2
end

=begin
Assumptions
1. Probability of two or more investers having the same max price is
negligible
2. Investers do not know each other's willing prices
3. A margin can't be zero...to be explained later
=end

#Continue bidding as long as the highest bid is less or equal to
valuation price.
#Trivially, the property will be sold to the agent that reaches or
exceeds the valuation price

# keep going untill we have a winner.
# NOTE ** this will continue forever if none of the bidders has a
max_price
# >= the valuation
# You'll need to add a check for this as well
# Hint: you'll reach a round where those_still_bidding will be empty
# (everyone has dropped out)

#initialize out winner as no one
winner= nil

while winner.nil? do
# check who should bid first
# we need to find the lowest bid that's not greater than that
investors'
# max_price

# To do this, let's take out list of investors, and narrow it down
to only
# those still bidding (bid <= max_price)


those_still_bidding= investors.select do |investor|
# if the following evaluates as true, this investor will join our
new list
investor[:bid] <= investor[:max_price]
end

# Now, from those let's find the lowest bidder.
# One way to do this is to sort the list by bid, then pick the
first one
# Step 1: sort them
those_still_bidding.sort! do |investor_a, investor_b|
investor_a[:bid] <=> investor_b[:bid]
end
# Step 2: get the first
lowest_bidder= those_still_bidding.first

puts "Investor #{lowest_bidder[:index]} is bidding
#{lowest_bidder[:bid]}"

# Two possibilities now:
# 1: This bid wins, and the action ends
# 2: This bid doesn't win, this investor raises their bid and we
continue
if lowest_bidder[:bid]>= valuation then
# Only need to set winner here.
# This will cause the while loop to stop (winner is no longer nil)
# We'll display the winning details at the end
winner= lowest_bidder
else
lowest_bidder[:bid]+= lowest_bidder[:margin] * 0.25
end

end # whle

# The programme will only get to here once a winner has been declared

puts "\nThis property has been sold to Invester #{winner[:index]} for
#{winner[:bid]}"
 
B

Bashka Dooble

Hi Dave,

I'm sure you don't mind that :)

Actually there's no problem with the code, it was me behaving stupid
newish. Again I appreciate your help. I guess it's through such forums
as ruby-forum that morons like me get to learn and like programming.

Best regards,

Bishar
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top