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

Rock, Paper, Scissors Game in Python: Part I

Rock, Paper, Scissors Game in Python: Part I

You probably have played the little hand game Rock, Paper, Scissors one in a while. Essentially two players bring up a fist, a flat hand ot two fingers to represent rock, paper or scissors. The winner is based on these three simple rules:

  • Rock breaks scissors
  • Scissors cuts paper
  • Paper covers rock

In the case of a tie, no one wins.

This little game is easy to create in Python using the keyboard to enter R, P or S, or Q to quit. The second player is the program itself which uses a random number generator to choose one of the three outcomes. This little game is sometimes given as an early assignment, but beginners usually miss some of the really clever features of Python that can make the game more elegant and succinct. We’ll illustrate tuples, classes and subclasses, and dictionaries in this simple article.

We can start by using a tuple to represent the three possible moves:

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

These are the only three characters that the player should be allowed to enter. So we can create a simple entry loop that repeats until one of those three characters is entered. We use the upper method to make sure the entry is uppercase. Note that the code “play in moves” returns True if the character entered is P, R or S and otherwise returns False.

legal = False
while not legal:
    play = input("enter play (P, R, S): ").upper()
    legal = play in moves 

 And, if you want to allow the player to enter “Q” to quit the game you could check for that Q and set a quit flag:

def playit(self):
    legal = False
    while not legal:
        play = input("enter play (P, R, S): ").upper()
        if play=="Q":
            quit = True
        legal = play in Player.moves or quit

 As you can see, this is now a function.  But why not make it part of a class?

You may recall that classes are a major part of Python. Classes are components that can contain data, and can exist in many instances with differing data in each.

A Player class

Our complete player class has the name of the player and a play variable containing the latest play. It also keeps the state of the quit flag and the legal flag.

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

    def __init__(self, name):
        self.name = name    #initialize name,quit, and count
        self.quit = False
        self.wincount = 0   #counter of wins

    def playit(self):
        legal = False
        while not legal:
            self.play = input("enter play (P, R, S): ").upper()
            if self.play=="Q":
                self.quit = True

            legal = self.play in Player.moves or self.quit
 # the number of wins is counted here
def countWin(self):
    self.wincount += 1
 

So, as you can see, the Player class has a playit method which sets the play variable to P, R or S. It also can be set to Q, and the quit flag indicates that this is not a real play. Note that the moves tuple is a class variable. This means it is part of all classes of this type and you can access it by Player.moves.

But, what about the other player? It is the computer program itself, and it uses the randint method to select 0, 1 or 2 and these indices indicate which of the three plays has been choses. So, we need another class like Player for the computer player.

As you may recall, you can derive new classes from old ones, so we create an AutoPlayer class derived from Player. It only contains the new playit method. All the other variables and methods are in the base Player class. So, our simple AutoPlayer class is just

class AutoPlayer(Player):
    def __init__(self, name):
        super().__init__(name) # pass the name into the parent class

    def playit(self):
        playval = randint(0, 2)     # select 0, 1 or 2
        self.play = Player.moves[playval] # get that play from the tuple
        # print out what it has selected
        print(self.name + " selects " + self.play)

So, now, we see how we can write a loop for you to play the game:

player1 = Player("You")
player2 = AutoPlayer("Auto")
while not player1.quit: #loop until a 'Q' is entered
    player1.playit()
    if not player1.quit:
        player2.playit()

Picking a Winner

But how do we know who won? This is really simple, since there are only 3 cases (plus the tie) to check for.  We can create a Dictionary of these cases and the resulting message you print out:

game= {"RS": "rock breaks scissors",
       "SP": "scissors cuts paper",
       "PR": "paper covers rock"
       }

We only need to check for ties and check for who wins, by combining the string for the two players.We do all this within a Winner class which then returns the outcome:  First we initialize the variables:

class Winner():
    game= {"RS": "rock breaks scissors",
           "SP": "scissors cuts paper",
           "PR": "paper covers rock"
           }

    def __init__(self, p1, p2):
        # copy variables into class
        # to make this simpler to read
        self.p1 = p1
        self.p2 = p2

Note that the game dictionary is also a class variable.

Then, the findWin method checks for ties and if there is no tie, it calls checkWin to check if p1 beat p2 or p2 beat p1:

# A winner matches on of the three
# game dictionary entries abouve
# we check p1+2 and p2+p1
def checkWin(self, p1, p2):
    # here are the two outcomes
    # for both player orders
    match1 = p1.play + p2.play
    match2 = p2.play + p1.play
    mesg = Winner.game.get(match1)
    if mesg != None:
        p1.countWin()
        outcome = p1.name + " win -- "+mesg
    else:
        mesg = Winner.game.get(match2)
        p2.countWin()
        outcome =  p2.name + " win -- " + mesg
    return outcome

def findWin(self):
    if self.p1.play == self.p2.play:
       return "Tie, no winner"
    else:
        return self.checkWin(self.p1,self.p2)

Note that Player class contains a countWin method that increments the winner count of that player won. Then, when you finally type ‘Q’ the program can print out the final score.

player1 = Player("You")
player2 = AutoPlayer("Auto")
while not player1.quit: #loop until a 'Q' is entered
    player1.playit()
    if not player1.quit:
        player2.playit()
        # compute the winner
        winner = Winner(player1, player2)
        print(winner.findWin()) # print winner

# print out the wins for each player
# when you type "q" for quit
print(player1.name, player1.wincount)
print(player2.name, player2.wincount)

The final output

Here is how the program works:

enter play (P, R, S): r
Auto selects R
Tie, no winner
enter play (P, R, S): r
Auto selects S
You win -- rock breaks scissors
enter play (P, R, S): q
You 2
Auto 2

Summary

We used the tuple to check for legal input (P,R or S) and then created a Player class which has a playit method and contains a play variable which contains the charact representing that play. Then we created a derived AutoPlayer class which has the same internal variables and methods, but where the playit method uses a random number function to generate 0, 1 or 2. These are then indexes into the tuple  to find the character representing that play.

Finally, we created a dictionary of the three possible plays and the message describing the winning cases and used the Winner class to find if p1+p2 won or id p2+p1 won. Thus, in this simple example we used the tuple, the dictionary, classes and a derived class to write a simple game program.

The complete code for this and the programs in the following articles is available at GitHub under jameswcooper/articles

Easy Eggs Benedict

Easy Eggs Benedict

There’s really not much to making this fabulous breakfast (or lunch or dinner) dish. This video shows how to make Eggs Benedict in about 10 minutes.

Actually, the video is only 9 minutes, because we cut out part of the egg poaching time.

But all you need to make Eggs Benedict is

  • 2 English muffins, split and toasted
  • 4 slices ham, sauteed in butter
  • 4 eggs to poach
  • 3 egg yolks
  • 1-2 Tb lemon juice
  • ¼ lb butter melted and still hot

Sauté the ham slices in butter for about a minute.

Toast the split English muffins and top each half with a ham slice.

The important part of making the Hollandaise in a blender is to melt the butter so it is hot and bubbly. In our microwave, this is about 75 seconds (1:15 minutes). Make sure the butter is quite hot, so it cooks the egg yolks a bit when you pour it into the blender with the yolks and lemon juice.

To poach the eggs, we use a 3-quart saucepan with water gently simmering. Add salt and about 2 Tb white vinegar to the water, and quickly slip the 4 eggs into the water. No need to stir or swirl. Set a timer for 3:00 minutes and then lift the eggs out and put them on the toasted English muffins with the hams slice. Pour on some hollandaise and serve right away. Decorate with a bit of parsley if you like.

This makes a festive breakfast in about 15 minutes, including the time to bring the water to a boil. Enjoy it!

Entering data in Python: console or GUI

Entering data in Python: console or GUI

Suppose you want the user to enter some data for a Python program to work on. For this, Python provides the input statement, which can print out a prompting string and wait for keyboard input. 

name = input("What is your name? ")
print("Hi "+name +" boy!")

This little program asks for your name and waits for you to type a string and press Enter. The input statement accepts keyboard input and returns a string. So, the resulting console results might look like this:

What is your name? Jim
Hi Jim boy!

Heinlein fans may recognize the reference.

You can paste that 2-line program into any development environment, such as Thonny, PyCharm or even Jupyter Notebook and see it work right away.

Adding two numbers

Of course, you can enter numbers as well, but you must be sure to convert the resulting strings into an int or a float. Here we use the more general float.

x = float(input("Enter x: "))
y = float(input("Enter y: "))
print("The sum is: ", x+y)

The resulting output is:

Enter x: 23.45|
Enter y: 41.46
The sum is:  64.91

Of course, this naïve program expects only legal input. If you enter, say, “qq” instead of 22, you will get a Python error:

File "C:\Users\James\PycharmProjects\input\inputdemo.py", line 7, in <module>    
y = float(input("Enter y: "))
ValueError: could not convert string to float: 'qq'

There are ways to check for this, of course, such as catching Exceptions, and we will explain those in the following example.

However, you will only find the input statement in rudimentary examples. Most programs that need user input get it from a windowing interface. We’ll show these same examples next using the tkinter GUI library.

Making a windowing example program

You can do much the same thing by using the Entry field in the tkinter GUI (graphical user interface). Here we repeat those examples in simple tkinter windows.  To use tkinter, you have to import that library into your program:

from tkinter import *
import tkinter as tk

You also create an abbreviation for tkinter, naming it just tk.

Then, most of the setup code creates the visual widgets and their arrangement. In the following example, we use an Entry field, a Button and two Labels. You start by getting the window system pointer tk.Tk() and use it to attach the widgets to. After you create this objects, you run the mainloop() function which displays the window and receives mouse and keyboard input. The window keeps running until you close it by clicking on the “X” in the upper right corner or selects some widget that causes the window to close.

Our first example above was one where you enter your name and it says Hello back, again giving homage to Heinlein in the process. The tkinter program does the same thing

The code for this program creates the two labels, the Entry field and the OK button:

def build(self):
    root = tk.Tk()
    # top label
    Label(root,
         text="""What is your name?""",
         justify=LEFT, fg='blue', pady=10, padx=20).pack()

    # create entry field
    self.nmEntry = Entry(root)
    self.nmEntry.pack()   # and put it into the window

    # OK button calls getName when clicked
    self.okButton = Button(root, text="OK",
                            command=self.getName )
    self.okButton.pack()

    # This is the label whose text changes
    self.cLabel = Label(root, text='name', fg='blue')
    self.cLabel.pack()
    mainloop()      #run loop until window closes

When you click on the OK button, it calls the getName method, which fetches the text from the entry field and inserts it into the bottom label text.

# gets the entry field text
# places it on the cLabel text field
def getName(self):
   newName = self.nmEntry.get()
   self.cLabel.configure(text="Hi "+newName+" boy!")

Adding two numbers

And our second example rewritten from above reads two Entry fields, converts them to floats and puts the sum in the lower label.

 The code for this window is much the same, except that we fetch and add two numbers. Here is the function the OK button calls.

xval= float(self.xEntry.get())
yval = float(self.yEntry.get())
self.cLabel.configure(text="Sum = "+str(xval+yval))

Catching the error

However, if you enter some illegal non-numeric value, you can catch the exception and issue a error message:

try:
    xval= float(self.xEntry.get())
    yval = float(self.yEntry.get())
    self.cLabel.configure(text="Sum = "+str(xval+yval))
except:
    messagebox.showerror("Conversion error",
                              "Not numbers")

If you enter non-numeric strings, the program displays this message box:

And that’s all there is to creating a program with a simple graphical user interface.

Steak béarnaise using a blender

Steak béarnaise using a blender

Steak béarnaise is a simple dish. You cook a steak and pour some sauce béarnaise over it. You can cook the steak over a grill, in a cast iron pan, or even in the oven. Here is a classic description of cooking an (effing) steak.

But how to make béarnaise? It’s really very easy, and here we simplify it even more by using a blender and a microwave.

  • 1/3 to ½ cup dry white wine
  • 2 scallions, chopped
  • 2 tsp tarragon
  • 3 egg yolks
  • ¼ lb (1 stick) butter
  • Another 2 tsp tarragon
  • 1 steak (sirloin or ribeye works well)
  1. Put the wine in a small saucepan and add the scallions and tarragon.
  2. Boil the wine down to about 1-2 tablespoons. Do this slowly, so the pan doesn’t suddenly go dry.
  3. Strain the wine reduction into a small dish, pressing the scallions to squeeze out any remaining wine.
  4. Put the 3 egg yolks and the wine reduction in a blender and pulse briefly.
  5. Melt the butter in a microwave for about 1 minute. The butter should be hot and bubbly. If it isn’t, add another 15 seconds or so. You need the butter hot to cook the egg yolks.

  1. Slowly  pour the hot butter into the running blender. Add the remaining tarragon and turn off the  blender. Let it set while you prepare the steak.
  2. Cook the steak to about 120˚ F.  Let it rest for at least 5 minutes. Then cut it into serving strips.
  3. Pour the béarnaise over the steak and  serve it. If by any chance you want the béarnaise thicker, you can heat it briefly over low heat, with constant stirring.

Serve with baked potatoes and a veggie or salad (or both).

Ten products you can skip –as seen on TV

Ten products you can skip –as seen on TV

Cable news, even when its reporting is sound, is rife with advertising of products you never heard of. And for good reason, advertising is relatively cheap on cable news and anyone can flood the news with “wonderful new products” that probably aren’t that great.

Prevagen does not improve your memory, as explained in this Harvard Health blog. . You have probably seen Prevagen ads everywhere. Targeted particularly at seniors who may experience normal word finding difficulties, the claims may mention “studies,” but not “doctors,” because no doctor recommends. It. Allegedly extracted from jellyfish (apoaequorin) actual studies have shown no significant effect, although by rearranging their data (called p-hacking) Quincy Biosciences has claimed it does. The FDA does not agree as explained in this Science Based Medicine article. The Global Council on Brain Health concludes that  “there is no convincing evidence to recommend daily dietary supplements for brain health in healthy older adults.”

The ASPCA does not help your local animal shelter. Despite their tear-jerking ads, the ASPCA is a New York City organization, and is not an umbrella organization for your local SPCA. Give to your local animal shelter instead. Further the ASPCA has been criticized for euthanizing pets rather than saving them.

Zerowater is a water filtering pitcher which takes about six minutes to filter a quart of water. Consumer Reports rated it Very Good and the competing Britta filter Excellent. It takes only about 1:15 to filter a quart of water. However, the Zerowater seems to removes 98% more contaminants. Unless your tap water has an unpleasant taste or smell, these may not  be that valuable.

Mr Clean Magic Eraser.  These products look like a good idea and have positive reviews, although it is not clear how they improve on a damp paper towel and some SoftScrub.  According to reviews at The Spruce, “Because the eraser works by scrubbing at the surface with tiny but extremely hard threads, you should not use on highly glossy or satin finishes….it is not appropriate for paneling or wood finished surfaces. It will strip away the surface and create damage and the sponge does begin to break down after [several] uses.

Tac Shaver by Bell and Howell. The reviews of this shaver are mixed, but according to this review apparently it didn’t last long and the beard trimmer didn’t do much. The Bell and Howell company you may remember from years back essentially got out of the technology business in the 2000’s and is now just a name owned by Westview Capital Partners.

COQ10 with Turmeric – If you are taking statins, a COQ10 supplement won’t do much of anything more. And turmeric is mostly good in curries.

Flex Seal is one of those As Seen on TV pitches you probably are skeptical of. You should be. It works for some things, but has a cumulative review of 1.5 out of 5 stars.

Yoshi Copper Grill MatIt “sort of works” but can’t be placed over an open flame. You could use it on a gas grill with covered burners, though.

Spin Power – is a multi-outlet charging station for your cordless devices. It does not include any spot for phones that can be charged by induction. It has mixed reviews on Amazon as you might expect from anything from ASOTV.

WATCHMAN – is an implant from Boston Scientific for stroke prevention. It is FDA approved and in wide use, But it was criticized in a handful of studies cited by Dr David Becker from Chestnut Hill Temple Cardiology and by Dr John Mandrola of Baptist Medical Associates of Louisville. If you are a candidate for this implant, discuss these objection with your cardiologist. The product has been generally  successful.

Spurtles – I never heard the word outside of the commercials from Lucinda’s Kitchen. They seem to be a set of wooden kitchen utensils made of acacia wood. Lucinda claims these exactly fit pans and jars and are more useful than what you have now. (I seriously doubt that.) You must hand wash them rather than tossing them in the dishwasher. This review calls them low-quality, not durable and having delayed delivery.