reid@decwrl.dec.com (Brian Reid) (01/29/88)
I've been doing a lot of PostScript hacking for years. Just to show you the outer limits of the genre, here is an exam scoring program written in PostScript. This is real data from a midterm exam I gave at Stanford a couple of years ago, but I have replaced all of the names with strings chosen at random from /usr/dict/words, to protect the privacy of the individuals. There's no documentation because I wrote it for my own use, but hard-core PS hackers should be able to cope. This prints at the rate of about a minute a page on a LaserWriter, and maybe 10 seconds per page on an LPS40. If you want to try printing just a few pages, edit the "for" loop that is 0 1 n into something like 0 1 10 or 10 1 20. %! /maxn 100 def /nq 7 def /maxscore 110 def /qmaxscore [25 28 12 20 5 10 10] def /Whatcourse (CS108B: Fundamentals of Computer Science) def /Whatexam (Midterm Examination Results WQ 86) def /Whatprof (Professor Brian K. Reid) def % -------------------------------------- /scores maxn array def /names maxn dict def /rawscores maxn dict def /n 0 def /gtotal 0 def /qscores [ 0 nq {dup} repeat pop ] def /xx {/svec exch def /name exch def names n name put rawscores n svec put /total 0 def /i 0 def svec length nq ne {name print ( bad score vector\n) print} if svec { dup /total exch total add def qscores i get add qscores exch i exch put /i i 1 add def } forall scores n total put /gtotal gtotal total add def /n n 1 add def } def (Abelian, Babcock) [25 21 9 0 2 0 0] xx (Albanian, MacDonald) [25 28 12 0 0 2 0] xx (Alsatian, Machiavelli) [0 28 12 0 0 3 5] xx (Annapolis, Jacobean) [25 28 12 11 5 0 0] xx (Aristotelean, Hadamard) [25 28 12 4 5 10 0] xx (Atropos, Daedalus) [25 26 12 6 1 7 3] xx (Ballard, Lagrange) [23 21 9 0 0 7 0] xx (Bavaria, Laidlaw) [22 28 9 0 5 0 5] xx (Bennett, Haitian) [25 9 12 20 5 0 10] xx (Bessemer, Malagasy) [25 26 12 4 0 7 0] xx (Bohemia, Maldive) [25 26 9 4 5 3 5] xx (Brandenburg, Salesian) [25 28 12 6 4 10 10] xx (Brookline, Salisbury) [25 28 12 4 5 0 9] xx (Burundi, Galloway) [25 28 12 16 5 7 10] xx (Canaveral, Maltese) [23 28 9 4 5 5 0] xx (Carroll, Calvinist) [25 9 12 18 0 8 6] xx (Chambers, Cameroun) [25 28 12 14 2 10 5] xx (Chinamen, Hampton) [25 28 9 4 5 7 8] xx (Claremont, Manchester) [25 28 0 0 0 0 1] xx (Columbus, Sanderson) [20 28 12 20 5 10 4] xx (Cornelia, Bangladesh) [15 21 12 18 2 0 0] xx (Cushman, Hanover) [25 21 9 4 0 0 1] xx (Decatur, January) [23 27 12 17 5 7 10] xx (Domesday, Capetown) [0 21 0 11 2 0 0] xx (Dusenbury, Caracas) [23 28 9 0 0 0 0] xx (Ellison, Barbara) [25 26 9 18 5 7 1] xx (Ernestine, Harding) [16 16 6 0 0 3 3] xx (Falstaff, Marilyn) [20 19 6 11 5 7 0] xx (Flagstaff, Darlene) [25 28 12 9 0 0 0] xx (Fredericks, Yarmouth) [20 28 12 4 0 0 0] xx (Gannett, Carolyn) [15 19 6 0 5 3 2] xx (Gifford, Harriman) [25 14 6 3 5 0 0] xx (Goodrich, Marseilles) [25 21 12 20 2 7 3] xx (Guggenheim, Martian) [25 13 9 13 0 0 0] xx (Harcourt, Pasadena) [25 28 9 4 2 9 5] xx (Henderson, Masonite) [25 21 9 4 5 0 0] xx (Hildebrand, Hastings) [23 28 6 4 2 10 10] xx (Hopkinsian, Lateran) [15 7 0 0 5 0 5] xx (Indianapolis, Hathaway) [25 14 0 16 5 6 0] xx (Jacobian, Lathrop) [25 28 9 16 5 0 10] xx (Johansen, Patrick) [25 26 12 8 2 7 2] xx (Katowice, Caucasian) [19 26 9 0 4 5 8] xx (Knightsbridge, Bauhaus) [22 21 12 14 5 10 0] xx (Langley, Maurice) [25 23 6 0 5 0 8] xx (Leonardo, Havilland) [23 28 12 20 5 5 4] xx (Lockhart, Hawthorne) [15 28 12 0 5 9 2] xx (Macassar, Raymond) [21 26 12 0 0 0 0] xx (Malraux, Abelson) [25 28 9 18 5 10 4] xx (Martinique, McCarthy) [25 28 9 18 5 0 1] xx (McCarty, McDaniel) [0 28 9 15 0 3 5] xx (McKinley, McGowan) [22 28 12 4 0 0 0] xx (Merrimack, McLaughlin) [25 28 12 20 5 10 10] xx (Minneapolis, Oceania) [24 28 12 5 1 0 2] xx (Missouri, Melissa) [25 26 9 20 2 3 10] xx (Monongahela, Delmarva) [21 14 12 0 5 2 4] xx (Simonson, Schmidt) [20 17 10 11 5 9 4] xx (Spencer, Schumacher) [22 28 9 17 2 7 5] xx (Stockholm, Scotsman) [24 28 9 0 0 4 5] xx (Swenson, Scythia) [25 28 9 13 5 7 0] xx (Theresa, Edmonton) [24 28 12 7 5 7 5] xx (Triplett, Zealand) [25 28 9 11 2 10 5] xx (Venezuela, Beaujolais) [25 27 9 4 2 0 4] xx (Wallace, Nebraska) [25 21 6 4 5 0 9] xx (Whatley, Bedford) [0 28 6 14 5 3 0] xx (Wiedmann, Selectric) [25 21 9 14 5 10 5] xx (Windsor, Jeffrey) [25 28 9 12 5 10 10] xx (Yonkers, Segundo) [25 28 12 3 2 0 0] xx (Zoroaster, Tektronix) [25 28 9 10 4 10 5] xx /n names length def /scores scores 0 n getinterval def % scores setcounts /setcounts { /stcvec exch def /counts localmax 1 add array def 0 1 localmax {counts exch 0 put} for stcvec {0.5 add dup localmax gt {pop localmax} if cvi dup counts exch get 1 add counts 3 1 roll put} forall /sigma /total 0 def stcvec {mean sub dup mul total add /total exch def} forall total n div sqrt def } def % score counts pctile /pctile { /pcvec exch def /psc exch 0.5 sub cvi def /cum 0 def 0 1 psc {pcvec exch get cum add /cum exch def} for cum 100 mul n div 0.5 add cvi } def % counts hx hy score mean histo /histo { /label exch def /xbar exch def /flag exch def /hy exch def /hx exch def /cvec exch def /dx hx localmax 1 add div def /dy dx 4 gt {4}{dx} ifelse def gsave currentpoint translate 0 1 localmax {/i exch def i dx mul dx 2 div add 0 moveto i 10 mod 0 eq {0 dy -2 mul rlineto 0.5 setlinewidth stroke} {i 5 mod 0 eq {0 dy -1.3 mul rlineto 0.4 setlinewidth stroke} {0 dy neg rlineto 0.2 setlinewidth stroke} ifelse} ifelse } for /di 10 def dx 2 gt {/di 5 def} if dx 5 gt {/di 2 def} if dx 10 gt {/di 1 def} if /fsize dx di mul dup cvi 10 gt {pop 10} if def /Courier findfont fsize scalefont setfont 0 0 moveto gsave 90 rotate -8 dx neg 1 sub translate 0 di localmax { dup 0 exch 0.5 sub dx neg mul moveto zs cvs dup stringwidth pop neg fsize -4 div rmoveto show } for grestore /maxcount 1 def cvec {dup maxcount gt {/maxcount exch def}{pop} ifelse} forall /cdy hy maxcount div def /dmax maxcount 10 gt {10}{1} ifelse def 0 dmax maxcount {dup cdy mul hx exch moveto gsave dy 0 rlineto 1 setlinewidth stroke grestore zs cvs dy 2 add dy -1.7 div rmoveto show } for 0 1 localmax {/i exch def /j cvec i get cdy mul def dx i mul 0 moveto 0 j rlineto dx 0 rlineto 0 j neg rlineto closepath gsave 0.8 setgray fill grestore 0 setlinewidth stroke } for 0 hy moveto 0 0 lineto hx 0 lineto hx hy lineto closepath 1 setlinewidth stroke 7 hy 10 sub moveto label 7 hy 20 sub moveto (Mean: ) show mean zs cvs show flag 0.5 add dx mul hy moveto /Symbol findfont 12 scalefont setfont (\337) dup stringwidth pop -2 div 0 rmoveto show newpath xbar 0.5 add dx mul 0 moveto 0 hy rlineto 0 setlinewidth stroke grestore } def /zs 20 string def /localscores scores length array def 0 1 n { /id exch def /name names id get def /svec rawscores id get def /score scores id get def /localmax maxscore def /mean gtotal n div 100 mul cvi 100 div def scores setcounts /Helvetica-Bold findfont 11 scalefont setfont 60 756 moveto Whatcourse show /xmarg currentpoint pop 20 add def /Helvetica findfont 11 scalefont setfont 60 740 moveto Whatexam show 60 729 moveto Whatprof show /Courier findfont 18 scalefont setfont xmarg 756 moveto name show /Courier findfont 10 scalefont setfont xmarg 740 moveto (Raw score: ) show score zs cvs show ( T score: ) show score mean sub sigma div 100 mul cvi 100 div zs cvs show xmarg 730 moveto (Percentile: ) show score counts pctile zs cvs show 72 580 moveto counts 6.5 72 mul 120 score mean {(Overall exam) show} histo 0 1 nq 1 sub {/j exch def /jrow j 2 div 1 add cvi def /localmax qmaxscore j get def 0 1 n 1 sub {/i exch def localscores i rawscores i get j get put } for /mean qscores j get n div 100 mul cvi 100 div def localscores setcounts /score svec j get def /dpx 3.5 72 mul def /dpy 510 nq 2 div 1 add cvi div def 72 j 2 mod cvi dpx mul add 530 jrow dpy 1 sub mul sub 30 add moveto counts 3 72 mul dpy 40 sub score mean /jquesno j 1 add def {(Question ) show jquesno zs cvs show} histo } for showpage } for