HP Forums

Full Version: Yahtzee scoring with lists
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Dave Britten's recent post regarding RPN models that could self-score a Yahtzee game prompted me to look up the game rules that I hadn't looked at since the early '70s. As I am inclined of late to see a list-based approach to many problems, this seemed like an interesting exercise to try. Several of the ListExt commands are a nice fit for the scenarios presented for scoring in the game.

First, some ground rules for my approach:
  • A group of rolled dice is represented as a list of approximate numbers (a quantity of 5 in this case).
  • In keeping with the game definition, each scoring subroutine will return either the defined score for that category, or 0 if the dice list doesn't match at all.
  • The source code below needs fraction marks to work properly. I've omitted them from the comments simply to make them easier to read.
  • These routines only consider primary scoring. Secondary issues like conditional bonuses would need to be considered in the context of a complete game.
  • Each instance of the SORT command below can be replaced by Werner's excellent LSORT command. If you don't have it, you should!


Aces - Sixes

The "upper section" scoring simply sums the values of a chosen die value (1 through 6). LCNT (List Count) is a good fit for this one:

Code:
\<<
   @ scores aces, twos, threes, fours, fives, sixes
   @ SL2: dice list
   @ SL1: denomination (1..6)

   SWAP OVER                  @ denomination, dice list, denomination
   LCNT *                     @ result = count * denomination
\>>


Sorted Group Counts

A couple of the "lower section" scoring subroutines make use of a shared intermediate step. I think of this as "sorted group counts", and have named the subroutine that computes it SGC accordingly. SGC returns a list of counts of matching dice in the supplied input, sorted in ascending order.

Example:

If the input list is { 1 6 4 1 4 }, SGC returns { 1 2 2 } (one 6, two 1s, two 4s). Note that the results are sorted by quantity, not die value.

The line comments below show the intermediate results with the above input for better understanding.

Code:
SGC
\<<
   @ returns a sorted list of die value group counts
   @ SL1: dice list
   
                              @ initial input: { 1 6 4 1 4 }
                              
   SORT                       @ { 1 1 4 4 6 }
   LRPCT                      @ { { 1 4 6 } { 2 2 1 } }
   LPOPR                      @ SL2: { { 1 4 6 } }     SL1: { 2 2 1 }
   NIP                        @ { 2 2 1 }
   SORT                       @ { 1 2 2 }
\>>


Three or Four of a Kind

This subroutine checks the size of the largest group of repeated die. If 3 or 4 is <= the largest count, then the sum of all dice is returned.

Code:
\<<
   @ scores three or four of a kind
   @ SL2: dice list
   @ SL1: 3 or 4

   SWAP DUP LSUM UNROT        @ Determines possible score, leaves on stack above input
   SGC                        @ Sorted Group Count
   LPOPR NIP                  @ Highest group count from the list
   \<= *                      @ multiply the computed score by 1 or 0 for the result
\>>


Full House

This one is fairly brute-force. It simply finds the sorted group count, and checks to see if it exactly matches 2 of one value and 3 of another.

Code:
\<<
   @ scores Full House
   @ SL1: dice list

   25. SWAP                   @ possible score placed above input list
   SGC                        @ Sorted Group Count
   { 2. 3. } SAME *           @ score given only if exactly 2 and 3 of a kind
\>>


Small or Large Straight

The approach used here is to look at the differences of the sorted dice list to determine if a straight of the specified size exists. The ListExt command LDLTA gives the same result as the built-in \GDLIST, but is slightly faster and much easier to type into a program. :-)

Code:
\<<
   @ scores Small or Large Straight
   @ SL2: dice list
   @ SL1: 3. (small) or 4. (large)

   10. OVER * UNROT           @ possible score (30 or 40) placed above input list
   SWAP SORT LDLTA SORT       @ sort the dice list and determine the sorted differences
   SWAP LTAKE 1. +            @ keep the first 3 or 4 differences, then add a 1 to the list
   LEQ *                      @ if all of the list values are 1, return the score
\>>


Yahtzee (5 of a Kind)

A very simple scenario to check.

Code:
\<<
   @ scores Yahtzee (5 of a kind)
   @ SL1: dice list

   50. SWAP                   @ place possible score above input list
   LEQ *                      @ if all values are the same, return the score
\>>


Chance (any combination)

Even simpler than Yahtzee!

Code:
\<<
   @ scores Chance (simple sum of dice)
   @ SL1: dice list

   LSUM                       @ that's it!
\>>

These are just the methods that came to mind as I looked at the rules. I'm sure there's other approaches (list-based and otherwise), and thoughts and alternate methods are always appreciated.
Very interesting techniques. I'll bet they could serve as the basis for implementations on RPN models.
Reference URL's