>emeli@magnus.acs.ohio-state.edu (Eric J Meli) writes:
>>The Cast (in order of appearance [roughly]):
>> KING ARTHUR : Graham Chapman
>> PATSY : Terry Gilliam
>> GUARD #1 : Michael Palin
>Ok, the assignment for today:
>Given that the script was typed in a format that is fairly easy to
>parse, write a python program that reads it, loads pictures of the
>specified actors and plays the script (by putting text-balloons next
>to them). Do this in less than 50 lines of python (not counting
>comments). If you add a speech-synthesizer to also pronounce the
>script you are allowed another 20 lines.
Well, I tried it myself (without pictures, though, but they shouldn't
be too much trouble to add) and I was rather disappointed that I
didn't succeed. I took me 153 lines. Still, appended below is the
result, for your amusement. There's one little problem: somewhere in
scene 10 the format loosens up a bit, causing some lines to appear in
strange places.
I wonder: should I post it to alt.fan.monty-python as well?
----------------------------------------
# Pass this program the Holy Grail script on stdin. (c) Jack Jansen, CWI, 1994
import sys
import string
import stdwin
from stdwinevents import *
WINWIDTH = 1000
[NOTHING, NEWSCENE, ACT, TEXT, MORETEXT] = range(5)
def parseline(line):
stripline = string.strip(line)
if not stripline:
return NOTHING, ''
if stripline[:5] == 'Scene':
return NEWSCENE, stripline
if line[0] == '[':
return ACT, stripline
if line[0] == ' ' and ':' in line:
splitline = string.splitfields(stripline, ':')
stripline = string.joinfields(splitline[1:], ':')
return TEXT, (splitline[0], string.strip(stripline))
return MORETEXT, stripline
def readscript(file):
lines = file.readlines()
acts = []
actor_dict = {}
longest = 0
prev_act = 0
for i in range(len(lines)):
tp, data = parseline(lines[i])
if tp == NEWSCENE:
acts.append(actor_dict.keys(), lines[prev_act:i])
prev_act = i
actor_dict = {}
elif tp == TEXT:
actor_dict[data[0]] = 1
lines[i] = tp, data
return acts[1:]
class Main:
def __init__(self):
self.acts = readscript(sys.stdin)
maxactor = 0
for actorlist, actdata in self.acts:
if len(actorlist) > maxactor:
maxactor = len(actorlist)
if not self.loadnextact():
print 'No acts to play!'
sys.exit(1)
self.lh = stdwin.lineheight()
self.winheight = (maxactor+2)*self.lh
stdwin.setdefwinsize(WINWIDTH, self.winheight)
self.win = stdwin.open('The Play')
self.win.setdocsize(WINWIDTH, self.winheight)
self.win.change(((0,0),(WINWIDTH, self.winheight)))
self.menu = self.win.menucreate('Play')
self.menu.additem('Faster', '>')
self.menu.additem('Slower', '<')
self.menu.additem('Quit', 'Q')
self.speed = 4
def loadnextact(self):
if not self.acts: return 0
actors, lines = self.acts[0]
del self.acts[0]
prevactor = 0
for i in range(len(lines)):
tp, data = lines[i]
if tp == NOTHING:
continue
elif tp in (NEWSCENE, ACT):
lines[i] = 0, data
elif tp == TEXT:
prevactor = actors.index(data[0])
lines[i] = prevactor+1, data[1]
else:
lines[i] = prevactor+1, data
self.lines = lines
self.actors = [''] + actors
self.actorlines = [''] * len(self.actors)
self.prevline = 0
self.actwidth = 0
for a in self.actors:
w = stdwin.textwidth(a)
if w > self.actwidth:
self.actwidth = w
return 1
def loadnextline(self):
if not self.lines: return 0
self.actorlines[self.prevline] = ''
top = self.lh*self.prevline
self.win.change(((0, top), (WINWIDTH, top+self.lh)))
line, data = self.lines[0]
del self.lines[0]
self.actorlines[line] = data
self.prevline = line
top = self.lh*self.prevline
self.win.change(((0, top), (WINWIDTH, top+self.lh)))
if line == 0:
self.win.settimer(5*self.speed)
else:
nwords = len(string.split(data))
self.win.settimer(self.speed*(nwords+1))
return 1
def timerevent(self):
while 1:
if self.loadnextline(): return
if not self.loadnextact():
stdwin.message('The END')
self.win.close()
sys.exit(0)
self.win.change(((0,0), (WINWIDTH, self.winheight)))
def redraw(self, top, bottom, draw):
for i in range(len(self.actors)):
tpos = i*self.lh
bpos = (i+1)*self.lh-1
if tpos < bottom and bpos > top:
draw.setfgcolor(4)
draw.text((0, tpos), self.actors[i])
if i == 0:
draw.setfgcolor(1)
else:
draw.setfgcolor(0)
draw.text((self.actwidth+5, tpos), self.actorlines[i])
def run(self):
self.win.settimer(10)
while 1:
ev, win, arg = stdwin.getevent()
if ev == WE_DRAW:
((left, top), (right, bot)) = arg
self.redraw(top, bot, self.win.begindrawing())
elif ev == WE_TIMER:
self.timerevent()
elif ev == WE_CLOSE:
self.win.close()
sys.exit(0)
elif ev == WE_MENU and arg[0] == self.menu:
if arg[1] == 0:
if self.speed > 1:
self.speed = self.speed/2
elif arg[1] == 1:
self.speed = self.speed * 2
elif arg[1] == 2:
self.win.close()
sys.exit(0)
main = Main()
main.run()
-----------------------------------------
---- Jack Jansen | If I can't dance I don't want to be part of Jack.Jansen@cwi.nl | your revolution -- Emma Goldman uunet!cwi.nl!jack G=Jack;S=Jansen;O=cwi;PRMD=surf;ADMD=400net;C=nl