chiark / gitweb /
yellow: wip
[quacks.git] / pumpkin-books.ps.pl
1 #!/usr/bin/perl -w
2
3 use strict;
4
5 my $pumpkin = ["255/185/15", "0 0 0"];
6 my $green   = ["0/238/118", "1 1 1"];
7 my $red     = ["1   0  0", "0 0 0"];
8 my $blue    = ["0  .4 1 ", "1 1 1"];
9 my $yellow  = ["1  1   0", "0 0 0"];
10 my $moth    = [" 0  0  0", "1 1 1"];
11 my $purple  = ["145/44/238", "0 0 0"];
12 my $lotus   = [("0/245/255",) x 2];
13 my $white   = ["1  1   1", "0 0 0"];
14
15 my $anychip = ['0.8', '0'];
16
17 our $page_pre = <<END;
18 72 25.4 div dup scale
19 %210 0 translate
20 %90 rotate
21 7 10 translate
22 END
23
24 sub colour ($) {
25   my ($c) = @_;
26   if ($c =~ m{^(\d+)/(\d+)/(\d+)$}) {
27     return (join ' ', map { $_ / 255.0 } ($1,$2,$3)).' setrgbcolor';
28   } elsif ($c =~ m/[^ 0-9.]/) {
29     return $c;
30   } elsif ($c =~ m/^\s*\S+\s*$/) {
31     return "$c setgray";
32   } elsif ($c =~ m/./) {
33     return "$c setrgbcolor";
34   } else {
35     return '';
36   }
37 }
38
39 our $black = colour('0');
40
41 sub chip ($$) {
42   my ($cary, $pips) = @_; # put in a gsave translate
43   my $o = <<END;
44   newpath
45   0 0 chip 0.5 mul 0 360 arc
46   gsave 1 setlinewidth $black stroke grestore
47   ${\ colour($cary->[0]) } fill
48 END
49   if ($pips) {
50     $o .= <<END;
51   ${\ colour($cary->[1]) }
52 END
53   }
54   my $spot = sub {
55     my ($x,$y) = @_;
56     $o .= <<END;
57     newpath
58     spot 0.5 sqrt mul 1.1 mul dup
59     $x mul exch $y mul
60     spot 0.5 mul
61     0 360 arc fill
62 END
63   };
64
65   $spot->( 0, 0) if $pips & 1;
66   $spot->(-1,-1) if $pips & 6;
67   $spot->(+1,+1) if $pips & 6;
68   $spot->(-1,+1) if $pips & 4;
69   $spot->(+1,-1) if $pips & 4;
70
71   $o;
72 }
73
74 sub veepsspot ($) {
75   my ($chip) = @_;
76   <<END;
77 gsave
78   0 chip -0.5 mul translate
79   $black
80   newpath 0 0 chip 0.5 mul 0 360 arc stroke
81   /Times-Bold findfont 7 scalefont setfont
82   -1 -5 translate
83   0 0 moveto (?) show
84   newpath
85    -1 -1 moveto 6 0 rlineto 0 7 rlineto -6 0 rlineto
86     closepath 0.5 setlinewidth stroke
87 grestore
88   $chip
89 END
90 }
91
92 sub anychip ($) {
93   my ($pips) = @_;
94   my $fsz = 10;
95   <<END;
96 gsave
97   chip -0.5 mul  $fsz -0.30 mul  moveto
98   /Helvetica-Bold findfont $fsz scalefont setfont
99   (Any) dup stringwidth  3 2 roll show
100   pop pop
101   20 0 translate
102   ${\ chip($anychip, $pips) }
103 grestore
104 END
105 }
106
107 sub ruby () { # put in gsave translate
108   <<END;
109   newpath
110     rubysz neg  0 moveto
111     0  rubysz neg lineto
112     rubysz      0 lineto
113     0      rubysz lineto
114     closepath
115     ${\ colour('1 .2 .2') } gsave fill grestore
116     $black 1 setlinewidth stroke
117 END
118 }
119
120 sub exposition ($) {
121   my ($text) = @_;
122   my $fontsz = 6;
123   my $o = <<END;
124     /Times-Roman findfont $fontsz scalefont setfont $black
125 END
126   $text =~ s/\n$//;
127   my @lines = split /\n/, $text;
128   foreach my $y (0..$#lines) {
129     my $l = $lines[$y];
130     $l =~ s/[()\\]/\\$&/g;
131     my $yd = $fontsz * (0.5*@lines - $y);
132     $o .= <<END;
133     0 0.70 dc moveto
134     0 $yd rmoveto
135     ($l)  dup stringwidth pop -0.5 mul 0 rmoveto
136     show
137 END
138   }
139   $o;
140 }
141
142
143 sub general_book ($$) { # put in a gsave
144   my ($this, $costs) = @_;
145   my $o = <<END;
146 tw  0  translate
147
148 3 setlinewidth
149 0.9 setgray
150 newpath
151 0 0 dc moveto
152 0 1 dc lineto stroke
153
154 $black
155 1 setlinewidth
156
157 newpath
158 -1 0  dc moveto
159 +1 0  dc lineto
160 +1 1  dc lineto
161 -1 1  dc lineto
162 closepath stroke
163
164 newpath
165 0 0 dc         moveto
166 0 thirdlineh dc rlineto
167 -1 thirdlineh dc lineto stroke
168
169 /thirddivline {               % xprop
170   newpath
171   dup -3 div  0               dc moveto
172       -3 div  thirdlineh      dc lineto stroke
173                               %
174 } def
175
176 END
177
178   $o .= <<END if @$costs == 3;
179 1 thirddivline
180 2 thirddivline
181 END
182
183   foreach my $costi (0..2) {
184     my ($cost, $pips);
185     if (@$costs == 3) {
186       $cost = $costs->[$costi];
187       $pips = qw(1 2 4)[$costi];
188     } else {
189       next unless $costi == 1;
190       $cost = $costs->[0];
191       $pips = $costs->[1];
192     }
193     $o .= <<END
194   costfont setfont
195   -2.5 $costi add 3 div
196 gsave
197   dup costcirch dc translate
198   ${\ chip($this,$pips) }
199 grestore
200   costtexth exch costtextdx add exch dc moveto
201   $black
202   ($cost)
203   dup stringwidth pop  -0.5 mul  costtextsz neg  rmoveto
204   show
205 END
206   }
207
208   $o;
209 }
210   
211 sub green_book () {
212   my $o = general_book($green, [qw(5 9 15)]);
213
214   $o .= <<END;
215 gsave 0.25 0.15 dc translate ${\ chip($pumpkin,0) } grestore
216 gsave 0.25 0.40 dc translate ${\ chip($green,0) } grestore
217
218 /Times-Bold findfont
219 dup
220   6 scalefont setfont
221   0.40 0.17 dc moveto (last) show
222 %
223   8 scalefont setfont
224   0.40 0.09 dc moveto (3) show
225 /Times-Roman findfont
226   38 scalefont setfont
227   0.45 0.14 dc moveto (}) show
228
229 gsave
230   0.85 0.275 dc translate
231   ${\ ruby() }
232 grestore
233 END
234
235   $o .= exposition(<<END);
236 For each pumpkin in the last 3 chips,
237 receive 1 ruby.
238 But, not more rubies than the number
239 of green chips in your pot.
240 END
241
242   $o;
243 }
244   
245 sub red_book () {
246   my $o = general_book($red, [qw(4 9 16)]);
247
248   $o .= <<END;
249 gsave 0.35 0.30 dc translate ${\ chip($pumpkin,0) } grestore
250
251 /Times-Bold findfont
252   15 scalefont setfont
253   0.50 0.24 dc moveto (+1) show
254
255 END
256
257   $o .= exposition(<<END);
258 The next 1/2/4 pumpkins you place are
259 each moved one extra space.
260 (After applying any other special effects;
261 one extra space no matter how many reds)
262 END
263
264   $o;
265 }
266
267 sub blue_book () {
268   my $o = general_book($blue, [qw(4 10 18)]);
269
270   $o .= <<END;
271 /Times-Bold findfont 15 scalefont setfont $black
272
273 gsave
274   0.50 0.65 dc translate
275   0.65 dup scale
276   gsave -10 0 translate ${\ chip($pumpkin,1) } grestore
277   arrow
278 grestore
279 END
280
281   my $exchip = sub {
282     my ($that, $pips) = @_;
283     <<END;
284   gsave ${\ chip($that, $pips) } grestore
285 END
286   };
287   my $exslash = sub {
288     <<END;
289     8 -5 moveto (/) show
290     20 0 translate
291 END
292   };
293   
294   my $exchline = sub {
295     my ($y, $pips, $content) = @_;
296     <<END;
297 gsave 
298   0.16 0.15 0.16 $y mul add dc translate
299   0.60 dup scale
300   gsave ${\ chip($blue,$pips) } grestore
301   8 -3 moveto (:) show
302   3 0 translate
303   0.8 dup scale
304   21 0 translate
305 $content
306 grestore
307 END
308   };
309
310   $o .= $exchline->(2, 1, <<END);
311   ${\ $exchip->($green,1) }  ${\ $exslash->() }
312   ${\ $exchip->($red,  1) }  ${\ $exslash->() }
313   ${\ $exchip->($blue, 1) }  ${\ $exslash->() }
314   ${\ $exchip->($yellow, 1) }
315 END
316
317   $o .= $exchline->(1, 2, <<END);
318   ${\ $exchip->($moth,1) }  ${\ $exslash->() }
319   ${\ $exchip->($purple,1) }  ${\ $exslash->() }
320   ${\ anychip(2) }
321 END
322
323   $o .= $exchline->(0, 4, <<END);
324   ${\ anychip(4) }
325 END
326
327   $o .= exposition(<<END);
328 If the previous chip placed was a pumpkin,
329 you may exchange it as follows:
330
331  
332 END
333
334   $o;
335 }
336
337 sub lotus_book () {
338   my $o = general_book($lotus, [8, 0]);
339
340   $o .= <<END;
341 /Times-Bold findfont 15 scalefont setfont $black
342
343 gsave
344   0.36 0.38 dc translate
345   0.80 dup scale
346   gsave ${\ chip($lotus,0) } grestore
347
348   9 -4 moveto (=) show
349 grestore
350 gsave
351   0.20 0.15 dc translate
352   0.80 dup scale
353   gsave ${\ chip($pumpkin,0) } grestore
354   chip 0.5 mul 0 translate
355   gsave ${\ chip($pumpkin,0) } grestore
356
357   10 -4.5 moveto (... +1) show
358
359 grestore
360 END
361 <<END;
362 gsave
363   0.16 0.20  dc translate
364   0.60 dup scale
365
366   gsave ${\ veepsspot(chip($pumpkin, 0)) } grestore
367   gsave 0 20 translate ${\ chip($purple, 1) } grestore
368   27 0 translate
369 grestore
370 END
371
372
373   $o .= exposition(<<END);
374 The value of this chip is
375 1 higher than the number of pumpkins
376 previously placed in the pot (but max.4)
377 END
378
379   $o;
380 }
381
382 sub purple_book () {
383   my $o = general_book($purple, [10, 1]);
384
385   my $input = <<END;
386   gsave ${\ veepsspot(chip($pumpkin, 0)) } grestore
387   gsave 0 20 translate ${\ chip($purple, 1) } grestore
388 END
389
390   $o .= <<END;
391 /Times-Bold findfont 15 scalefont setfont $black
392 gsave
393   0.16 0.20  dc translate
394   0.60 dup scale
395
396 $input
397   8 -12 moveto (...) show
398   27 0 translate
399 $input
400 grestore
401
402 gsave
403 /Times-Roman findfont
404   32 scalefont setfont
405   0.48 0.14 dc moveto (}) show
406 grestore
407
408 gsave
409    0.83 0.25 dc translate
410    0.85 dup scale
411    ${\ chip($anychip, 0) }
412 grestore
413
414 gsave
415   0.72 0.22 dc translate
416   0.50 dup scale
417    $black 0 0 moveto (?+?) show
418 grestore
419 END
420
421   $o .= exposition(<<END);
422 For each pumpkin in the pot (but
423  not more than the number of purple chips),
424 add up the VPs of the covered spaces.
425 Buy 1/2 chips of up to that total value.
426 END
427
428   $o;
429 }
430
431 sub tile {
432   my $index = scalar @_;
433   my $pos = 0;
434   my $o = '';
435   my $showpage = sub {
436     $o .= <<END;
437 showpage
438 $page_pre
439 END
440   };
441   while (my $d = pop @_) {
442     if ($pos >= 5) {
443       $pos -= 5;
444       $showpage->();
445     }
446     $o .= <<END;
447 gsave
448 END
449     if ($pos < 3) {
450       $o .= <<END
451         0   th 10 add  $pos mul  translate
452 END
453     } else {
454       $o .= <<END
455 tw 2 mul 7 add
456    dup    th add  0 translate
457    90 rotate
458    $pos 3 sub mul  0 translate
459 END
460     }
461     $o .= "\n".$d."\n";
462     $o .= <<END;
463
464     /Courier-Bold findfont 6 scalefont setfont
465     -0.98 0.94 dc moveto
466     ($index) show
467
468 grestore
469 END
470     $pos++;
471     $index--;
472   }
473   $showpage->();
474   $o;
475 }
476
477 sub yellow_book () {
478   my $o = general_book($yellow, [qw(7 12 19)]);
479
480   $o .= <<END;
481 gsave
482   0.50 0.62 dc translate
483   0.65 dup scale
484   -26 0 translate
485   gsave 26 0 translate ${\ chip($anychip,0) } grestore
486   gsave 46 0 translate ${\ chip($pumpkin,0) } grestore
487 grestore
488 END
489
490   my $exchip = sub {
491     my ($that, $pips) = @_;
492     <<END;
493   gsave ${\ chip($that, $pips) } grestore
494 END
495   };
496   my $exslash = sub {
497     <<END;
498     8 -5 moveto (/) show
499     20 0 translate
500 END
501   };
502   
503   my $exchline = sub {
504     my ($y, $pips, $content) = @_;
505     <<END;
506 gsave 
507   0.20 0.12 0.16 $y mul add dc translate
508   0.60 dup scale
509   gsave ${\ chip($yellow,$pips) } grestore
510   8 -3 moveto (:) show
511   3 0 translate
512   0.8 dup scale
513   24 0 translate
514 $content
515 grestore
516 END
517   };
518
519   $o .= $exchline->(2, 1, <<END);
520   ${\ $exchip->($white,1) }  ${\ $exslash->() }
521   ${\ $exchip->($anychip,1) }  ${\ $exslash->() }
522   ${\ $exchip->($lotus,0) }
523 END
524
525   $o .= $exchline->(1, 2, <<END);
526   ${\ $exchip->($white,2) }  ${\ $exslash->() }
527   ${\ $exchip->($anychip,2) }
528 END
529
530   $o .= $exchline->(0, 4, <<END);
531   ${\ $exchip->($white,3) }  ${\ $exslash->() }
532   ${\ $exchip->($anychip,4) }
533 END
534
535   $o .= exposition(<<END);
536 Put a chip, no bigger than the yellow,
537 where the next placed chip is a pumpkin,
538 back in your bag.
539
540  
541 END
542
543   $o;
544 }
545   
546 print <<END or die $!;
547 %!
548
549 $page_pre
550
551 /tw 57.5 def
552 /th 73 def
553 /bdiag 5 def
554 /thirdlineh 0.45 def
555 /costcirch 0.3 def
556 /chip 15 def
557 /spot 3.5 def
558 /arrowlen 6 def
559 /arrowhead 3 def
560
561 /costtexth 0.215 def
562 /costtextsz 12 def
563 /costtextdx -0.03 def
564 /costfont /Heletica-BoldOblique findfont costtextsz scalefont def
565
566 /rubysz 4 def
567
568 % diagonal conversion
569 /dc {                    % xprop yprop
570     dup th mul           % xprop yprop y
571     3 1 roll             % y xprop yprop
572     bdiag mul neg        % y xprop x-margin-at-this-height
573     tw add               % y xprop x-width-at-this-height
574     exch mul             % y x-width-at-this-height xprop
575     exch                 % x y
576 } def
577
578 /arrow {
579   $black 1 setlinewidth
580     newpath
581        0 0 moveto  arrowlen 0 rlineto
582        arrowhead dup neg exch  rmoveto
583        arrowhead dup neg       rlineto
584        arrowhead neg dup       rlineto
585        stroke
586 } def
587
588 END
589
590 print "gsave\n" or die $!;
591
592 print tile(
593            red_book(),
594            green_book(),
595            purple_book(),
596            blue_book(),
597            lotus_book(),
598            yellow_book(),
599           ) or die $! if 1;