Talks

Playing a Hand with Ruby Pattern Matching

Playing a Hand with Ruby Pattern Matching

by Brandon Weaver

Summary of 'Playing a Hand with Ruby Pattern Matching'

In this engaging talk presented by Brandon Weaver at RubyDay 2021, the focus is on utilizing the newly introduced Ruby 2.7 feature, Pattern Matching, through a lively theme of playing poker. Brandon elaborates on innovative use cases for Pattern Matching, particularly in the context of scoring poker hands.

Key Points Discussed:

- Introduction to Pattern Matching:

- Pattern Matching is a new feature in Ruby 2.7 that allows for more elegant ways to handle data structures.

- The discussion begins with a comparison of traditional Ruby syntax with the new pattern matching syntax.

  • Creating Card and Hand Structures:

    • Brandon demonstrates how to define a card and a hand using classes.
    • Constants are established for suits (Spades, Hearts, Diamonds, Clubs) and ranks (ranging from 2 to Ace) to provide structure and validation.
  • Implementation of Scoring for Hands:

    • The talk explores various poker hands and how to score them using Pattern Matching.
    • Examples include a royal flush (highest hand), straight flush, four of a kind, full house, flush, straight, three of a kind, and pairs.
    • Brandon illustrates how to match hands against defined patterns and checks conditions to determine the type of hand.
  • Pattern Matching Techniques:

    • The importance of a deconstruct method to allow classes to interface with pattern matching effectively.
    • Different methods are implemented for comparing cards and organizing them for scoring purposes.
  • Potential Applications and Future Use:

    • Brandon emphasizes the broader implications of Pattern Matching in Ruby, including potential uses in real-world applications like data processing and HTTP response matching.
    • He encourages further exploration and utilization of this feature in various programming contexts.

Conclusions and Takeaways:

- Pattern Matching is an exciting and powerful feature that enhances Ruby’s capabilities, especially in terms of code clarity and readability.

- The community is encouraged to experiment with Pattern Matching to unlock its full potential for diverse programming challenges.

- Brandon wraps up by thanking contributors to the development of this feature and advocates for its adoption in more libraries and frameworks, noting ongoing community efforts to enhance Ruby development overall.

00:00:00.120 Oh my gosh.
00:00:33.899 Foreign.
00:00:46.620 I hope you are ready for the last talk before our big break, where we will see each other in the hallway.
00:00:53.340 Our next talk is by Brandon Weaver.
00:01:02.070 Thank you.
00:01:15.320 Welcome, Brandon! Great to be here. The talk today is interesting for two reasons.
00:01:22.080 First, it’s about pattern matching, which is something relatively new in the Ruby world.
00:01:27.659 Second, it’s about poker. Brandon is a Ruby architect at Square.
00:01:34.500 He helps his company define standards for Ruby and is also an artist. I would love to hear more about lemurs and cartoons in programming afterwards.
00:01:42.240 Welcome, glad to be here. I guess I can leave the stage to you.
00:02:22.800 Hello, everyone! So glad you can make it.
00:02:27.900 Get comfy because we’re about to go on a wild ride through the depths of Ruby pattern matching.
00:02:35.099 This talk explores some novel usages and ideas regarding this exciting feature.
00:02:42.239 So who exactly am I? Simply put, my name is Brandon, I work for Square, and I enjoy doing fun things with Ruby.
00:02:49.319 You can find my Twitter in the bottom left of most slides, which will have resources related to the talk.
00:02:55.860 Shall we get started? Let’s begin with a short preview of pattern matching to see what it looks like.
00:03:07.860 The following code may have been common in older versions of Ruby, but with 2.7, we introduced a new syntax for pattern matching.
00:03:15.060 With this code, we compare values using triple equals.
00:03:20.640 We’ll primarily look at array-like matchers today.
00:03:27.959 This compares each element positionally; the first should be an integer, the second should be a two, and the third should just be there.
00:03:34.319 This also captures nil, but it does serve a useful purpose.
00:03:41.040 There’s also experimental one-liner syntax which I’ll be using heavily in this talk.
00:03:47.640 Based on its usefulness and documented use cases, I believe it will likely be included in future versions of Ruby.
00:03:54.720 I certainly hope so, because it’s all types of fun.
00:04:05.400 So, where were we? Ah, yes. I like lemurs, and lemurs like games.
00:04:12.659 They figured out how to play poker but are horrible at scoring the games, so they’ve asked us to help.
00:04:18.900 That brings us to the task of employing pattern matching.
00:04:24.720 To start, we'll need to set up some structure for our game, like a card or maybe a hand.
00:04:33.660 Let’s start with something simple, like creating a single card.
00:04:40.259 We can create a class to describe our card, starting with constants.
00:04:47.340 Constants will describe what our data is, how we validate it, and give us structure.
00:04:54.900 The suits will be S for Spades, H for Hearts, D for Diamonds, and C for Clubs.
00:05:00.300 Unicode symbols could be used, but using letters is quicker and easier.
00:05:06.660 Next, we need to consider ranks.
00:05:12.240 Ranks go from 2 up to Ace, and we typically use strings to avoid having to deal with numbers downstream.
00:05:18.360 We want numerical indices for each rank to reference their associated scores.
00:05:25.560 Now we have constants to describe the data of our class.
00:05:31.020 Next, we need to make a card, which is a combination of a suit like Spades and a rank like Ace.
00:05:36.660 Now let’s take a look at creating a hand, which is a collection of many cards.
00:05:43.620 To start, we want to define constants for our hand class.
00:05:49.560 The highest type of hand is a royal flush, and the lowest is a high card.
00:05:55.800 We’ll go into each one of these examples later in the talk.
00:06:01.860 After establishing those scores, we’ll create a list in reverse order to see that the royal flush has the highest score.
00:06:07.620 Now, let’s take a look at how hands are actually constructed.
00:06:13.740 A hand is a container for many cards, initialized with those cards.
00:06:19.740 You might notice one piece of code that is crucial for this layer – the sort method.
00:06:26.580 We want to have some methods to make it easier to create card hands and view their contents.
00:06:31.740 Let's consider viewing a card by implementing an array-bracket method.
00:06:38.640 This serves as an effective alias for the new method.
00:06:44.880 You might also notice a dot dot dot, which forwards all arguments.
00:06:50.160 Now, back to our card; we also want to have string and array representations.
00:06:56.250 Nothing too exciting here, just using one-liner methods for quick definitions.
00:07:02.040 We have a method called deconstruct, which is important for pattern matching.
00:07:09.060 This tells our class how to match against array-like patterns when asked.
00:07:15.840 Next, we’ll look at methods for creating and viewing our hands.
00:07:22.020 The hand class can define a similar method to from string to create it.
00:07:28.200 We want string and array representations along with pattern matching capabilities.
00:07:35.160 Now let’s get into actually creating a hand.
00:07:41.580 We can split the input string on either commas or spaces to allow multiple formats.
00:07:48.600 We can map these into cards using the underscore for numbered brands.
00:07:54.040 The sort method helps order our cards after mapping.
00:08:01.140 Now we should consider how to actually sort the cards.
00:08:07.440 We can start by defining card precedence to determine their rank.
00:08:13.740 We'll define the precedence for each card to score them against one another.
00:08:20.040 The interface for comparable enables us to use the rocket ship operator for comparisons.
00:08:29.100 This means we can sort them with ease.
00:08:36.540 Let’s consider comparing cards to see how this works.
00:08:42.840 If the left side is greater than zero, they are the same, and if negative, the right is greater.
00:08:50.040 As we sort the hand, we want to ensure the order is consistent for pattern matching.
00:08:57.560 This reduces potential match cases significantly.
00:09:05.160 With all this set up, we still need to focus on scoring.
00:09:12.180 Let’s explore some examples of scoring hands.
00:09:17.579 Our first hand is a royal flush, consisting of all cards of the same suit from ten to ace.
00:09:23.580 We’ll define methods on our hand to establish what constitutes a royal flush.
00:09:29.580 By matching our cards against a pattern, we can encapsulate this idea.
00:09:35.880 The pattern will start with a card with brackets.
00:09:42.300 This captures the suit and specifies the first rank must be ten.
00:09:48.600 We’ll ensure that all subsequent cards have the same suit.
00:09:55.920 Now, let’s test that out to see if it works.
00:10:01.019 This brings us to our next hand: a straight flush.
00:10:06.300 A straight flush requires all cards to be in order and of the same suit.
00:10:11.100 Unlike the royal flush, we need to define both conditions.
00:10:16.740 If both of these exist, our test returns true.
00:10:22.260 Next up is four of a kind. This means four cards of the same rank.
00:10:27.600 With four aces of different suits, we can check that our cards match this pattern.
00:10:33.300 As in previous cases, we’ll pin the rank to ensure the four cards are the same.
00:10:39.120 Now we’ll define a full house, which consists of three of one rank and two of another.
00:10:47.280 For this, we’ll match three aces and two kings.
00:10:54.480 We need to ensure we account for both rank configurations.
00:11:00.720 Next, we’ll establish a flush: all cards of the same suit.
00:11:05.520 We’ll match against all cards in the hand for the same suit.
00:11:12.300 After that, we can define a straight: all cards in order but any suit.
00:11:18.840 To implement this, we must define what the next card in the sequence is.
00:11:25.680 In the hand class, we'll check that ranks increase by one.
00:11:31.560 Though not an ideal solution, for now we must use string interpolation.
00:11:38.760 Back to our examples, a hand can be identified as a straight.
00:11:43.620 Next, we’ll look at three of a kind: three cards of the same rank.
00:11:50.280 Using the fine pattern method again, we’ll ensure we have those three cards.
00:11:57.060 Two pairs are next, which are two pairs of the same ranked card.
00:12:03.840 We’ll define a method to match against those pairs.
00:12:10.680 The issue is that we must ensure the pairs are distinct.
00:12:17.280 Finally, we have a single pair; this is like two pairs, but only one.
00:12:23.520 In testing, we’ll confirm our scoring implementation is effective.
00:12:29.880 With our foundation established, we can implement scoring for hands.
00:12:35.760 Using our scores, we can rank hands based on their types.
00:12:41.520 If nothing else matches, we can return the highest card.
00:12:48.300 Let’s run some examples to see if they all work.
00:12:54.060 Now we’ll check our constants.
00:13:01.080 If we run these tests, we will find that we can solve poker hands with pattern matching.
00:13:07.740 Pattern matching is an exciting feature with a multitude of possibilities.
00:13:14.400 I hope this talk inspires you to try a few of your own ideas.
00:13:23.220 Pattern matching has immense potential, especially when considering hash-like matching.
00:13:32.160 For those interested in more examples, you can follow my work on social media platforms.
00:13:44.940 I would like to thank everyone who contributed to the development of pattern matching.
00:13:54.540 It’s a community effort that continues to advance Ruby.
00:14:07.020 Thank you all for your time, and have a great day!
00:14:46.800 Welcome back! That was as great as I was expecting.
00:15:01.400 Thank you so much for your talk! It was an interesting deep dive into pattern matching and poker.
00:15:11.340 While we wait for questions, could you share where else you see pattern matching being utilized in the programming community?
00:15:21.660 Arrays tend to be the less powerful variant, which needs explanation.
00:15:33.080 What's fascinating is when you utilize hash-like matches, for example, matching HTTP responses.
00:15:43.080 With the expressive capabilities of pattern matching, you can perform complex queries on structured data.
00:15:53.040 This can be beneficial for processing JSON or CSV data easily.
00:16:00.540 In production, there could be numerous applications.
00:16:06.060 Historically, people shunned IF statements, but pattern matching provides clarity and enhances readability.
00:16:18.060 In Rails, we're exploring its use in models to facilitate data exploration.
00:16:28.620 It's especially useful during live coding or interacting with production data.
00:16:39.180 Pattern matching requires a deconstruct method to function effectively.
00:16:48.480 We’re advocating for support of this in various libraries and gems.
00:17:00.180 The community has yet to fully realize its potential but is making strides.
00:17:07.140 Thank you, let's keep exploring pattern matching together.