We haven't talked too much about debugging ruby in class. Is there a debugger that we can step through ?
jgn
· 1 year ago
Yes. See Programming Ruby -- p. 214 in the latest PDF of the 3rd ed.
Another option is to use the embedded debugger in an IDE such as NetBeans; but Ruby IDEs are outside the scope of the course.
plu
· 1 year ago
Looking through the documentation of Hand:
For contains_one_pair?(), it specifies: Returns true if the hand contains at least one pair.
However, none of the other methods state 'at least' so I would just like to validate this (I know it probably does not impact too much if it is searching from the biggest hand down to the smallest hand, but I just want to make sure the methods are defined correctly)
In the case of one pair, it means that even if it is three of a kind, four of a kind, two pairs, full house, etc, it'll return true.
However, for others such as three of a kind, should it ONLY return true for three of a kind or should it return true for 'at least' a three of a kind - meaning that the four of a kind, full house, etc will return true under the that method as well?
Thanks!
jgn
· 1 year ago
Did you notice that the one_pair? method does not get tested?
You may find that implementing this method will help you implement the methods that are tested.
In other words, implementing a one_pair? method is just a hint. You needn't do it at all if you don't want to; and you may freely implement it according to your own semantics.
Now, as for what "at least" means.
If you tested the hand to see if it has a four of a kind (for instance), would you even be interested in finding out if the hand satisifies one_pair?
If you tested the hand to see if it has a full house (3 of a kind + one pair), would you care if one_pair? returned true were there 2 pair (note that it can't happen by definition of already matching a full house).
In other words:
(1) The semantics of one_pair? as written may have something to do with the way the other methods are leveraged to assess the hand as a whole; (2) YOU DON'T HAVE TO IMPLEMENT IT! Or you can decide to implement it in a completely different way; it doesn't get tested.
There are some extremely clever ways to satisfy the requirements of this assignment, so don't get too obsessed with the optional methods.
John
Student1
· 1 year ago
I find ruby's string and character a bit odd: In irb, I say: >> a = "A3" >> if (a.slice(1) == "3") then print "hello" else print "world" end world=> nil >> if (a.slice(1) == 51) then print "hello" else print "world" end hello=> nil
It seems like when you have a string with a length being 1, then, it turns into an integer representing the character. What is a good way to deal with this ? I mean when I have a string of length 1, should I always treat it as an integer.
I also find the if-elsif-end very confusing, not knowing which end matches which if. What is people's general style of doing thing to avoid confusion ?
Thanks
jgn
· 1 year ago
Before posting questions like this, review the documentation. I have removed a lot of stuff here to foreground the key bit:
jgnmbair:rdoc jgn$ ri String#slice ----------------------------------------------------------- String#slice str[fixnum] => fixnum or nil ------------------------------------------------------------------------ Element Reference---If passed a single Fixnum, returns the code of the character at that position.
Regarding if / elsif / end: Could you paste in an example that you find confusing?
jgn
· 1 year ago
P.S. In the bit of documentation I just pasted in, notice that I requested documentation for String#slice -- which you can see in the right margin.
slice is a synonym for using square braces after the name of the String -- hence the fact that the doc looks a bit at odds with what I requested.
Student1
· 1 year ago
I did look at the doc. It says:
a = "hello there" a[1] #=> 101 a[1,3] #=> "ell"
It still feels odd because I was expecting a return value of "String" - like "e" instead of 101. Maybe I was a bit uncomfortable with ruby giving different types of return value. (I forgot that Ruby does not have static typing) Somehow, it also feels strange that one is still worrying about character code. But maybe that is the Ruby way. I thought that my code was very ugly (in having to deal with character code ) as in:
# now add the number for ths suite case (stringRep.slice(0)) when 72 # equivalent to "H" @cardNumber += 13 when 67 # equivalent to "C" @cardNumber += 26 when 68 # equvialent to "D" @cardNumber += 39 end # end of c
So I was asking do people really program like so, or is here better way to deal with single character string.
w.r.t to if-then-else...at this point, I have fixed up my if-then-else, so I don't really have the original confusing code anymore. It just took me a long time to match the if-then-else.
This part, I haven't really read clearly. Maybe it is something to come (meta programming ???), but, I want to make my cards Enumerable. Can I just implement the SUCC method only or do I have to do all the methods in the mixin ? I am not quite clear what this mean. Perhaps you'll be going over this. But, the long and short of it is that, now I want my card to be enumerable. In Java term, I might have wanted to find an interface Enumerable, and then implement all its interface. In Ruby, what would I do ? In Java, if I implement all the method of interface A, then, I am an A. In Ruby, if I implement SUCC, do I become a Enumerable ?
Thanks
jgn
· 1 year ago
As it happens, in Ruby 1.9 slice does return a String.
In any case, I hope you saw the slide in Lecture 2 that mentioned Integer#chr -- I mentioned it, and demonstrated it.
Student1
· 1 year ago
Thanks.
Sorry, there was no SUCC/NEXT in Enumerable. (I was confused again :-( ) But I must have seen it somewhere.
Yes, you did Integer in class. Thanks
jgn
· 1 year ago
You might have been thinking about the #succ method because I mentioned that the Range class will use it if the endpoints have implement it.
sa
· 1 year ago
On running the demo.rb, I get >ruby demo.rb
Demonstration of instantiation of a hand, then checking how strong it is.
demo.rb:6: undefined method `accept' for #<Hand:0x2b1572c> (NoMethodError)
jgn
· 1 year ago
The demo won't work until you finish the assignment -- i.e., demo is for "final checkout."
I am planning to do a screencast that will show you what the demo will look like when you're done.
Glenda E
· 1 year ago
Can we presume that the Card class will only need to process one card at a time?
jgn
· 1 year ago
Glenda -- Yes, I think so. Are you asking if you need to synchronize methods, as is done in Java?
Glenda E
· 1 year ago
No, I just wanted to know since the initialize method of the Card accepts multiple arguments (*args).
jgn
· 1 year ago
The doc says: "Initializes a card." Singular.
jgn
· 1 year ago
P.S. I wanted to mention one more thing on this:
The rdoc for Card is below. Note where I put ***. The idea here is that the an exception will be raised if the number of parameters is wrong. This is more about helping you discover raising exceptions than anything else.
---------- Card
Initializes a card.
A Fixnum argument constructs a card so that 0 creates the Two of Spades, 1 the Three of Spades,…, 12 the Ace of Spades, 13 the Two of Hearts, and so forth. For the sequence of Suits and Ranks, see constants.rb.
If there is one argument and it is a String, then it is first trimmed and uppercased. If the resultant size is 2, then an attempt is made to initialize the card so that the suit is the value of the first character, and the rank is the second character, according to the values of SUITS and RANKS in constants.rb. If the characters don‘t match the possible suits and ranks, an ArgumentError is raised.
If there are no args, or *** more than 1 arg, an ArgumentError is raised.
If there is one arg but it is not a Fixnum or a String, an ArgumentError is raised.
Morris
· 1 year ago
(Using a little bit of domain-specific knowledge here)
Can we limit ourselves to 5-card hands, here? Assume and/or enforce that a hand must have exactly 5 cards?
Or do we need to consider games like 7-card stud or Texas Hold-em, where we can choose 5 cards to score, out of a larger hand?
jgn
· 1 year ago
Only 5 cards.
Unless I'm mistaken, the links to Wikipedia are only for the 5 card game.
Morris
· 1 year ago
The spot tests in test/tc_spot.rb are testing at least one method that's not called for in the rdoc specifications: Card#card_number It appears that it should return the Fixnum that would have been passed to Card#new to instantiate the card.
Which is correct? The specification or the tests?
jgn
· 1 year ago
card_number is a publicly-readable attribute according to the rdoc: "Returns a 0 for the Two of Spades, 1 for the Three of Spades, …, 12 the Ace of Spades, 13 the Two of Hearts, etc. For Suit/Rank order, see constants.rb."
Note that whether or not it is the Fixnum passed in is not defined. For example, you might store the identity of the card internally as a combination of suit and rank, and compute card_number based on such internals.
Does that help?
Morris
· 1 year ago
Yes, thanks. I was looking at methods, and missed the Attributes section. It seems clear from the near-identical wording of the card_number attribute and the new() method that the card_number must have the same value as the Fixnum argument, which is what I was getting at.
Looking further at the documentation (and my tests that are failing), it appears that even though the synopsis for Hand#accept is "accept(*dealt_cards)", in fact what the method should be taking is either a single Card or a single Array, but not multiple Cards. E.g.
accept(c1)
or
accept( [c2, c3] )
but NOT
accept(c4, c5)
Is this correct?
jgn
· 1 year ago
"Accepts a single Card, or an Array of Card into the hand." Need we say more?
Morris
· 1 year ago
"Need we say more?" You'd think not, except for a) the apparent ambiguity of the synopsis "accept(*dealt_cards)", and b) demo.rb line 6, which is attempting to call Hand#accept with 5 arguments of type Card.
My implementation currently passes "rake spot" and "rake test", but fails to run demo.rb, because of this.
jgn
· 1 year ago
We will probably change demo.rb - more on this tomorrow.
akv
· 1 year ago
What was the resolution on the demo.rb?
jgn
· 1 year ago
Thanks for reminding me. I must send an e-mail on this.
The requirements and the tests say that hand#accept should accept a single card or an array into the hand.
Unfortunately, the reference implement will accept a single card, an array of cards, OR a list of more than one argument where each argument is interpreted as a card.
So . . . if you implemented it as required, and passed the tests, demo.rb should work fine if you just pass in an Array of the cards -- e.g., change from:
I'm getting a goofy error I'm hoping you can help me with. It has to do with test_0195_hand_strength_025... This is a random test, so sometimes, it submits a straight flush. I return an 8 for straight flush, and it complains that it wanted a 5 (flush). I return true from Hand.can_handle_ace_low?... I'm looking for the place where you are checking for this flag in this test case, and I do not see it.
All else appears to be working.
Thanks, Mike
jgn
· 1 year ago
First off, don't handle the low ace -- return false. I don't think it should get checked in the tests, but that may be the problem.
philadelphia
· 1 year ago
Okey Dokey... No worries... My code handles the low ace. Some of the tests don't seem to. I'll change my code to work with only a high ace.
I'll play around a bit with the hand compare thingy... That should be interesting.
Thanks! Mike
jgn
· 1 year ago
Yeah, I ripped out a lot of low ace handling. Why don't you e-mail me ( john at 7fff dot com ) and I'll send you last year's package and you can try those tests.
Jody
· 1 year ago
There is a method called take in the deck class. It seems from the docs that it should return the lowest number available card. It says "cards" though so I just wanted to make sure I'm only supposed to be returning 1 (the lowest).
jgn
· 1 year ago
It returns one card at a time. Note that the cards are returned in their order in the deck; the deck can be shuffled.
Keith
· 1 year ago
Yes, it returns a single card at a time.
Jody
· 1 year ago
Thanks. So should I be thinking about adding an attribute of a card that it is "used?"
jgn
· 1 year ago
If it will make your implementation work, that's fine, though note that no such attribute is tested.
A lot of times these things can be figured out if you think about how you would do it with a real deck of cards.
If I had a deck of 52 cards, and gave you one, how many are left?
Then if I gave you one, how many are left?
Finally, if I gave you all 52, how many are left? Can I give you any more?
Jody
· 1 year ago
Ahh, so we don't need to know which cards are taken out of the deck. Just how many.
jgn
· 1 year ago
Well, yes and no. The tests on Deck will verify that you haven't shoved some extra ace's in there, or have otherwise cheated . . .
In effect, a well-planned Deck class always knows what's in it.
In a more elaborate simulation, you could imagine a Hand class that would attempt to identify anomalies in the cards taken from the deck.
Student1
· 1 year ago
I am using instance variables, and I thought I understand what it is until I see page 387 of PickAxe. The most recent version. It reads "Newcomers to Ruby commonly makes the mistake of setting instance variables inline in the class definition..... The example is something like
class Test @var = 99
def self.var @var end
So is @var not an instance variable. Earlier on in the chapter on classes /variables /attributes (chapter 4), we have variables like @isbn, and that was an instance variable. It confuses me.
The other question I have is, how do you return the instance of itself (as in "this" in Java) in Ruby. One of the questions seems to ask for it. The "self" is not "this"
Thanks
Student1
· 1 year ago
Actually, one more thing that was confusing. We define the "initialize" method, which is called when we want to create a new instance. But, do we also have to define a "new" method as well. Lookint at rdoc generated, it says that we have to create a "new" method. I am not clear on the differences between "new" and "initialize". The other thing that I didn't understand is about self.methodA. I took it to mean that self.methodA makes methodA a class method. So, why don't one has to say self.new ? I guess chapter 24 (which is what we are supposed to read) is not very clear to me.
jgn
· 1 year ago
Regarding new and initialize: Here is what I said in lecture:
You call .new on the CLASS (not on an object instance). In the typical case, you do not yourself write code for .new. Example:
Array.new
What Ruby does then is allocate memory for a new Array, and sets up the instance of the class. THEN it calls .initialize which you write. It passes the params you gave to .new right on to .iniitialize.
rdoc simply provides what you say about your implementation of initialize to its doc for new (which makes sense, because when when you want to create a new instance, you use .new, provide some params, and then those params are passed right on to initialize).
-----
As I say in my answer about "this" vs. "self" -- I said (please read it carefully), than when you are CALLING a method or need a reference to the current object, you can use self.
What you are talking about is using "self" in a method declaration. That will create a class method. I haven't discussed that yet, though I will, and you will probably not need to declare a class method in Assignment 2.
jgn
· 1 year ago
I will say a bit about "this" / "self" at the end.
Always manipulate your instance variables (prefixed with @) inside of a method. It is inside of methods that instance variables are "scoped" to the instance.
When the @variable is outside of a method, it is a class instance variable (which is different from a class variable).
Incidentally, in the revised slides I provide an example like so:
class Player
# Next line: WRONG!! # instance variables (@) go inside instance methods @completed_games = 0
def initialize(first_name, number) @first_name, @number = first_name, number # Next line: RIGHT!! @completed_games = 0 end
end
------
"self" means "the current object." So if you call a bare method, it will send a message to the current object. In most cases, when you are CALLING a method or need a reference to the current object, self will work like Java's this.
Student1
· 1 year ago
Thanks. I think that I understand the instance variable now. There are instance variable , class instance variable and class variable. (Not used to having class instance variable - so when people say instance variable, I automatically take it to mean the first kind).
What about for methods ? Are there also 3 types as well : instance method, and class method. Is there class instance method as well ?
class A def methodB ... end The methodB is an instance method, I take an instance method to mean an object of type classA can receive the method.
class A def self.methodB ... end We call it with A.methodB
w.r.t self-vs-this, I must have missed the discussion. Perhaps it is in the slides.
Thanks
jgn
· 1 year ago
I haven't talked about "self" in the lectures yet.
I will be talking self, class, and instance methods this evening.
Glenda
· 1 year ago
Can you give me a hint of how deck.shuffle is supposed to work? I.e., if the deck of cards is supposed to get shuffled n times, what variables in the method are supposed to change? It seems that the "rand" function in deck.take can give the effect of a "shuffle". I think I'm missing something. Thanks.
jgn
· 1 year ago
As it happens, it would be hard for us to test whether you've truly shuffled "n" times, unless the test could inspect the deck between each shuffle -- and we didn't require an implementation that would allow such testing. I put in the shuffle n times for fun.
So . . . your task is to figure out a way to permute the order of your internal representation of the deck so that the cards will come out in a different order.
One way to do it would be to pick two cards (at random); exchange them. Pick two cards (at random); exchange them. Etc.
The assignent says, "Along the way, add whatever documentation is appropriate internally. Internal documentation should note concisely anything fancy, clever, interesting, or hard to understand." Does that mean that we don't have to worry about rdoc - and just write document on places that might be unclear. Anything you have provided in your instruction rdoc, we don't have to repeat ?
Thanks
Student1
· 1 year ago
Sorry, you probably addressed this already in your instruction. No need to repeat what you have documented. You want only internal documentation.
jgn
· 1 year ago
Indeed, we have addressed these matters at some length in the instructions.
The point is this:
-- The "official" documentation, outlining how the public methods should work, has been defined through the requirements for the assignments. So, in effect, the rdoc is done.
HOWEVER, you definitely should note internals that need explanations. You would be very wise to help your grader understand where key comments are. It would be appropriate to say in the readme that you've done something brilliant in a certain section of the code (then put the comment in the code).
Truly, we will not generate rdoc for this project.
For later work, where it will be appropriate for you to write comments suitable for rdoc: Even then, you don't have to actually generate the rdoc. We will see the rdoc comments while looking at the code.
Upshot:
For Assignment 2:
1. If you do anything cool, add a comment. 2. Helpful: List such interesting bits in your readme. 3. And the readme in general. Here's what we say:
Before submitting, you will write a file called readme.txt for the root of the project. It must describe what you did, in particular how you tackled the hand evaluation methods in the Hand class. We have put a very short readme.txt in place to get you started. More on the readme.txt below.
Internal documentation and writeup (the readme.txt). Is the internal documentation concise but clarifying? Does the readme.txt explain to me, in sentences and paragraphs, how your code works?
NOTE: There is no need to write things like "The Card class represents a playing card." Please, do not state the obvious. If you feel that you need to address this briefly, you may, but do not repeat the assignment or the requirements for your implementation.
NOTE: There is no need to write RDoc (public comments before "class" and public methods) for the tested methods in Card, Deck, and Hand. Why? Because the documentation we hand out is what you must code to. If you ADD public methods, provide RDoc comments for them.
You must specifically address your strategy for evaluating hands. Not doing so will render the 15% portion of the grade devoted to documentation very close to 0.
You must discuss any additional files, classes, or methods that result in additional functionality or convenience for you as the implementer.
It is hard to imagine a readme.txt that is fewer than 350 words. Please make an ordinary text file. No Word, PDF, etc.
See below for a question regarding the readme.txt.
You may also optionally add a method called strength_with_extras that reports, in addition to the number representing the type of hand, an Array for the high cards appropriate for the hand classification and an additional Array of kickers. This method would itself return an Array, the first element the value returned by strength, the other being the Array of kickers. (e.g., it might return [ 3, [ 12 ], [ 0, 1, 2 ] ], representing a Three of a Kind, a high card in the Three of a Kind (the Ace Spaces), followed by kickers of the 2, 3, and 4 of Spades. Another way to do it is to return instances of Card rather than the card numbers. It‘s up to you.
If you attempt this, discuss your implementation thoroughly in your readme.txt.
What should the readme.txt look like?
Put your name, the course name, and the assignment number at the top of the readme.txt.
The audience of the readme.txt is yourself or another technical staff member such as yourself. The reader knows Ruby and Rails, but may not currently be coding in it. This reader will be responsible for maintaining your code in the future. The reader may be your technical manager. Therefore:
1. Your writeup must be clear. 2. Your writeup must explain where everything is. If you introduce new files, classes, or public methods, say where they are, and what they do, and why they‘re important. A good way convey this kind of information is in the form of a list. 3. If you do anything fancy, you have to explain yourself. 4. The fact that the audience is also yourself is important. Think of what you are doing as a letter to yourself, which you will read in a year long after you‘ve forgotten the code. You will kick yourself if you find your own writing unclear or confusing.
These are the criteria we will be using during grading!
Student1
· 1 year ago
Yesterday, it was mentioned in class that anything starting with a Capital letter is a "constants". I am not clear on when one should use symbol and when one should use constant. Could you explain ?
Thanks
Jody
· 1 year ago
I'm having trouble with test 90. It seems the previous test requires that I return an object. If I do return an object, it isn't nil and therefore won't pass test 90. Any hints?
Keith
· 1 year ago
I assume you're talking about test_0090_hand_at_010 in the spot test. If you read the code for the test, especially the comment, it should become clear what the assertion means -- a method on hand is supposed to return nil, but hand itself is not expected to be nil.
Ana
· 1 year ago
I was trying to write some tests for my game and I'm having a little trouble. I define this test:
class TestHand < Test::Unit::TestCase include CardTestUtils
def test_has_lowest_card? h = Hand.new("some_player") h.accept(shuffle(to_cards(%w{ sa sk s2 d2 da dk }))) assert(h.has_lowest_card?, "Recognize that hand contains the lowest card")
h = Hand.new("some_player") h.accept(shuffle(to_cards(%w{ sa sk s3 d2 da dk }))) refute(h.has_lowest_card?, "Recognize that hand does not contain the lowest card") end end
assert() is fine but for refute() I get the following error:
test_has_lowest_card?(TestHand): NoMethodError: undefined method `refute' for #<TestHand:0x44402b0> lib/testpusoydos.rb:33:in `test_has_lowest_card?'
Folks: Ana is writing tests because she's simulating a different game from poker.
For assignment 2, you should not need to write any of your own tests.
Ana
· 1 year ago
Weird, I got that right out of the pickaxe. Thanks, John!
jgn
· 1 year ago
It must be something new for 1.9.
I wrote a message on Thomas's "errata" page at pragprog.com asking that he flag new things a bit better.
Amy, Keith, Harlan - refute must be new?
Manuel Ledesma
· 1 year ago
I was looking at the documentation for Hand.accept and according to the rules on Wikipedia, we can only hold 5 cards at a time. How should we deal with this:
Throw an exception if limit is reach and try to accept another card?
Push new card or cards to the hand and and slice out existing one?
Throw exception is passing cards are bigger than 5?
jgn
· 1 year ago
I don't think there is a test to ensure that the hand can only hold 5 -- so you don't need to worry about it.
In a real simulation, you could either throw an exception, or, possibly, write code to notify the other hands that one hand is illigitimately trying to accept a 6th card; then the other hands could complain and/or quit the game on the grounds that someone is cheating.
Morris
· 1 year ago
I've already put in some code to raise an exception if accept is called on a hand that's full. Should I take this out? In general, for this assignment, should we be limiting ourselves very strictly to the specification, or is it okay to have a little more error-checking than what's minimally required?
jgn
· 1 year ago
I think it would be premature to raise an exception when an attempt is made to accept a sixth card. Suppose we extended the game so that you could "improve" your hand by allowing to take an additional card; after which another card would be discarded. In that situation, briefly, the hand could have six cards.
Also, I am not sure that a hand should be responsible for such an exception. The reason is that if a 6th card is added to a hand, and that is not allowed, then, arguably, your deck is corrupted ('cos in the current model, the card is taken from the deck and THEN accepted into the hand -- there isn't a mechanism to force a card back into the deck). This suggests that if you did have a problem with a sixth card, it should be handled at a different level of abstraction. You could argue that it is the responsibility of the Dealer to not screw up a player's hand. OR, you might believe that the dealer should be able to do this, and the hand should be able to take advantage of such a bonus card . . .
Manuel Ledesma
· 1 year ago
I running the testcases and I'm confuse with the failures, example
test_0120_hand_strength_010(HandTest) [./test/tc_hand.rb:270:in `check_hand' ./test/tc_hand.rb:263:in `accept_and_check' ./test/tc_hand.rb:90:in `test_0120_hand_strength_010' ./test/tc_hand.rb:89:in `each' ./test/tc_hand.rb:89:in `test_0120_hand_strength_010']: Expected S2, S2, S2, S2, S2 to be evaluated as a Royal Flush. <9> expected but was <5>.
According to wikipedia information this is not a Roya Flush, Roya Flush is T, J, Q, K, A
See Card.new(a)? What does your code do with Card.new('HA') ? It would seem that it's not working right.
THEREFORE, if your Card.initialize method is screwed up -- if it can't create a Card that represents an Ace of Hearts from the two character sequence 'HA' -- then there is going to be a problem.
In your case, it looks like your Card (no matter WHAT suit/rank is being handled) is always being created as a 2 of Spades.
Let me point out that the instructions strongly suggest that you start with the "spot" testing first -- this will verify some of the most crucial bits first. One of the earliest tests in tc_spot looks like this:
That's checking to make sure that your code creates cards correctly.
I hope you read the instructions.
John
Manuel Ledesma
· 1 year ago
Never mind, I changed something in Card class by mistake.
Sorry for the trouble
Thanks for your quick response.
Manuel Ledesma
· 1 year ago
rake rdoc is always failing
'zip' is not recognized as an internal or external command, operable program or batch file. rm -f FIND_ZIP.zip c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require': no such file to load -- zip/zip (LoadError ) from c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require' from C:/harvard/CSCIE-168/assn2/bin/zip_in_ruby.rb:7 rm -f FIND_ZIP.zip PKZIP(R) Version 2.50 FAST! Compression Utility for Windows 95/NT 4-15-1998 Copyright 1989-1998 PKWARE Inc. All Rights Reserved. Shareware Version PKZIP Reg. U.S. Pat. and Tm. Off. Patent No. 5,051,745
Creating .ZIP: FIND_ZIP.zip Adding File: demo.rb Deflating (50.9%), done. Adding File: pkg/e168-assignment2-Manuel Ledesma-1.0.000/demo.rb Deflating (50.9%), done. rm -f FIND_ZIP.zip Using ZIP command: "C:/harvard/CSCIE-168/assn2/bin/PKZIPC.exe" -add -dir rake aborted! Don't know how to build task 'README'
(See full trace by running task with --trace)
Manuel Ledesma
· 1 year ago
using the --trace option I got the following
(in C:/harvard/CSCIE-168/assn2) zip -r FIND_ZIP.zip demo.rb 'zip' is not recognized as an internal or external command, operable program or batch file. rm -f FIND_ZIP.zip ruby "C:/harvard/CSCIE-168/assn2/bin/zip_in_ruby.rb" -r FIND_ZIP.zip demo.rb c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require': no such file to load -- zip/zip (LoadError ) from c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require' from C:/harvard/CSCIE-168/assn2/bin/zip_in_ruby.rb:7 rm -f FIND_ZIP.zip "C:/harvard/CSCIE-168/assn2/bin/PKZIPC.exe" -add -dir -r FIND_ZIP.zip demo.rb PKZIP(R) Version 2.50 FAST! Compression Utility for Windows 95/NT 4-15-1998 Copyright 1989-1998 PKWARE Inc. All Rights Reserved. Shareware Version PKZIP Reg. U.S. Pat. and Tm. Off. Patent No. 5,051,745
I have different number of assertions in different runs of "rake test". Is this an indication of error. I always have 85 tests, but sometimes, I have 2722 assertions, other times 2720, sometimes 2718, and sometimes 2726.
Does that mean that some tests are not run. There is no indication of errors. Thanks
jgn
· 1 year ago
That's an excellent question. Some of the tests create quasi-random data -- it's a short cut to testing every single possible deal/hand combination. So the number of assertions will go up or down depending on how the randomization is working.
Jody
· 1 year ago
I've noticed that there are some things that aren't tested for and yet aren't marked as optional.
For example, new in the Card class states: If there are no args, or more than 1 arg, an ArgumentError is raised. If there is one arg but it is not a Fixnum or a String, an ArgumentError is raised.
My classes are fully functional and pass all of the tests so do I need to implement other things on top of that such as my example above?
jgn
· 1 year ago
Hmm, That's funny, I was sure I provided a test for that. I would advise implementing that functionality if it is documented -- and I will review the tests.
Jody
· 1 year ago
Bonus points for writing and passing the 2 tests ourselves? Had to try.
:)
Jody
· 1 year ago
There also seems to be no specific test for inspect and a few others. You may want to create one to finish it but you can create a well working class structure without it.
akv
· 1 year ago
When we are initializing a card can we introduce new attributes that set the suit, rank, etc or are we only allowed to have the one attribute card_number?
jgn
· 1 year ago
Here are some things to consider:
You can introduce all of the instance variables you want. Those are private to your implementation.
If you introduce an acessor (attr_accessor) then other classes can manipulate those items. Do you want that?
akv
· 1 year ago
When we implement the Deck class, are we supposed to include modules such as enumerable, etc to let us get at the internals of the class so we can shuffle the deck? I have added cards to the desk class, but I am not sure how I can traverse or iterate the contents of the Deck. I tried to to do a self.to_enum in the shuffle method, but that threw an error when I ran the deck unit test? Am I on the right track here?
jgn
· 1 year ago
You should be able to implement Deck very easily without including any modules.
Remember that any class (such as your implementation of Deck) can have an instance variable that can represent anything you like.
Just for example, you might have an instance variable that is an Array or a Hash or something else to represent the cards currently in the deck.
Then shuffle would (somehow) randomize that data structure.
Our reference implementation of Deck has about 12 lines of executable code (excluding "class ... end" "def cards_remaining ... end" -- and so fortth.
Don't overthink the problem.
rajatbaner
· 1 year ago
I'm running Windows, and had all sorts of errors when running "rake spot". Here are the two things I did to squash the errors, hopefully it helps other windows users. "gem install rubyzip"
found a copy of "zip.exe" In the folder of a utility called LogMeIn on my computer. I copied it to c:\windows\system32\
I can email anyone the zip.exe binary if they need it. Rajat
jgn
· 1 year ago
Rajat -- Try and send me (John) that zip.exe by any means you can think of -- you might need to change the file type to something else.
It may very well get returned if you send it to my gmail account . . . So try:
john at 7fff dot com john at h3 dot com jnorman at digitaladvisor dot com
rajatbaner
· 1 year ago
Sure, Tried. Lets see if it gets through. Otherwise i'll post it on my web server?
jgn
· 1 year ago
Rajat -- That would be great.
The problem with the PKZIPC.exe in the code bundle is that it's not compatible with the Unix zip, so there is some code in the rake file that doesn't play nice with all versions of Windows.
From the documentation, the sentence below refers to "kickers". I have read this over and over and I'm still not sure what "kickers" are. Can you explain?
"You may also optionally add a method called strength_with_extras that reports, in addition to the number representing the type of hand, an Array for the high cards appropriate for the hand classification and an additional Array of kickers. This method would itself return an Array, the first element the value returned by strength, the other being the Array of kickers. (e.g., it might return [ 3, [ 12 ], [ 0, 1, 2 ] ], representing a Three of a Kind, a high card in the Three of a Kind (the Ace Spaces), followed by kickers of the 2, 3, and 4 of Spades. Another way to do it is to return instances of Card rather than the card numbers. It‘s up to you. "
jgn
· 1 year ago
The idea is this:
If the hand is tied, the extra cards are the "kickers" that decide the tie.
So say I have a pair of aces, and you have a pair of aces: What is the top card among the kickers (extra cards) that would decide which of us has won?
Thanks! Who knew that searching wikipedia would be the thing to do :)
MaureenB
· 1 year ago
I note that my tc_hand.rb takes up to 65 seconds to run. I removed the three longest loops (the three tests loop 1..100) and got it down to 16 seconds to execute.
So. Is this because my code is, ahem, un-optimized, or does everyone have the same execution time?
Also, I am used to stepping through a debugger to see where the clogs happen. Is there a recommended method of doing something similar in Ruby to see where my code could be improved?
EDIT: I see that test_0195_hand_strength_025, test_0193_hand_strength_023 take the longest. I put a "puts self" in the test code functions to see what was running at execution. So I took them out and ran them separately, they are all fine. The difference is I ran them without the "accept_and_check" function.
So....I wonder if accept_and_check is slowing thing down...
Removing "accept_and_check" from the two function reduced execution time for the entire script from over 60 sec to 23 sec.
Keith
· 1 year ago
There are tools like ruby-prof that you can use to profile code.
That said, I think you probably have something in accept_and_check that is slowing things down. These tests should run very fast. I'd send the code to your TA and see if they can spot something that might be causing your execution time to rise.
MaureenB
· 1 year ago
What does "very fast" mean? Is this 5 seconds? 2 seconds? 15 seconds? Some dependency on the computer, but I am curious to know a ballpark figure so I don't spend more time than necessary on this issue.
Thanks!
Keith
· 1 year ago
If I run tc_hand.rb, it executes in about 3/10 of a second.
jgn
· 1 year ago
For the "reference" implementation on my Mac, rake spot takes 0.2 seconds, and rake test takes 0.5 seconds.
MaureenB
· 1 year ago
Hmmm. I got my rake test down to 2.05 seconds, but my rake spot is .03 seconds. Consistently. I am looking for more ways to better the code within the spec. I think this exercise has taught me some huge lessons about assumptions I have made about what goes on under the hood without actually knowing. Not there yet, but progressing :)
jgn
· 1 year ago
Very interesting.
Maybe next time we'll blend profiling into the rake script.
MaureenB
· 1 year ago
Thanks for the tip. ruby-prof got me there quicker than without, I believe. I have a tendency to "make things work", then go back and make improvements. I see how this is not always a good thing. Also, I find that the terseness of Ruby compared to say, C# or Java, is not only a different mindset, but some functions of Ruby are vastly more efficient than others that have the same return value. In some languages, using regex is faster(?), but in Ruby, using what I presume is regex based, the split function, is a huge cycle hog, particularly if you just mindlessly throw a str.split('') into a looping array.each.
I can only assume that learning the traditional Ruby will help me in this regard. Simply finding a function that works isn't good enough. Bad habits I have, I guess.
Rambling further, I think I'm just surprised that similar functionality in Ruby has such vast performance differences. I obviously don't know what I thought I knew about programming. I would think I would have had a more obvious confrontation with these issues in my past (I do C# and Java). I am now feeling humbled.
MaureenB
· 1 year ago
I have narrowed it down a bit to my strength algorithm. Probably rebuilding an array inside a loop rather than just once at initialization.
akv
· 1 year ago
When accepting a card in hand, isn't this ok to do the below - provided that if we initialize our array in the initialie method.
if (dealt_cards.length == 1) @myHand.push(dealt_cards[0]) else
Similar logic works in card when trying to create a new card and parsing input. This code does not pass the unit test test_0100_hand_at_020. The array is initialized and passes the unit test before. The error I get is that <nil> not expected to be nil. Is there some more information regarding the splat operator in the pickaxe? I tried looking in there, but couldn;t find anything, maybe I misse it.
Thanks.
Keith
· 1 year ago
Look at the test again --- the method being tested is not accept (and it is not related to the splat operator). Also, a proper Ruby variable would be my_hand, not myHand.
rajatbaner
· 1 year ago
In Lecture 5a, the prof showed us some code like this: points = 82 grade = case points when 90..100 'A' when 80..89 'B' ..... else 'E' end puts "Points: #{points}; Grade: #{grade}"
How can this be extended to take in an Array instead of a single FixNum ? I've tried a couple of things including === but can't get the syntax quite right. any hints would be much appreciated.
jgn
· 1 year ago
Something like "is this Array within this range"?
Or: Is this point value within this Array?
rajatbaner
· 1 year ago
"Is every value in this array between 0...10" , please
I'm sure I could write my own function to do this quickly, but in the spirit of code reuse...
jgn
· 1 year ago
What you might do is write your own include? method, and then redefine the existing method in range. Something like:
class Range def include?(val) if val.is_a? Array # do your check else super(val) end end end
plu
· 1 year ago
In the instruction for submission, it states:
E-mail the ZIP in pkg/ to your section leader. Remember to include E168 in the subject, and submission:assignment3 in the body.
Should we do submission:assignment3 in the body or submission:assignment2 in the body since it is referenced as assignment 2 everywhere else?
Thanks!
jgn
· 1 year ago
submission:assignment2 - ideal
But we certainly won't refuse a submission that says submission:assignment3 !!!
swithin
· 1 year ago
On "test_0072_deck_shuffle_020" I am encountering two tough problems.
1) I cannot mixin "shuffle" due to its not being part of "Enumerable". Do I have to use "srand" or require "SecureRandom" to return integers between 0 and 52? I am having trouble imagining how to use such random number generators in a one-liner to shuffle the array.
2) I get the error "undefined method 'card_number' for 51:Fixnum". Does this mean that I have to use a Metaprogramming Singleton to create a class for the already dynamic "51"? I tried it unsuccessfully. I will try again, but just want to know if I am headed in a good direction.
jgn
· 1 year ago
Josh--You're making it WAY too complex. Who said you need to mixin anything?
Simply write your own shuffle method. The shuffle could be as simple as exchanging the cards many, many times by random switches.
Regarding the undefined method card_number : Have you defined an ordinary instance method or accessor called card_number ?
It's truly not asking for anything fancy. This assignments requires not one jot of metaprogramming jujitsu.
xtine78
· 1 year ago
Here is an error I cannot resolve.
The error is: NoMethodError: undefined method `method1' for []:Array
I get the error when I run the case statement. Any idea what's happening?
def thismethod() myvariable = case when @hand.method1() == true something when @hand.method2() == true something! else nothing end end
jgn
· 1 year ago
What you have posted has this line:
@hand.method1()
Does @hand have a method called "method1" on it?
The error message (did you read it?) says: undefined method `method1' for []:Array
So it would seem that when @hand.method1() is executed, @hand is an Array, perhaps; is it? You can find out what class it is before this statement is run by adding:
puts @hand.class
John
xtine78
· 1 year ago
I know! I can't call @hand.thismethod and have that method call @hand.method1! I just call method1. Thanks for looking!
Another option is to use the embedded debugger in an IDE such as NetBeans; but Ruby IDEs are outside the scope of the course.
For contains_one_pair?(), it specifies:
Returns true if the hand contains at least one pair.
However, none of the other methods state 'at least' so I would just like to validate this (I know it probably does not impact too much if it is searching from the biggest hand down to the smallest hand, but I just want to make sure the methods are defined correctly)
In the case of one pair, it means that even if it is three of a kind, four of a kind, two pairs, full house, etc, it'll return true.
However, for others such as three of a kind, should it ONLY return true for three of a kind or should it return true for 'at least' a three of a kind - meaning that the four of a kind, full house, etc will return true under the that method as well?
Thanks!
You may find that implementing this method will help you implement the methods that are tested.
In other words, implementing a one_pair? method is just a hint. You needn't do it at all if you don't want to; and you may freely implement it according to your own semantics.
Now, as for what "at least" means.
If you tested the hand to see if it has a four of a kind (for instance), would you even be interested in finding out if the hand satisifies one_pair?
If you tested the hand to see if it has a full house (3 of a kind + one pair), would you care if one_pair? returned true were there 2 pair (note that it can't happen by definition of already matching a full house).
In other words:
(1) The semantics of one_pair? as written may have something to do with the way the other methods are leveraged to assess the hand as a whole;
(2) YOU DON'T HAVE TO IMPLEMENT IT! Or you can decide to implement it in a completely different way; it doesn't get tested.
There are some extremely clever ways to satisfy the requirements of this assignment, so don't get too obsessed with the optional methods.
John
In irb, I say:
>> a = "A3"
>> if (a.slice(1) == "3") then print "hello" else print "world" end
world=> nil
>> if (a.slice(1) == 51) then print "hello" else print "world" end
hello=> nil
It seems like when you have a string with a length being 1, then, it turns into an integer representing the character.
What is a good way to deal with this ? I mean when I have a string of length 1, should I always treat it as an integer.
I also find the if-elsif-end very confusing, not knowing which end matches which if.
What is people's general style of doing thing to avoid confusion ?
Thanks
jgnmbair:rdoc jgn$ ri String#slice
----------------------------------------------------------- String#slice
str[fixnum] => fixnum or nil
------------------------------------------------------------------------
Element Reference---If passed a single Fixnum, returns the code of
the character at that position.
Regarding if / elsif / end: Could you paste in an example that you find confusing?
slice is a synonym for using square braces after the name of the String -- hence the fact that the doc looks a bit at odds with what I requested.
a = "hello there"
a[1] #=> 101
a[1,3] #=> "ell"
It still feels odd because I was expecting a return value of "String" - like "e" instead of 101.
Maybe I was a bit uncomfortable with ruby giving different types of return value. (I forgot that Ruby does not
have static typing)
Somehow, it also feels strange that one is still worrying about character code.
But maybe that is the Ruby way. I thought that my code was very ugly (in having to deal with character code ) as in:
# now add the number for ths suite
case (stringRep.slice(0))
when 72 # equivalent to "H"
@cardNumber += 13
when 67 # equivalent to "C"
@cardNumber += 26
when 68 # equvialent to "D"
@cardNumber += 39
end # end of c
So I was asking do people really program like so, or is here better way to deal with single character string.
w.r.t to if-then-else...at this point, I have fixed up my if-then-else, so I don't really have the original confusing code anymore. It just took me a long time to match the if-then-else.
This part, I haven't really read clearly. Maybe it is something to come (meta programming ???),
but, I want to make my cards Enumerable.
Can I just implement the SUCC method only or do I have to do all the methods in the mixin ?
I am not quite clear what this mean. Perhaps you'll be going over this.
But, the long and short of it is that, now I want my card to be enumerable.
In Java term, I might have wanted to find an interface Enumerable, and then implement all its
interface. In Ruby, what would I do ?
In Java, if I implement all the method of interface A, then, I am an A.
In Ruby, if I implement SUCC, do I become a Enumerable ?
Thanks
In any case, I hope you saw the slide in Lecture 2 that mentioned Integer#chr -- I mentioned it, and demonstrated it.
Sorry, there was no SUCC/NEXT in Enumerable. (I was confused again :-( )
But I must have seen it somewhere.
Yes, you did Integer in class. Thanks
>ruby demo.rb
Demonstration of instantiation of a hand, then checking how strong it is.
demo.rb:6: undefined method `accept' for #<Hand:0x2b1572c> (NoMethodError)
I am planning to do a screencast that will show you what the demo will look like when you're done.
The rdoc for Card is below. Note where I put ***. The idea here is that the an exception will be raised if the number of parameters is wrong. This is more about helping you discover raising exceptions than anything else.
---------- Card
Initializes a card.
A Fixnum argument constructs a card so that 0 creates the Two of Spades, 1 the Three of Spades,…, 12 the Ace of Spades, 13 the Two of Hearts, and so forth. For the sequence of Suits and Ranks, see constants.rb.
If there is one argument and it is a String, then it is first trimmed and uppercased. If the resultant size is 2, then an attempt is made to initialize the card so that the suit is the value of the first character, and the rank is the second character, according to the values of SUITS and RANKS in constants.rb. If the characters don‘t match the possible suits and ranks, an ArgumentError is raised.
If there are no args, or *** more than 1 arg, an ArgumentError is raised.
If there is one arg but it is not a Fixnum or a String, an ArgumentError is raised.
Can we limit ourselves to 5-card hands, here? Assume and/or enforce that a hand must have exactly 5 cards?
Or do we need to consider games like 7-card stud or Texas Hold-em, where we can choose 5 cards to score, out of a larger hand?
Unless I'm mistaken, the links to Wikipedia are only for the 5 card game.
It appears that it should return the Fixnum that would have been passed to Card#new to instantiate the card.
Which is correct? The specification or the tests?
Note that whether or not it is the Fixnum passed in is not defined. For example, you might store the identity of the card internally as a combination of suit and rank, and compute card_number based on such internals.
Does that help?
Looking further at the documentation (and my tests that are failing), it appears that even though the synopsis for Hand#accept is
"accept(*dealt_cards)", in fact what the method should be taking is either a single Card or a single Array, but not multiple Cards. E.g.
accept(c1)
or
accept( [c2, c3] )
but NOT
accept(c4, c5)
Is this correct?
a) the apparent ambiguity of the synopsis "accept(*dealt_cards)", and
b) demo.rb line 6, which is attempting to call Hand#accept with 5 arguments of type Card.
My implementation currently passes "rake spot" and "rake test", but fails to run demo.rb, because of this.
The requirements and the tests say that hand#accept should accept a single card or an array into the hand.
Unfortunately, the reference implement will accept a single card, an array of cards, OR a list of more than one argument where each argument is interpreted as a card.
So . . . if you implemented it as required, and passed the tests, demo.rb should work fine if you just pass in an Array of the cards -- e.g., change from:
h.accept( Card.new('S3'), Card.new('D3'), Card.new('H3'), Card.new('D2'), Card.new('S2') )
to
h.accept( [ Card.new('S3'), Card.new('D3'), Card.new('H3'), Card.new('D2'), Card.new('S2') ])
John
I'm getting a goofy error I'm hoping you can help me with. It has to do with test_0195_hand_strength_025... This is a random test, so sometimes, it submits a straight flush. I return an 8 for straight flush, and it complains that it wanted a 5 (flush). I return true from Hand.can_handle_ace_low?... I'm looking for the place where you are checking for this flag in this test case, and I do not see it.
All else appears to be working.
Thanks,
Mike
I'll play around a bit with the hand compare thingy... That should be interesting.
Thanks!
Mike
A lot of times these things can be figured out if you think about how you would do it with a real deck of cards.
If I had a deck of 52 cards, and gave you one, how many are left?
Then if I gave you one, how many are left?
Finally, if I gave you all 52, how many are left? Can I give you any more?
In effect, a well-planned Deck class always knows what's in it.
In a more elaborate simulation, you could imagine a Hand class that would attempt to identify anomalies in the cards taken from the deck.
It reads "Newcomers to Ruby commonly makes the mistake of setting instance variables inline in the class definition.....
The example is something like
class Test
@var = 99
def self.var
@var
end
So is @var not an instance variable. Earlier on in the chapter on classes /variables /attributes (chapter 4), we
have variables like @isbn, and that was an instance variable. It confuses me.
The other question I have is, how do you return the instance of itself (as in "this" in Java) in Ruby.
One of the questions seems to ask for it.
The "self" is not "this"
Thanks
But, do we also have to define a "new" method as well. Lookint at rdoc generated, it says that we have to create a "new" method.
I am not clear on the differences between "new" and "initialize".
The other thing that I didn't understand is about self.methodA. I took it to mean that self.methodA makes methodA a class method.
So, why don't one has to say self.new ?
I guess chapter 24 (which is what we are supposed to read) is not very clear to me.
You call .new on the CLASS (not on an object instance). In the typical case, you do not yourself write code for .new. Example:
Array.new
What Ruby does then is allocate memory for a new Array, and sets up the instance of the class. THEN it calls .initialize which you write. It passes the params you gave to .new right on to .iniitialize.
rdoc simply provides what you say about your implementation of initialize to its doc for new (which makes sense, because when when you want to create a new instance, you use .new, provide some params, and then those params are passed right on to initialize).
-----
As I say in my answer about "this" vs. "self" -- I said (please read it carefully), than when you are CALLING a method or need a reference to the current object, you can use self.
What you are talking about is using "self" in a method declaration. That will create a class method. I haven't discussed that yet, though I will, and you will probably not need to declare a class method in Assignment 2.
Always manipulate your instance variables (prefixed with @) inside of a method. It is inside of methods that instance variables are "scoped" to the instance.
When the @variable is outside of a method, it is a class instance variable (which is different from a class variable).
Incidentally, in the revised slides I provide an example like so:
class Player
# Next line: WRONG!!
# instance variables (@) go inside instance methods
@completed_games = 0
def initialize(first_name, number)
@first_name, @number = first_name, number
# Next line: RIGHT!!
@completed_games = 0
end
end
------
"self" means "the current object." So if you call a bare method, it will send a message to the current object. In most cases, when you are CALLING a method or need a reference to the current object, self will work like Java's this.
(Not used to having class instance variable - so when people say instance variable, I automatically take it to mean the first kind).
What about for methods ? Are there also 3 types as well : instance method, and class method. Is there class instance method as well ?
class A
def methodB
...
end
The methodB is an instance method, I take an instance method to mean an object of type classA can receive the method.
class A
def self.methodB
...
end
We call it with A.methodB
w.r.t self-vs-this, I must have missed the discussion. Perhaps it is in the slides.
Thanks
I will be talking self, class, and instance methods this evening.
So . . . your task is to figure out a way to permute the order of your internal representation of the deck so that the cards will come out in a different order.
One way to do it would be to pick two cards (at random); exchange them. Pick two cards (at random); exchange them. Etc.
You might be able to simulate an existing shuffle: http://www.youtube.com/watch?v=ch_SMNQ-awM
Does that mean that we don't have to worry about rdoc - and just write document on places that might be unclear. Anything you have provided in your instruction rdoc, we don't have to repeat ?
Thanks
The point is this:
-- The "official" documentation, outlining how the public methods should work, has been defined through the requirements for the assignments. So, in effect, the rdoc is done.
HOWEVER, you definitely should note internals that need explanations. You would be very wise to help your grader understand where key comments are. It would be appropriate to say in the readme that you've done something brilliant in a certain section of the code (then put the comment in the code).
Truly, we will not generate rdoc for this project.
For later work, where it will be appropriate for you to write comments suitable for rdoc: Even then, you don't have to actually generate the rdoc. We will see the rdoc comments while looking at the code.
Upshot:
For Assignment 2:
1. If you do anything cool, add a comment.
2. Helpful: List such interesting bits in your readme.
3. And the readme in general. Here's what we say:
Before submitting, you will write a file called readme.txt for the root of the project. It must describe what you did, in particular how you tackled the hand evaluation methods in the Hand class. We have put a very short readme.txt in place to get you started. More on the readme.txt below.
Internal documentation and writeup (the readme.txt). Is the internal documentation concise but clarifying? Does the readme.txt explain to me, in sentences and paragraphs, how your code works?
NOTE: There is no need to write things like "The Card class represents a playing card." Please, do not state the obvious. If you feel that you need to address this briefly, you may, but do not repeat the assignment or the requirements for your implementation.
NOTE: There is no need to write RDoc (public comments before "class" and public methods) for the tested methods in Card, Deck, and Hand. Why? Because the documentation we hand out is what you must code to. If you ADD public methods, provide RDoc comments for them.
You must specifically address your strategy for evaluating hands. Not doing so will render the 15% portion of the grade devoted to documentation very close to 0.
You must discuss any additional files, classes, or methods that result in additional functionality or convenience for you as the implementer.
It is hard to imagine a readme.txt that is fewer than 350 words. Please make an ordinary text file. No Word, PDF, etc.
See below for a question regarding the readme.txt.
You may also optionally add a method called strength_with_extras that reports, in addition to the number representing the type of hand, an Array for the high cards appropriate for the hand classification and an additional Array of kickers. This method would itself return an Array, the first element the value returned by strength, the other being the Array of kickers. (e.g., it might return [ 3, [ 12 ], [ 0, 1, 2 ] ], representing a Three of a Kind, a high card in the Three of a Kind (the Ace Spaces), followed by kickers of the 2, 3, and 4 of Spades. Another way to do it is to return instances of Card rather than the card numbers. It‘s up to you.
If you attempt this, discuss your implementation thoroughly in your readme.txt.
What should the readme.txt look like?
Put your name, the course name, and the assignment number at the top of the readme.txt.
The audience of the readme.txt is yourself or another technical staff member such as yourself. The reader knows Ruby and Rails, but may not currently be coding in it. This reader will be responsible for maintaining your code in the future. The reader may be your technical manager. Therefore:
1. Your writeup must be clear.
2. Your writeup must explain where everything is. If you introduce new files, classes, or public methods, say where they are, and what they do, and why they‘re important. A good way convey this kind of information is in the form of a list.
3. If you do anything fancy, you have to explain yourself.
4. The fact that the audience is also yourself is important. Think of what you are doing as a letter to yourself, which you will read in a year long after you‘ve forgotten the code. You will kick yourself if you find your own writing unclear or confusing.
These are the criteria we will be using during grading!
I am not clear on when one should use symbol and when one should use constant.
Could you explain ?
Thanks
class TestHand < Test::Unit::TestCase
include CardTestUtils
def test_has_lowest_card?
h = Hand.new("some_player")
h.accept(shuffle(to_cards(%w{ sa sk s2 d2 da dk })))
assert(h.has_lowest_card?, "Recognize that hand contains the lowest card")
h = Hand.new("some_player")
h.accept(shuffle(to_cards(%w{ sa sk s3 d2 da dk })))
refute(h.has_lowest_card?, "Recognize that hand does not contain the lowest card")
end
end
assert() is fine but for refute() I get the following error:
test_has_lowest_card?(TestHand):
NoMethodError: undefined method `refute' for #<TestHand:0x44402b0>
lib/testpusoydos.rb:33:in `test_has_lowest_card?'
Am I doing something wrong?
Here's the whole list: http://www.ruby-doc.org/stdlib/libdoc/test/unit...
Folks: Ana is writing tests because she's simulating a different game from poker.
For assignment 2, you should not need to write any of your own tests.
I wrote a message on Thomas's "errata" page at pragprog.com asking that he flag new things a bit better.
Amy, Keith, Harlan - refute must be new?
Throw an exception if limit is reach and try to accept another card?
Push new card or cards to the hand and and slice out existing one?
Throw exception is passing cards are bigger than 5?
In a real simulation, you could either throw an exception, or, possibly, write code to notify the other hands that one hand is illigitimately trying to accept a 6th card; then the other hands could complain and/or quit the game on the grounds that someone is cheating.
In general, for this assignment, should we be limiting ourselves very strictly to the specification, or is it okay to have a little more error-checking than what's minimally required?
Also, I am not sure that a hand should be responsible for such an exception. The reason is that if a 6th card is added to a hand, and that is not allowed, then, arguably, your deck is corrupted ('cos in the current model, the card is taken from the deck and THEN accepted into the hand -- there isn't a mechanism to force a card back into the deck). This suggests that if you did have a problem with a sixth card, it should be handled at a different level of abstraction. You could argue that it is the responsibility of the Dealer to not screw up a player's hand. OR, you might believe that the dealer should be able to do this, and the hand should be able to take advantage of such a bonus card . . .
test_0120_hand_strength_010(HandTest)
[./test/tc_hand.rb:270:in `check_hand'
./test/tc_hand.rb:263:in `accept_and_check'
./test/tc_hand.rb:90:in `test_0120_hand_strength_010'
./test/tc_hand.rb:89:in `each'
./test/tc_hand.rb:89:in `test_0120_hand_strength_010']:
Expected S2, S2, S2, S2, S2 to be evaluated as a Royal Flush.
<9> expected but was
<5>.
According to wikipedia information this is not a Roya Flush, Roya Flush is T, J, Q, K, A
accept_and_check([ suit + 'A', suit + 'K', suit + 'Q', suit + 'J', suit + 'T' ], 9)
So look at the element: suit + 'A'
In side the loop, suit is going to be 'H' or 'C' or 'D' or 'S'
So, the combination is going to be a two-letter sequence such as: 'HA' (ace of Hearts)
Go down to accept_and_check (near the bottom).
See how that two-letter sequence is used here:
def accept_and_check(abbrevs, strength, allow_ace=nil, dump=false)
cards = abbrevs.map { |a| Card.new(a) }
See Card.new(a)? What does your code do with Card.new('HA') ? It would seem that it's not working right.
THEREFORE, if your Card.initialize method is screwed up -- if it can't create a Card that represents an Ace of Hearts from the two character sequence 'HA' -- then there is going to be a problem.
In your case, it looks like your Card (no matter WHAT suit/rank is being handled) is always being created as a 2 of Spades.
Let me point out that the instructions strongly suggest that you start with the "spot" testing first -- this will verify some of the most crucial bits first. One of the earliest tests in tc_spot looks like this:
assert_equal 'DA', CARD.new(51).abbrev
assert_equal 51, CARD.new('DA').card_number
assert_equal 'Ace of Diamonds', CARD.new('DA').human_readable
That's checking to make sure that your code creates cards correctly.
I hope you read the instructions.
John
Sorry for the trouble
Thanks for your quick response.
'zip' is not recognized as an internal or external command,
operable program or batch file.
rm -f FIND_ZIP.zip
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require': no such file to load -- zip/zip (LoadError
)
from c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
from C:/harvard/CSCIE-168/assn2/bin/zip_in_ruby.rb:7
rm -f FIND_ZIP.zip
PKZIP(R) Version 2.50 FAST! Compression Utility for Windows 95/NT 4-15-1998
Copyright 1989-1998 PKWARE Inc. All Rights Reserved. Shareware Version
PKZIP Reg. U.S. Pat. and Tm. Off. Patent No. 5,051,745
Creating .ZIP: FIND_ZIP.zip
Adding File: demo.rb Deflating (50.9%), done.
Adding File: pkg/e168-assignment2-Manuel Ledesma-1.0.000/demo.rb Deflating
(50.9%), done.
rm -f FIND_ZIP.zip
Using ZIP command: "C:/harvard/CSCIE-168/assn2/bin/PKZIPC.exe" -add -dir
rake aborted!
Don't know how to build task 'README'
(See full trace by running task with --trace)
(in C:/harvard/CSCIE-168/assn2)
zip -r FIND_ZIP.zip demo.rb
'zip' is not recognized as an internal or external command,
operable program or batch file.
rm -f FIND_ZIP.zip
ruby "C:/harvard/CSCIE-168/assn2/bin/zip_in_ruby.rb" -r FIND_ZIP.zip demo.rb
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require': no such file to load -- zip/zip (LoadError
)
from c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
from C:/harvard/CSCIE-168/assn2/bin/zip_in_ruby.rb:7
rm -f FIND_ZIP.zip
"C:/harvard/CSCIE-168/assn2/bin/PKZIPC.exe" -add -dir -r FIND_ZIP.zip demo.rb
PKZIP(R) Version 2.50 FAST! Compression Utility for Windows 95/NT 4-15-1998
Copyright 1989-1998 PKWARE Inc. All Rights Reserved. Shareware Version
PKZIP Reg. U.S. Pat. and Tm. Off. Patent No. 5,051,745
Creating .ZIP: FIND_ZIP.zip
Adding File: demo.rb Deflating (50.9%), done.
Adding File: pkg/e168-assignment2-Manuel Ledesma-1.0.000/demo.rb Deflating
(50.9%), done.
rm -f FIND_ZIP.zip
Using ZIP command: "C:/harvard/CSCIE-168/assn2/bin/PKZIPC.exe" -add -dir
** Invoke rdoc (first_time)
** Invoke docs/rdoc/index.html (first_time)
rake aborted!
Don't know how to build task 'README'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:1718:in `[]'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:590:in `invoke_prerequisites'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:589:in `each'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:589:in `invoke_prerequisites'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:581:in `invoke_with_call_chain'
c:/ruby/lib/ruby/1.8/monitor.rb:242:in `synchronize'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:575:in `invoke_with_call_chain'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:592:in `invoke_prerequisites'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:589:in `each'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:589:in `invoke_prerequisites'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:581:in `invoke_with_call_chain'
c:/ruby/lib/ruby/1.8/monitor.rb:242:in `synchronize'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:575:in `invoke_with_call_chain'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:568:in `invoke'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2031:in `invoke_task'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2009:in `top_level'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2009:in `each'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2009:in `top_level'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2048:in `standard_exception_handling'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2003:in `top_level'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:1982:in `run'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2048:in `standard_exception_handling'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:1979:in `run'
c:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/bin/rake:31
c:/ruby/bin/rake:19:in `load'
c:/ruby/bin/rake:19
rake aborted!
Command failed with status (1): [C:/Ruby/bin/ruby -w -Ilib/;test/ "C:/Ruby/...]
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:974:in `sh'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:987:in `call'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:987:in `sh'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:1084:in `sh'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:1019:in `ruby'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:1084:in `ruby'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake/testtask.rb:117:in `define'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:1102:in `verbose'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake/testtask.rb:102:in `define'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:621:in `call'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:621:in `execute'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:616:in `each'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:616:in `execute'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:582:in `invoke_with_call_c
hain'
C:/Ruby/lib/ruby/1.8/monitor.rb:242:in `synchronize'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:575:in `invoke_with_call_c
hain'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:568:in `invoke'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2031:in `invoke_task'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2009:in `top_level'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2009:in `each'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2009:in `top_level'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2048:in `standard_exceptio
n_handling'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2003:in `top_level'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:1982:in `run'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:2048:in `standard_exceptio
n_handling'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/lib/rake.rb:1979:in `run'
C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.2/bin/rake:31
C:/Ruby/bin/rake:19:in `load'
C:/Ruby/bin/rake:19
Can you provide some help on what this means?
I always have 85 tests, but sometimes, I have 2722 assertions, other times 2720, sometimes 2718, and sometimes 2726.
Does that mean that some tests are not run. There is no indication of errors.
Thanks
For example, new in the Card class states:
If there are no args, or more than 1 arg, an ArgumentError is raised.
If there is one arg but it is not a Fixnum or a String, an ArgumentError is raised.
My classes are fully functional and pass all of the tests so do I need to implement other things on top of that such as my example above?
:)
You can introduce all of the instance variables you want. Those are private to your implementation.
If you introduce an acessor (attr_accessor) then other classes can manipulate those items. Do you want that?
Remember that any class (such as your implementation of Deck) can have an instance variable that can represent anything you like.
Just for example, you might have an instance variable that is an Array or a Hash or something else to represent the cards currently in the deck.
Then shuffle would (somehow) randomize that data structure.
Our reference implementation of Deck has about 12 lines of executable code (excluding "class ... end" "def cards_remaining ... end" -- and so fortth.
Don't overthink the problem.
"gem install rubyzip"
found a copy of "zip.exe" In the folder of a utility called LogMeIn on my computer. I copied it to c:\windows\system32\
I can email anyone the zip.exe binary if they need it.
Rajat
It may very well get returned if you send it to my gmail account . . . So try:
john at 7fff dot com
john at h3 dot com
jnorman at digitaladvisor dot com
The problem with the PKZIPC.exe in the code bundle is that it's not compatible with the Unix zip, so there is some code in the rake file that doesn't play nice with all versions of Windows.
So I'd like to try yours.
or
http://www.hindoogle.com/Software/zip.zip
"You may also optionally add a method called strength_with_extras that reports, in addition to the number representing the type of hand, an Array for the high cards appropriate for the hand classification and an additional Array of kickers. This method would itself return an Array, the first element the value returned by strength, the other being the Array of kickers. (e.g., it might return [ 3, [ 12 ], [ 0, 1, 2 ] ], representing a Three of a Kind, a high card in the Three of a Kind (the Ace Spaces), followed by kickers of the 2, 3, and 4 of Spades. Another way to do it is to return instances of Card rather than the card numbers. It‘s up to you. "
If the hand is tied, the extra cards are the "kickers" that decide the tie.
So say I have a pair of aces, and you have a pair of aces: What is the top card among the kickers (extra cards) that would decide which of us has won?
http://en.wikipedia.org/wiki/Kicker_(poker)
So. Is this because my code is, ahem, un-optimized, or does everyone have the same execution time?
Also, I am used to stepping through a debugger to see where the clogs happen. Is there a recommended method of doing something similar in Ruby to see where my code could be improved?
EDIT: I see that test_0195_hand_strength_025, test_0193_hand_strength_023 take the longest. I put a "puts self" in the test code functions to see what was running at execution. So I took them out and ran them separately, they are all fine. The difference is I ran them without the "accept_and_check" function.
So....I wonder if accept_and_check is slowing thing down...
Removing "accept_and_check" from the two function reduced execution time for the entire script from over 60 sec to 23 sec.
That said, I think you probably have something in accept_and_check that is slowing things down. These tests should run very fast. I'd send the code to your TA and see if they can spot something that might be causing your execution time to rise.
Thanks!
Maybe next time we'll blend profiling into the rake script.
I can only assume that learning the traditional Ruby will help me in this regard. Simply finding a function that works isn't good enough. Bad habits I have, I guess.
Rambling further, I think I'm just surprised that similar functionality in Ruby has such vast performance differences. I obviously don't know what I thought I knew about programming. I would think I would have had a more obvious confrontation with these issues in my past (I do C# and Java). I am now feeling humbled.
if (dealt_cards.length == 1)
@myHand.push(dealt_cards[0])
else
Similar logic works in card when trying to create a new card and parsing input. This code does not pass the unit test test_0100_hand_at_020. The array is initialized and passes the unit test before. The error I get is that <nil> not expected to be nil. Is there some more information regarding the splat operator in the pickaxe? I tried looking in there, but couldn;t find anything, maybe I misse it.
Thanks.
points = 82
grade = case points
when 90..100
'A'
when 80..89
'B'
.....
else
'E'
end
puts "Points: #{points}; Grade: #{grade}"
How can this be extended to take in an Array instead of a single FixNum ? I've tried a couple of things including === but can't get the syntax quite right. any hints would be much appreciated.
Or: Is this point value within this Array?
I'm sure I could write my own function to do this quickly, but in the spirit of code reuse...
class Range
def include?(val)
if val.is_a? Array
# do your check
else
super(val)
end
end
end
E-mail the ZIP in pkg/ to your section leader. Remember to include E168 in the subject, and submission:assignment3 in the body.
Should we do submission:assignment3 in the body or submission:assignment2 in the body since it is referenced as assignment 2 everywhere else?
Thanks!
But we certainly won't refuse a submission that says submission:assignment3 !!!
1) I cannot mixin "shuffle" due to its not being part of "Enumerable". Do I have to use "srand" or require "SecureRandom" to return integers between 0 and 52? I am having trouble imagining how to use such random number generators in a one-liner to shuffle the array.
2) I get the error "undefined method 'card_number' for 51:Fixnum". Does this mean that I have to use a Metaprogramming Singleton to create a class for the already dynamic "51"? I tried it unsuccessfully. I will try again, but just want to know if I am headed in a good direction.
Simply write your own shuffle method. The shuffle could be as simple as exchanging the cards many, many times by random switches.
Regarding the undefined method card_number : Have you defined an ordinary instance method or accessor called card_number ?
It's truly not asking for anything fancy. This assignments requires not one jot of metaprogramming jujitsu.
The error is:
NoMethodError: undefined method `method1' for []:Array
I get the error when I run the case statement. Any idea what's happening?
def thismethod()
myvariable = case
when @hand.method1() == true
something
when @hand.method2() == true
something!
else
nothing
end
end
@hand.method1()
Does @hand have a method called "method1" on it?
The error message (did you read it?) says: undefined method `method1' for []:Array
So it would seem that when @hand.method1() is executed, @hand is an Array, perhaps; is it? You can find out what class it is before this statement is run by adding:
puts @hand.class
John