Scribbled games docs

svn: r9246
This commit is contained in:
Matthew Flatt 2008-04-11 00:16:05 +00:00
parent 890cd46fa1
commit 18f4087673
54 changed files with 836 additions and 1080 deletions

View File

@ -8,7 +8,7 @@ possible to remap single click (instead of double click)?
#lang mzscheme
(require games/cards mred mzlib/class mzlib/list mzlib/unit string-constants
"../show-help.ss")
"../show-scribbling.ss")
(provide game@)
(define game@ (unit (import) (export)
@ -16,7 +16,8 @@ possible to remap single click (instead of double click)?
(define table (make-table "Aces" 6 5))
(make-object button% (string-constant help-menu-label) table
(let ([show-help (show-help (list "games" "aces") "Aces Help")])
(let ([show-help (show-scribbling '(lib "games/scribblings/games.scrbl")
"aces")])
(lambda x (show-help))))
(define draw-pile null)

View File

@ -53,7 +53,8 @@
;; Set up the table
(define t (make-table "Blackjack" 6 3))
(define status-pane (send t create-status-pane))
(send t add-help-button status-pane '("games" "blackjack") "Blackjack Help" #f)
(send t add-scribble-button status-pane
'(lib "games/scribblings/games.scrbl") "blackjack")
(send t show #t)
(send t set-double-click-action #f)
(send t set-button-action 'left 'drag/one)

View File

@ -1,26 +0,0 @@
** To play Blackjack, run the "PLT Games" application.
Standard Blackjack rules, plus the following specifics:
* 1 player (not counting the dealer)
* 4 decks, reshuffled after 3/4 of the cards are used
* Dealer stands on soft 17s
* Splitting is allowed only on the first two cards, and only if they
are equal; 10 and the face cards are all considered equal for
splitting
* Doubling is allowed on all unsplit hands, not on split hands
* No blackjacks after splitting
* No surrender
* No insurance
* No maximum under-21 hand size
* Dealer's second card is not revealed if the player busts (or both
halves of a split hand bust)

View File

@ -5,7 +5,7 @@
@title{@bold{Cards}: Virtual Playing Cards Library}
@defmodule[games/cards/main]{The @schememodname[games/cards/main]
@defmodule[games/cards]{The @schememodname[games/cards]
module provides a toolbox for creating cards games.}
@; ----------------------------------------------------------------------
@ -357,12 +357,22 @@ Removes @scheme[card] from the table.}
[tt? any/c])
void?]{
Adds a @onscreen{Help} button to the give pane, where clicking the
Adds a @onscreen{Help} button to the given pane, where clicking the
button opens a new window to display @filepath{doc.txt} from the given
collection. The @scheme[str] argument is used for the help window
title. If @scheme[tt?] is true, then @filepath{doc.txt} is displayed
verbatim, otherwise it is formatted as for @scheme[show-help] from
@scheme[(lib "show-help.ss" "games")].}
@schememodname[games/show-help].}
@defmethod[(add-scribble-button [pane (is-a?/c area-container<%>)]
[mod-path module-path?]
[tag string?])
void?]{
Adds a @onscreen{Help} button to the given pane, where clicking the
button opens Scribble-based documentation, as with
@scheme[show-scribbling] from @schememodname[games/show-scribbling].}
}
@; ----------------------------------------------------------------------

View File

@ -10,7 +10,8 @@
"make-cards.ss"
"region.ss"
string-constants
"../show-help.ss")
"../show-help.ss"
"../show-scribbling.ss")
(provide pasteboard%
table%)
@ -601,6 +602,15 @@
(label (string-constant help-menu-label))
(callback
(let ([show-help (show-help where title tt?)])
(lambda x
(show-help))))))]
[add-scribble-button
(lambda (pane mod tag)
(new mred:button%
(parent pane)
(label (string-constant help-menu-label))
(callback
(let ([show-help (show-scribbling mod tag)])
(lambda x
(show-help))))))])
(begin

View File

@ -1,311 +0,0 @@
The _Virtual Playing Cards Library_
-----------------------------------
Load the virtual card library with
(require games/cards)
The _cards_ module defines the following procedures:
> (make-table [title-string] [w] [h]) returns a table named by
`title-string' that is `w' cards wide and `h' cards high. A
table is an frame% object, with extra methods described
below. The table is not initially shown; (send table show #t)
shows it. The arguments are optional, with the default values
being "Cards", 7, and 3.
> (make-deck) returns a list of 52 cards, one for each suit-value
combination. The cards are all face-down, sorted lowest-suit
then lowest-value. A card is an object, with methods described
below. A card can only be on one table at a time.
> (make-card front-bm back-bm-or-#f suit-id value) returns a single
card given a bitmap for the front, an optional bitmap for the
back, and arbitrary values for the card's suit and value (which
are returned by the card's `get-value' and `get-suit-id'
methods). All provided bitmaps should be 71 by 96 pixels.
> (shuffle-list list n) shuffles the given `list' `n' times, returning
the new list. Shuffling simulates an actual shuffle: the list is
split into halves which are merged back together by repeatedly
pulling the top card off one of the halves, randomly selecting
one half or the other. According to some mathematical theorem, 7
is a large enough `n' to get a perfect shuffle.
plus a structure:
> struct:region :: (struct region (x y w h label callback))
`x', `y', `w', `h' are coordinates on the table,
`label' is a string or bitmap to label the region or #f for no
label. When the region is added to a table, a text label is
drawn in 12-pixel text, and the label is centered horizontally
and 5 pixels down from the region's top outline. If label is
#f, no label or box is drawn for the region.
`callback' is a procedure that takes a list of cards that were
dragged to the region; if callback is #f, the region is not
active (i.e., dragging cards to the region doesn't highlight the
region box). The region remains hilited until the callback returns.
The only mutator on the structure that is available is set-region-callback!.
The structure created by make-region actually has extra hidden fields.
> (make-button-region x y w h label callback) - returns a region like
one made by make-region, but the is drawn slightly differently and
it reacts differently to cards and the mouse. The label is drawn
in the middle of the box instead of at the top, and the callback is
called with no arguments when the user clicks the region (instead
of dragging cards to the region).
> (make-background-region x y w h paint-callback) - returns a region that
does not respond to mouse clicks, but which has a general paint
callback. The `paint-callback' function is called with five
arguments: a drawing context, x and y offsets, and the width and
height (which are always `w' and `h'). The x and y offsets can be
different than the supplied `x' and `y' when part of the table is
drawn offscreen. Regions are painted in the order that they are
added to a table, and all regions are painted before any card.
The `paint-callback' procedure should not assume a particular
state for the drawing context (i.e.,current brush or pen), and it
should restore any modified drawing context state before
returning.
Plus some extra callback procedures on regions:
> (region-interactive-callback r)
> (set-region-interactive-callback! r hilite-callback)
Get and set a callback procedure that is invoked when a region is
[un]hilited as the user drags a set of cards to the region. The
callback is provided two arguments: a boolean indicating whether the
region is hilited, and the list of cards being dragged. Like
region-callback, the default is #f, which indicates that the region
has no interactive callback (but does not affect whether the region
is hilited as cards are dragged). The final unhilite (when cards are
potentially delivered) does not trigger this callback.
Table methods: [in addition to standard frame% methods]
--------------
> add-card :: (send t add-card card x y) - adds `card' to the table
with its top-left corner at (`x',`y') in table pixels.
> add-cards :: (send t add-cards cards x y [offset-proc]) - adds list
of cards at (`x',`y'); the optional `offset-proc' procedure is
called with an index i (counting from 0) and should return two
values: `dx' and `dy'; the ith card is the placed at `x'+`dx'
and `y'+`dy'. The cards are added in order on top of cards
already one the table such that the first card in `cards' is
topmost.
> add-cards-to-region :: (send t add-cards-to-region cards r) - adds
`cards' to fill the region `r', fanning them out bottom-right
to top-left. The region `r' does not have to be added to the
table.
> remove-card :: (send t remove-card card) - removes `card' from the
table
> remove-cards :: (send t remove-cards cards) - removes `cards' from
the table
> move-card :: (send t move-card card x y)
> move-cards :: (send t move-cards cards x y [offset-proc])
> move-cards-to-region :: (send t move-cards-to-region cards r)
These are like the `add-card' methods, except that they move
cards already on the table. The movement of the cards is
animated. All of the cards are moved at once. If the cards are
in snap-back-after-move mode and a drag is active, snapping
back will use the new location.
> flip-card :: (send t flip-card card) - flips `card' over with
animation.
> flip-cards :: (send t flip-cards cards) - flips all `cards' over (at
once) with animation.
> card-face-up :: (send t card-face-up card)
> cards-face-up :: (send t cards-face-up cards)
> card-face-down :: (send t card-face-down card)
> cards-face-down :: (send t cards-face-down cards)
These are like `flip-card', but only cards that are not
already face up/down are flipped.
> card-to-front :: (send t card-to-front card) - moves `card' in front
of all other cards.
> card-to-back :: (send t card-to-back card) - moves `card' behind all
other cards.
> stack-cards :: (send t stack-cards cards) - the first card in
`cards' is not moved; the second card is moved to follow
immediately behind the first one, then (send t stack-cards
(cdr cards)) is called. If `cards' is empty or contains only
one card, no action is taken.
> card-location :: (send t card-location card) - returns the position
of the given card; an exception is raised if the card is not
on the table.
> all-cards :: (send t all-cards) - returns a list of all cards on the
table in stacking order from front to back
> table-width :: (send t table-width) - returns the width of the table
in pixels.
> table-height :: (send t table-height) - returns the height of the
table in pixels.
> begin-card-sequence :: (send t begin-card-sequence) - starts a
sequence of card or region changes that won't be animated or
updated until the end of the sequence.
> end-card-sequence :: (send t end-card-sequence) - ends a sequence;
begin-/end- pairs can be nested.
> add-region :: (send t add-region r) - adds the region `r' to the
table; regions are drawn in the order that they are added to
the table, and when a region added later is hilighted, it can
obscure regions added earlier.
> remove-region :: (send t remove-region r) - removes the region `r'
from the table.
> hilite-region :: (send t hilite-region r) - manual hilite (usually
for animation)
> unhilite-region :: (send t unhilite-region r) - manual unhilite
(usually for animation)
> set-button-action :: (send t set-button-action which action) - sets
the way that a mouse click is handled. The which argument must
be 'left, 'middle, or 'right. The action argument must be one
of:
'drag/one - drag only the clicked-on card
'drag-raise/one - like drag/one, but raise the card to the
top on a click
'drag/above - drag the card along with any card on top of the
card (i.e., more towards the front and overlapping with
the card). The on-top-of relation is closed transitively.
'drag-raise/above
'drag/below - drag the card along with any card underneath the
card (i.e., more towards the back and overlapping with
the card). The underneath relation is closed transitively.
'drag-raise/below
The initial settings are:
'left - 'drag-raise/above
'middle - 'drag/one
'right - 'drag/below
> set-double-click-action :: (send t set-double-click-action proc) -
sets the procedure to be called when a card is
double-clicked. The procedure is called with the
double-clicked card. The default procedure flips the cards
along with its on-top-of cards, raises the cards, and reverses
the front-to-back order of the cards
> set-single-click-action :: (send t set-single-click-action proc) -
sets the procedure to be called when a card is single-clicked,
after the button action is initiated. (If the card is
double-clicked, this action is invoked for the first click,
then the double-click action is invoked.) The default action
does nothing.
> pause :: (send t pause n-secs) - pauses, allowing the table display
to be updated (unless a sequence is active), but does not let
the user click on the cards.
> animated :: (send t animated) - returns #t is animation is on.
> animated :: (send t animated on?) - enables/disables animation.
> create-status-pane :: (send t create-status-pane) - creates a
pane with a status message (initially empty) and returns
the pane so that you can add additional controls
> set-status :: (send t set-status str) - sets the text message
in the status pane
> add-help-button :: (send t add-help-button pane coll-path str tt?) -
adds a "Help" button to the give pane, where clicking the
button opens a new window to display "doc.txt" from the given
collection (where `coll-path' is a list of strings to select
the collection). The `str' is used for the help window title.
If `tt?' is true, then "doc.txt" is displayed verbatim,
otherwise it is formatted as for `show-help' from
`(lib "show-help.ss" "games").
Card methods:
-------------
> card-width :: (send c card-width) - returns the width of the card in
pixels.
> card-height :: (send c card-height) - returns the height of the card
in pixels. All cards have the same width and height.
> flip :: (send c flip) - flips the card without animation. This is
useful for flipping a card before it is added to a table.
> face-up :: (send c face-up)
> face-down :: (send c face-down)
Makes the card face up/down without animation.
> face-down? :: (send c face-down?) - #t if the card is currently
face down.
> get-suit-id :: (send c get-suit-id) - normally 1, 2, 3, or 4 (see
`get-suit' for corresponding suit names), but the result can be
anything for a card created by `make-card'
> get-suit :: (send c get-suit) - 'clubs, 'diamonds, 'hearts, 'spades,
or 'unknown, depending on whether `get-suit-id' returns 1, 2,
3, 4, or something else
> get-value :: (send c get-value) - normally 1 (Ace), 2, ... 10, 11
(Jack), 12 (Queen), or 13 (King), but the result can be
anything for a card created by `make-card'
> user-can-flip :: (send c user-can-flip)
> user-can-flip :: (send c user-can-flip can?)
Determines whether the user can flip the card interactively,
usually by double-clicking it. Initially #t.
> user-can-move :: (send c user-can-move)
> user-can-move :: (send c user-can-move can?)
Determines whether the user can move the card interactively,
usually by dragging it. Disabling moves has the side-effect of
disabling raises and double-clicks. Initially #t.
> snap-back-after-move :: (send c snap-back-after-move)
> snap-back-after-move :: (send c snap-back-after-move on?)
Assuming user can move the card interactively, determines
whether the card stays where the user dragged it or snaps back
to its original place. Initially #f. A region's *interactive*
callback can disable snap-back for a card so that the card can
be delivered to the region. (A region's normal callback cannot
release the card, because it's too late.)
> stay-in-region :: (send c stay-in-region r)
> stay-in-region :: (send c stay-in-region)
If `r' is a region, the user cannot move the card out of r.
Initially #f.
> home-region :: (send c home-region r)
> home-region :: (send c home-region)
If `r' is a region, the user can move the card freely within
the region, but it snaps back if moved completely out of the
region. If moved partly out of the region, the card is moved
enough to get completely back in. Initially #f. A region's
*interactive* callback can disable snap-back for a card so that
the card can be delivered to the region. (A region's normal
callback cannot release the card, because it's too late.)
> dim :: (send c dim dim?)
> dim :: (send c dim)
"Highlights" the card by drawing it dimmer than normal.
> copy :: (send c copy) - makes a new card with the same suit and
value.

View File

@ -81,8 +81,8 @@
[parent status-pane]
[label "Options..."]
[callback (lambda (b e) (configure-dialog))])
(send t add-help-button status-pane
(list "games" "crazy8s") "Crazy 8s Help" #f)
(send t add-scribble-button status-pane
'(lib "games/scribblings/games.scrbl") "crazy8s")
;; The "Options.." button opens a configuration dialog that
;; starts a new game:

View File

@ -1,144 +0,0 @@
_Games_
=======
The "PLT Games" (Unix: plt/bin/plt-games) executable is created by
"Setup PLT" (Unix: plt/bin/setup-plt).
The Games program lets you select one of the games distributed by PLT,
or other games installed as sub-collections of the "games" collection
(see below).
* Aces - A solitaire card game. Click the "Help" button in Aces for
more details.
- by Robby
* Same - The object is to score points by removing dots from the
board. Click the "Help" button in Same for more details.
- by Robby
* Go Fish (against two computer players) - The children's card game
where you try to get rid of all you cards by forming pairs.
- by Matthew
* Crazy 8s - The card game where you try to get rid of all you cards
by matching the top card in the discard pile. Click "Help" in the
game for details.
- by Matthew
* Blackjack - Standard rules. Click "Help" in the game for specifics.
- by Matthew
* Rummy (against one computer player) - A simple variant of the
popular card game. Click "Help" in the game for details.
- by Matthew
* _Minesweeper_ - A simple version of the classic tile-removing game.
- by Matthew
* _Memory_ (matching game) - In case you have small children, too.
- by Matthew
* Paint by Numbers - A logic game. Click the "Help" button in Paint
by Numbers for more details.
- by Robby
* _Lights Out_ - A color-toggling game. Click the "Help" button in
Lights Out for more details.
- by Robby
* Pousse - A game similar to tic-tac-toe, but tokens are pushed
onto the board and can move other pieces. Click the "Help" button
in Pousse for more details. You can install your own player
programs. (This game was part of the 1998 ICFP programming
contest.)
- by Matthew
* GCalc - Not really a game, but a demonstration of "concrete
abstractions". See
http://www.grame.fr/Research/GCalcul/Graphic_Calculus.html
ftp://ftp.grame.fr/pub/Documents/ICMC94LambdaCalc.pdf
for the theoretic details, and right-click anywhere in the game
for instructions.
- by Eli
* Checkers - A simple checkers game (with no AI player) intended
as a demonstration use of the gl-board-games library.
- by Scott
* Jewel - Swap the jewels to make 3-in-a-row.
- by Dave Ashley
and Peter Ivanyi
Implementing new Games
----------------------
The game-starting console inspects the sub-collections of the "games"
collection. If a sub-collection has an info.ss definition (see the mzc
manual), the following fields of the collection's "info.ss" file are
used:
* `game' [required] : used as a module name in the sub-collection to
load for the game; the module must provide a `game@' unit (see
MzLib's "unit.ss" form) with no particular exports; the unit is
invoked with no imports to start the game.
* `name' [defaults to the collection name] : used to label the
game-starting button in the game console.
* `game-icon' [defaults to collection name with ".png"] : used as a
path to a bitmap file that is used for the game button's label;
this image should be 32 x 32 and have a mask.
* `game-set' [defaults to "Other Games"] : a label used to group
games that declare themselves to be in the same set.
To implement card games, see the documentation for the "cards"
sub-collection of the "games" collection. Card games typically belong
in the "Cards" game set.
Showing Help
------------
The _show-help.ss_ library provides a `show-help' function for
displaying a help window.
> (show-help collection frame-title-str verbatim?)
Returns a thunk for showing a help window. Multiple invocations
of the thunk bring the same window to the foreground (until the
user closes the window).
The help window displays "doc.txt" from the given collection, where
`coll-path' is a list of strings to select the collection.
The `frame-title-str' string is used for the help window title.
If `verbatim?' is true, then "doc.txt" is displayed verbatim,
otherwise it is formatted as follows:
- Any line of the form "** ... **" is omitted.
- Any line that starts with "*" after whitespace is indented
as a bullet point.
- Any line that contains only "-"s and is as long as the previous
line causes the previous line to be formatted as a title.
- Other lines are paragraph-flowed to fit the window.
The `verbatim?' argument is optional, and it defaults to #f.

View File

@ -1,8 +0,0 @@
_doors.ss_
The "doors.ss" library builds on "gl-board.ss" to support simple
maze-like games, where the maze is formed by a grid of squares and
doors of various types appears between adjacent squares.
But it's not ready, yet. Check back later.

View File

@ -1,79 +0,0 @@
GCalc is a system for visually demonstrating the Lambda Calculus.
(Not really a game...)
See the following for the principles:
http://www.grame.fr/Research/GCalcul/Graphic_Calculus.html
ftp://ftp.grame.fr/pub/Documents/ICMC94LambdaCalc.pdf
The window layout
-----------------
The window is divided into three working areas, each made of cells.
Cells hold cube objects, which can be dragged between cells (with a
few exceptions that are listed below). The working areas are:
1. The right side is the storage area. This is used for saving
objects -- drag any cube to/from here. Note that cubes can be
named for convenience.
2. The left side is a panel of basic color cubes. These cells always
contain a set of basic cubes that are used as the primitive
building blocks all other values are made of. They cannot be
overwritten. (Note that this includes a transparent cell.)
3. The center part is the working panel. This is the main panel where
new cubes are constructed. The center cell is similar to a storage
cell, and the surrounding eight cells all perform some operation on
this cell.
User Interaction
----------------
Right-click any cell except for the basic colors on the left panel, or
hit escape or F10 for a menu of operations. The menu also includes
the keyboard shortcuts for these operations.
Cube operations
---------------
There are six simple operations that are considered part of the simple
graphic cube world. The operations correspond to six of the operation
cells: a left-right composition is built using the left and the right
cells, a top-bottom using the top and the bottom, and a front-back
using the top-left and bottom-right. Dragging a cube to one of these
cells will use the corresponding operator to combine it with the main
cell's cube. Using a right mouse click on one of these cells can be
used to cancel dragging an object to that cell, this is not really an
undo feature: a right-click on the right cell always splits the main
cube to two halves and throws the right side.
The colored cubes and the six basic operators make this simple domain,
which is extended to form a Lambda-Calculus-like language by adding
abstractions and applications. Right-clicking on a basic cube on the
left panel creates an abstraction which is actually a lambda
expression except that colors are used instead of syntactic variables.
For example, if the main cell contains `R|G' (red-green on the left
and right), then right-clicking the green cube on the left panel
leaves us with `lambda G . R|G', which is visualized as `R|G' with a
green circle. The last two operator cells are used for application of
these abstractions: drag a function to the top-right to have it
applied on the main cube, or to the bottom-left to have the main cube
applied to it. As in the Lambda Calculus, all abstractions have
exactly one variable, use currying for multiple variables.
So far the result is a domain of colored cubes that can be used in the
same way as the simple Lambda Calculus. There is one last extension
that goes one step further: function cubes can themselves be combined
with other functions using the simple operations. This results in a
form of "spatial functions" that behave differently in different parts
of the cube according to the construction. For example, a left-right
construction of two functions `f|g' operates on a given cube by
applying `f' on its left part and `g' on its right part. You can use
the preferences dialog to change a few aspects of the computation.
Use the "Open Example" menu entry to open a sample file that contains
lots of useful objects (Church numerals, booleans, lists,
Y-combinator, etc).

View File

@ -5,7 +5,7 @@
#lang mzscheme
(require mzlib/class mred mzlib/etc "../show-help.ss" mzlib/unit)
(require mzlib/class mred mzlib/etc "../show-scribbling.ss" mzlib/unit)
(provide game@)
(define customs '())
@ -527,7 +527,9 @@
(instantiate horizontal-pane% (gcalc-frame)))
(define help
(show-help (list "games" "gcalc") "GCalc Help" #t))
(show-scribbling
'(lib "games/scribblings/games.scrbl")
"gcalc"))
(define file-name #f)
(define modified? #f)

View File

@ -26,7 +26,8 @@
;; Set up the table
(define t (make-table "Rummy" 8 4.5))
(define status-pane (send t create-status-pane))
(send t add-help-button status-pane '("games" "ginrummy") "Rummy Help" #f)
(send t add-scribble-button status-pane
'(lib "games/scribblings/games.scrbl") "ginrummy")
(send t show #t)
(send t set-double-click-action #f)
(send t set-button-action 'left 'drag-raise/one)

View File

@ -1,95 +0,0 @@
_gl-board.ss_
The gl-board.ss library uses OpenGL, via the sgl library, to provide generic
functionality for 3-dimensional views of board games. It provides support for
viewing and positioning the board as well as for moving pieces on the board.
It does not handle rendering of the board and pieces themselves. The arrow
keys rotate the board, the = and - keys move the board closer and further, and
the _ and + keys control the field of vision. Games are played by left
clicking the mouse on a piece and dragging it to a space.
The checkers and goblet games both use the gl-board.ss library.
The gl-board.ss module provides _gl-board%_, a subclass of canvas%, with the
following public methods:
> (add-space draw info): (->) X ->
Adds a space to the board. The draw argument function should draw the space
using GL drawing commands. The info argument is associated with the space.
Spaces should be drawn on the z = 0 plane.
> (add-piece x y z draw info): real real real (bool ->) X ->
Adds a piece to the board. The draw argument function should draw the piece
using GL drawing commands; the argument is #t if the piece is being drawn
only for its shadow, #f otherwise. The info argument is associated with the
piece. The x, y, and z arguments are the position at which the piece resides.
> (add-heads-up w h draw info): real real (->) X ->
Adds an item to a "heads-up" display at the bottom of the board area. The
heads-up area is not affected by rotation or scaling of the board, though
it does scale as the window is enlarged. The w and h arguments inidicate
the width and height of the object that is shown by `draw'; the heads-up
area is intended to show objects up to size 1 x 1. The `draw' function
should draw at the origin.
> (get-spaces): -> (listof X)
Returns a list of the infos associated with the current spaces.
> (get-pieces): -> (listof X)
Returns a list of the infos associated with the current pieces.
> (get-heads-ups) -> (listof X)
Returns a list of the infos associated with the current heads-up items.
> (set-space-draw info draw): X (->) ->
Sets to draw the drawing method of all spaces whose info is equal? to the
given info.
> (set-piece-draw info draw): X (boolean ->) ->
Sets to draw the drawing method of all pieces whose info is equal? to the
given info. The drawing method takes a boolean. If the value it true,
then the piece should be drawn for creating its shadow. Otherwise is should
be drawn normally.
> (set-heads-up-draw info draw): X (->) ->
Sets to draw the drawing method of all heads-up objects whose info
is equal? to the given info.
> (enable-piece info on?): X boolean ->
Enables or disables a piece whose info is equal? to the given info.
Disabled pieces are not selectable.
> (enabled? info): X -> boolean
If a piece whose info is equal? to the given info is enabled or not.
> (remove-piece info): X ->
Removes all pieces whose info is equal? to the given info.
> (remove-heads-up info): X ->
Removes all heads-up objects whose info is equal? to the given info.
A gl-board object is constructed as follows:
(new gl-board% (min-x real) (max-x real)
(min-y real) (max-y real)
(lift real)
(move (X gl-double-vector ->))
;; Optional:
(theta real) (phi real))
The min-x, max-x, min-y, and max-y parameters all specify the dimensions of
the board. They are used to setup viewing parameters. The board is viewed
centered around the center of the coordinates, and the view attempts to fill
the window to them. The optional theta and phi arguments determine the initial
rotation of the board, with respective defaults 45 and 0; theta corresponds to
the up and down keys, and phi corresponds to the left and right keys. (Holding
down Command/Meta/Alt while pressing an arrow key pans the display, instead
of rotating.)
The lift parameter specifies how high off the board mouse-dragged pieces are.
The gl-board% class invokes the move callback when a piece is selected
(left-click) and then unselected. It is given the info associated with the
selected piece, and the coordinates the user has dragged it to. If the piece
should be moved permanently, the move function must update the board state
with remove-piece and add-piece.

View File

@ -1,111 +0,0 @@
** To play Goblet, run the "PLT Games" application.
"Gobblet!" is a board game from Blue Orange Games:
http://www.blueorangegames.com/
Our 3x3 version actually corresponds to "Gobblet! Jr.", while the 4x4
version matches "Gobblet!".
The Blue Orange web site provides rules for Gobblet! Jr. and
Gobblet!. The rules below are in our own words; see also the Blue
Orange version.
Game Rules
----------
The 3x3 game is a generalization of tic-tac-toe:
* The object of the game is to get three in a row of your color,
vertically, horizontally, or diagonally. Size doesn't matter for
determining a winner.
* Each player (red or yellow) starts with 6 pieces: two large, two
medium, and two small.
* On each turn, a player can either place a new piece on the board,
or move a piece already on the board --- from anywhere to anywhere,
as long as the "from" and "to" are different.
* A piece can be placed (or moved to) an empty space, or it can be
placed/moved on top of a smaller piece already on the board,
"gobbling" the smaller piece. The smaller piece does not have to
be an opponent's piece, and the smaller piece may itself have
gobbled another piece previously.
* Only visible pieces can be moved, and only visible pieces count
toward winning. Gobbled pieces stay on the board, however, and
when a piece is moved, any piece that it gobbled stays put and
becomes visible.
* If moving a piece exposes a winning sequence for the opponent, and
if the destination for the move does not cover up one of the other
pieces in the sequence, then the opponent wins --- even if the move
makes a winning sequence for the moving player.
* Technically, if a player touches a piece, then the piece must be
moved on that turn. In other words, you're not allowed to peek
under a piece to remind yourself whether it gobbled anything. If
the piece can't be moved, the player forfeits. This particular
rule is not enforced by our version --- in part because our version
supports a rewind button, which is also not in the official game.
The 4x4 game has a few changes:
* The object of the game is to get four in a row of your color.
* Each player (red or yellow) starts with 12 pieces: three large,
three medium-large, three medium-small, and three small.
* Each player's pieces are initially arranged into three stacks off
the board, and only visible pieces can be moved onto the board.
The initial stacks prevent playing a smaller piece before a
corresponding larger piece.
* When a piece is moved from off-board onto the board, it must be
moved to either (1) an empty space, or (2) a space to gobble an
opponent's piece that is part of three in a row (for the opponent).
In other words, a new piece can gobble only an opponent's piece,
and only to prevent an immediate win on the opponent's next turn.
These restrictions do not apply when a piece that is already on the
board is moved.
Controls
--------
Click and drag pieces in the obvious way to take a turn. The shadow
under a piece shows where it will land when you drop it.
Use the arrow keys on your keyboard to rotate the board. Use the "-"
and "=" keys to zoom in and out. Use "_" and "+" to make the game
smaller and larger. (Changing the size adjusts perspective in a
slightly different way than zooming.) Depending on how keyboard focus
works on your machine, you may have to click the board area to make
these controls work.
The button labeled "<" at the bottom of the window rewinds the game by
one turn. The button labeled ">" re-plays one turn in a rewound game.
An alternate move can be made at any point in a rewound game,
replacing the old game from that point on.
Auto-Play
---------
Turn on a computer player at any time by checking the "Auto-Play Red"
or "Auto-Play Yellow" checkbox. If you rewind the game, you can
choose an alternate move for yourself or for the auto-player to find
out what would have happened. The auto-player is not always
deterministic, so replying the same move might lead to a different
result. You can disable an auto-player at any point by unchecking the
corresponding "Auto-Play" checkbox.
Important: In the 3x3 game, you CANNOT win as yellow against the smart
auto-player (if the auto-player is allowed to play red from the start
of the game). In other words, red has a forced win in the 3x3 game,
and the smart auto-player knows the path to victory. You might have a
chance to beat the red player in the default mode, though, which is
represented by the "Ok" choice (instead of "Smart") in the "Auto-Play
Options" dialog.
Configure the auto-player by clicking the "Auto-Play Options" button.
Currently, there's no difference between "Smart" and "Ok" in the 4x4
game.

View File

@ -8,7 +8,7 @@
"gui.ss"
"heuristics.ss"
"explore.ss"
"../show-help.ss")
"../show-scribbling.ss")
(provide game@)
@ -34,8 +34,8 @@
(queue-callback
(lambda ()
(unless help
(set! help (show-help (list "games" "gobblet")
"Gobblet Help" #f)))
(set! help (show-scribbling '(lib "games/scribblings/games.scrbl")
"gobblet")))
(help)))))))]
[MODEL : model^ (model-unit CONFIG)]
[HEURISTICS : heuristics^ (heuristics-unit CONFIG MODEL EXPLORE)]

View File

@ -36,7 +36,8 @@
;; Set up the table
(define t (make-table "Go Fish" 8 4.5))
(define status-pane (send t create-status-pane))
(send t add-help-button status-pane '("games" "gofish") "Go Fish Help" #f)
(send t add-scribble-button status-pane
'(lib "games/scribblings/games.scrbl") "gofish")
(send t show #t)
(send t set-double-click-action #f)
(send t set-button-action 'left 'drag-raise/one)

View File

@ -1,4 +1,6 @@
#lang setup/infotab
(define scribblings '(("scribblings/games.scrbl" (multi-page))))
(define mred-launcher-libraries (list "main.ss"))
(define mred-launcher-names (list "PLT Games"))

View File

@ -14,7 +14,7 @@
"shapes.scm"
"array.scm"
"text.scm"
"../show-help.ss"
"../show-scribbling.ss"
)
(provide game@)
@ -50,17 +50,18 @@
(define jewel-difficulty 0)
; table of high scores, loaded from a file
(define high-scores #( ("NOBODY" "0" "1")
("NOBODY" "0" "1")
("NOBODY" "0" "1")
("NOBODY" "0" "1")
("NOBODY" "0" "1")
("NOBODY" "0" "1")
("NOBODY" "0" "1")
("NOBODY" "0" "1")
("NOBODY" "0" "1")
("NOBODY" "0" "1")
))
(define high-scores (vector
'("NOBODY" "0" "1")
'("NOBODY" "0" "1")
'("NOBODY" "0" "1")
'("NOBODY" "0" "1")
'("NOBODY" "0" "1")
'("NOBODY" "0" "1")
'("NOBODY" "0" "1")
'("NOBODY" "0" "1")
'("NOBODY" "0" "1")
'("NOBODY" "0" "1")
))
(define startlife 1000.0)
(define lifevisible (* startlife 2.0))
@ -1786,8 +1787,7 @@
(jewel-init-game)
(define show-jewel-help
(show-help (list "games" "jewel")
"Jewel Help" #f))
(show-scribbling '(lib "games/scribblings/games.scrbl") "jewel"))
(define *MAIN_WINDOW*
(new jewel-frame%

View File

@ -1,6 +1,6 @@
#lang mzscheme
(require "board.ss"
"../show-help.ss"
"../show-scribbling.ss"
mred
mzlib/class
mzlib/unit)
@ -173,7 +173,7 @@
(lambda x
(init-board original-board)))
(let ([help (show-help (list "games" "lights-out") "Lights Out Help")])
(let ([help (show-scribbling '(lib "games/scribblings/games.scrbl") "lights-out")])
(make-object button% "Help" button-panel (lambda x (help))))
(make-object grow-box-spacer-pane% button-panel)

View File

@ -4,7 +4,7 @@
(prefix solve: "solve.ss")
"all-problems.ss"
"problem.ss"
"../show-help.ss"
"../show-scribbling.ss"
framework
mzlib/class
mzlib/unit
@ -66,9 +66,9 @@
(send g set-value counter)]))))
(define show-this-help
(show-help
(list "games" "paint-by-numbers")
"Paint by Numbers Help"))
(show-scribbling
'(lib "games/scribblings/games.scrbl")
"paint-by-numbers"))
(define (configure-font frame)
(let ([font (get-font-from-user

View File

@ -14,7 +14,6 @@ corresponds to the unplayed move! that's confusing.
"moves.ss"
"rules.ss"
"best-players.ss"
"../show-help.ss"
framework
mzlib/class
mzlib/list

View File

@ -1,47 +0,0 @@
** To play Parcheesi, run the "PLT Games" application.
Parcheesi is a race game for four players. The goal is for each
player to move their pieces from the starting position (the circles in
the corners) to the home square (in the center of the board), passing
a nearly complete loop around the board in the counter-clockwise
direction and then heads up towards the main row. For example, the
green player enters from the bottom right, travels around the board on
the light blue squares, passing each of the corners, until it reaches
the middle of the bottom of the board, where it turns off the light
blue squares and heads into the central region.
On each turn, the player rolls two dice and advances the pawn, based
on the die rolls. Typically the players may move a pawn for each die.
The pawn moves by the number of pips showing on the die and all of the
dice must be used to complete a turn.
There are some exceptions, however:
- you must roll a 5 (either directly or via summing) to enter from
the start area to the main ring.
- if two pieces of the same color occupy a square, no pieces may
pass that square.
- if an opponent's piece lands on your piece, you piece is returned
to the starting area and the opponent receives a bonus of 20
(which is treated just as if they had rolled a 20 on the dice).
- if your piece makes it home (and it must do so by exact count) you
get a bonus of 10, to be used as an additional die roll.
These rules induce a number of unexpected corner cases, but the GUI
only lets you make legal moves. Watch the space along the bottom of
the board for reasons why a move is illegal or why you have not used
all of your die rolls.
The automated players are:
- Reckless Renee, who she tries to maximize the chances that someone
else bops her.
- Polite Polly, who tries to minimize the distance her pawns move
("no, after _you_. I insist."), and
- Amazing Grace, who tries to minimize the chance she gets bopped
while moving as far as possible.

View File

@ -1,50 +0,0 @@
** To play Pousse, run the "PLT Games" application.
Pousse (French for "push", pronounced "poo-ss") is a 2 person game,
played on an N by N board (usually 4x4). Initially the board is
empty, and the players take turns inserting one marker of their color
(X or O) on the board. The color X always goes first. The columns
and rows are numbered from 1 to N, starting from the top left, as in:
1 2 3 4
+-+-+-+-+
1 | | | | |
+-+-+-+-+
2 | | | | |
+-+-+-+-+
3 | | | | |
+-+-+-+-+
4 | | | | |
+-+-+-+-+
A marker can only be inserted on the board by sliding it onto a
particular row from the left or from the right, or onto a particular
column from the top or from the bottom. So there are 4*N possible
"moves" (ways to insert a marker). They are be named "Li", "Ri",
"Ti", "Bi" respectively, where "i" is the number of the row or column
where the insertion takes place.
When a marker is inserted, there may be a marker on the square where
the insertion takes place. In this case, all markers on the insertion
row or column from the insertion square upto the first empty square
are moved one square further to make room for the inserted marker.
Note that the last marker of the row or column will be pushed off the
board (and must be removed from play) if there are no empty squares on
the insertion row or column.
A row or a column is a "straight" of a given color, if it contains N
markers of the given color.
The game ends either when an insertion
1) repeats a previous configuration of the board; in this case the
player who inserted the marker LOSES.
2) creates a configuration with more straights of one color than
straights of the other color; the player whose color is dominant
(in number of straights) WINS.
A game always leads to a win by one of the two players. Draws are
impossible.
[From the 1998 ICFP programming contest.]

View File

@ -2,6 +2,7 @@
(require "utils.ss"
"board.ss"
"board-size.ss"
"../show-scribbling.ss"
mzlib/class
mzlib/class100
(all-except mzlib/unit rename) ; rename collides with class100
@ -655,7 +656,7 @@
(define misc-panel (make-object horizontal-panel% frame))
(send misc-panel stretchable-height #f)
(make-object button% "Help" misc-panel (lambda (b e) (help #f)))
(make-object button% "Help" misc-panel (lambda (b e) (help)))
(make-object button% "Setup..." misc-panel (lambda (b e) (setup)))
(make-object vertical-pane% misc-panel) ; spacer
@ -747,39 +748,12 @@
(send setup-dialog show #t))
;; Help or source code window:
(define (help code?)
(define f (make-object frame%
(if code? "Pousse GUI Source Code" "Pousse Help")
#f 580 300))
(define p (if code?
(void)
(make-object choice% #f '("Rules" "Using the GUI" "Writing Players")
f
(lambda (p ev)
(send e lock #f)
(send e load-file
(local-file (case (send p get-selection)
[(0) "doc.txt"]
[(1) "help.txt"]
[(2) "robots.txt"])))
(when (zero? (send p get-selection))
;; Delete the "run the Games app" line
(send e delete 0 (send e line-start-position 2)))
(send e lock #t)))))
(define c (make-object editor-canvas% f))
(define e (make-object text%))
(send c set-editor e)
(send (send (send e get-style-list)
find-named-style
"Standard")
set-delta
(make-object style-delta% 'change-family 'modern))
(send e load-file (local-file "doc.txt"))
;; Delete the "run the Games app" line
(send e delete 0 (send e line-start-position 2))
(send e lock #t)
(send f show #t))
(define help
(show-scribbling
'(lib "games/scribblings/games.scrbl")
"pousse"))
; Draw initial board
(send canvas repaint)

View File

@ -1,18 +0,0 @@
** To play Same, run the "PLT Games" application.
The object of Same is to score points by removing dots from the board.
To remove a dot, click on it. As long as there is another dot of the
same color next to the clicked dot, it will disappear along with all
adjacent dots of the same color. After the dots disappear, dots in
the rows above the deleted dots will fall into the vacated spaces. If
an entire column is wiped out, all of the dots from the right will
slide left to take up the empty column's space.
Your score increases for each ball removed from the board. The score
for each click is a function of the number of balls that disappeared.
The "This Click" label shows how many points you would score for
clicking the dots underneath the mouse pointer. The score varies
quadratically with the number of balls, so eliminating many balls with
one click is advantageous.
Click the New Game button to play again.

View File

@ -4,7 +4,7 @@
mzlib/unit
mred
mzlib/list
"../show-help.ss")
"../show-scribbling.ss")
(provide game@)
@ -352,9 +352,9 @@
(define help-button (make-object button% "Help"
hp
(let ([show-help
(show-help
(list "games" "same")
"Same Help")])
(show-scribbling
'(lib "games/scribblings/games.scrbl")
"same")])
(lambda (_1 _2)
(show-help)))))

View File

@ -1,4 +1,7 @@
** To play Aces, run the "PLT Games" application.
#lang scribble/doc
@(require "common.ss")
@gametitle["Aces" "aces" "Solitaire Card Game"]
Aces is a solitaire card game. The object is to remove all of the
cards from the board, except the four Aces.

View File

@ -0,0 +1,33 @@
#lang scribble/doc
@(require "common.ss")
@gametitle["Blackjack" "blackjack" "21 Card Game"]
Standard Blackjack rules with the following specifics:
@itemize[
@item{1 player (not counting the dealer).}
@item{4 decks, reshuffled after 3/4 of the cards are used.}
@item{Dealer stands on soft 17s.}
@item{Splitting is allowed only on the first two cards, and only if
they are equal. 10 and the face cards are all considered equal
for splitting.}
@item{Doubling is allowed on all unsplit hands, not on split hands.}
@item{No blackjacks after splitting.}
@item{No surrender.}
@item{No insurance.}
@item{No maximum under-21 hand size.}
@item{Dealer's second card is not revealed if the player busts (or
both halves of a split hand bust).}
]

View File

@ -0,0 +1,7 @@
#lang scribble/doc
@(require "common.ss")
@gametitle["Checkers" "checkers" "Board Game"]
This simple checkers game (with no AI player) is intended as a
demonstration use of the @schememodname[games/gl-board-games] library.

View File

@ -0,0 +1,27 @@
#lang scheme/base
(require scribble/manual
scribble/decode
setup/main-collects)
(provide (all-from-out scribble/manual)
selflink
gametitle
game)
(define (selflink str) (link str (tt str)))
(define game onscreen)
(define (gametitle name subcol subtitle)
(make-splice
(list
(title #:tag subcol
(image (path->main-collects-relative
(build-path (collection-path "games" subcol)
(format "~a.png" subcol))))
" " (onscreen name) " --- " subtitle)
(margin-note "To play "
(onscreen name)
", run the "
(exec "PLT Games") " program."
" (Under Unix, it's called " (exec "plt-games") ")."))))

View File

@ -1,14 +1,18 @@
** To play Crazy 8s, run the "PLT Games" application.
#lang scribble/doc
@(require "common.ss")
@gametitle["Crazy 8s" "crazy8s" "Card Game"]
Try to get rid of all you cards by matching the value or suit of the
top card in the discard pile. In the default mode, click a card to
discard it; you can adjust the options so that you discard by dragging
a card from your hand to the discard pile.
An 8 can be discarded at any time, and in that case, the player who
discarded the 8 gets to pick any suit for it (hence the craziness of
8s). When you discard an 8, a panel of buttons appears to the right
of the discard pile, so you can pick the suit.
An @onscreen{8} can be discarded at any time, and in that case, the
player who discarded the @onscreen{8} gets to pick any suit for it
(hence the craziness of @onscreen{8}s). When you discard an
@onscreen{8}, a panel of buttons appears to the right of the discard
pile, so you can pick the suit.
A player can choose to draw a card instead of discarding, as long as
cards are left in the draw pile. A player's turn continues after
@ -18,7 +22,7 @@ middle of the table; you can adjust the options to that you draw by
dragging it from the draw pile to your hand.
If no cards are left in the deck, a player may pass instead of
discarding. To pass, click the "Pass" button.
discarding. To pass, click the @onscreen{Pass} button.
The status line at the bottom of the window provides instructions as
you go.

View File

@ -0,0 +1,89 @@
#lang scribble/doc
@(require "common.ss")
@title{@bold{Games}}
The @exec{PLT Games} executable (or @exec{plt-games} under Unix) lets
you select one of the games distributed by PLT or other games
installed as sub-collections of the @filepath{games} collection (see
@secref["new-games"]).
@table-of-contents[]
@; ----------------------------------------------------------------------
@include-section["std-games.scrbl"]
@; ----------------------------------------------------------------------
@section[#:tag "new-games"]{Implementing new Games}
The game-starting console inspects the sub-collections of the
@filepath{games} collection. If a sub-collection has an
@filepath{info.ss} module (see @schememodname[setup/infotab]), the
following fields of the collection's "info.ss" file are used:
@itemize[
@item{@schemeidfont{game} [required] : used as a module name in the
sub-collection to load for the game; the module must provide a
@schemeidfont["game@"] unit (see @schememodname[scheme/unit]) with
no particular exports; the unit is invoked with no imports to
start the game.}
@item{@schemeidfont{name} [defaults to the collection name] : used to
label the game-starting button in the game console.}
@item{@schemeidfont{game-icon} [defaults to collection name with
@filepath{.png}] : used as a path to a bitmap file that is used for
the game button's label; this image should be 32 by 32 pixels and
have a mask.}
@item{@schemeidfont{game-set} [defaults to @scheme["Other Games"]] :
a label used to group games that declare themselves to be in the
same set.}
]
To implement card games, see @schememodname[games/cards]. Card games
typically belong in the @scheme["Cards"] game set.
@; ----------------------------------------------------------------------
@section{Showing Help}
@defmodule[games/show-help]
@defproc[(show-help [coll-path (listof string?)]
[frame-title string?]
[verbatim? any/c #f])
(-> any)]{
Returns a thunk for showing a help window based on plain
text. Multiple invocations of the thunk bring the same window to the
foreground (until the user closes the window).
The help window displays @filepath{doc.txt} from the collection
specified by @scheme[coll-path].
The @scheme[frame-title] argument is used for the help window title.
If @scheme[verbatim?] is true, then @filepath{doc.txt} is displayed
verbatim, otherwise it is formatted as follows:
@itemize[
@item{Any line of the form @litchar{**}....@litchar{**} is omitted.}
@item{Any line that starts with @litchar{*} after whitespace is indented
as a bullet point.}
@item{Any line that contains only @litchar{-}s and is as long as the previous
line causes the previous line to be formatted as a title.}
@item{Other lines are paragraph-flowed to fit the window.}
]}

View File

@ -0,0 +1,90 @@
#lang scribble/doc
@(require "common.ss")
@(define Lambda "\u3BB")
@gametitle["GCalc" "gcalc" "Visual \u3BB-Calculus"]
@onscreen{GCalc} is a system for visually demonstrating the
@|Lambda|-Calculus (not really a game).
See the following for the principles:
@centerline{@selflink{http://www.grame.fr/Research/GCalcul/Graphic_Calculus.html}}
@centerline{@selflink{ftp://ftp.grame.fr/pub/Documents/ICMC94LambdaCalc.pdf}}
@section{The Window Layout}
The window is divided into three working areas, each made of cells.
Cells hold cube objects, which can be dragged between cells (with a
few exceptions that are listed below). The working areas are as
follows:
@itemize[
@item{The right side is the storage area. This is used for saving
objects -- drag any cube to/from here. Note that cubes can be
named for convenience.}
@item{The left side is a panel of basic color cubes. These cells
always contain a set of basic cubes that are used as the primitive
building blocks all other values are made of. They cannot be
overwritten. (Note that this includes a transparent cell.)}
@item{The center part is the working panel. This is the main panel where
new cubes are constructed. The center cell is similar to a storage
cell, and the surrounding eight cells all perform some operation on
this cell.}
]
@section{User Interaction}
Right-click any cell except for the basic colors on the left panel, or
hit escape or F10 for a menu of operations. The menu also includes
the keyboard shortcuts for these operations.
@section{Cube operations}
There are six simple operations that are considered part of the simple
graphic cube world. The operations correspond to six of the operation
cells: a left-right composition is built using the left and the right
cells, a top-bottom using the top and the bottom, and a front-back
using the top-left and bottom-right. Dragging a cube to one of these
cells will use the corresponding operator to combine it with the main
cell's cube. Using a right mouse click on one of these cells can be
used to cancel dragging an object to that cell, this is not really an
undo feature: a right-click on the right cell always splits the main
cube to two halves and throws the right side.
The colored cubes and the six basic operators make this simple domain,
which is extended to form a @|Lambda|-Calculus-like language by adding
abstractions and applications. Right-clicking on a basic cube on the
left panel creates an abstraction which is actually a lambda
expression except that colors are used instead of syntactic variables.
For example, if the main cell contains @onscreen{R|G} (red-green on
the left and right), then right-clicking the green cube on the left
panel leaves us with @onscreen{@|Lambda| G . R|G}, which is visualized
as @onscreen{R|G} with a green circle. The last two operator cells
are used for application of these abstractions: drag a function to the
top-right to have it applied on the main cube, or to the bottom-left
to have the main cube applied to it. As in the @|Lambda|-Calculus,
all abstractions have exactly one variable, use currying for multiple
variables.
So far the result is a domain of colored cubes that can be used in the
same way as the simple @|Lambda|-Calculus. There is one last
extension that goes one step further: function cubes can themselves be
combined with other functions using the simple operations. This
results in a form of "spatial functions" that behave differently in
different parts of the cube according to the construction. For
example, a left-right construction of two functions @onscreen{f|g}
operates on a given cube by applying @onscreen{f} on its left part and
@onscreen{g} on its right part. You can use the preferences dialog to
change a few aspects of the computation.
Use the @onscreen{Open Example} menu entry to open a sample file that
contains lots of useful objects: Church numerals, booleans, lists,
Y-combinator, etc.

View File

@ -1,4 +1,7 @@
** To play Rummy, run the "PLT Games" application.
#lang scribble/doc
@(require "common.ss")
@gametitle["Rummy" "ginrummy" "Card Game"]
This is a simple variant of Rummy.

View File

@ -0,0 +1,121 @@
#lang scribble/doc
@(require "common.ss")
@gametitle["Gobblet" "gobblet" "Strategy Game"]
@bold{Gobblet!} is a board game from Blue Orange Games:
@centerline{@selflink{http://www.blueorangegames.com/}}
Our 3x3 version actually corresponds to @bold{Gobblet! Jr.}, while
the 4x4 version matches @onscreen{Gobblet!}.
The Blue Orange web site provides rules for @bold{Gobblet! Jr.} and
@bold{Gobblet!}. The rules below are in our own words; see also the
Blue Orange version.
@section{Game Rules}
The 3x3 game is a generalization of tic-tac-toe:
@itemize[
@item{The object of the game is to get three in a row of your color,
vertically, horizontally, or diagonally. Size doesn't matter for
determining a winner.}
@item{Each player (red or yellow) starts with 6 pieces: two large,
two medium, and two small.}
@item{On each turn, a player can either place a new piece on the
board, or move a piece already on the board---from anywhere to
anywhere, as long as the ``from'' and ``to'' are different.}
@item{A piece can be placed (or moved to) an empty space, or it can
be placed/moved on top of a smaller piece already on the board,
``gobbling'' the smaller piece. The smaller piece does not have to
be an opponent's piece, and the smaller piece may itself have
gobbled another piece previously.}
@item{Only visible pieces can be moved, and only visible pieces count
toward winning. Gobbled pieces stay on the board, however, and
when a piece is moved, any piece that it gobbled stays put and
becomes visible.}
@item{If moving a piece exposes a winning sequence for the opponent, and
if the destination for the move does not cover up one of the other
pieces in the sequence, then the opponent wins---even if the move
makes a winning sequence for the moving player.}
@item{Technically, if a player touches a piece, then the piece must
be moved on that turn. In other words, you're not allowed to peek
under a piece to remind yourself whether it gobbled anything. If
the piece can't be moved, the player forfeits. This particular
rule is not enforced by our version --- in part because our version
supports a rewind button, which is also not in the official game.}
]
The 4x4 game has a few changes:
@itemize[
@item{The object of the game is to get four in a row of your color.}
@item{Each player (red or yellow) starts with 12 pieces: three large,
three medium-large, three medium-small, and three small.}
@item{Each player's pieces are initially arranged into three stacks
off the board, and only visible pieces can be moved onto the board.
The initial stacks prevent playing a smaller piece before a
corresponding larger piece.}
@item{When a piece is moved from off-board onto the board, it must be
moved to either (1) an empty space, or (2) a space to gobble an
opponent's piece that is part of three in a row (for the opponent).
In other words, a new piece can gobble only an opponent's piece,
and only to prevent an immediate win on the opponent's next turn.
These restrictions do not apply when a piece that is already on the
board is moved.}
]
@section{Controls}
Click and drag pieces in the obvious way to take a turn. The shadow
under a piece shows where it will land when you drop it.
Use the arrow keys on your keyboard to rotate the board. Use the
@onscreen{-} and @onscreen{=} keys to zoom in and out. Use
@onscreen{_} and @onscreen{+} to make the game smaller and larger.
(Changing the size adjusts perspective in a slightly different way
than zooming.) Depending on how keyboard focus works on your machine,
you may have to click the board area to make these controls work.
The button labeled @onscreen{<} at the bottom of the window rewinds
the game by one turn. The button labeled @onscreen{>} re-plays one
turn in a rewound game. An alternate move can be made at any point in
a rewound game, replacing the old game from that point on.
@section{Auto-Play}
Turn on a computer player at any time by checking the
@onscreen{Auto-Play Red} or @onscreen{Auto-Play Yellow} checkbox. If
you rewind the game, you can choose an alternate move for yourself or
for the auto-player to find out what would have happened. The
auto-player is not always deterministic, so replying the same move
might lead to a different result. You can disable an auto-player at
any point by unchecking the corresponding
@onscreen{Auto-Play"}checkbox.
Important: In the 3x3 game, you @emph{cannot} win as yellow against
the smart auto-player (if the auto-player is allowed to play red from
the start of the game). In other words, red has a forced win in the
3x3 game, and the smart auto-player knows the path to victory. You
might have a chance to beat the red player in the default mode,
though, which is represented by the @onscreen{Ok} choice (instead of
@onscreen{Smart}) in the @onscreen{Auto-Play Options} dialog.
Configure the auto-player by clicking the @onscreen{Auto-Play Options}
button. Currently, there's no difference between @onscreen{Smart} and
@onscreen{Ok} in the 4x4 game.

View File

@ -1,25 +1,33 @@
** To play Go Fish, run the "PLT Games" application.
#lang scribble/doc
@(require "common.ss")
Go Fish is the children's card game where you try to get rid of all
you cards by forming pairs. You play against two computer players.
@gametitle["Go Fish" "gofish" "Kid's Card Game"]
On Each turn, if you have a match in your hand, drag one of the
@game{Go Fish} is the children's card game where you try to get rid of
all you cards by forming pairs. You play against two computer
players.
On each turn, if you have a match in your hand, drag one of the
matching cards to your numbered box, and the match will move into the
box.
After forming matches from your own hand, drag one of your cards to an
opponent's area to ask the opponent for a matching card:
* If the opponent has a card with the same value as the card that you
drag, the opponent will give you the card, and they'll go into your
match area. Drag another card to an opponent.
@itemize[
* If the opponent has no matching card, the top card on draw pile
will move, indicating that you must "Go Fish!". Draw a card by
@item{If the opponent has a card with the same value as the card that you
drag, the opponent will give you the card, and they'll go into your
match area. Drag another card to an opponent.}
@item{If the opponent has no matching card, the top card on draw pile
will move, indicating that you must ``Go Fish!'' Draw a card by
dragging it from the draw pile to your hand. If the drawn card
gives you a match, then the match will automatically move into your
match area, and it's still your turn (so drag another card to one
of the opponents).
of the opponents).}
]
The game is over when one player runs out of cards. The winner is the
one with the most matches.

View File

@ -1,16 +1,23 @@
** To play Jewel, run the "PLT Games" application.
#lang scribble/doc
@(require "common.ss")
The board is an 8x8 array of jewels of 7 types. You need to get 3 or
more in a row horizontally or vertically in order to score points.
@gametitle["Jewel" "jewel" "3-D Skill Game"]
The board is an 8 by 8 array of jewels of 7 types. You need to get 3
or more in a row horizontally or vertically in order to score points.
You can swap any two jewels that are next to each other up and down or
left and right. The mechanic is to either:
* Click the mouse on the first one, then drag in the direction for
the swap.
@itemize[
* Move a bubble using the arrow keys, lock the bubble to a jewel with
@item{Click the mouse on the first one, then drag in the direction for
the swap.}
@item{Move a bubble using the arrow keys, lock the bubble to a jewel with
the space bar, and the swap the locked jewel with another by using
the arrow keys. Space unlocks a locked bubble without swapping.
the arrow keys. Space unlocks a locked bubble without swapping.}
]
Jewels can only be swapped if after the swap there are at least 3 or
more same shape or color in a row or column. Otherwise the jewels
@ -19,15 +26,11 @@ left. When it counts down to 0 the game is over. Getting 3 in a row
adds time to the clock.
Hit spacebar to start a new game then select the difficulty number by
pressing '0', '1', '2', '3' or '4'. You can always press 'ESC' to
exit. During playing press 'p' to pause the game.
pressing @onscreen{0}, @onscreen{1}, @onscreen{2}, @onscreen{3}, or
@onscreen{0}. You can always press ESC to exit. During playing press
@onscreen{P} to pause the game.
The code is released under the LGPL. The code is a conversion of Dave
Ashley's C program to Scheme with some modifications and enhancements.
Enjoy.
Peter Ivanyi
(Matthew edited Peter's code and help text a little: added keyboard
support, plus other minor changes.)

View File

@ -1,4 +1,7 @@
** To play Lights Out, run the "PLT Games" application.
#lang scribble/doc
@(require "common.ss")
@gametitle["Lights Out" "lights-out" "Logic Game"]
The object of this game is to turn all of the lights off. Click on a
button to turn that light off, but beware it will also toggle the

View File

@ -0,0 +1,9 @@
#lang scribble/doc
@(require "common.ss")
@gametitle["Memory" "memory" "Kid's Game"]
Flip two cards in a row that have the same picture, and the cards are
removed. If the two cards don't match, they are flipped back over, and
you try again. Each card has a single match on the board. The game is
over and the clock stops when all cards are removed.

View File

@ -0,0 +1,17 @@
#lang scribble/doc
@(require "common.ss")
@gametitle["Minesweeper" "mines" "Logic Game"]
Remove all the tiles that have no bomb underneath. When you remove
such a tile, a number appears that indicates how many of the
surrounding squares (up to 8) have a bomb; a blank means zero bombs,
and the game automatically uncovers all surrounding tiles in that
case.
Right- or Control-click to flag a tile that you think has a bomb, so
that you cannot accidentally uncover it. Right- or Control-click again
to remove the flag.
You don't have to use flags. When all of the non-bomb tiles are
removed, the game is over, and the clock stops.

View File

@ -1,20 +1,23 @@
** To play Paint By Numbers, run the "PLT Games" application.
#lang scribble/doc
@(require "common.ss")
The object of Paint By Numbers is to discover which cells should be
colored blue and which should be colored white. Initially, all
squares are grey, indicating that the correct colors are not known.
The lists of numbers to the left and above the grid are your clues to
the correct color of each square. Each list of numbers specifies the
pattern of blue squares in the row beside it or the column below it.
Each number indicates the length of a group of blue squares. For
example, if the list of numbers beside the first row is "2 3" then you
know that there is a contiguous block of two blue squares followed by
a contiguous block of three blue squares with at least one white
square between them. The label does not tell you where the blue
squares are, only their shapes. The trick is to gather as much
information as you can about each row, and then use that information
to determine more about each column. Eventually you should be able to
fill in the entire puzzle.
@gametitle["Paint By Numbers" "paint-by-numbers" "Logic Game"]
The object of @game{Paint By Numbers} is to discover which cells
should be colored blue and which should be colored white. Initially,
all squares are grey, indicating that the correct colors are not
known. The lists of numbers to the left and above the grid are your
clues to the correct color of each square. Each list of numbers
specifies the pattern of blue squares in the row beside it or the
column below it. Each number indicates the length of a group of blue
squares. For example, if the list of numbers beside the first row is
@onscreen{2 3} then you know that there is a contiguous block of two
blue squares followed by a contiguous block of three blue squares with
at least one white square between them. The label does not tell you
where the blue squares are, only their shapes. The trick is to gather
as much information as you can about each row, and then use that
information to determine more about each column. Eventually you
should be able to fill in the entire puzzle.
Click on a square to toggle it between blue and gray. Hold down a
modifier key (shift, command, meta, or alt depending on the platform)
@ -22,22 +25,23 @@ to toggle a square between white and gray. The third button under
unix and the right button under windows also toggles between white and
gray.
For some puzzles, hints are available. Choose the Nongram|Show
Mistakes menu item to receive the hints. This will turn all
For some puzzles, hints are available. Choose the @menuitem["Nongram"
"Show Mistakes"] menu item to receive the hints. This will turn all
incorrectly colored squares red.
Thanks to Shoichiro Hattori for his puzzles! Visit him on the web at:
http://hattori.m78.com/puzzle/
@centerline{@selflink["http://hattori.m78.com/puzzle/"]}
Thanks also to many of the contributors to the Kajitani web site for
permission to re-distribute their puzzles. Visit them online at:
http://www02.so-net.ne.jp/~kajitani/index.html
@centerline{@selflink["http://www02.so-net.ne.jp/~kajitani/index.html"]}
The specific contributers who have permitted their puzzles to be
redistributed are:
@verbatim[#:indent 2]{
snordmey /at/ dayton <dot> net
jtraub /at/ dragoncat <dot> net
e0gb258s /at/ mail <dot> erin <dot> utoronto <dot> ca
@ -94,4 +98,4 @@ redistributed are:
williamson /at/ proaxis <dot> com
vacko_6 /at/ hotmail <dot> com
jojess /at/ earthlink <dot> net
}

View File

@ -0,0 +1,60 @@
#lang scribble/doc
@(require "common.ss")
@gametitle["Parcheesi" "parcheesi" "Board Game"]
@onscreen{Parcheesi} is a race game for four players. The goal is for
each player to move their pieces from the starting position (the
circles in the corners) to the home square (in the center of the
board), passing a nearly complete loop around the board in the
counter-clockwise direction and then heads up towards the main row.
For example, the green player enters from the bottom right, travels
around the board on the light blue squares, passing each of the
corners, until it reaches the middle of the bottom of the board, where
it turns off the light blue squares and heads into the central region.
On each turn, the player rolls two dice and advances the pawn, based
on the die rolls. Typically the players may move a pawn for each die.
The pawn moves by the number of pips showing on the die and all of the
dice must be used to complete a turn.
There are some exceptions, however:
@itemize[
@item{You must roll a 5 (either directly or via summing) to enter from
the start area to the main ring.}
@item{If two pieces of the same color occupy a square, no pieces may
pass that square.}
@item{If an opponent's piece lands on your piece, you piece is
returned to the starting area and the opponent receives a bonus of
20 (which is treated just as if they had rolled a 20 on the
dice).}
@item{If your piece makes it home (and it must do so by exact count) you
get a bonus of 10, to be used as an additional die roll.}
]
These rules induce a number of unexpected corner cases, but the GUI
only lets you make legal moves. Watch the space along the bottom of
the board for reasons why a move is illegal or why you have not used
all of your die rolls.
The automated players are:
@itemize[
@item{@onscreen{Reckless Renee}, who tries to maximize the chances
that someone else bops her.}
@item{@onscreen{Polite Polly}, who tries to minimize the distance her
pawns move. (``No, after @emph{you}. I insist.'')}
@item{@onscreen{Amazing Grace}, who tries to minimize the chance she
gets bopped while moving as far as possible.}
]

View File

@ -0,0 +1,62 @@
#lang scribble/doc
@(require "common.ss")
@gametitle["Pousse" "pousse" "Tic-Tac-Toe-like Game"]
@onscreen{Pousse} (French for "push", pronounced "poo-ss") is a 2
person game, played on an @math{N} by @math{N} board (usually 4 by 4).
Initially the board is empty, and the players take turns inserting one
marker of their color (@onscreen{X} or @onscreen{O}) on the board.
The color @onscreen{X} always goes first. The columns and rows are
numbered from 1 to @math{N}, starting from the top left, as in:
@verbatim[#:indent 3]{
1 2 3 4
+-+-+-+-+
1 | | | | |
+-+-+-+-+
2 | | | | |
+-+-+-+-+
3 | | | | |
+-+-+-+-+
4 | | | | |
+-+-+-+-+
}
A marker can only be inserted on the board by sliding it onto a
particular row from the left or from the right, or onto a particular
column from the top or from the bottom. So there are @math{4*N}
possible ``moves'' (ways to insert a marker). They are named
L@math{i}, R@math{i}, T@math{i}, and B@math{i} respectively, where
@math{i} is the number of the row or column where the insertion takes
place.
When a marker is inserted, there may be a marker on the square where
the insertion takes place. In this case, all markers on the insertion
row or column from the insertion square upto the first empty square
are moved one square further to make room for the inserted marker.
Note that the last marker of the row or column will be pushed off the
board (and must be removed from play) if there are no empty squares on
the insertion row or column.
A row or a column is a @defterm{straight} of a given color if it
contains @math{N} markers of the given color.
The game ends either when an insertion
@itemize[
@item{repeats a previous configuration of the board; in this case the
player who inserted the marker LOSES.}
@item{creates a configuration with more straights of one color than
straights of the other color; the player whose color is dominant
(in number of straights) WINS.}
]
A game always leads to a win by one of the two players. Draws are
impossible.
This game is from the 1998 ICFP programming contest.

View File

@ -0,0 +1,21 @@
#lang scribble/doc
@(require "common.ss")
@gametitle["Same" "same" "Dot-Removing Game"]
The object of @game{Same} is to score points by removing dots from the
board. To remove a dot, click on it. As long as there is another dot
of the same color next to the clicked dot, it will disappear along
with all adjacent dots of the same color. After the dots disappear,
dots in the rows above the deleted dots will fall into the vacated
spaces. If an entire column is wiped out, all of the dots from the
right will slide left to take up the empty column's space.
Your score increases for each ball removed from the board. The score
for each click is a function of the number of balls that disappeared.
The @onscreen{This Click} label shows how many points you would score
for clicking the dots underneath the mouse pointer. The score varies
quadratically with the number of balls, so eliminating many balls with
one click is advantageous.
Click the @onscreen{New Game} button to play again.

View File

@ -0,0 +1,7 @@
#lang scribble/doc
@(require "common.ss")
@gametitle["Slidey" "slidey" "Picture Puzzle"]
Click a tile to slide it into the adjacent space, and keep shifting
tiles that way to repair the picture.

View File

@ -0,0 +1,62 @@
#lang scribble/doc
@(require "common.ss")
@gametitle["Spider" "spider" "Solitaire Card Game"]
Spider is a solitaire card game played with 104 cards. The cards can
include either a single suit, two suits, or four suites. (Choose your
variant through the @onscreen{Options} item in the @onscreen{Edit}
menu.)
Terminology:
@itemize[
@item{@deftech{Tableau}: one of the ten stacks of cards in the play
area. The game starts with six cards in the first four
@tech{tableau}s, and five cards in the rest; only the topmost card
is face up, and others are revealed when they become the topmost
card of the @tech{tableau}.}
@item{@deftech{Sequence}: a group of cards on the top of a
@tech{tableau} that are in the same suit, and that are in
@tech{sequence}, with the lowest numbered card topmost (i.e.,
closer to the bottom of the screen). King is high and ace is low.}
]
The object of the game is to create a @tech{sequence} with ace through
king, at which point the @tech{sequence} is removed from play. Create
eight such @tech{sequence}s to win the game.
On each move, you can take one of the following actions:
@itemize[
@item{Move a @tech{sequence} from any @tech{tableau} to one whose
topmost card (i.e., closest to the bottom of the screen) has a
value that's one more than the @tech{sequence}'s value. Note that
if the top card of the target @tech{tableau} has the same suit as
the @tech{sequence}, a larger @tech{sequence} is formed, but the
target @tech{tableau}'s card is not required to have the same suit.}
@item{Move a @tech{sequence} to an empty @tech{tableau}.}
@item{Deal ten cards from the deck (in the upper left corder), one to
each @tech{tableau}. This move is allowed only if no
@tech{tableau} is empty.}
]
To move a @tech{sequence}, either drag it to the target
@tech{tableau}, or click the @tech{sequence} and then click the top
card of the target @tech{tableau} (or the place where a single card
would be for an empty @tech{tableau}). Click a select card to
de-select it. Clicking a card that is not a valid target for the
currently selected @tech{sequence} causes the clicked card's
@tech{sequence} to be selected (if the card is face up in a
@tech{sequence}).
To deal, click the deck.
To undo a move, use @onscreen{Undo} from the @onscreen{Edit} menu.

View File

@ -0,0 +1,25 @@
#lang scribble/doc
@(require "common.ss")
@title[#:style 'toc #:tag "bundled"]{Bundled Games}
@local-table-of-contents[]
@include-section["aces.scrbl"]
@include-section["gofish.scrbl"]
@include-section["crazy8s.scrbl"]
@include-section["blackjack.scrbl"]
@include-section["ginrummy.scrbl"]
@include-section["spider.scrbl"]
@include-section["memory.scrbl"]
@include-section["slidey.scrbl"]
@include-section["same.scrbl"]
@include-section["mines.scrbl"]
@include-section["paint-by-numbers.scrbl"]
@include-section["lights-out.scrbl"]
@include-section["pousse.scrbl"]
@include-section["gobblet.scrbl"]
@include-section["jewel.scrbl"]
@include-section["parcheesi.scrbl"]
@include-section["checkers.scrbl"]
@include-section["gcalc.scrbl"]

View File

@ -0,0 +1,23 @@
#lang scheme/base
(require setup/xref
scribble/xref
scribble/basic
scheme/promise
net/url
net/sendurl)
(provide show-scribbling)
(define (show-scribbling mod-path tag)
(let ([xref (delay (load-collections-xref))])
(lambda ()
(let-values ([(path anchor)
(xref-tag->path+anchor
(force xref)
(list 'part (list (module-path-prefix->string mod-path) tag)))])
(if path
(let ([u (path->url path)])
(send-url (url->string u)))
(error 'show-scribbling "cannot find docs for: ~e ~e" mod-path tag))))))

View File

@ -1,46 +0,0 @@
** To play Spider, run the "PLT Games" application.
Spider is a solitaire card game played with 104 cards. The cards can
include either a single suit, two suits, or four suites. (Choose your
variant through the "Options" item in the "Edit" menu.)
Terminology:
* Tableau: one of the ten stacks of cards in the play area. The game
starts with six cards in the first four tableaus, and five cards in
the rest; only the topmost card is face up, and others are revealed
when they become the topmost card of the tableau.
* Sequence: a group of cards on the top of a tableau that are in the
same suit, and that are in sequence, with the lowest numbered card
topmost (i.e., closer to the bottom of the screen). King is high
and ace is low.
The object of the game is to create a sequence with ace through king,
at which point the sequence is removed from play. Create eight such
sequences to win the game.
On each move, you can either:
* Move a sequence from any tableau to one whose topmost card (i.e.,
closest to the bottom of the screen) has a value that's one more
than the sequence's value. Note that if the top card of the target
tableau has the same suit as the sequence, a larger sequence is
formed, but the target tableau's card is not required to have the
same suit.
* Move a sequence to an empty tableau.
* Deal ten cards from the deck (in the upper left corder), one to
each tableau. This move is allowed only if no tableau is empty.
To move a sequence, either drag it to the target tableau, or click the
sequence and then click the top card of the target tableau (or the
place where a single card would be for an empty tableau). Click a
select card to de-select it. Clicking a card that is not a valid
target for the currently selected sequence causes the clicked card's
sequence to be selected (if the card is face up in a sequence).
To deal, click the deck.
To undo a move, use "Undo" from the "Edit" menu.

View File

@ -1,7 +1,7 @@
#lang mzscheme
(require games/cards mred mzlib/class mzlib/list mzlib/file mzlib/unit
"../show-help.ss")
"../show-scribbling.ss")
(define (list-first-n l n)
(if (zero? n)
@ -131,7 +131,8 @@
(send d center)
(send d show #t))])
(define help (show-help '("games" "spider") "Spider Rules" #f))
(define help (show-scribbling '(lib "games/scribblings/games.scrbl")
"spider"))
(new menu-item%
[label "&Rules"]
[parent (make-object menu% "&Help" mb)]

View File

@ -758,7 +758,7 @@
`((a ((name ,(url-anchor-name style)))
,@(super render-element e part ri)))]
[(image-file? style)
(let* ([src (image-file-path style)]
(let* ([src (main-collects-relative->path (image-file-path style))]
[scale (image-file-scale style)]
[sz (if (= 1.0 scale)
null
@ -776,7 +776,7 @@
`((width ,(to-num w))
(height ,(to-num h))))
null))))])
`((img ((src ,(install-file src)) ,@sz))))]
`((img ((src ,(install-file src))) ,@sz)))]
[else (super render-element e part ri)])))
(define/override (render-table t part ri need-inline?)

View File

@ -4,6 +4,7 @@
mzlib/class
scheme/runtime-path
scheme/port
setup/main-collects
(for-syntax scheme/base))
(provide render-mixin)
@ -162,7 +163,9 @@
(/ (cadddr style) 255.0))))
#f)]
[(image-file? style)
(let ([fn (install-file (image-file-path style))])
(let ([fn (install-file
(main-collects-relative->path
(image-file-path style)))])
(printf "\\includegraphics[scale=~a]{~a}" (image-file-scale style) fn))]
[else (super render-element e part ri)])))
(when part-label?

View File

@ -174,7 +174,9 @@
[target-url ([addr (or/c string? path?)][style any/c])]
[url-anchor ([name string?])]
[image-file ([path path-string?]
[image-file ([path (or/c path-string?
(cons/c (one-of/c 'collects)
(listof bytes?)))]
[scale real?])])
;; ----------------------------------------

View File

@ -64,16 +64,19 @@
;; resulting html
(define (xref-render xrefs doc dest-file
#:render% [render% (html:render-mixin render%)])
(let* ([dest-file (if (string? dest-file) (string->path dest-file) dest-file)]
[renderer (new render% [dest-dir (and dest-file (path-only dest-file))]
[css-path 'inline])]
[ci (send renderer collect (list doc) (list dest-file))]
[_ (send renderer transfer-info ci (resolve-info-ci (xrefs-ri xrefs)))]
[ri (send renderer resolve (list doc) (list dest-file) ci)]
[xs (send renderer render (list doc) (list dest-file) ri)])
(if dest-file
(void)
(car xs))))
;; In case rendering writes a file (like an image file), which to the
;; temp directory:
(parameterize ([current-directory (find-system-path 'temp-dir)])
(let* ([dest-file (if (string? dest-file) (string->path dest-file) dest-file)]
[renderer (new render% [dest-dir (and dest-file (path-only dest-file))]
[css-path 'inline])]
[ci (send renderer collect (list doc) (list dest-file))]
[_ (send renderer transfer-info ci (resolve-info-ci (xrefs-ri xrefs)))]
[ri (send renderer resolve (list doc) (list dest-file) ci)]
[xs (send renderer render (list doc) (list dest-file) ri)])
(if dest-file
(void)
(car xs)))))
;; Returns (values <tag-or-#f> <form?>)
(define xref-binding-tag