Skip to content

Instantly share code, notes, and snippets.

@lancereinsmith
Created December 13, 2020 19:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lancereinsmith/19200357c9412df06d3b5322be7a8101 to your computer and use it in GitHub Desktop.
Save lancereinsmith/19200357c9412df06d3b5322be7a8101 to your computer and use it in GitHub Desktop.

Lance Reinsmith, M.D. is a radiologist and programming hobbyist who lives and works in San Antonio, TX. Dr. Reinsmith is no better at playing dreidel than random chance would indicate.

Dreidel is a game commonly played during the celebration of the Hanukkah holiday. Each player starts with a bank of coins and takes turns spinning a four-sided top. The results of the spins dictate how the game progresses. For more information, check out the Wikipedia entry on dreidel.

To summarize, each player usually antes one coin into the pot to start and when it is empty. If a player rolls a:

  • נ‎ (nun), the player does nothing.
  • ג‎ (gimel), the player gets everything in the pot.
  • ה‎ (hey), the player gets half of the coins in the pot. If there are an odd number of coins in the pot, the player takes half the pot rounded up to the nearest whole number.
  • ש‎ (shin), the player adds one to three coins to the pot. (For historical and geographic purposes, some dreidels have a פ‎ (pey) instead of a shin, but this has the same function.)

This article reviews how to write a simple dreidel simulation script using Python. It assumes you have intermediate familiarity with Python 3, including classes, list comprehension, lambda functions, and type hinting.

To spin the dreidel, we'll need to define our dreidel faces and import the choice method from the random module.

https://gist.github.com/f690bbee8d8b32488bed46c45fcb61b4

Most dreidel games involve about 4-6 players with a starting bank of about 10 coins. Let's set some constants for our game:

https://gist.github.com/978cda82c148bc86680dde3e119d19a7

Of course, you can change these.

I'll eventually want the console output to be color-coded for better readability. The colorama package helps simplify this in Python. Install using:

https://gist.github.com/3b93ec95b18925262a47e1fb48c304e2

Appending colorama color codes to strings can get quite busy and cumbersome; but, we can simplify this using lists and/or variables with short names:

https://gist.github.com/fd4448220cac65c9a10e7f966ea896d8

This way, we can reference the list by an index and append that to the string. If this sounds confusing, it will be more clear below.

We'll now construct a Player class to serve as a blueprint for each player in the game.

https://gist.github.com/abb0fd2903de2bdf40fd511233e9fb7c

This init method assigns a name and starting bank to the Player. It also assigns a color using a modulus to rotate through the list of colors defined above. (The double underscores before and after "init" make this a "dunder" function--which usually means a class function run internally and not intended to be called de novo.)

https://gist.github.com/d3a7fa6b750d707b73e6d64c7f2dd0ea

Next, we create a simple method to determine if a player is bankrupt which returns a boolean based on their bank. It returns True if the patient's bank is zero or less.

https://gist.github.com/2ab721dccd8839548e45253205767696

Then, we create an ante method which takes in a parameter of the ante_amount. (This defaults to the amount defined above.) It first checks if the player is bankrupt. If so, it returns 0 to the pot. If the player is not bankrupt, it then checks if the player has enough to ante up. If so, the ante is deducted from the player's bank and returned to the pot. If not, the player pays its residual to the pot and the player's bank goes to zero.

https://gist.github.com/ef0b653ecd81a4d1da5011e3e9da2455

Next, it's time to spin! The turn method takes in the current pot as a parameter. A random choice of the faces is made. Based on this, the player's bank and the pot are adjusted. The method returns the spin and the final pot value as a tuple.

There are a few things to point out here:

  • (pot+1) // 2 makes sure the player gets half of the pot rounded up to the nearest whole number
  • The SHIN_PENALTY is defined above. If the player cannot pay this, it adds the residual amount in their bank to the pot and sets their bank to zero.

https://gist.github.com/c52fdb821a02049936ce2c6bf50fd136

Finally, we make a string representation for the Player for completeness sake. The entire class is shown here:

https://gist.github.com/81db4962acf3099272910d31522382b5

We then make a function to check all of the players in the game to see if there is a winner:

https://gist.github.com/8c41782a060afd6475e1fea59f4d127c

This can be a bit tricky if you're not used to the map function and lambda functions. The function takes in a list of Players as a parameter, each Player with an is_bankrupt() method. It then maps the is_bankrupt() method over all of the Players and calculates the sum of the results. Since is_bankrupt() returns 0 for a bankrupted player, a sum of 1 means there is only a single non-bankrupt player.

Finally, we need to set up the game:

https://gist.github.com/4fb2ff3afe9d6a2ea0e370efff91480b

This function appears complex, so we'll break it down step-by-step.

The function accepts the number of players (num_players) and starting bank amount for each player (starting_bank) as parameters. These default to 4 and 10 by default.

Next, the group of Players is constructed using list comprehension. While doing so, the index of the for loop is used to assign a rotating color to the Player. (I use "_" as an index variable, but you could use "I" or anything else.)

The pot and spin_count are then reset to zero.

Next, the script enters a loop where each player takes turns. Prior to each turn, the function checks if the pot is zero. If so, everyone needs to ante (see ante method above) if they can. It then checks for a winner by passing the list of Players to the check_for_winner function defined above.

If there is a winner, it loops through the players to find the winner and prints a message in white (by prepending the text with the w variable defined with the colors) declaring the game stats, the winner name, and the number of spins it took to complete the game. The game is then over.

If no one has won, it then checks if the current player is bankrupt. If not, the player takes their turn spinning and the pot is updated and spin count increased. The function then prints a message to the console in the player's color (by prepending the text with the player.color value) specifying who has spun, what the result is, and the new values of their pot and the bank.

It's now time to tell the script to set up and play the game if the script is run:

https://gist.github.com/327912e108f6453dea696dab91e6f28c

That's it! If you like this, try adjusting the parameters to see how the game changes. Or, try playing a real game of dreidel with friends or family! Here is the entire script.

https://gist.github.com/361d9e375ca038240bed0d8385e0f258

Happy Holidays!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment