Решение на Трета задача от Борис Минев

Обратно към всички решения

Към профила на Борис Минев

Резултати

  • 6 точки от тестове
  • 0 бонус точки
  • 6 точки общо
  • 19 успешни тест(а)
  • 0 неуспешни тест(а)

Код

require 'bigdecimal'
require 'bigdecimal/util'
class Inventory
attr_accessor :products, :coupons
CouponMap =
{ :percent => 'PercentCoupon',
:amount => 'AmountCoupon' }
def initialize
@products, @coupons= {}, {}
end
def register(name, price, promotion = nil)
if validate(name, price)
@products[name] = Product.new(name, BigDecimal(price), promotion)
else
raise "Invalid parameters passed."
end
end
def validate(name, price)
name.length.between?(1, 40) &&
price.to_f.between?(0.01, 999.99) &&
@products.values.none? { |product| product.name == name }
end
def new_cart()
Cart.new @products, @coupons
end
def register_coupon(name, info)
type, discount = info.to_a[0]
@coupons[name] =
Kernel.const_get(CouponMap[type]).new name, type, discount
end
end
class Product
attr_accessor :name, :price, :promotion
PromotionMap =
{ :get_one_free => 'NthFreePromotion',
:package => 'PackagePromotion',
:threshold => 'TresholdPromotion' }
def initialize(name, price, promotion_info = nil)
promotion =
if promotion_info
key, args = promotion_info.to_a[0]
Kernel.const_get(PromotionMap[key]).new args
else promotion_info
end
@name, @price, @promotion = name, price, promotion
end
end
class Cart
attr_accessor :cart, :inventory, :coupons, :coupon_in_use
def initialize(inventory = {}, coupons = {})
@cart, @inventory, @coupons = {}, inventory, coupons
@coupon_in_use = nil
end
def add(item, qty = 1)
if @inventory[item] && qty.between?(1, 99)
cart[item] ? cart[item] += qty : cart[item] = qty
else raise "Invalid parameters passed."
end
end
def total()
bill = apply_promotions()
("%.2f" % (@coupon_in_use ? @coupon_in_use.apply(bill) : bill)).to_d
end
def apply_promotions()
cart.to_a.inject(0) do |total, item|
price = inventory[item.first].price
qty = item.last
if inventory[item.first].promotion
total += inventory[item.first].promotion.apply(price, qty)
else total += price * qty
end
end
end
def use(coupon_name)
@coupon_in_use = @coupons[coupon_name] if !@coupon_in_use
end
def invoice
sep = "+"+"-"*48+"+"+"-"*10+"+\n"
title = "| Name".ljust(45)+"qty | price |\n"
content = print_cart()
total = "| TOTAL".ljust(49)+"| "+("%.2f" % total()).rjust(8)+" |\n"
sep+title+sep+content+sep+total+sep
end
def print_cart
res = ""
@cart.keys.each do |item|
res += print_line(item)
if inventory[item].promotion
res += inventory[item].promotion.print(inventory[item].price, @cart[item])
end
end
if @coupon_in_use
res += @coupon_in_use.print(apply_promotions())
else res
end
end
def print_line(item)
"| "+item.ljust(44)+
@cart[item].to_s.rjust(2)+" | "+
("%.2f" % (@cart[item] * inventory[item].price)).rjust(8)+" |\n"
end
end
class NthFreePromotion
def initialize(n)
@n = n
end
def apply(price, qty)
(qty - qty.div(@n))*price#.to_d
end
def print price, qty
"| (buy #{@n-1}, get 1 free)".ljust(49)+"| "+
("%.2f" % (apply(price, qty) - price*qty)).rjust(8)+" |\n"
end
end
class PackagePromotion
def initialize(args)
@size, @discount = args.to_a[0]
end
def apply(price, qty)
((qty-qty % @size)*(1-@discount/100.0) + (qty % @size))*price#.to_d
end
def print price, qty
"| (get #{@discount}% off for every #{@size})".ljust(49)+"| "+
("%.2f" % (apply(price, qty) - price*qty)).rjust(8)+" |\n"
end
end
class TresholdPromotion
NumbersMap = { 1 => '1st', 2 => '2nd', 3 => '3rd' }
def initialize(args)
@size, @discount = args.to_a[0]
end
def apply(price, qty)
diff = qty-@size < 0 ? 0 : qty-@size
([@size, qty].min + diff*(1-@discount/100.0))*price
end
def print price, qty
number = (NumbersMap[@size] ? NumbersMap[@size] : (@size.to_s) +'th')
"| (#{@discount}% off of every after the #{number})".ljust(49)+"| "+
("%.2f" % (apply(price, qty) - price*qty)).rjust(8)+" |\n"
end
end
class PercentCoupon
attr_accessor :name, :type, :discount
def initialize(name, type, discount)
@name, @type, @discount = name, type, discount
end
def apply(bill)
bill * (1-@discount/100.0)
end
def print(bill)
"| Coupon #{@name} - #{@discount}% off".ljust(49)+"| "+
("%.2f" % (apply(bill) - bill)).rjust(8)+" |\n"
end
end
class AmountCoupon
attr_accessor :name, :type, :discount
def initialize(name, type, discount)
@name, @type, @discount = name, type, discount.to_d
end
def apply(bill)
final_price = bill - @discount
(final_price > 0) ? final_price : '0.00'.to_d
end
def print(bill)
"| Coupon #{@name} - #{"%.2f" % @discount} off".ljust(49)+"| "+
("%.2f" % (apply(bill) - bill)).rjust(8)+" |\n"
end
end

Лог от изпълнението

...................

Finished in 0.57272 seconds
19 examples, 0 failures

История (1 версия и 0 коментара)

Борис обнови решението на 06.11.2011 23:28 (преди около 13 години)

+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class Inventory
+ attr_accessor :products, :coupons
+ CouponMap =
+ { :percent => 'PercentCoupon',
+ :amount => 'AmountCoupon' }
+
+ def initialize
+ @products, @coupons= {}, {}
+ end
+
+ def register(name, price, promotion = nil)
+ if validate(name, price)
+ @products[name] = Product.new(name, BigDecimal(price), promotion)
+ else
+ raise "Invalid parameters passed."
+ end
+ end
+
+ def validate(name, price)
+ name.length.between?(1, 40) &&
+ price.to_f.between?(0.01, 999.99) &&
+ @products.values.none? { |product| product.name == name }
+ end
+
+
+ def new_cart()
+ Cart.new @products, @coupons
+ end
+
+ def register_coupon(name, info)
+ type, discount = info.to_a[0]
+ @coupons[name] =
+ Kernel.const_get(CouponMap[type]).new name, type, discount
+ end
+end
+
+
+class Product
+ attr_accessor :name, :price, :promotion
+ PromotionMap =
+ { :get_one_free => 'NthFreePromotion',
+ :package => 'PackagePromotion',
+ :threshold => 'TresholdPromotion' }
+
+ def initialize(name, price, promotion_info = nil)
+ promotion =
+ if promotion_info
+ key, args = promotion_info.to_a[0]
+ Kernel.const_get(PromotionMap[key]).new args
+ else promotion_info
+ end
+ @name, @price, @promotion = name, price, promotion
+ end
+end
+
+
+class Cart
+ attr_accessor :cart, :inventory, :coupons, :coupon_in_use
+
+ def initialize(inventory = {}, coupons = {})
+ @cart, @inventory, @coupons = {}, inventory, coupons
+ @coupon_in_use = nil
+ end
+
+ def add(item, qty = 1)
+ if @inventory[item] && qty.between?(1, 99)
+ cart[item] ? cart[item] += qty : cart[item] = qty
+ else raise "Invalid parameters passed."
+ end
+ end
+
+ def total()
+ bill = apply_promotions()
+ ("%.2f" % (@coupon_in_use ? @coupon_in_use.apply(bill) : bill)).to_d
+ end
+
+ def apply_promotions()
+ cart.to_a.inject(0) do |total, item|
+ price = inventory[item.first].price
+ qty = item.last
+ if inventory[item.first].promotion
+ total += inventory[item.first].promotion.apply(price, qty)
+ else total += price * qty
+ end
+ end
+ end
+
+ def use(coupon_name)
+ @coupon_in_use = @coupons[coupon_name] if !@coupon_in_use
+ end
+
+ def invoice
+ sep = "+"+"-"*48+"+"+"-"*10+"+\n"
+ title = "| Name".ljust(45)+"qty | price |\n"
+ content = print_cart()
+ total = "| TOTAL".ljust(49)+"| "+("%.2f" % total()).rjust(8)+" |\n"
+ sep+title+sep+content+sep+total+sep
+ end
+
+ def print_cart
+ res = ""
+ @cart.keys.each do |item|
+ res += print_line(item)
+ if inventory[item].promotion
+ res += inventory[item].promotion.print(inventory[item].price, @cart[item])
+ end
+ end
+ if @coupon_in_use
+ res += @coupon_in_use.print(apply_promotions())
+ else res
+ end
+ end
+
+ def print_line(item)
+ "| "+item.ljust(44)+
+ @cart[item].to_s.rjust(2)+" | "+
+ ("%.2f" % (@cart[item] * inventory[item].price)).rjust(8)+" |\n"
+ end
+end
+
+
+class NthFreePromotion
+ def initialize(n)
+ @n = n
+ end
+
+ def apply(price, qty)
+ (qty - qty.div(@n))*price#.to_d
+ end
+
+ def print price, qty
+ "| (buy #{@n-1}, get 1 free)".ljust(49)+"| "+
+ ("%.2f" % (apply(price, qty) - price*qty)).rjust(8)+" |\n"
+ end
+end
+
+
+class PackagePromotion
+ def initialize(args)
+ @size, @discount = args.to_a[0]
+ end
+
+ def apply(price, qty)
+ ((qty-qty % @size)*(1-@discount/100.0) + (qty % @size))*price#.to_d
+ end
+
+ def print price, qty
+ "| (get #{@discount}% off for every #{@size})".ljust(49)+"| "+
+ ("%.2f" % (apply(price, qty) - price*qty)).rjust(8)+" |\n"
+ end
+end
+
+
+class TresholdPromotion
+ NumbersMap = { 1 => '1st', 2 => '2nd', 3 => '3rd' }
+
+ def initialize(args)
+ @size, @discount = args.to_a[0]
+ end
+
+ def apply(price, qty)
+ diff = qty-@size < 0 ? 0 : qty-@size
+ ([@size, qty].min + diff*(1-@discount/100.0))*price
+ end
+
+ def print price, qty
+ number = (NumbersMap[@size] ? NumbersMap[@size] : (@size.to_s) +'th')
+ "| (#{@discount}% off of every after the #{number})".ljust(49)+"| "+
+ ("%.2f" % (apply(price, qty) - price*qty)).rjust(8)+" |\n"
+ end
+end
+
+
+class PercentCoupon
+ attr_accessor :name, :type, :discount
+
+ def initialize(name, type, discount)
+ @name, @type, @discount = name, type, discount
+ end
+
+ def apply(bill)
+ bill * (1-@discount/100.0)
+ end
+
+ def print(bill)
+ "| Coupon #{@name} - #{@discount}% off".ljust(49)+"| "+
+ ("%.2f" % (apply(bill) - bill)).rjust(8)+" |\n"
+ end
+end
+
+
+class AmountCoupon
+ attr_accessor :name, :type, :discount
+
+ def initialize(name, type, discount)
+ @name, @type, @discount = name, type, discount.to_d
+ end
+
+ def apply(bill)
+ final_price = bill - @discount
+ (final_price > 0) ? final_price : '0.00'.to_d
+ end
+
+ def print(bill)
+ "| Coupon #{@name} - #{"%.2f" % @discount} off".ljust(49)+"| "+
+ ("%.2f" % (apply(bill) - bill)).rjust(8)+" |\n"
+ end
+end