DISQUS

e168f08: Assignment 2

  • Student1 · 1 year ago
    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:

    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
  • philadelphia · 1 year ago
    Hi,

    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.

    You might be able to simulate an existing shuffle: http://www.youtube.com/watch?v=ch_SMNQ-awM
  • Student1 · 1 year ago
    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?'

    Am I doing something wrong?
  • jgn · 1 year ago
    There is no method: refute

    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.
  • 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
  • jgn · 1 year ago
    Notice that the Hand is tested like so:

    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
  • 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


    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
  • Ana · 1 year ago
    Looks like the script is expecting "README" (not "readme.txt"). Just rename your file "README" and it works.
  • Manuel Ledesma · 1 year ago
    Thanks, It works.
  • Rachel · 1 year ago
    I'm also getting an error with my rake spot ..

    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?
  • Student1 · 1 year ago
    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.

    So I'd like to try yours.
  • rajatbaner · 1 year ago
  • MaureenB · 1 year ago
    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?

    http://en.wikipedia.org/wiki/Kicker_(poker)
  • MaureenB · 1 year ago
    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!