Beer batter shrimp

Beer batter shrimp

       

You can make these nice, puffy beer-battered shrimp with very little effort. You just need to let the batter sit for 30-45 minutes before you start dipping and frying the shrimp. We found that the best frying temperature for the shrimp was about 350˚ F. They still take only minutes to brown.

If you are using a stand mixer, you might find that it can’t beat a single egg white. We usually put in two so the beaters will catch the whites, and then only use about half of the beaten whites.

  • 1 lb shrimp, peeled and deveined.
  • ½ cup flour
  • Dash of salt
  • 1 beaten egg
  • 1 Tb melted butter
  • ½ cup beer
  • 1 egg white, beaten
  • About 3-4 cups canola oil
  • Lemon wedges
  • Seafood sauce of your choice

Folding egg whites into batter

Frying the shrimp
  1. Mix the flour and salt and stir in the butter and egg.
  2. Add the beer gradually, stirring only until smooth.
  3. Let the batter stand in a warm place for 30-45 minutes
  4. Preheat the oil to 350˚ F.
  5. Beat the egg white to stiff peaks.
  6. Fold the egg white into the batter.
  7. Dip the shrimp into the batter and drop directly into the hot oil. Cook only 5-6 at a time to keep the oil from cooling.
  8. Serve with French fries, lemon wedges and cocktail sauce.

French fries

Since you have the hot oil, why not make some French fries, too? Cut about 1 or potatoes per person into strips and soak in cold water for an hour, and then drain them.

Turn the oil temperature up to 375˚ F.  Dry the fries, and cook them in a couple of batches. Serve at once.

Shrimp and fries, with corn

Hoodoo Brown Barbecue in Ridgefield

Hoodoo Brown Barbecue in Ridgefield

We’ve been thinking about visiting Hoodoo Brown since before the pandemic, and now that we and they are more open, we thought we’d give it a whirl. It’s right at the intersection of Route 7 and Route 35, with a fair amount of parking behind as well as some in front.

We first attempted to have dinner there Saturday about three weeks ago, leaving Wilton about 5:15pm and getting there before 5:45. They politely told me there was a 1-1/2 hour wait, and maybe we should come back on a week night. So we did.

We got there last night (Thursday) about 5:45pm, and were able to park right in front. There was no crowd at all. The really friendly hostess seated us right away, mentioning twice where the bathroom was. Either we looked like we needed it or she thought their food did.

Our waitress was really helpful with their beer list, which was way longer than was printed in the menu. We ordered an IPA she recommended., and it was great While the menu itself is not large, it can be daunting, since so much of it seems to be quite large portions of meats. It features meats by the half pound including: brisket, pulled pork, pork belly, pastrami, pork ribs, smoked chicken, smoked sausage and beef rib. Their special that night was smoked prime rib 1 lb for $35 and 2 lbs for $44. It seemed a bit much for us.

There were also several appetizers, including BBQ Nachos, Texas Poutine, Fried Green Tomatoes, Chicken wings (several sauces are offered) and Burnt End Deviled Eggs. We got the chicken wings with barbecue sauce and the deviled eggs.

Wings with barbecue sauce
Burnt ends on Deviled Eggs

Of these, the chicken wings were tender and flavorful, but the deviled eggs just plain weird. The little bits of burnt ends were variable in tenderness and the deviled eggs themselves pretty flavorless.  They would be better if they added some mustard or horseradish to the egg filling so they rose to the flavor profile of the burnt ends.

Oddly enough, the waitress said there was no pork belly (not ready yet) and no bacon or sausage. This was disappointing since pork belly is featured in several of the menu items.

We ended up ordering their copious sandwiches, made up of brisket, pulled pork, pork belly and chicken in various combinations. We settled on the Hogzilla, made up of shaved pork ribs, pulled pork, pork belly, fried green tomatoes and supposedly Hoodoo Voodoo sauce. It also comes with copious French fries as well. The waitress said they’d add extra puled pork to make up for the missing pork belly.

The French fries were quite good, but the pulled pork was dry with no barbecue sauce within. We did each get a small 1 oz cup of sauce with our place setting, and we probably could have asked for more, but it would have been better if it had been mixed into the pork.

Hogzilla

If you look at the two pictures of the sandwich, you will see an odd orange square of something or other. The waitress identified it as pork belly crackling, but we think not, as it was hard enough to break a tooth on. And you could play a tune on your metal tray by banging it with that square, which I finally decided was more like petrified bacon. Luckily, we didn’t bite into one! We wished we’d stuck to ordering the ribs.

Hogzilla interior

Their dessert menu looked sort of interesting, especially the Carmelita Sundae, but we didn’t partake. Our bill with tax, but before tip, including 3 beers was $72.

Hoodoo Brown is at 967 Ridgefield Rd and is open T-Th 4:00pm-9pm, F-Sa 11:30am-9:30pm
Su 11:30am-8pm, and takes phone orders up to half an hour before their closing times.

Raised garden beds– an evaluation

Raised garden beds– an evaluation

We started raised bed gardening in 2014 when we realized that they would keep the soil from washing away. We bought cedar beds made by Greene’s Fence both from Home Depot and Amazon, and over several years worked up to about 23 4×4 beds. We had some topsoil delivered and added our compost and some commercial compost as we built them up.

Greene’ Fence raised beds, 1 year old and 2 years old.

But by the third year, the cedar beds started to deteriorate and we began replacing the beds about every three years. Needless to say, this can get expensive. In the above picture, you can see the one year old frame in the foreground and a two-year old frame behind it, already starting to fall apart.

Last year we decided we’d had enough, and we ordered 4 vinyl 4×4 beds to replace four of our rotting beds. The original ones were made by New England Arbors. These were very sturdy and still look great today. However, they don’t seem to be available any more.

New England Arbors– dog not included

This January we ordered some from Amazon made by Kdgarden which were pretty similar, but the Chinese company (Qingdao Kdgarden) that makes them seems to have dropped them from their product line. Or maybe they fell into the Suez?

Barton and Kdgarden match each other

We looked at ones from Home Depot made by Vigoro, but when we tried to assemble them, we discovered that they snapped together without any strong vinyl vertical tracks in the support poles and they came apart very easily. They also had some tiny little corner locks that were very hard to insert and didn’t stay together either, so we returned them to Home Depot.

The final order through Amazon was for frames made by Barton. These were identical to those from Kdgarden and the panels and posts were interchangeable. These are what we have switched to. They are very strong and fairly nice looking.  However, they don’t exactly match the panels and posts from New England Arbors so we will have to use our table saw to cut a groove in the other side of one of the new Barton boards to lock into the posts from NE Arbor. 

Joints in Barton (left) and NE Arbors (right)

All of the Barton frames come with glue to secure them. We haven’t bothered yet but may use it on the ones of separate ancestries. These vinyl frames cost about twice what we paid for the original Greene’s Fence cedar frames (they are about $80 each) but considering the cost of replacing the cedar frames several times this is a far better deal. Thankfully, they are still available.

Buttermilk brined roast chicken

Buttermilk brined roast chicken

If you like juicy roast chicken, you will love this recipe. It produces the juiciest, tenderest chicken we’ve ever tried. All you have to do is brine the chicken in salted buttermilk overnight or for at least 12 hours. You will love the results! This recipe is based on one in the New York Times, originally by Samin Nosrat, and it is well worth the little extra effort.

You can apply this recipe to smaller chickens (3.4-4.5 lbs), roasting chicken (7 lbs or more) or smaller turkeys (say 16 lbs). The only limiting factor is a plastic bag nig enough to hold the buttermilk without leaking in your fridge.

For the two of us, we often roast a chicken for dinner, eating the legs and saving the chicken breasts for sandwiches.  And what moist sandwiches this recipe makes!

  • One moderate chicken (around 4lbs)
  • Around 2-3 cups buttermilk
  • Kosher salt

To prepare the chicken,

  1. Cut off the wing tips with shears and remove any giblet packages. Run the chicken with kosher salt and let it sit for 30 minutes or so.
  2. Put the chicken in a zip lock plastic bag and add the buttermilk: enough to pretty much cover the chicken.
  3. Stir in 2 Tb kosher salt and mix the liquid a bit.
  4. Then seal the bag and put it in an outer plastic bag to avoid leaks, and refrigerate overnight.
  5. Take the chicken out of the fridge about an hour before roasting.
  6. Preheat the oven to 425 ˚ F. Scrape excess buttermilk off the chicken and place it on a rack in a cast iron pan. Tie the legs together with twine.
  7. Roast for 20 minutes with the legs pointed toward a rear corner (which is a hot spot), or using the Convection Bake setting at 400˚ F.
  8. After that 20 minutes, reduce the heat to 400 (or 375 if convection). Rotate the pan to point towards the other back corner. The skin should be starting to brown.
  1. If the skin darkens too much, put a foil tent over the bird.
  2. Continue to roast until a meat thermometer registers about 160˚ F, which will probably take no more than 30 more minutes, but be careful not to overcook it. Remove the chicken and let it rest for 10 minutes, during which the temperature will rise a bit more.
  3. Serve at once. It will be really moist and juicy because of the brining. Enjoy it!

The breast meat from this juicy chicken makes absolutely terrific chicken sandwiches. You  will note that they aren’t dry and don’t shred, but cut easily into slices. These sandwiches are the second payoff for this delicious recipe!

Can you slide eggs around in a non-stick pan?

Can you slide eggs around in a non-stick pan?

There have been a lot of commercials for various cheesy and quality pans that show off how you can slide the eggs around on the non-stick surface. But they never answer the question: why the heck would you do this? We have a good quality Misen nonstick pan, so we decided to try this silly experiment. We got out Misen pan over a year ago and really like it. We use it quite frequently: at least once a week and it has performed well for us. But we never tried to cook an egg without any butter or bacon drippings before!

So, we set our pan over medium-low heat on our gas stove, and broke an egg into a cup and slipped it into the pan. After it started to solidify, we tried to slide it around with wrist motion. That wasn’t enough, but after we briefly slipped a spatula under the egg, we could slide it around promiscuously!

Of course, we had to wait until the white was mostly cooked, but we could then easily pour the egg out of the pan and onto a plate. Of course, this really isn’t the best way to cook an egg: you would normally baste it was bacon drippings or butter, or flip the egg over, but we got it cooked.

Then we melted a little unsalted butter in the pan and cooked another egg. We had to cook it at a slightly lower temperature to avoid burning the butter, so it took a little longer. We had to dislodge it slightly with a spatula, but then it slid around in the bit of butter just as gleefully. And we could slip that egg onto a plate just as easily.

Results

So what are the results?  The egg cooked in the dry pan didn’t have much flavor, since fat carries the flavor. The one cooked in butter tasted a lot better, but both were pretty tough, because they were only cooked on the one side. We actually took two butter fried eggs, put them back in the pan, flipped them and cooked them for maybe 15 seconds. Then we put them between bread and made nice sandwiches. We added a little mayo for moisture, and some onion salt for flavor.

They weren’t bad, but would have been better flipped sooner, or basted in a bit of butter. But the dry-cooked one just wasn’t very good.

Overall, whole thing is silly.

Cheery Ring for Breakfast

Cheery Ring for Breakfast

Here’s a simple and delicious breakfast coffee cake you can delight Mom or anyone else with. It’s great for Valentines Day, Easter, Mother’s Day or any other special occasion.

 It’s a yeast dough that rises twice: once the night before and once during the night.  You can also make the rings in the morning in about 2 hours start to finish.

You make it using canned cherries (not cherry pie filling). You can find canned cherries at supermarkets in the aisle with the canned fruits, not with the baking supplies where that horrible canned pie filling is found.

The dough

  • ½ cup milk
  • 1/3 cup shortening
  • ¼ cup sugar
  • ½ cup lukewarm water
  • 1 package yeast (not instant)
  • ½ tsp sugar
  • 1 egg
  • 3-4 cups flour

The filling

  • 1/2 cup chopped pecans
  • 1/2 cup flour
  • 1/2 cup brown sugar
  • 1/2 cup butter
  • 1 can red pitted cherries, drained

The icing

  • ½ lb confectioner’s sugar
  • 4 Tb butter
  • Milk about 3-4 Tb
  1. Place the milk, sugar and shortening in a glass pitcher or bowl and microwave for one minute. The shortening does not need to melt completely.
  2. Place the yeast, water and ½ tsp sugar in another pitcher and stir. Let it sit a few minutes until it’s foamy.
  3. Put the warm milk mixture into the bowl of a food processer and add 1 cup of the flour.
  4. Pulse briefly to mix.
  5. Add the egg and mix.
  6. Add the yeast and mix.
  7. Add 2 more cups of flour, and enough more to make a smooth dough.
  8. Let the dough rise for 60-90 minutes
  9. Melt the butter and combine with the brown sugar and flour.
  10. When the dough has risen, remove it from the food processor and divide it in half.
  11. Roll out each half on a floured board to a 6″ by 18″ rectangle.
  1. Sprinkle half the cherries, half the brown sugar mixture and half the nuts on each rectangle.
  2. Roll the dough into a long tube and place the tube on a greased cookie sheet. Connect the ends and pinch them together to make a ring. Since this makes a round dough ring, you can use a pizza pan for the cookie sheet.
  3. Repeat for the second half of the dough.
  4. Make a series of cuts about 3/4 inch apart going from the outside about 3/4 of the way into the tube.
  5. Take each slice and rotate it about 90 degrees, lifting and twisting it with your knife, so the cherry mixture is horizontal.
  6. Cover the pan containing each ring with aluminum foil (sprayed with a little cooking spray) and cover both wrapped rings with a damp towel.
  7. Allow them to rise in a cool place such as a basement or garage overnight. If you allow them to rise in the refrigerator, make sure they are tightly wrapped. In that case you may have to let them rise a bit more outside the refrigerator in the morning.
  8. Before you go to bed, wash out the food processor so you can use it to make the icing in the morning.
  9. In the morning, preheat the oven to 375 F.
  10. Uncover the rings and bake them for about 15 minutes, until brown.

Ice with butter cream icing and serve warm.

Buttercream icing

Place the confectioners sugar and the butter in a clean food processor bowl and pulse until uniform. Add the milk, a little at a time until the icing is a smooth, spreadable mixture.

Why I gave up on Microsoft Edge

All the tech press (and here) has been gag about the new version of Microsoft’s Edge browser. It uses the same Chromium rendering engine that Google Chrome does and seems a little faster. It definitely uses less memory, although not orders of magnitude less, but maybe half as much. Here is a Task Manager screen shot showing Chrome and Edge with the same 9 tabs open. In both cases there are many more instances running than were open at that moment. Over time this number of instances tends to grow more in Chrome than in Edge, but it is seldom an actual performance issue.

Since it clearly is less of a memory hog, they conclude you should switch. Edge has more privacy settings, but Chrome is better hooked into the Google  “ecosystem,” of Google Docs, Maps and Gmail.

Default search engine

Edge uses Bing as its default search engine, which among other things means that getting to Gmail or Google docs won’t work directly.  Bing is OK but not as all-encompassing at Google’s engine. Changing Edge to use Google as its default search engine is a little involved. Open the menu button, select Settings, and Privacy, Search and Services. Then scroll down to Search Engine Used in Address Bar. You can select Google, Bing, Yahoo, Duck Duck Go, and a couple of others.

You would think that’s all there is to it, but it isn’t. Every time you click on “+” to open a new tab, the Microsoft Bing page comes up. You can get Google instead if you have put a link to it in your menu bar. If you hold down Ctrl and click on Google it opens a new tab.  Slightly inconvenient.

And look at the difference between what comes up in Edge and in Google:

If Edge calls up the Bing engine, you get an empty address bar to type in. If it calls up Google, the URL to Google is displayed and you have to sweep the mouse to remove it before typing in a new URL.

There is no way to set Edge to open a Google search panel from the +-sign from the menu. The only way is to install a Google-provided plugin. But even then, clicking on that plus sign does not provide you with an empty address bar.  This is simply dumb, (or intentional) on Microsoft’s part.

Importing data from Google

Edge will import all your Chrome address bar tabs and Chrome’s file of passwords. Almost. I found that it did not correctly import my password to my credit card provider, Citibank. Instead, it imported several old passwords, but not the current one, although this is hard to track since it masks the passwords as “*******” so you can’t find the right one.

Edge also doesn’t seem to import anything from your browser history, which provides valuable type-ahead data for entering sites you don’t bookmark but want to get to by just typing 2 or 3 characters. You have to do it over again for all those sites.

Cookies

If I tried to access my bank account, the bank system sees a new browser without any cookies to tell it that I am the same customer, and it wants to send me an Email or SMS message with a numeric key to tell it I am the same user.

That would be OK, except the Edge never learns that fact, and the bank continue wants to validate me. I asked the bank about this and got no reply. I would assume that means they have no solution. That and the inelegant address bar were really my deal breakers. I’d have to switch back and forth to check if payments had cleared and so forth.

Switching Back

You would think that just going to Chrome and setting it as the default browser would undo all this, but it might not. The first time I switched back, I found that got Bing some of the time anyway. I had to go to the Windows search bar and type Default Apps to bring up the app where I could switch all searched back to Google. This went away after a recent Windows update, and now Chrome brings up that Default Apps program window directly.

However, once you again make Chrome your default browser, that Google plugin in Edge that makes the +-sign open a Google search page no longer works, and you have to reinstall it or revert to the Ctrl/click method to open a new tab as a Google window.  Bah!

Kindred: a fascinating look at Neanderthals

Kindred: a fascinating look at Neanderthals

Kindred,  Neanderthal Life, Love, Death and Art, the new book by Rebecca Wragg Sykes, is a thorough look at what science now actually knows about Neanderthals and their dominant position for thousands of years. Sykes explains that recent research shows that Neanderthals were the dominant hominin in Europe for over 350,000 years (350 ka). And by Europe, we actually mean a huge swath from Britain all the way to Israel!

This is one of the most fascinating books I have read in many years. It covers their entire history and lives in much more detail than I had any idea we knew about.

Living

Sykes explains that Neanderthals were a nomadic people, apparently moving from camp to camp, and to some extent following the migration of game that was so important to them.  Many of these camps included caves or “rock shelters,” and they apparently returned to them many times over the years. She explains that their meat rich diet included reindeer, horses, aurochs (huge early oxen), and even mammoths and elephants, and it appears that each individual consumed 5000-7500 calories a day because of their active lifestyle as well as the sometimes very cold climate. Plants were also part of their diet, but the evidence for which ones is a bit scanty. They survived several glacial and inter-glacial periods and persisted until relatively recently.

While popular imagination considered Neanderthals to be very primitive, current evidence shows that they had much the same vocal apparatus we do, and probably had speech and some language. They were probably closer to Alley Oop (without Dinny) than to the Flintstones (with recycled Honeymooners voices and humor), but we know that they made complex tools from various types of rock, and used them for sophisticated butchery, hide scraping and construction of fur clothing. In fact, the lack of many nicks on the recovered animal bones suggest that their butchers were very skilled indeed.

They even mastered some chemistry: tools exist that had stone blades but wooden handles, glued on by reduced birch sap cooked under low oxygen conditions, or when that wasn’t available, pine sap tempered with beeswax.

Sykes explains that Neanderthals were a bit shorter than us homo sapiens, and of course had the sloping brow you see in most pictures. Their fingers were a bit longer than ours, but their brain case was much the same as ours, implying they had the same level of intelligence we do.

Rather than the rough-looking images reconstructed from their skeletons, you might consider the beautiful paintings of Thomas Björklund more representative of what Neanderthals really looked like. They were as human as we are and lived and loved much as we do.

Art

Much of the art that Neanderthals produced was using red and yellow and black colors that they dug from the ground. There is evidence that they decorated shells that way and added colors to their tanned leather clothing. But one of the most astonishing finds was the arrangement of stalactites in a cave at Bruniquel in Spain. Sykes explains that they broke off over 400 stalagmites, selecting the middles of them by size,  and arranged them in two rings, with the larger one 6 by 4 meters.

There is also a flat plate balanced on a cylinder.  And careful dating shows that this construction is 174,000 years old.  There were fires placed on some of these structures. Bear in mind that all this took place deep in a barely accessible cave with no light whatever.  We have no idea whether it was art or some ceremonial construction, although there may have been some bear remains in some of the fires. It remains an amazing mystery.

Pieces of cave art were also reported in Spain in 2018 in Cantabria and two other sites that were about 65,000 years old. If you look carefully, you will see a painting of a red ladder pattern with some sort of pathway along the top. This is the oldest known cave painting and took place long before there were homo sapiens in Spain.

Interbreeding

Homo sapiens didn’t begin to arrive in Europe from Africa until about 100 ka, and evidence seems to indicate that there was some interbreeding with Neanderthals. Most people of European descent have about 2% Neanderthal genes while indigenous Americans, Asians and those from Oceana and Papa “have up to a fifth more.” Those of sub-Saharan descent have much less, and when they do it appears to have come from later interactions.

The major migration of homo sapiens from Africa to Europe didn’t take place until about 42ka and eventually they dominated, although we still do not understand what happened to the Neanderthals. Their burial customs were variable but for the most part we have found far fewer bones than you would expect from such a dominant race. Sykes believes there is still a lot more work and excavating to do to resolve this mystery. There are also genetic theories of one species’ DNA replacing another’s, although this has happened in other species, we have no proof it happened with Neanderthals.

In summary, Sykes describes the lives of Neanderthals over much of their long reign in Europe and gives us a fascinating picture of their accomplishments. You really need to read this book.

Rock, Paper, Scissors in Python: Part III – Improving the GUI

Rock, Paper, Scissors in Python: Part III – Improving the GUI

In our previous article, we developed a simple Python tkinter user interface for a rock[paper-scissors game. However, if you tried the code, you might stumble on one infelicitous problem:

No buttons selected

The program comes up with no boxes checked, but if you click on the Play button, the program plays a game anyway, assuming that Scissors had been selected. Why does this happen?

When we set up the 3 radio buttons we set the IntVar to -1 so that none of the buttons would be selected.

ChoiceButton.gvar = IntVar()
ChoiceButton.gvar.set(-1)   # none selected
ChoiceButton(lbf, "Paper", 0).grid(row=0, column=0, sticky=W)
ChoiceButton(lbf,"Rock", 1).grid(row=1, column=0,sticky=W)
ChoiceButton(lbf, "Scissors", 2).grid(row=2,column=0, sticky=W)

But let’s see what happens when our code checks the index to see which button is selected:

# play one game
def playit(self):
    index  = int(ChoiceButton.gvar.get())
    self.play = Player.moves[index]

The index returned is -1 as expected. And the three moves are in a tuple:

moves=("P", "R", "S")   #tuple of legal play characters

 And what do we get when we ask for

Player.moves[-1]

Python is unusual among common computer languages in that indexes of less than zero in arrays (lists), strings and tuples mean start at the end and work backward. So the index of -1 gives us the character ‘S’ and -2 would get us ‘R’ and so forth. This also rotates around so that -4 would give us ‘S’ again. In other words, Python apparently takes the index modulo the length of the array so that negative indexing never gives us a  out of bounds error. If we had set the gvar to 3 or more, no radio button would have been selected, and an error would occur.

So, how do we prevent this infelicitous behavior, where a player can click on the Play button when no radio button has been selected?  It would be possible to trap this out-of-range indexes and prevent play from taking place, but since the program assumes that only legal plays can occur, this would take a good deal of careful checking.

Instead, we do what we should have done in the first place and disable the Play button until a radio button has been clicked.

playButton['state']=DISABLED

But how do we turn the button back on?  We recommend using a Mediator.

The Mediator Pattern

The Mediator Design Pattern is a really simple little software trick that keeps classes from having to know about the internal workings of other classes. And when you are dealing with GUI widgets, there might be a number of GUI classes that needn’t know about each other.

Instead, we create a Mediator class and tell it about the push button and the radio buttons, and let it do the work. The Mediator keeps a reference to the pushbutton and receives a call when a radio button is clicked.  The whole thing is just a few lines of code:

class Mediator() :
    def __init__(self, button):
        self.button = button    # save the button reference    

    # called when a radiobutton is selected
    def choiceClick(self):
        self.button['state']=NORMAL # enable the button

So, how do we go about connecting up this Mediator? We create the button and then create the Mediator, passing it a reference to that button:

playButton = Button(root, text="Play", command=self.playgame)
playButton.grid(row=3, column=0, pady=20)
playButton['state'] = DISABLED
med = Mediator(playButton)     # create the Mediator 

So, now the Mediator knows about the button. What about the radio buttons? You may recall that we have derived a ChoiceButton class so it can contain the gvar variable. All we need to do is pass the mediator reference to each button as we create it:

ChoiceButton(lbf, "Paper", 0, med).grid(row=0, column=0, sticky=W)
ChoiceButton(lbf, "Rock", 1, med).grid(row=1, column=0, sticky=W)
ChoiceButton(lbf, "Scissors", 2, med).grid(row=2, column=0, sticky=W)

And the ChoiceButtpm itself creates a command that calls choiceClick in the Mediator:

class ChoiceButton(Radiobutton):
    gvar = None
    def __init__(self, rt, label, index, med):
        super().__init__(rt, text=label,
                         variable=ChoiceButton.gvar,
                         command=self.comd,
                         value=index)
        self.med = med  # Save the Mediator reference

    def comd(self):
         self.med.choiceClick() #call the Mediator

So anytime a ChoiceButton is clicked, it calls choiceClick and that enables the Play button.

Summary

So, to summarize, we use the Mediator to take care of classes that need to send each other information. In this case, clicks on the radio buttons tell the Mediator to enable the Play button. Before that it is disabled. In general, the Mediator is an excellent solution when two or more classes need to tell each other about click events and the like and prevents you having to write GUI classes that know about other GUI classes, and thus getting entangled.

Code for this and the previous two articles can be found on GitHub at jameswcooper/articles

Rock, Paper Scissors in Python: Part II,  Building a GUI

Rock, Paper Scissors in Python: Part II, Building a GUI

In our first article, we designed a Rock, Paper, Scissors game that works from the keyboard. It printed out messages and shows the total score when you quit. But even a game this simple will benefit from a graphical user interface (GUI). Here we show how to use the Tkinter toolkit to create that simple interface. Specifically, we are going to use the tkinter.ttk toolkit, because it has a nice LabelFrame widget to hold the three RadioButtons.  It looks like this:

You can select the three possible plays from the radio buttons in the “Plays” LabelFrame, and then click on the Play button to have the program player select its move and tell you who won.  The messages from the program are shown in the Listbox on the right, showing what the Auto player has selected, and who wins. The total score for the two players is shown in the blue label above the Listbox.

Creating the GUI

For simple programs like this, we usually create a Builder class with a build method and a few other methods as needed. Here the only method we’ll need is the playit method, that triggers one round of play.

 Here is the program’s outline:

import tkinter as tk
from random import randint
from tkinter import *
from tkinter.ttk import *

class Builder():
    # play one game
    def playgame(self):
        # players play game

    # create window     
    def build(self):
       root = tk.Tk()
       root.geometry("300x200")
       root.title("Rock paper scissors")
        #UI creation code   
        mainloop()     # start the window

# Program starts here
if __name__== "__main__":
    bld = Builder()
    bld.build()

Adding GUI Controls

We use the Grid layout to arrange the GUI widgets, with the LabelFrame and Play  button in column 0 and the score label and Listbox in column 1. The three radio buttons are inserted into the label frame inside their own three line grid.

The only sneaky part is the way the Radio Buttons work. All of radio buttons in a group use the same variable to tell you which button has been selected. That variable is an IntVar, an integer wrapped in an object that is required by the underlying tk toolkit. So, when you create each Radiobutton, you have to pass it a reference to that IntVal variable, and the value that that button will pass to the IntVar, usually small integers, such 0, 1 and 2.

The design question we have to solve is where that IntVar variable will be located so each of the RadioButtons can access it. The obvious place is right inside the radio button code itself. So we derive a new ChoiceButton from Radiobutton that contains the class level variable gvar. Now all instances of the ChoiceButton have access to that same variable, and can change it to 0, 1 or 2 depending on which button is clicked. Here’s the whole new ChoiceButton class.

class ChoiceButton(Radiobutton):
    gvar = None  # will be set to an IntVar

    def __init__(self, rt, label, index):
        super().__init__(rt, text = label,
                         variable =ChoiceButton.gvar,
                         value=index)
        self.text = label
        self.index=index

When we create the GUI, we will set that gvar to an IntVar. The complete GUI code is

def build(self):
    root = tk.Tk()
    root.geometry("300x200")
    root.title("Rock paper scissors")
    # create a label frame for the radio buttons
    lbf = LabelFrame(root, text="Plays")
    lbf.grid(row=0, column=0, rowspan=3, pady=10, padx=10)
    
# create 3 radio buttons, but set none as selected

    ChoiceButton.gvar = IntVar()
    ChoiceButton.gvar.set(-1)   # none selected
    ChoiceButton(lbf, "Paper", 0).grid(row=0, column=0, sticky=W)
    ChoiceButton(lbf,"Rock", 1).grid(row=1, column=0,sticky=W)
    ChoiceButton(lbf, "Scissors", 2).grid(row=2,column=0, sticky=W)

    # create Play button - calls playgame method
    playButton = Button(root,text="Play", command=self.playgame)
    playButton.grid(row=3,column=0,pady=20)

    # create score label
    self.scoreLabel = Label(text="scores", foreground="blue")
    self.scoreLabel.grid(row=0, column=1)

    # create listbox
    self.mesgList = Listbox(root, width=30)
    self.mesgList.grid(row=1, column=1, rowspan=3)

    # create two players
    self.player1 = Player("You")
    self.player2 = AutoPlayer("Auto", self.mesgList)
    mainloop()

Note that we use the same Player and AutoPlayer classes as in the previous example;. The only difference is that the AutoPlayer adds a message to the Listbox instead of printing it on the console:

class AutoPlayer(Player):
    def __init__(self, name, list):
        super().__init__(name)
        self.list = list

    def playit(self):
        playval = randint(0, 2)
        self.play = Player.moves[playval]
        self.list.insert(END, self.name + " selects " + self.play)
        self.list.yview(END)

The Player class differs only in its playit method, which obtains the selected Radiobutton from the index in gvar. Note the yview(END) method on the Listbox, which scrolls to the bottom of the list so that the last line always shows.

# play one game
def playit(self):
    playval = ChoiceButton.gvar.get()
    index  = int(ChoiceButton.gvar.get())
    self.play = Player.moves[index]

And the playGame method of the Builder class differs only in that the winner is added to the Listbox, and the label is updated to show the current score:

def playgame(self):
   self.player1.playit()    # read buttons
   self.player2.playit()    # calc random play  
# compute winner
   winner = Winner(self.player1, self.player2)
   self.mesgList.insert(END, winner.findWin())  # print winner
   self.mesgList.yview(END) #move to bottom of list 
# show current score
   self.scoreLabel.config(text="You: "
                            +str(self.player1.wincount)+"--- Auto: "
                            +str(self.player2.wincount))

Conclusion

The differences in the console game and the GUI version are pretty small. The Player class gets your play from the radio button selected, and all the messages are added to the Listbox. The running score is changed in the scoreLabel each time.

All of the code for this example can be found in Github at jameswcooper/articles/rockpaper