Forum: Ruby Card tricks with Ruby

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
F82cffce6c0b609f002236943a6b3301?d=identicon&s=25 grrr (Guest)
on 2006-03-16 21:53
(Received via mailing list)
So suppose you have a deck of cards, that might have some number of
cards.

First the cards are shuffled, in effect placed in random order.

Then the deck is split, ie. some number of cards are lifted from the top
of the deck and placed under the remaining cards.

How would one implement this? I was thinking of using an array, but how
to
shuffle the deck, and how to split the deck?

grrr
6dab365a82517fb694650a57ee88e4a4?d=identicon&s=25 joey__ (Guest)
on 2006-03-16 22:04
grrr wrote:
> So suppose you have a deck of cards, that might have some number of
> cards.
>
> First the cards are shuffled, in effect placed in random order.
>
> Then the deck is split, ie. some number of cards are lifted from the top
> of the deck and placed under the remaining cards.
>
> How would one implement this? I was thinking of using an array, but how
> to
> shuffle the deck, and how to split the deck?
>
> grrr

class Array
  def shuffle
    self.sort_by{rand}
  end

  def cut(index)
    (self-self[0..index]).push(*self[0..index])
  end
end
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-03-16 22:06
(Received via mailing list)
On Mar 16, 2006, at 2:53 PM, grrr wrote:

> how to shuffle the deck

 >> cards = %w{A 2 3 4 5 6 7 8 9 T J Q K A}
=> ["A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K",
"A"]
 >> cards = cards.sort_by { rand }  # shuffle
=> ["6", "T", "Q", "5", "A", "J", "2", "7", "4", "8", "A", "9", "K",
"3"]

> and how to split the deck?

 >> cards = cards.values_at(3..-1, 0..2)  # cut
=> ["5", "A", "J", "2", "7", "4", "8", "A", "9", "K", "3", "6", "T",
"Q"]

Hope that gives you some new ideas.

James Edward Gray II
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-03-16 22:06
(Received via mailing list)
Hi --

On Fri, 17 Mar 2006, grrr wrote:

> So suppose you have a deck of cards, that might have some number of cards.
>
> First the cards are shuffled, in effect placed in random order.
>
> Then the deck is split, ie. some number of cards are lifted from the top
> of the deck and placed under the remaining cards.
>
> How would one implement this? I was thinking of using an array, but how to
> shuffle the deck, and how to split the deck?

You could do:

   def shuffle
     sort_by { rand }
   end

(Disclaimer: I haven't really followed the discussions of how random
this and other techniques for shuffling are.)

Here's a demo of how you might cut the deck (using a small deck here):

   irb(main):015:0> deck = *1..10
   => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
   irb(main):016:0> deck.concat(deck.slice!(0,5))
   => [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]


David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black
81d609425e306219d54d793a0ad98bce?d=identicon&s=25 Matthew Moss (Guest)
on 2006-03-16 22:09
(Received via mailing list)
deck = (1..52).to_a

# shuffle
deck = deck.sort_by { rand }

# cut
x = rand(52)
deck = deck[x..-1] + deck[0...x]   # notice differing amounts of dots
25e11a00a89683f7e01e425a1a6e305c?d=identicon&s=25 Wilson Bilkovich (Guest)
on 2006-03-16 22:21
(Received via mailing list)
On 3/16/06, grrr <grrr@toto.maatti> wrote:
> So suppose you have a deck of cards, that might have some number of cards.
>
> First the cards are shuffled, in effect placed in random order.
>
> Then the deck is split, ie. some number of cards are lifted from the top
> of the deck and placed under the remaining cards.
>
> How would one implement this? I was thinking of using an array, but how to
> shuffle the deck, and how to split the deck?
>

How about this as a starting point?

class Card
  attr_reader :card_id
  def initialize(card_id)
    @card_id = card_id
  end
end

class Deck
  attr_reader :cards
  def initialize(card_count = 52)
    @cards = []
    card_count.times {|i| @cards << Card.new(i)}
    shuffle
  end
  def shuffle
    @cards.sort! {rand}
  end
  def cut(offset = nil)
    top = @cards[0,(offset || @cards.length / 2)]
    @cards = (@cards - top) + top
  end
end

deck.cut defaults to cutting the deck in half.  deck.cut(5) takes the
top 5 cards and puts them on the bottom of the deck.
In real life, the attr_reader is bad form, because it exposes the
implementation of '@cards' to clients.  You don't really want people
shuffling the deck without calling Deck#shuffle.
To fix that, you could make custom accessors, like:
each_card, card_at(position), deal_card, etc.
Ffcb418e17cac2873d611c2b8d8d891c?d=identicon&s=25 Benjohn Barnes (Guest)
on 2006-03-17 01:01
(Received via mailing list)
> >> cards = cards.values_at(3..-1, 0..2)  # cut
> => ["5", "A", "J", "2", "7", "4", "8", "A", "9", "K", "3", "6",
> "T", "Q"]

:) Heh, cool - I didn't know values_at did that. Nice :)

> Hope that gives you some new ideas.

:) I'm sure it'll be useful!
280b41a88665fd8c699e83a9a25ef949?d=identicon&s=25 Stephen Waits (Guest)
on 2006-03-17 07:13
(Received via mailing list)
Matthew Moss wrote:
> deck = deck[x..-1] + deck[0...x]   # notice differing amounts of dots

I find myself constantly pointing this out too.. is anyone else bothered
by it?  Has Matz weighed in on this in the past?

It seems error-prone to me.  Extraordinarily more error-prone than other
"stuff" in Ruby.

--Steve
18ec2a014a37e792f7279d18dcd0e322?d=identicon&s=25 francisrammeloo@hotmail.com (Guest)
on 2006-03-17 13:45
(Received via mailing list)
>> cards = cards.sort_by { rand }

How does this work??
I thought the code block should yield either -1, 0 or +1, but rand
yields a number between 0 and 1. Or am I mistaken?

Best regards,
Francis
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-03-17 14:01
(Received via mailing list)
Hi --

On Fri, 17 Mar 2006, Stephen Waits wrote:

> Matthew Moss wrote:
>> deck = deck[x..-1] + deck[0...x]   # notice differing amounts of dots
>
> I find myself constantly pointing this out too.. is anyone else bothered by
> it?  Has Matz weighed in on this in the past?
>
> It seems error-prone to me.  Extraordinarily more error-prone than other
> "stuff" in Ruby.

Maybe I need more caffeine, but what exactly is the problem you're
referring to?


David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black
10d4acbfdaccb4eee687a428ca00a5d8?d=identicon&s=25 Jim Weirich (weirich)
on 2006-03-17 14:01
francisrammeloo@hotmail.com wrote:
>>> cards = cards.sort_by { rand }
>
> How does this work??
> I thought the code block should yield either -1, 0 or +1, but rand
> yields a number between 0 and 1. Or am I mistaken?
>

You are thing of the normal sort method which looks like this:

   cards.sort { |a, b|
     (a.suit <=> b.suit).nonzero? || (a.value <=> b.value)
   }

With sort_by, you need to return a key value that will be used as the
comparison key for that particular value.

   cards.sort_by { |card|  [card.suit, card.value] }

Sort_by actually does a "Schwartzian Transform"[1] on the array to
perform the sorting.

--
-- Jim Weirich

[1] A trick developed by Randall Schwartz to speed sorting in Perl.  See
http://en.wikipedia.org/wiki/Schwartzian_Transform
05be5d6610e2c3f1780aa0e39e902e93?d=identicon&s=25 Farrel Lifson (Guest)
on 2006-03-17 14:07
(Received via mailing list)
I think you're confusing the <=> operator needed to mixin Enumerable.

The block in sort_by just returns a value that the sort_by method
should assign to each element in the array so that they may be
ordered. The returned value itself could be anything as long as it
implements Comparable (or it might just need <=>). So for instance
when you say

deck.sort_by do |card|
  card.suite
end

the sort_by method get's all the values of the suites of the cards in
the deck and then sorts them according to that. The suite could be a
string ("Hearts") or a numeric value (0=Hearts, 1=Diamonds etc). For
instance

[1,2,3,4].sort_by do |number|
  number % 2
end

will return [4,2,3,1]. Because the value of the block can either be 0
or 1 the array is sorted into two 'chunks': 4 & 2 (number % 2 ==0)  1
& 3 (number % 2 == 1).

Farrel
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-03-17 14:16
(Received via mailing list)
Hi --

On Fri, 17 Mar 2006, grrr wrote:

> So suppose you have a deck of cards, that might have some number of cards.
>
> First the cards are shuffled, in effect placed in random order.
>
> Then the deck is split, ie. some number of cards are lifted from the top
> of the deck and placed under the remaining cards.
>
> How would one implement this? I was thinking of using an array, but how to
> shuffle the deck, and how to split the deck?

I have to say, it only dawned on me just now that it's kind of funny
to cut the deck when the dealer is a computer.  The idea of cutting
the deck is to thwart attempts by the dealer to stack the deck.  I
actually kind of love the idea that one has to do this in the case of
a computer :-)


David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black
F9497029243610884623d758ec1c8984?d=identicon&s=25 gparsons (Guest)
on 2006-03-17 14:50
(Received via mailing list)
> deck = deck[x..-1] + deck[0...x]   # notice differing amounts of
dots

I'd never seen this before so i decided to give it a try.  Without the
three dots on the righthand side it would be inclusive right?  As in
you'd get the xth element twice.

- Geoff
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-03-17 15:06
(Received via mailing list)
Hi --

On Fri, 17 Mar 2006, gparsons wrote:

> > deck = deck[x..-1] + deck[0...x]   # notice differing amounts of
> dots
>
> I'd never seen this before so i decided to give it a try.  Without the
> three dots on the righthand side it would be inclusive right?  As in
> you'd get the xth element twice.

Yes, that's right.


David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-03-17 15:15
(Received via mailing list)
On Mar 17, 2006, at 7:04 AM, Farrel Lifson wrote:

> I think you're confusing the <=> operator needed to mixin Enumerable.

Technically, the only method required by Enumerable is each().  You
do need to provide <=>() if you want to use method like sort(), min
(), or max() without a block though.

The Comparable mix-in requires <=>().

James Edward Gray II
81d609425e306219d54d793a0ad98bce?d=identicon&s=25 Matthew Moss (Guest)
on 2006-03-17 15:21
(Received via mailing list)
I point it out to people who I think may not have seen it before, just
so they don't think it a typo.

It doesn't really bother me, because I've gotten used to it.  And I
regularly make use of it, as deep as I am into C++ standard template
library practice.

Unit testing could catch some errors, but I do agree if something
reasonably simple could replace it syntax-wise, it might be a tad
better.  What that something simple is, I don't know...  The simplest
solution would be to use mathematical notation, but that would be a
pita for the compiler to parse:   [0..x)
05be5d6610e2c3f1780aa0e39e902e93?d=identicon&s=25 Farrel Lifson (Guest)
on 2006-03-17 15:28
(Received via mailing list)
My bad I meant comparable.
280b41a88665fd8c699e83a9a25ef949?d=identicon&s=25 Stephen Waits (Guest)
on 2006-03-17 17:55
(Received via mailing list)
Matthew Moss wrote:
>
>
[snip]

Well, it's definitely one of the (very) few things that has bothered me
about Ruby.  For example:

A Rubyist might argue that this is more error prone:

     for(int i=0;i<10;i++)

than this:

     10.times

Which is a valid argument, and the result is elegant.  And, we see stuff
like this throughout Ruby.  As Why's guide says often, read the code
aloud.

So yes, .. vs ... really bugs me.  While they are convenient operators,
I also see them as too error prone to fit in Ruby.

As an earlier mentioned example, when I've taught Ruby, I always feel
like I have to wave the red flags when I talk about ranges.

 > Unit testing could catch some errors, but I do agree if something
 > reasonably simple could replace it syntax-wise, it might be a tad
 > better.  What that something simple is, I don't know...  The simplest
 > solution would be to use mathematical notation, but that would be a
 > pita for the compiler to parse:   [0..x)

Yah, [x..y], [x..y), (x..y], (x..y) would be sweetness.  It's slightly
less error-prone IMO since it's following a common (math) notation.
Still, maybe not perfect.

Do any of the Ruby dinosaurs know if Matz has a stance on this issue?

--Steve
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-03-17 18:05
(Received via mailing list)
Hi --

On Sat, 18 Mar 2006, Stephen Waits wrote:

>
> As an earlier mentioned example, when I've taught Ruby, I always feel like I
> not perfect.
Can you really stand to look at that?  It gives me the same feeling as
putting my shoes on the wrong feet :-)

I'm not sure what it is about the range operators that bothers you.
Are you finding it hard to remember which is which?  My way of
remembering is: every range is the same width, in relation to the
operators.  Since the ... operator is wider, the end-point gets pushed
outside the range:

         v  v
         a..b
         a...b
         ^  ^

So b is off the map in the second one.  This is of course a schematic
way to view it (not proportional to the contents of the range), but I
found it helpful and maybe you will.


David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black
F82cffce6c0b609f002236943a6b3301?d=identicon&s=25 grrr (Guest)
on 2006-03-17 18:11
(Received via mailing list)
First of all I wish to humbly send my thanks everyone taking their time
to
share their pearls of wisdom! You have taught me alot! Hehe my honorable
mention goes to James for the cards.sort_by{ rand } which is nice and
snappy. Also, I thought the 'deck = deck[x..-1] + deck[0...x]' was clear
to me, even if I am a ruby newb. Now lets move on..

On Fri, 17 Mar 2006 22:14:47 +0900, dblack wrote:
> I have to say, it only dawned on me just now that it's kind of funny to
> cut the deck when the dealer is a computer.  The idea of cutting the deck
> is to thwart attempts by the dealer to stack the deck.  I actually kind of
> love the idea that one has to do this in the case of a computer :-)

Yes, I want the whole deal to be as realistic as possible! Down to
last detail! In real life cards are not really shuffled into random
order!

And thus theres need for realistic Riffle! 8)

Around here, before any card games, after the deck has been
cut into two by the dealer it is of course 'recombined' by taking the
two
decks, and mixing them back into one deck, in a manouver called 'the
riffle'.

"A riffle, in which half of the deck is held in each hand with the
thumbs
inward, then cards are released by the thumbs so that they fall to the
table intertwined." Thus *almost* every card other card is from the
other
half of the deck, and vice versa - with the odd double, triple or
quadruple cards sometimes falling on the table from either pack!

You can find a photo and detailed description of the riffle here:
http://en.wikipedia.org/wiki/Shuffle

This is done three times, and finally one of the players
gets to cut the deck and the dealer then recombines it and deals out
cards. Ie. dealer does 'cut + riffle' three times, then player 'cuts',
then dealer riffles, and game can then begin.

How would you code riffle?
81d609425e306219d54d793a0ad98bce?d=identicon&s=25 Matthew Moss (Guest)
on 2006-03-17 18:11
(Received via mailing list)
> > Yah, [x..y], [x..y), (x..y], (x..y) would be sweetness.  It's slightly less
> > error-prone IMO since it's following a common (math) notation. Still, maybe
> > not perfect.
>
> Can you really stand to look at that?  It gives me the same feeling as
> putting my shoes on the wrong feet :-)

As part-mathematician, I whole-heartedly say, "Yes!"  It's a compact,
consistent and clear representation of closed [ and open ( ends of
ranges.

As part-programmer, I recognize that it would be a bitch to parse,
considering how often we make use of braces for all sorts of other
needs (array access, expression grouping, function calls, etc, etc,
etc).


> I'm not sure what it is about the range operators that bothers you.
> Are you finding it hard to remember which is which?  My way of
> remembering is: every range is the same width, in relation to the
> operators.  Since the ... operator is wider, the end-point gets pushed
> outside the range:
>
>          v  v
>          a..b
>          a...b
>          ^  ^

This is basically how I now remember the difference between the two,
and so having both operators doesn't bother me as much anymore.  But I
will admit that at first I could never remember the difference, and
can see it as confusing to newbs.
81d609425e306219d54d793a0ad98bce?d=identicon&s=25 Matthew Moss (Guest)
on 2006-03-17 18:37
(Received via mailing list)
> How would you code riffle?

Start with a merge sort:

def merge(left, right, &pred)
   if right.empty?
      left.dup
   elsif left.empty?
      right.dup
   elsif pred.call(left.first, right.first)
      [left.first] + merge(left[1..-1], right, &pred)
   else
      [right.first] + merge(left, right[1..-1], &pred)
   end
end

And then riffle!

def riffle(deck)
   n = deck.size / 2
   left, right = deck[0...n], deck[n..-1]
   merge(left, right) { rand < 0.5 }
end

Or, to simulate one side's cards being more likely given the other
side's card just went down:

def riffle(deck)
   n = deck.size / 2
   left, right = deck[0...n], deck[n..-1]
   p = 0.5
   merge(left, right) do
      res = (rand < p)
      p = res ? p*p : Math.sqrt(p)
      res
   end
end
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-03-17 18:40
(Received via mailing list)
Hi --

On Sat, 18 Mar 2006, grrr wrote:

>> love the idea that one has to do this in the case of a computer :-)
> riffle'.
That's different from the person next to the dealer cutting the deck,
though, which happens after all the shuffling is over.

> gets to cut the deck and the dealer then recombines it and deals out
> cards. Ie. dealer does 'cut + riffle' three times, then player 'cuts',
> then dealer riffles, and game can then begin.
>
> How would you code riffle?

   class Deck
     def riffle
       sort_by { rand }   # just don't tell anyone :-)
     end
   end

But seriously... here's a first attempt, maybe useful at least as a
starting point for better:

class Deck < Array
   def initialize
     concat([*1..52])
   end

   def split            # an even cut; you'd want a real cut too
     [self[0...26],self[26..52]]
   end

   def pure_riffle
     s = split
     s[0].zip(s[1]).flatten
   end

   def riffle(max_consec = 3)
     s,t = split
     done = []
     until s.empty? || t.empty?
       done.push(s.shift,t.shift)
       x = if rand(2).zero? then s else t end
       if time_for_glitch?
         rand(max_consec + 1).times { done.push(x.shift) }
       end
     end
     done + s + t
   end

   def time_for_glitch?
     rand(5).zero?
   end
end


--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black
Ffcb418e17cac2873d611c2b8d8d891c?d=identicon&s=25 Benjohn Barnes (Guest)
on 2006-03-18 01:47
(Received via mailing list)
On 17 Mar 2006, at 06:11, Stephen Waits wrote:

> Matthew Moss wrote:
>> deck = deck[x..-1] + deck[0...x]   # notice differing amounts of dots
>
> I find myself constantly pointing this out too.. is anyone else
> bothered by it?  Has Matz weighed in on this in the past?

I like being able to express either. I often don't remember which is
which though. It feels like they're the wrong way round because three
dots ought to go a little bit further than two :)
10d4acbfdaccb4eee687a428ca00a5d8?d=identicon&s=25 Jim Weirich (weirich)
on 2006-03-18 06:18
Benjohn Barnes wrote:
> I like being able to express either. I often don't remember which is
> which though. It feels like they're the wrong way round because three
> dots ought to go a little bit further than two :)

The dots *do* go a bit further ... far enough to push the last value
right out of the range ;)

-- Jim Weirich
280b41a88665fd8c699e83a9a25ef949?d=identicon&s=25 Stephen Waits (Guest)
on 2006-03-18 07:20
(Received via mailing list)
dblack@wobblini.net wrote:
> I'm not sure what it is about the range operators that bothers you.
> Are you finding it hard to remember which is which?  My way of
> remembering is: every range is the same width, in relation to the
> operators.  Since the ... operator is wider, the end-point gets pushed
> outside the range:

That you had to invent that mnemonic device just to remember what they
is what I don't like about them.  That they differ by a single '.' is
error-prone.  It just one of the few things I've run across in Ruby that
doesn't feel like the rest of Ruby (very straightforward, POLS, etc.).

I don't want to start a whole thing, though, which is why I inquired as
to whether Matz has discussed this publicly in the past.

Thanks,
Steve
37a3c73ffbf864e4b28f7f2384ee12ce?d=identicon&s=25 Timothy Hunter (tim-hunter)
on 2006-03-18 13:44
(Received via mailing list)
Benjohn Barnes wrote:
>
>
> I like being able to express either. I often don't remember which is
> which though. It feels like they're the wrong way round because three
> dots ought to go a little bit further than two :)
>
>
>
from _why's (poignant) guide:

"When you see that third dot, imagine opening the accordion slightly.
Just enough to let one note from its chamber. The note is that end
value. We?ll let the sky eat it."
Bd0203dc8478deb969d72f52e741bd4f?d=identicon&s=25 Daniel Baird (Guest)
on 2006-03-18 19:49
(Received via mailing list)
On 18/03/06, Tim Hunter <cyclists@nc.rr.com> wrote:
>
>
> from _why's (poignant) guide:
>
> "When you see that third dot, imagine opening the accordion slightly.
> Just enough to let one note from its chamber. The note is that end
> value. We'll let the sky eat it."
>
>
"We'll let the sky eat it." .. is my favourite sentence in the whole
(poignant) guide.

--
Daniel Baird
http://danielbaird.com (TiddlyW;nks! :: Whiteboard Koala :: Blog ::
Things
That Suck)
[[My webhost uptime is ~ 92%.. if no answer pls call again later!]]
Ddcd8a3f27c52e666bef86b1ab3d74bc?d=identicon&s=25 Vinney C. (vinney_c)
on 2012-09-19 04:23
Daniel Baird wrote in post #49575:
> On 18/03/06, Tim Hunter <cyclists@nc.rr.com> wrote:
>>
>>
>> from _why's (poignant) guide:
>>
>> "When you see that third dot, imagine opening the accordion slightly.
>> Just enough to let one note from its chamber. The note is that end
>> value. We'll let the sky eat it."
>>
>>
> "We'll let the sky eat it." .. is my favourite sentence in the whole
> (poignant) guide.
>
> --
> Daniel Baird
> http://danielbaird.com (TiddlyW;nks! :: Whiteboard Koala :: Blog ::
> Things
> That Suck)
> [[My webhost uptime is ~ 92%.. if no answer pls call again later!]]


I googled "we'll let the sky eat it" to see where else on the internet
it turns up because it was my favorite sentence in the whole guide as
well. Favorite sentence I've seen around for a short while, for that
matter.
This topic is locked and can not be replied to.