# Trouble with a while loop

**URL:** <https://www.ruby-forum.com/t/trouble-with-a-while-loop/121729>\
**Category:** Ruby\
**Created:** [November 30, 2007, 10:00am UTC](https://www.ruby-forum.com/t/trouble-with-a-while-loop/121729 "2007-11-30T10:00:45Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![bishar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/f17d59/32.png) [@bishar](https://www.ruby-forum.com/u/bishar)\
**Post date:** [November 30, 2007, 10:00am UTC](https://www.ruby-forum.com/t/trouble-with-a-while-loop/121729/1 "2007-11-30T10:00:45Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![bishar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/f17d59/32.png) [@bishar](https://www.ruby-forum.com/u/bishar)\
**Post date:** [November 30, 2007, 1:56pm UTC](https://www.ruby-forum.com/t/trouble-with-a-while-loop/121729/2 "2007-11-30T13:56:00Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![bishar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/f17d59/32.png) [@bishar](https://www.ruby-forum.com/u/bishar)\
**Post date:** [November 30, 2007, 12:53pm UTC](https://www.ruby-forum.com/t/trouble-with-a-while-loop/121729/3 "2007-11-30T12:53:49Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![bishar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/f17d59/32.png) [@bishar](https://www.ruby-forum.com/u/bishar)\
**Post date:** [December 4, 2007, 2:06pm UTC](https://www.ruby-forum.com/t/trouble-with-a-while-loop/121729/4 "2007-12-04T14:06:16Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![bishar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/f17d59/32.png) [@bishar](https://www.ruby-forum.com/u/bishar)\
**Post date:** [December 1, 2007, 12:26am UTC](https://www.ruby-forum.com/t/trouble-with-a-while-loop/121729/5 "2007-12-01T00:26:12Z")

</div>

> 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]}”
