Moving a specific value to the end of a randomly populated array

Viewed 56

I am creating a blackjack scoring method and I'm trying to move the Ace(s) to the end of the array in order to count it last. How would I do this? Because this is not working

if hand.include?("Ace") 
  hand.map{ |card| hand.last(card) if card == "Ace" }
end
2 Answers

Two approaches work. One is to sort them to the end:

hand = %w[ 2 9 4 Q 3 2 A T J 6 ]

hand.sort_by { |v| v == 'A' ? 1 : 0 }
# => ["6", "9", "4", "Q", "3", "2", "2", "T", "J", "A"]

Another is to partition like this:

hand.partition { |v| v != 'A' }.flatten
# => ["2", "9", "4", "Q", "3", "2", "T", "J", "6", "A"]

If you had a proper Card class that implemented something like ace? then this is even easier:

hand.partition(&:ace?).reverse.flatten

You could also make it so that an A sorts as 11, so it ends up last, as in:

CARD_SORT_VALUE = Hash.new { |h,k| h[k] = k.to_i }.merge(
  'J' => 10,
  'Q' => 10,
  'K' => 10,
  'A' => 11
).freeze

Where you can use that to sort, like:

hand.sort_by { |c| CARD_SORT_VALUE[c] }

Again, even better if you have a Card class that implements Comparable and has a <=> method to allow for sorting as in cards.sort just works.

If you want to solve the general problem of "what value(s) does this hand have" consider defining values as an array, as in:

CARD_VALUE = {
  '2' => [ 2 ],
  '3' => [ 3 ],
  '4' => [ 4 ],
  '5' => [ 5 ],
  '6' => [ 6 ],
  '7' => [ 7 ],
  '8' => [ 8 ],
  '9' => [ 9 ],
  'T' => [ 10 ],
  'J' => [ 10 ],
  'Q' => [ 10 ],
  'K' => [ 10 ],
  'A' => [ 1, 11 ]
}.freeze

Where you can then work through all possible combinations of values to arrive at the final results:

def hand_value(hand)
  hand.map { |c| CARD_VALUE[c] }.inject([ [ ] ]) do |accum, arr|
    accum.flat_map do |a|
      arr.map do |v|
        a + [ v ]
      end
    end
  end.map(&:sum).uniq
end

As in:

hand_value(%w[ A T Q ])
# => [21, 31]

hand_value(%w[ A A 2 ])
# => [4, 14, 24]

If Ace exists, the index function will return it's index. There's an array method for deleting at a particular index that returns the deleted element. the returned element can then be pushed to the back of the array. All of this can be accomplished in one line, Excuse LoD violations:

hand=["heart","spade","Ace","olive", "branch"]

if hand.include?("Ace")
  hand.push(hand.delete_at(hand.index("Ace")))
end

p hand #["heart", "spade", "olive", "branch", "Ace"]

NB:only the first 'Ace' will be relocated.

Related