From stephen at touset.org Tue Jan 16 14:55:56 2007 From: stephen at touset.org (Stephen Touset) Date: Tue, 16 Jan 2007 14:55:56 -0500 Subject: [Libpoker-devel] Poker::Hand direction Message-ID: <1168977356.6248.1.camel@midas> This was from a conversation between Ben Hidalgo and I earlier. I felt it would be useful outside the context of our original discussion. On Tue, 2007-01-16 at 08:59 -0500, Ben Hidalgo wrote: > Right... the hand evaluator is game specific. I wouldn't have the > hand evaluator be aware of the shared cards. I'd let some other class > feed the evaluator permutations, and pick the highest. I think the direction I'm intending to go is similar to the latest checkin of Poker::Hand. Essentially, it's a subclass of Array with two additional features: initialize takes an "evaluator", and an array of community cards. Since every variable in ruby is a reference, that array will get updated as the community cards do. Example: irb(main):001:0> array = [ :a, :b, :c ] => [:a, :b, :c] irb(main):002:0> a = array => [:a, :b, :c] irb(main):003:0> array << :d => [:a, :b, :c, :d] irb(main):004:0> a => [:a, :b, :c, :d] The evaluator parameter is just a class with a class method "evaluate" that takes two arrays (the hand, and the community cards) and returns an integer that can be compared against other hands. For games like Stud Hi/Lo, where we need multiple comparisons, the evaluator is an attr_accessor, so the user of the class can change it as necessary. Hypothetical example of Stud Hi/Lo evaluation: h1 = Hand.new(Poker::HandEvaluator::7StudHi) h2 = Hand.new(Poker::HandEvaluator::7StudHi) hands = [h1, h2] # ... hands get filled ... hands.sort hi_winner = hands[0] hands.each {|hand| hand.evaluator = Poker::HandEvaluator::7StudLo } hands.sort lo_winner = hands[0] Or something like that. It'd be more generic (since this part would supposedly be part of the core Ruleset "engine"), but that's close enough. > Another app I've seen that was pretty cool, was a poker coordinator. > Your blinds and rounds implementation reminded me of it. You > basically program it with a progression of blinds and time limits and > it provides a clock countdown and alarms when blinds are to be raised. > Additional features could be a seat organizer, chip distribution > calculator and payout calculator. I've seen them. The library will definitely grow classes/functions for that (specifically, for the purposes of automatically running tournaments), so something like that could easily and naturally be built as an additional tool. -- Stephen Touset -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: This is a digitally signed message part Url : http://rubyforge.org/pipermail/libpoker-devel/attachments/20070116/6c65499e/attachment.bin From stephen at touset.org Tue Jan 16 15:42:20 2007 From: stephen at touset.org (Stephen Touset) Date: Tue, 16 Jan 2007 15:42:20 -0500 Subject: [Libpoker-devel] Poker::Hand direction In-Reply-To: <1168977356.6248.1.camel@midas> References: <1168977356.6248.1.camel@midas> Message-ID: <1168980140.8291.20.camel@midas> On Tue, 2007-01-16 at 14:55 -0500, Stephen Touset wrote: > For games like Stud Hi/Lo, where we need multiple comparisons, the > evaluator is an attr_accessor, so the user of the class can change it as > necessary. Hypothetical example of Stud Hi/Lo evaluation: > > h1 = Hand.new(Poker::HandEvaluator::7StudHi) > h2 = Hand.new(Poker::HandEvaluator::7StudHi) > hands = [h1, h2] > > # ... hands get filled ... > > hands.sort > hi_winner = hands[0] > > hands.each {|hand| hand.evaluator = Poker::HandEvaluator::7StudLo } > hands.sort > lo_winner = hands[0] > > Or something like that. It'd be more generic (since this part would > supposedly be part of the core Ruleset "engine"), but that's close > enough. With regards to this, is it possible there's a better way? Perhaps having evaluate_high, evaluate_low parameters to Poker::Hand.initialize. This would be incompatible with the Comparable mixin, however, since there are *two* innate methods for comparison. Perhaps another approach would be better: # ...in the game definition... @high_evaluator = Poker::HandEvaluator::Standard @low_evaluator = Poker::HandEvaluator::Lowball8 # ...later on, when hands are created... hands = Array.new(2) do Hand.new do |h| h.high_evaluator = @high_evaluator h.low_evaluator = @low_evaluator end end # ...hands get filled... if @high_evaluator hi_winner = hands.sort {|a, b| a.high_value <=> b.high_value }.first end if @low_evaluator lo_winner = hands.sort {|a, b| b.low_value <=> a.low_value }.first end Where Poker::HandEvaluator::Standard is mapped behind the scenes to the StdDeck_StdRules_EVAL_N libpoker-eval function, and P::HE::Lowball8 is mapped to StdDeck_Lowball8_EVAL_N. This approach requires a block to define sorting (rather than using a defined <=> through Comparable) but is a little cleaner to use overall. Plus, we aren't hiding the fact that there are multiple comparison methods. And if either is nil, we ignore that comparison. Ignore, of course, that the example doesn't account for split pots. I actually think I like this approach better. Any comments? -- Stephen Touset -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: This is a digitally signed message part Url : http://rubyforge.org/pipermail/libpoker-devel/attachments/20070116/7c94dd2f/attachment.bin From stephen at touset.org Tue Jan 16 22:44:41 2007 From: stephen at touset.org (Stephen Touset) Date: Tue, 16 Jan 2007 22:44:41 -0500 Subject: [Libpoker-devel] Poker::Hand direction In-Reply-To: References: <1168977356.6248.1.camel@midas> <1168980140.8291.20.camel@midas> Message-ID: <1169005481.9146.21.camel@midas> Okay, I've written the first part of a binding for a "standard" hand evaluation in ext/hand_evaluators/hand_evaluator.c. It maps Poker::HandEvaluator::Standard to the libpoker-eval method StdDeck_StdRules_EVAL_N. This evaluator can take a hand of any size, plus community cards, and runs a standard poker evaluator on them. A straight will generate a higher number than two pair or trips, a flush will be higher than a straight, etc. It also has stubbed a "describe" function, which should return a human-readable description of a hand's strength. There's a function in libpoker-eval that can do this, but I haven't written the code yet. It's important that all evaluators take two parameters: a hand, and a set of community cards. In games without community card we can always pass an empty array. However, there are some games that use community cards in situations where not enough cards remain in the deck (7 card stud for instance; with 8 people seeing the river it uses a community card, although it's rare). Is anyone fluent in C? Since I've already got the first mapping written, it shouldn't be too hard to write a similar mapping between Poker::HandEvaluator::Lowball => StdDeck_Lowball_EVAL_N Poker::HandEvaluator::Lowball8 => StdDeck_Lowball8_EVAL_N Poker::HandEvaluator::Lowball27 => StdDeck_Lowball27_EVAL_N Poker::HandEvaluator::OmahaHi => StdDeck_OmahaHiLow8_EVAL Poker::HandEvaluator::OmahaLow8 => StdDeck_OmahaHiLow8_EVAL so if anyone wants to do this and email me the code, I'll be glad to commit it (this would go a long way towards having me accept you as a developer, by the way *grin*). If you need some direction, let me know. Ruby's C API isn't too well documented, but most of what you should need is in my code already. I do have to mention this, though, because too many open source projects get stuck on it. If you contribute code to this project, I will require that you explicitly assign the copyright over the code to me. No sinister reason -- simply it's easier to enforce copyright or change the license (e.g., GPL2 => GPL3), even when contributors might no longer be active. http://www.gnu.org/licenses/gpl-faq.html#AssignCopyright Lastly, I guess I should get around to how you can use the code that's already written :) It should be pretty simple: go into the source directory, do an export RUBYLIB="lib" irb -rpoker and you should be in a Ruby shell, with the library loaded into place. The examples directory has a script that you can run (which doesn't work yet, but should demonstrate the intended library usage). On top of that, rake builds the C extensions, builds the rdoc documentation (in doc/html and doc/ri), and runs all the unit tests. That's all there is to it. -- Stephen Touset -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: This is a digitally signed message part Url : http://rubyforge.org/pipermail/libpoker-devel/attachments/20070116/670a81e3/attachment.bin From stephen at touset.org Fri Jan 19 00:45:42 2007 From: stephen at touset.org (Stephen Touset) Date: Fri, 19 Jan 2007 00:45:42 -0500 Subject: [Libpoker-devel] IRC channel Message-ID: <1169185542.1693.0.camel@midas> I've started an IRC channel on freenode. It's Server: irc.freenode.org Channel: #libpoker I'm in it whenever I'm online, as is the other developer on the project. It'll probably have more traffic than the email list... -- Stephen Touset -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: This is a digitally signed message part Url : http://rubyforge.org/pipermail/libpoker-devel/attachments/20070119/7ab7aac7/attachment.bin