M

#### Medi Ochre

I've been away from Python for some time, and I'm just starting to look
at Tkinter. Just so you know, I'm coming from Visual Basic, where this
would, I *think*, not have been a problem, so it must be a case of
getting my head around the Tkinter way of doing things.

In a nutshell, I've written an app wherein I wish to update the display
often. What's happening is that I get *no* display until main() hits
win.mainloop(). I've indicated the things I've tried (round about line
180). At the risk of exposing myself, here's the whole thing.

If you have a thought, I'd sure appreciate it!

Nick.

from random import *
from Tkinter import *

'''
Score the "good jack"
'''
def jack(h, f):
hand = h[:]
hand.remove(f)
for card in hand:
if card.rank == 10 and card.suit == f.suit:
return 1
return 0

'''
Count and return 2 for each combination that adds up to 15
'''
def fifteen(h):
if h[0].value() + h[1].value() + h[2].value() + h[3].value() +
h[4].value() == 15:
return 2
# 4-card combos
score = 0
for a in range(0,2):
for b in range(a+1,3):
for c in range(b+1,4):
for d in range(c+1,5):
if h[a].value() + h.value() + h[c].value() +
h[d].value() == 15:
score += 2

# 3-card combos
for a in range(0,3):
for b in range(a+1,4):
for c in range(b+1,5):
if h[a].value() + h.value() + h[c].value() == 15:
score += 2

# 2-card combos
for a in range(0,4):
for b in range(a+1,5):
if h[a].value() + h.value() == 15:
score += 2
return score

'''
Simplified flush rules:
Try the 4 flush and 5 flush, give the best score.
'''
def flushes(h, f):
# 5-flush
suit = h[0].suit
total = 0
for card in h:
if card.suit == suit:
total += 1
#end if
#end for
if total == 5: return 5

# 4-flush
hand = h[:]
hand.remove(f)
suit = hand[0].suit
total = 0
for card in hand:
if card.suit == suit:
total += 1
if total == 4:
return 4
return 0

'''
1 Point per card per run
'''
def runs(h):
# Is there a 5-run?
if h[0].rank == h[1].rank-1 and h[1].rank == h[2].rank-1 and \
h[2].rank == h[3].rank-1 and h[3].rank == h[4].rank-1 :
return 5
# Look for 4-runs:
score = 0
for a in range(0,2):
for b in range(a+1,3):
for c in range(b+1,4):
for d in range(c+1,5):
if h[a].rank == h.rank-1 and h.rank ==
h[c].rank-1 \
and h[c].rank == h[d].rank-1:
score += 4
if score != 0:
return score

#Look for 3-runs
for a in range(0,3):
for b in range(a+1,4):
for c in range(b+1,5):
if h[a].rank == h.rank-1 and h.rank == h[c].rank-1:
score += 3
return score

'''
Two points per pair
'''
def pairs(h):

'''
Tally me hand
'''
score = 0
for left in range(0,4):
for right in range(left+1, 5):
if h
.rank == h
.rank:
score += 2
return score

def tally(h, f):

return pairs(h) + runs(h) + flushes(h, f) + fifteen(h) + jack(h, f)

class Card:
def __init__(self, r, s):
self.rank = r
self.suit = s

def value(self):
return min([self.rank+1, 10])

def __repr__(self):
s = "HSCD"[self.suit]
r = "A23456789TJQK"[self.rank]
return r+s

__str__ = __repr__

class Deck:
def __init__(self):
self.deck = []
for r in range(13):
for s in range(4):
self.deck.append(Card(r,s))
shuffle(self.deck)
#self.card = 0

def deal(self):
#self.card += 1
if len(self.deck) == 2:
self.deck = []
for r in range(13):
for s in range(4):
self.deck.append(Card(r,s))
shuffle(self.deck)
return self.deck.pop()

class Cribbage:
def __init__(self, win):

#Draw the interface
self.f = Frame(win)
self.f.grid()
self.cardpix = [Label(self.f), Label(self.f), Label(self.f),
Label(self.f), Label(self.f)]
clr = ["red", "blue"]
n = 1
for c in self.cardpix:
c.configure(width=10, height=10, bg=clr[n%2], text="card
"+str(n))
c.grid(row=0, column=n-1)
n += 1
self.scorebox = Label(self.f)
self.scorebox.configure(height=5, bg="green", text="Score: 0")
self.scorebox.grid(row=1, column=0, columnspan=5)

def play(self, win):
d = Deck()
hand = [d.deal(), d.deal(), d.deal(), d.deal()]
flipped = d.deal()
hand.append(flipped)
hand.sort()
score = tally(hand, flipped)
self.scorebox.configure(text= "Score: " + str(score))
#Eventually, display the actual card images, but for now...
for c, x in zip(hand, self.cardpix):
x.configure(text = str(c))
#I've tried both of these, to no avail.
win.iconify()
return score

def main():
win = Tk()
run = Cribbage(win)
score = 0
best = 0
while score < 24:
score = run.play(win)
if score >= best: best = score
win.mainloop()

main()​

J

#### John McMonagle

I've made a couple of minor changes to your code from the Cribbage class
down:

class Cribbage:
def __init__(self, win):

self.parent = win # <---- make the toplevel Tk window an
# <---- attribute of the class
#Draw the interface
self.f = Frame(self.parent)
self.f.grid()
self.cardpix = [Label(self.f), Label(self.f), Label(self.f),
Label(self.f), Label(self.f)]
clr = ["red", "blue"]
n = 1
for c in self.cardpix:
c.configure(width=10, height=10, bg=clr[n%2], text="card
"+str(n))
c.grid(row=0, column=n-1)
n += 1
self.scorebox = Label(self.f)
self.scorebox.configure(height=5, bg="green", text="Score: 0")
self.scorebox.grid(row=1, column=0, columnspan=5)

def play(self):
d = Deck()
hand = [d.deal(), d.deal(), d.deal(), d.deal()]
flipped = d.deal()
hand.append(flipped)
hand.sort()
score = tally(hand, flipped)
self.scorebox.configure(text= "Score: " + str(score))
#Eventually, display the actual card images, but for now...
for c, x in zip(hand, self.cardpix):
x.configure(text = str(c))
#I've tried both of these, to no avail.
self.parent.update() <---- update the toplevel window
return score

def main():
win = Tk()
run = Cribbage(win)
score = 0
best = 0
while score < 24:
score = run.play()
if score >= best: best = score
time.sleep(1) <--- short sleep to see what's happening
win.mainloop()

main()

Regards,

John

M

#### Medi Ochre

John said:
I've made a couple of minor changes to your code from the Cribbage class
down:

class Cribbage:
def __init__(self, win):
....
score = run.play()
if score >= best: best = score
time.sleep(1) <--- short sleep to see what's happening
win.mainloop()

main()

Regards,

John
Thank you, Mr. McMonagle!

D

#### Dennis Lee Bieber

def main():
win = Tk()
run = Cribbage(win)
score = 0
best = 0
while score < 24:
score = run.play(win)
if score >= best: best = score
win.mainloop()
mainloop() is the code that dispatches GUI events to event handlers.
Essentially, you need to move that while loop inside of the event
processing...

(Watch out for line wraps) Something like:

from random import *
from Tkinter import *

"""
Score the "good jack"
"""
def jack(h, f):
hand = h[:]
hand.remove(f)
for card in hand:
if card.rank == 10 and card.suit == f.suit:
return 1
return 0

"""
Count and return 2 for each combination that adds up to 15
"""
def fifteen(h):
if h[0].value() + h[1].value() + h[2].value() + h[3].value() +
h[4].value() == 15:
return 2
# 4-card combos
score = 0
for a in range(0,2):
for b in range(a+1,3):
for c in range(b+1,4):
for d in range(c+1,5):
if h[a].value() + h.value() + h[c].value() +
h[d].value() == 15:
score += 2

# 3-card combos
for a in range(0,3):
for b in range(a+1,4):
for c in range(b+1,5):
if h[a].value() + h.value() + h[c].value() == 15:
score += 2

# 2-card combos
for a in range(0,4):
for b in range(a+1,5):
if h[a].value() + h.value() == 15:
score += 2
return score

"""
Simplified flush rules:
Try the 4 flush and 5 flush, give the best score.
"""
def flushes(h, f):
# 5-flush
suit = h[0].suit
total = 0
for card in h:
if card.suit == suit:
total += 1
#end if
#end for
if total == 5: return 5

# 4-flush
hand = h[:]
hand.remove(f)
suit = hand[0].suit
total = 0
for card in hand:
if card.suit == suit:
total += 1
if total == 4:
return 4
return 0

"""
1 Point per card per run
"""
def runs(h):
# Is there a 5-run?
if (h[0].rank == h[1].rank-1
and h[1].rank == h[2].rank-1
and h[2].rank == h[3].rank-1
and h[3].rank == h[4].rank-1) :
return 5
# Look for 4-runs:
score = 0
for a in range(0,2):
for b in range(a+1,3):
for c in range(b+1,4):
for d in range(c+1,5):
if (h[a].rank == h.rank-1
and h.rank == h[c].rank-1
and h[c].rank == h[d].rank-1):
score += 4
if score != 0:
return score

#Look for 3-runs
for a in range(0,3):
for b in range(a+1,4):
for c in range(b+1,5):
if h[a].rank == h.rank-1 and h.rank ==
h[c].rank-1:
score += 3
return score

"""
Two points per pair
"""
def pairs(h):
score = 0
for left in range(0,4):
for right in range(left+1, 5):
if h
.rank == h
.rank:
score += 2
return score

"""
Tally me hand
"""
def tally(h, f):
return pairs(h) + runs(h) + flushes(h, f) + fifteen(h) + jack(h, f)

class Card(object):
def __init__(self, r, s):
self.rank = r
self.suit = s

def value(self):
return min([self.rank+1, 10])

def __repr__(self):
return "%s%s" % ("HSCD"[self.suit],
"A23456789TJQK"[self.rank])

__str__ = __repr__

class Deck(object):
def __init__(self):
self.deck = []
for r in range(13):
for s in range(4):
self.deck.append(Card(r,s))
shuffle(self.deck)
#self.card = 0

def deal(self):
#self.card += 1
if len(self.deck) == 2:
self.deck = []
for r in range(13):
for s in range(4):
self.deck.append(Card(r,s))
shuffle(self.deck)
return self.deck.pop()

class Cribbage(object):
def __init__(self):

self.top = Tk()
self.score = 0
self.best = self.score

#DEFINE the interface (it will be drawn by mainloop()
self.f = Frame(self.top)
self.f.grid()
self.cardpix = [ Label(self.f),
Label(self.f),
Label(self.f),
Label(self.f),
Label(self.f)]
clr = ["red", "blue"]
n = 1
for c in self.cardpix:
c.configure(width=10,
height=10,
bg=clr[n%2],
text="card %s" % n)
c.grid(row=0, column=n-1)
n += 1
self.scorebox = Label(self.f)
self.scorebox.configure(height=5, bg="green", text="Score: 0")
self.scorebox.grid(row=1, column=0, columnspan=5)

def mainloop(self):
self.f.after(1000, self.play, (None))
self.top.mainloop()

def play(self, *args):
# do you really want to create a new Deck each time play() is
invoked?
d = Deck()
hand = [d.deal(), d.deal(), d.deal(), d.deal()]
flipped = d.deal()
hand.append(flipped)
hand.sort()
self.score = tally(hand, flipped) #if you've appended "flipped",
why include it again
self.scorebox.configure(text= "Score: %3s" % self.score)
#Eventually, display the actual card images, but for now...
for c, x in zip(hand, self.cardpix):
x.configure(text = str(c))
if self.score > self.best:
self.best = self.score
if self.score >= 24:
self.f.after(10000) #wait ten seconds
self.top.quit()
else:
self.f.after(1000, self.play, (None))

def main():
game = Cribbage()
game.mainloop()

main()

--
Wulfraed Dennis Lee Bieber KD6MOG