How to tackle this Ruby candy store homework? - ruby

I have a class in university that asks students to learn three languages in
one semester. Like one is from really old languages such as Haskell, the other one should be from interpreter languages.
So, now I have to learn Ruby, and I need help. Let's say there is class that has
class Help
##array = Array.new
##count = 0
#store
#chocolate
#candy
#store_code
store is string (name of store)
chocolate, candy, store_code are integer (price, and code number)
Lets consider that I have an add function and call it twice
def add (s, i, i, i)
array = [s, i, i, i]
count += 1
end
store_a = Help.new
store_a.add (A, 20, 1, 100)
store_b = Help.new
store_b.add (B, 50, 1, 100)
Anyway, store_a chocolate price is 20
store_b chocolate price is 50 now
How do I make a function inside of class that calculates average of chocolate price? (I make the count variable for this, but I don't know if I need it or not).

This can be refactored and made shorter, also you can make use of class variables like you mentioned in the question using "##", but my goal here is to keep it basic so you can start grasping it and slowly moving to more advanced techniques and designs:
class Warehouse
attr_accessor :products_stores
def initialize
#products_stores = []
end
def add_product(args)
#products_stores << args
end
def product_price_avg
avg = 0
#products_stores.each do |o|
avg += o[:product].price
end
avg / #products_stores.count
end
end
class Store
attr_accessor :code
def initialize(code)
#code = code
end
end
class Chocolate
attr_accessor :price
def initialize(price)
#price = price
end
end
store_a = Store.new(100)
store_b = Store.new(200)
cheap_chocolate = Chocolate.new(20)
expensive_chocolate = Chocolate.new(50)
warehouse = Warehouse.new
warehouse.add_product({store: store_a, product: cheap_chocolate})
warehouse.add_product({store: store_b, product: expensive_chocolate})
puts warehouse.product_price_avg

Related

How to implement Aces in 5-Card-Draw game?

I'm taking an online course in Ruby programming and I need to make 5-Card Draw game as one of the projects. It all went well until I realized that Ace can have two values.
I've made 3 classes so far: Card, Deck and Hand. I'm currently working on a Hand class. The other two classes are below:
class Card
attr_reader :number, :sign, :color
def initialize(number, sign, color)
#number = number
#sign = sign
#color = color
end
end
require_relative 'card.rb'
class Deck
def initialize
#deck = make_deck
end
def make_deck
deck = []
signs = {'Club' => 'black', 'Spade' => 'black', 'Heart' => 'red', 'Diamond' => 'red'}
n = 1
while n < 15
if n == 11
n += 1
next
end
i = 0
4.times do
sign = signs.keys[i]
color = signs[sign]
deck << Card.new(n, sign, color)
i += 1
end
n += 1
end
deck
end
end
So, the problem appeared when I started coding the Poker Hands in Hand class. I'm not sure how to deal with the Ace because it can have a value of either 1 or 15. Any help/suggestion is welcomed.
"Ace can have two values" isn't the right way to think of it. Just make Aces high, always. Then, in the code that checks for straights you have to special-case the wheel. That is, a straight is defined as "5 cards in rank sequence, or A-2-3-4-5".

Not displaying it's corresponding values with it's key for Hash

Ok i am not here to ask for an answer. But to be honest i am not really good in class variable. So i would appreciate you can guide me along with this piece of code.
I have read on class variable at those docs. I some what kind of understand it. But it comes to applying it for my own use. I would get confused.
class Square
##sqArray = {}
#attr_accessor :length
def initialize
if defined?(##length)
randno = "%s" % [rand(20)]
##length = randno.to_i
##sqArray = ##length
else
randno = "%s" % [rand(20)]
##length = randno.to_i
##sqArray = ##length
end
end
def Area
##area = ##length * ##length
return ##area
##sqArray[##length.to_sym] = ##area
puts ##sqArray
end
end
s1 = Square.new
puts s1.Area
Let me explain this piece of code. Basically every time i create a Square object it would go to initialize method. A random number will be generated and pass it to ##length, and ##length will be assigned to hash ##sqArray as it's key. But now the problem is when i create a new object s1. When i want to display the Area i want to test out to print the hash ##sqArray with it's length as it's key and area as it's value. But now the problem is only returning it's area only. e.g 114 only.
suppose to be e.g [ 24 => 114]
When defining the object's property (i.e. it's length), the correct approach is to use an instance variable, not a class variable. This is because (in your particular example), length is an attribute of a specific square and not something that applies to all squares. Your code should look something like this:
class Square
def initialize(length = rand(20))
#length = length
end
def area
#length * #length
end
end
s1 = Square.new
puts s1.area
Now, I am a little unclear what exactly you aim to achieve by use of that class variable ##sqArray - but for example, you could use this store a list of all defined Squares:
class Square
##squares_list = []
def self.all_known
##squares_list
end
def initialize(length = rand(20))
#length = length
##squares_list << self
end
def area
#length * #length
end
end
This would allow you to write code like:
s1 = Square.new #=> #<Square:0x0000000132dbc8 #length=9>
s2 = Square.new(20) #=> #<Square:0x000000012a1038 #length=20>
s1.area #=> 81
s2.area #=> 400
Square.all_known #=> [#<Square:0x0000000132dbc8 #length=9>, #<Square:0x000000012a1038 #length=20>]
Class variables have some odd behaviour and limited use cases however; I would generally advise that you avoid them when starting out learning Ruby. Have a read through a ruby style guide to see some common conventions regarding best practice - including variable/method naming (use snake_case not camelCase or PascalCase), whitespace, etc.

How to find a value that match a first condition from mulpitple conditions

For example there is a array like this:
a = [1,2,3]
I want to find a value that is 2, but if that doesn't exist find a 3 and so on 5.
result = a.find{|i| i == 2} || a.find{|i| i == 3} || a.find{|i| i == 5}
Of course the real values are more complicated, Can I write the function more succinct?
I would recommend using separate validators that encapsulate each condition. It will help you decouple your business logic.
Consider this - instead of Integer array you have Car class instances
class Car
attr_accessor :producer, :colour, :max_speed
def initialize(producer, colour, max_speed)
#producer = producer
#colour = colour
#max_speed = max_speed
end
end
Now you want to select cars, by max_speed, colour and lastly by producer
cars = [
Car.new(:ford, :black, 200),
Car.new(:fiat, :yellow, 170),
Car.new(:renault, :green, 200),
]
instead of putting all conditions in one place, use separate validators
class ColourValidator
def initialize(colour)
#colour = colour
end
def matching?(car)
car.colour == #colour
end
end
class MaxSpeedValidator
def initialize(max_speed)
#max_speed = max_speed
end
def matching?(car)
car.max_speed == #max_speed
end
end
class ProducerValidator
def initialize(producer)
#producer = producer
end
def matching?(car)
car.producer == #producer
end
end
of course vaidators may be much more complex - this is just an idea
and no in one place you create validators
validators = [
ProducerValidator.new(:renault)
]
and later in your code you may write
cars.find { |car| validators.any? { |v| v.matching?(car) } }
benefit is here you don't have to check concrete business logic but just the mechanism of returning element for which any validator matches. Additionally when new validator comes up - you just have to test its logic without reference to the rest
You could use Array#&:
([2,3,5] & [1,2,3]).first #=> 2
([0,3,5] & [1,2,3]).first #=> 3
([0,4,5] & [1,2,3]).first #=> nil
From the doc: "The order is preserved from the original array."
#argus' suggestion (in a comment) should not be overlooked.

Determining a poker hand with two arrays

I want to create a simple multiplayer poker program in ruby, but I feel like I'm reinventing the wheel:
table = [card1, card2, card3, card4, card5]
mike = [card6, card7]
john = [card8, card9]
card6.face = "A"
card6.suit = "spades"
I'm having a hard time writing an algorithm to decide which of the possible hands each player has.
For example, in order to determine if a player was dealt a flush I wrote something like this:
together = table + hand
# Populate hash with number of times each suit was found
$suits.each do |suit|
matched[suit] = together.select{|card| card.suit == suit}.size
end
matched.each do |k,v|
if v == 5
puts "#{k} were seen five times, looks like a flush."
end
end
This doesn't seem very comprehensive (No way to tell if it's an Ace-high or a 6-high flush) nor very ruby-like.
Is there a more obvious way to determine hands in poker?
It's probably far from perfect, but I wrote some methods to detect poker hands to solve a project euler problem. Maybe it can give you some ideas ; full code is here: https://github.com/aherve/Euler/blob/master/pb54.rb
In a nutshell, Hand is defined by an array of Card, that respond to Card.value and Card.type:
def royal_flush?
return #cards if straight_flush? and #cards.map(&:value).max == Poker::values.max
end
def straight_flush?
return #cards if straight? and #cards.map(&:type).uniq.size == 1
end
def four_of_a_kind?
x_of_a_kind?(4)
end
def full_house?
return #hand if three_of_a_kind? and Hand.new(#cards - three_of_a_kind?).one_pair?
return nil
end
def flush?
return #cards if #cards.map(&:type).uniq.size == 1
end
def straight?
return #cards if (vs = #cards.map(&:value).sort) == (vs.min..vs.max).to_a
end
def three_of_a_kind?
x_of_a_kind?(3)
end
def two_pairs?
if (first_pair = one_pair?) and (second = Hand.new(#cards - one_pair?).one_pair?)
return first_pair + second
else
return false
end
end
def one_pair?
x_of_a_kind?(2)
end
def high_card?
#cards.sort_by{|c| c.value}.last
end
private
def x_of_a_kind?(x)
Poker::values.each do |v|
if (ary = #cards.select{|c| c.value == v}).size == x
return ary
end
end
return false
end
end

trying to count the number of times something comes up on a dice. ruby code

This is my code for a dice that shows a direction.
It shows either north, south, east or west when rolled.
I'm trying to figure out a way to count how many times each one of these appears anytime I roll the dice.
Any one any ideas?
class Dice
#def initialize()
#end
def roll
#dice = Array['north','south','east','west'] # makes dice with four sides (directions)
#dice_index = 0 + rand(4) # gets the random index of the array
puts #dice[#dice_index] # prints random direction like a dice
end
def stats
puts #dice_index
north_count =0;
south_count =0;
east_count=0;
west_count=0;
end
end
game_dice = Dice.new
game_dice.roll
game_dice.stats
Your class should look something like this:
class Dice
SIDES = [:north, :south, :east, :west]
def initialize
#rolls = Hash.new(0)
#num_of_sides = SIDES.count
end
def roll
roll = SIDES[rand(#num_of_sides)]
#rolls[roll] += 1
roll
end
def stats
puts #rolls.inspect
end
end

Resources