Use CherryPy add a web interface to a Python script

The Web Class

The web class (lines 8-80) will be passed to CherryPy (which I'll talk about later). Class methods are endpoints for web addresses. Any function that begins with @cherrypy.expose is accessible via the web interface.

As with any Python class, __init__ gets called automatically when the class is instantiated. Line 10 takes the pokerTable argument, which is a reference to the Poker class that represents the game itself, and stores it in a class variable of the same name. Line 11 initializes self.playerHash as a dictionary to store MD5 hashes. These hashes will be used to reference players on web interface rather than their nicknames directly.

Just as Apache and most other web servers will look for a page named index as the landing point for a directory, CherryPy will look for a function named index. Here, a small HTML form is presented to the potential player asking for a nickname to use in the game. Anything returned from a @cherrypy.expose function is sent to the requesting browser.

The join function is called as a form handler for the index function above. It calls the Poker class's newPlayer function and passes the nickname of the player, then creates an MD5 hash from the player's nickname. Then, the playerHash dictionary is updated with the player's nickname and hash value. The HTML that is sent back to the player's browser uses JavaScript to redirect players to the actual game screen.

The play function returns the actual game. Because all player's web browsers route through the same function, the first task is to find out who I'm currently communicating with. The program clears the me variable, then loops over the list of hashes until it matches the one provided. Then, it breaks out of the loop, figures out what to send, and ensures that nothing is returned if a valid player hash is not located.

The if/elif tree checks the game state and returns the appropriate information to the player. Right at the top, if I'm the dealer and the game is waiting to start, then a DEAL button is sent.

If the game state is FLOP, RIVER, or TURN then the player's stats and hand are sent. That looks like Figure 3. Finally, if it's my turn to bet, I am sent the HTML that gives me my choices (Figure 4).

Figure 3: My hand. By combining these cards with the cards on the table, I have my full hand. I need to decide how much I'm willing to bet that my combination of cards is the best in play.
Figure 4: My turn to bet. I can enter a dollar value, stand (not wager anything), or fold.

Next, processBet is the form handler for the form that is sent. It passes the bet along to the poker game's processBet function.

The deal function starts a hand. Each function called from pokerTable sets up a different game element. Namely, reset clears the table and shuffles a new deck of cards, deal gives the players their cards, and flop deals the initial three community cards. The state function is the game state, so it's reset to show that the hand is now in the FLOP phase. Finally, setupBets initializes all of the players internally so that a round of betting can happen.

The gfx Class

The gfx class (lines 82-148) initializes Pygame [4], loads the card images, and provides a few utility drawing functions. The init function initializes Pygame, sets the screen resolution, and stores the reference to the screen surface in self.screen.

The program initializes the Pygame font module and then creates two font objects with the default system font. SysFont says "find the closest name match to the name I provide." If nothing is provided, the default is used. The values 50 and 30 define the type size in pixels (not points).

The next code loads the card images. First, the program initializes a dictionary to store them, loops through the ranks loading each card, and takes care of cards with a named (rather than a numeric) value. The pygame.image.load() lines load the images from disk and use pygame.transform.smoothscale to resize each of the cards to 200x290 and to convert the surface to match the format of Pygame's screen while preserving the alpha channel. The alpha channel gives the cards their rounded corners.

Once everything is initialized, I call joinTheGame, which shows a welcome screen and directs players to the web interface. The lines with self.bigFont.render() render instructions to join the game; render returns a Pygame surface containing the text. Then, that surface can be blitted or manipulated just like any other Pygame surface.

The drawCard function is a convenience function to blit cards onto the screen. Its arguments (position, suit, rank) locate the card image in self.cardImages and draw it at the location provided by the position tuple. Next, drawPlayers lists the players as they join the game, and the next few lines initialize the draw location and render and draw each player's information. If the player is the dealer (if playerData.dealer), then dealString is set to "DEALER"; otherwise, it's empty.

The program saves the players' line positions in their class instance, which can then be used again without recalculating. Each player's data is rendered and blitted, and y is incremented for the next player. After all players have been plotted, the display flips to show everything.

Buy this article as PDF

Express-Checkout as PDF

Pages: 8

Price $2.95
(incl. VAT)

Buy Raspberry Pi Geek

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content