Class: Deck
- Defined in:
- lib/quiz1/t/solutions/Bill Guindon/solitaire.rb,
lib/quiz1/t/solutions/Jamis Buck/lib/cipher.rb,
lib/quiz1/t/solutions/Dennis Ranke/solitaire.rb,
lib/quiz1/t/solutions/Glen M. Lewis/solitaire.rb,
lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb,
lib/quiz1/t/solutions/Niklas Frykholm/solitaire.rb,
lib/quiz1/t/solutions/Jim Menard/solitaire_cypher.rb
Overview
Handles the deck
Instance Attribute Summary collapse
-
#cards ⇒ Object
Returns the value of attribute cards.
-
#order ⇒ Object
readonly
Returns the value of attribute order.
Instance Method Summary collapse
-
#add_card(name, suit, rank) ⇒ Object
build order while adding.
- #build_deck ⇒ Object
- #cipher_letter ⇒ Object
- #cipher_shuffle! ⇒ Object
-
#count_cut ⇒ Object
Perform a count cut using the value of the bottom card.
- #create_keystream(count) ⇒ Object
-
#cut_cards(cuts) ⇒ Object
does as many cuts as you give it.
- #dump ⇒ Object
-
#find_card(name, suit) ⇒ Object
Uses order to hunt for cards (Joker searches).
- #find_joker(j) ⇒ Object
-
#generate_next_keystream_value ⇒ Object
Return the next keystream value as a number 1-26 (not a string).
- #get ⇒ Object
-
#initialize ⇒ Deck
constructor
Initializes the deck with the default values.
-
#key ⇒ Object
Keys the deck and returns itself.
- #keystream_message(msg) ⇒ Object
- #letter_at(index) ⇒ Object
-
#move(card, distance) ⇒ Object
Move a card a certain distance.
- #move_a ⇒ Object
-
#move_A ⇒ Object
Operation “move a” (step 2).
- #move_b ⇒ Object
-
#move_B ⇒ Object
Operation “move b” (step 3).
- #move_card_down(pos, num) ⇒ Object
-
#move_down(index) ⇒ Object
Moves the index one place down while treating the used array as circular list.
-
#next_keystream ⇒ Object
Return the next kestream value as a number (not a string).
- #next_letter ⇒ Object
- #number_value(x) ⇒ Object
- #output ⇒ Object
-
#output_letter ⇒ Object
Operation “output the found letter” (step 6).
-
#output_number ⇒ Object
Return the output number (not letter).
-
#shuffle(init, method = :fisher_yates) ⇒ Object
Shuffle the deck using the initialization number
init
and the methodmethod
. -
#slice(from, to) ⇒ Object
Returns a non-nil cut of cards from the deck.
- #to_a ⇒ Object
- #to_s ⇒ Object
-
#triple_cut ⇒ Object
Perform a triple cut around the two jokers.
- #triple_cut_split(a, b) ⇒ Object
- #update ⇒ Object
-
#update_order ⇒ Object
simple, but not very efficient.
- #value_at(index) ⇒ Object
Methods inherited from Array
#collect_peel, #generate_keystream, #next_key, #peel, #wrap_down
Constructor Details
#initialize ⇒ Deck
Initializes the deck with the default values
10 11 12 13 |
# File 'lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb', line 10 def initialize @deck = (1..52).to_a + [ "A", "B" ] @length = @deck.length end |
Instance Attribute Details
#cards ⇒ Object
Returns the value of attribute cards.
13 14 15 |
# File 'lib/quiz1/t/solutions/Bill Guindon/solitaire.rb', line 13 def cards @cards end |
#order ⇒ Object (readonly)
Returns the value of attribute order.
13 14 15 |
# File 'lib/quiz1/t/solutions/Bill Guindon/solitaire.rb', line 13 def order @order end |
Instance Method Details
#add_card(name, suit, rank) ⇒ Object
build order while adding.
40 41 42 43 44 |
# File 'lib/quiz1/t/solutions/Bill Guindon/solitaire.rb', line 40 def add_card(name, suit, rank) card = Card.new(name, suit, rank) @cards << card @order << card.to_s end |
#build_deck ⇒ Object
25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/quiz1/t/solutions/Bill Guindon/solitaire.rb', line 25 def build_deck [:Clubs, :Diamonds, :Hearts, :Spades].each do |suit| rank = 0 'A23456789TJQK'.each_byte do |name| # 'real' cards have a rank value rank += 1 add_card(name.chr, suit, rank) end end # Jokers have no rank value 'AB'.each_byte {|name| add_card(name.chr, :Joker, 0)} end |
#cipher_letter ⇒ Object
32 33 34 35 36 37 38 39 |
# File 'lib/quiz1/t/solutions/Jamis Buck/lib/cipher.rb', line 32 def cipher_letter count = @deck.first count = 53 if count.is_a?( String ) result = @deck[ count ] return nil unless result.is_a? Fixnum result -= 26 while result > 26 return (result+64).chr end |
#cipher_shuffle! ⇒ Object
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/quiz1/t/solutions/Jamis Buck/lib/cipher.rb', line 10 def cipher_shuffle! # move joker A down one card, circularly reposition_card( "A", 1 ) # move joker B down two cards, circularly reposition_card( "B", 2 ) joker_A = @deck.index( "A" ) joker_B = @deck.index( "B" ) # move all cards above the top-most joker, below the bottom-most joker, and # all cards below the bottom-most joker, above the top-most joker. top = ( joker_A < joker_B ? joker_A : joker_B ) bottom = ( joker_A > joker_B ? joker_A : joker_B ) @deck = @deck[bottom+1..-1] + @deck[top..bottom] + @deck[0,top] # take value of the bottom-most card, and cut that many cards off the # top, inserting them just before the bottom-most card. cut = @deck.last @deck = @deck[cut..-2] + @deck[0,cut] + [ @deck.last ] end |
#count_cut ⇒ Object
Perform a count cut using the value of the bottom card. Cut the bottom card’s value in cards off the top of the deck and reinsert them just above the bottom card.
33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb', line 33 def count_cut print "before count_cut: " if $debug self.dump if $debug temp = self.dup self.clear num = temp[-1].value temp.slice(num..-2).each {|x| self.push(x) } temp.slice(0..(num-1)).each {|x| self.push(x) } self.push(temp[-1]) print "after count_cut: " if $debug self.dump if $debug end |
#create_keystream(count) ⇒ Object
6 7 8 9 10 11 12 13 14 |
# File 'lib/quiz1/t/solutions/Dennis Ranke/solitaire.rb', line 6 def create_keystream(count) stream = [] count.times do letter = next_letter redo unless letter stream << letter end return stream end |
#cut_cards(cuts) ⇒ Object
does as many cuts as you give it.
52 53 54 55 56 57 58 59 60 |
# File 'lib/quiz1/t/solutions/Bill Guindon/solitaire.rb', line 52 def cut_cards(cuts) cards = [] loc = 0 [cuts].flatten.each_with_index do |cut, idx| cards[idx] = @cards[loc...cut] loc = cut end cards << @cards[loc...@cards.length] end |
#dump ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/quiz1/t/solutions/Glen M. Lewis/solitaire.rb', line 64 def dump self.each do |c| if (c.value == 53) print c.face_value else print c.value end print " " end print "\n\n" if (@deck_size != self.size) then puts "ERROR! Deck size changed to #{self.size}" exit end end |
#find_card(name, suit) ⇒ Object
Uses order to hunt for cards (Joker searches).
47 48 49 |
# File 'lib/quiz1/t/solutions/Bill Guindon/solitaire.rb', line 47 def find_card(name, suit) return @order.index(Card.to_s(name, suit)) end |
#find_joker(j) ⇒ Object
80 81 82 83 84 85 86 87 |
# File 'lib/quiz1/t/solutions/Glen M. Lewis/solitaire.rb', line 80 def find_joker(j) self.each_index do |i| if (self[i].face_value == j) return i end end puts "ERROR: Could not find joker '#{j}' in deck." end |
#generate_next_keystream_value ⇒ Object
Return the next keystream value as a number 1-26 (not a string).
75 76 77 78 79 80 81 |
# File 'lib/quiz1/t/solutions/Jim Menard/solitaire_cypher.rb', line 75 def generate_next_keystream_value move(@joker_a, 1) move(@joker_b, 2) triple_cut() count_cut() return output_number() end |
#get ⇒ Object
61 62 63 64 65 66 67 68 69 70 |
# File 'lib/quiz1/t/solutions/Niklas Frykholm/solitaire.rb', line 61 def get while true update c = output if c != :A and c != :B letter = ( ((c-1) % 26) + 65 ).chr return letter end end end |
#key ⇒ Object
Keys the deck and returns itself.
59 60 61 62 |
# File 'lib/quiz1/t/solutions/Jim Menard/solitaire_cypher.rb', line 59 def key # do nothing; keyed when initialized self end |
#keystream_message(msg) ⇒ Object
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/quiz1/t/solutions/Glen M. Lewis/solitaire.rb', line 140 def (msg) # result = "DWJXHYRFDGTMSHPUURXJ" result = "" while (result.length < msg.length) do # Step 2 - Move the A Joker down one card pos = find_joker("AJoker") move_card_down(pos, 1) # Step 3 - Move the B Joker down two cards pos = find_joker("BJoker") move_card_down(pos, 2) # Step 4 - Triple cut split around two jokers apos = find_joker("AJoker") bpos = find_joker("BJoker") triple_cut_split(apos, bpos) # Step 5 - Count cut count_cut # Step 6 - Output letter - might be nil letter = output_letter result << letter if letter end return result end |
#letter_at(index) ⇒ Object
74 75 76 77 |
# File 'lib/quiz1/t/solutions/Dennis Ranke/solitaire.rb', line 74 def letter_at(index) id = @deck[index] (id > 51) ? nil : (id % 26) + 1 end |
#move(card, distance) ⇒ Object
Move a card a certain distance. Wrap around the end of the deck.
84 85 86 87 88 89 90 |
# File 'lib/quiz1/t/solutions/Jim Menard/solitaire_cypher.rb', line 84 def move(card, distance) old_pos = @cards.index(card) new_pos = old_pos + distance new_pos -= (@cards.length-1) if new_pos >= @cards.length @cards[old_pos,1] = [] @cards[new_pos,0] = [card] end |
#move_a ⇒ Object
15 16 17 |
# File 'lib/quiz1/t/solutions/Niklas Frykholm/solitaire.rb', line 15 def move_a move_down(@deck.index(:A)) end |
#move_A ⇒ Object
Operation “move a” (step 2)
15 16 17 |
# File 'lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb', line 15 def move_A move_down( @deck.index( 'A' ) ) end |
#move_b ⇒ Object
19 20 21 |
# File 'lib/quiz1/t/solutions/Niklas Frykholm/solitaire.rb', line 19 def move_b move_down(move_down(@deck.index(:B))) end |
#move_B ⇒ Object
Operation “move b” (step 3)
20 21 22 |
# File 'lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb', line 20 def move_B 2.times { move_down( @deck.index( 'B' ) ) } end |
#move_card_down(pos, num) ⇒ Object
89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/quiz1/t/solutions/Glen M. Lewis/solitaire.rb', line 89 def move_card_down(pos, num) print "before move_card_down(#{pos}, #{num}): " if $debug self.dump if $debug dest = pos + num dest -= (self.size-1) if (dest >= self.size) card = self.delete_at(pos) temp = self.dup self.clear temp.slice(0, dest).each {|x| self.push(x) } self << card temp.slice(dest..(-1)).each {|x| self.push(x) } print "after move_card_down(#{pos}, #{num}): " if $debug self.dump if $debug end |
#move_down(index) ⇒ Object
Moves the index one place down while treating the used array as circular list.
78 79 80 81 82 83 84 85 |
# File 'lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb', line 78 def move_down( index ) if index == @deck.length - 1 @deck[1..1] = @deck[index], @deck[1] @deck.pop else @deck[index], @deck[index + 1] = @deck[index + 1], @deck[index] end end |
#next_keystream ⇒ Object
Return the next kestream value as a number (not a string). Keep going until we have a non-joker value.
66 67 68 69 70 71 72 |
# File 'lib/quiz1/t/solutions/Jim Menard/solitaire_cypher.rb', line 66 def next_keystream val = JOKER_VALUE until val != JOKER_VALUE val = generate_next_keystream_value end val end |
#next_letter ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/quiz1/t/solutions/Dennis Ranke/solitaire.rb', line 16 def next_letter ## # move the jokers ## 2.times do |j| # find the joker index = @deck.index(52 + j) # remove it from the deck @deck.delete_at(index) # calculate new index index = ((index + j) % 53) + 1 # insert the joker at that index @deck[index, 0] = 52 + j end ## # do the tripple cut ## # first find both jokers a = @deck.index(52) b = @deck.index(53) # sort the two indeces low, hi = [a, b].sort # get the lower and upper parts of the deck upper = @deck.slice!((hi + 1)..-1) lower = @deck.slice!(0, low) # swap them @deck = upper + @deck + lower ## # do the count cut ## # find out the number of cards to cut count = value_at(53) # remove them from the top of the deck cards = @deck.slice!(0, count) # reinsert them just above the lowest card @deck[-1, 0] = cards return letter_at(value_at(0)) end |
#number_value(x) ⇒ Object
40 41 42 43 |
# File 'lib/quiz1/t/solutions/Niklas Frykholm/solitaire.rb', line 40 def number_value(x) return 53 if x == :A or x == :B return x end |
#output ⇒ Object
50 51 52 |
# File 'lib/quiz1/t/solutions/Niklas Frykholm/solitaire.rb', line 50 def output return @deck[ number_value(@deck[0]) ] end |
#output_letter ⇒ Object
Operation “output the found letter” (step 6)
40 41 42 43 44 45 46 47 48 |
# File 'lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb', line 40 def output_letter num = self[0].value card = self[num] return nil if (card.value == 53) num = (card.value > 26 ? card.value-26 : card.value) char = (num-1 + "A"[0]).chr puts "card.value=#{card.value}, char=#{char}" if $debug return char end |
#output_number ⇒ Object
Return the output number (not letter). Convert the top card to it’s value and count down that many cards from the top of the deck, with the top card itself being card number one. Look at the card immediately after your count and convert it to a letter. This is the next letter in the keystream. If the output card is a joker, no letter is generated this sequence. This step does not alter the deck.
122 123 124 125 126 127 128 |
# File 'lib/quiz1/t/solutions/Jim Menard/solitaire_cypher.rb', line 122 def output_number i = @cards[0].to_i i -= @cards.length if i >= @cards.length num = @cards[i].to_i num -= 26 if num > 26 num end |
#shuffle(init, method = :fisher_yates) ⇒ Object
Shuffle the deck using the initialization number init
and the method method
. Currently there are only two methods: :fisher_yates
and naive
.
54 55 56 57 |
# File 'lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb', line 54 def shuffle( init, method = :fisher_yates ) srand( init ) self.send( method.id2name + "_shuffle", @deck ) end |
#slice(from, to) ⇒ Object
Returns a non-nil cut of cards from the deck.
111 112 113 114 |
# File 'lib/quiz1/t/solutions/Jim Menard/solitaire_cypher.rb', line 111 def slice(from, to) slice = @cards[from..to] return slice || [] end |
#to_a ⇒ Object
41 42 43 |
# File 'lib/quiz1/t/solutions/Jamis Buck/lib/cipher.rb', line 41 def to_a @deck.dup end |
#to_s ⇒ Object
21 22 23 |
# File 'lib/quiz1/t/solutions/Bill Guindon/solitaire.rb', line 21 def to_s return @cards.to_s end |
#triple_cut ⇒ Object
Perform a triple cut around the two jokers. All cards above the top joker move to below the bottom joker and vice versa. The jokers and the cards between them do not move.
25 26 27 28 29 30 |
# File 'lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb', line 25 def triple_cut a = @deck.index( 'A' ) b = @deck.index( 'B' ) a, b = b, a if a > b @deck.replace( [@deck[(b + 1)..-1], @deck[a..b], @deck[0...a]].flatten ) end |
#triple_cut_split(a, b) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/quiz1/t/solutions/Glen M. Lewis/solitaire.rb', line 104 def triple_cut_split(a, b) a,b=b,a if (a > b) print "before triple_cut_split(#{a}, #{b}): " if $debug self.dump if $debug temp = self.dup self.clear temp.slice((b+1)..-1).each {|x| self.push(x) } temp.slice(a..b).each {|x| self.push(x) } temp.slice(0..(a-1)).each {|x| self.push(x) } print "after triple_cut_split(#{a}, #{b}): " if $debug self.dump if $debug end |
#update ⇒ Object
54 55 56 57 58 59 |
# File 'lib/quiz1/t/solutions/Niklas Frykholm/solitaire.rb', line 54 def update move_a move_b triple_cut count_cut end |
#update_order ⇒ Object
simple, but not very efficient.
70 71 72 |
# File 'lib/quiz1/t/solutions/Bill Guindon/solitaire.rb', line 70 def update_order @order = @cards.collect {|card| card.to_s} end |
#value_at(index) ⇒ Object
69 70 71 72 |
# File 'lib/quiz1/t/solutions/Dennis Ranke/solitaire.rb', line 69 def value_at(index) id = @deck[index] (id > 51) ? 53 : id + 1 end |