1
! -------------------------------------------------------------------------
2
! Adaptive Hints for Inform
3
! (c) 1995 Michael S. Phillips
4
! -------------------------------------------------------------------------
5
! Hints Library: Mar 25, 1996
6
! Adaptive Hints library, release 0.92a (960325)
7
! -------------------------------------------------------------------------
8
! This module is (c) 1996 Michael S. Phillips, but it is freely usable.
9
! The author may be reached at: mike@lawlib.wm.edu as of this release.
10
! -------------------------------------------------------------------------
12
! -------------------------------------------------------------------------
13
! A note about customizing the behavior of the hints system:
14
! A large number of '#ifdef xxx;' '#endif;' pairs are in the file, in
15
! order for the author using this hints system to be able to dictate the
16
! exact behavior of the hints system.
17
! Ideally, the definition of these variables would be done by the
18
! declaration of an appropriate Constant (e.g. 'Constant GIVEHINTSONCE;')
19
! before including AdHints.h into the game. This way, the library can be
20
! swapped if upgraded in such a manner that it does not require editing
21
! in order to preserve the desired behavior. Each meaningful definition
22
! (and its effect) is detailed below.
23
! -------------------------------------------------------------------------
24
! GIVEHINTSONCE: If defined, this will cause a set of hints to be given by
25
! the 'HINT' command once AND ONLY ONCE, and only the first time.
26
! Otherwise, the hint(s) will disappear and need to be viewed with
27
! 'REVIEW'. This is not particularly kind behavior, but it does match
28
! the behavior of adhint.t for TADS. If this and NOHINTREVIEW are both
29
! defined, then a given set of hints will appear ONE TIME ONLY and be
30
! utterly unretrievable afterwards.
31
!Constant GIVEHINTSONCE;
32
! -------------------------------------------------------------------------
33
! NOHINTREVIEW: If defined, this disables the 'REVIEW' command. Note that
34
! this only disables the grammar for 'REVIEW', and that ReviewSub() can
35
! still be called by the game if the author so desires (for instance, after
37
!Constant NOHINTREVIEW;
38
! -------------------------------------------------------------------------
39
! REVIEWGIVENONLY: If defined, this causes ONLY those hints which were
40
! actually given to be shown by the 'REVIEW' command.
41
!Constant REVIEWGIVENONLY;
42
! -------------------------------------------------------------------------
43
! SHOWSOLVEDTAG: If defined, the string '(solved)' will appear after each
44
! puzzle when 'REVIEW'ing hints if the puzzle has been solved.
45
!Constant SHOWSOLVEDTAG;
46
! -------------------------------------------------------------------------
47
! HINTDEBUG: If defined, this will give extra internal information about
48
! what is going on at certain key points of the hints code. You probably
49
! don't want to define this unless you're debugging this particular file.
51
! -------------------------------------------------------------------------
52
! HINTDEBUGVERBS: If defined, this allows the various hint debugging verbs
53
! (allhints, allpuzzles) to be used. If HINTDEBUG is defined, these will
55
!Constant HINTDEBUGVERBS;
56
! -------------------------------------------------------------------------
59
#ifndef HINTDEBUGVERBS;
60
Constant HINTDEBUGVERBS;
64
Attribute given alias visited;
65
Attribute solved alias open;
66
Attribute in_menu alias locked;
69
Property additive the_hints;
71
Global AH_hints_available = 1;
73
Global AH_num_pages = 0;
74
Global AH_current_page = 0;
75
Global AH_hints_per_page = 0;
77
! First, we define the 'hint' class
78
! When constructing a hint, make certain that it 'does the right thing' and
79
! is declared as such a class for appropriate defaults.
80
! A hint will have the 'general' attribute set if it is available, and the
81
! 'given' attribute (which is aliased to 'visited') if the hint has been
82
! used. Only if it is 'given' or 'solved' (which is aliased to 'open') will
83
! it appear with the REVIEW command.
89
Object Hints "hints" !selfobj
93
! If you need an AfterPrompt() routine yourself, then call it AfterPrompt2,
94
! and this will automatically call it after updating the hints.
102
! Okay, a meta-routine which is passed a hint object (well, hopefully :-) )
103
! and cycles through the hints.
104
[ AH_ShowHints hintobj i j k die_now hint_number;
108
print "^Hints for: ", (name) hintobj, "^";
110
i = hintobj.#the_hints / 2;
117
print "(Press Q to quit receiving hints, or any other key to continue)^";
119
while (j <= i && die_now==0) {
120
print "^^(", j, "/", i, ") ";
121
print_paddr (hintobj.&the_hints)-->(j-1);
125
if (k=='Q' or 'q') die_now = 1;
133
if (die_now == 1) return 2;
139
! Okay, another meta routine, this one blips through all the hints and
140
! calls the hint_check routine for all of them, to reset the solved and
141
! available flags. Note that once the puzzle is solved, it is no longer
142
! run (to speed things up).
143
[ AH_UpdateHints i j;
145
objectloop (i in Hints) {
147
print "Running hint_check for: ", (name) i, "^";
149
if (i hasnt solved) {
150
j = ZRegion(i.hint_check); ! only run if hint_check routine
151
if (j==2) PrintOrRun(i,hint_check,2); ! exists for hint i
153
if (i has solved) give i ~general;
157
! Okay, some debugging routines (useful stuff for me, but useless for most
158
! other people, I suspect).
159
#ifdef HINTDEBUGVERBS;
161
print "All Puzzles with Hints:^";
162
objectloop (i in Hints) {
164
#ifdef SHOWSOLVEDTAG;
165
if (i has solved) print " (solved)";
173
objectloop (i in Hints) {
179
objectloop (i in Hints) {
188
! General use function -- calculates the width of a string
189
Array width_calc table 64;
190
[ AH_CalcWidth s i j;
191
i = 0->33; if (i==0) i = 80;
192
@output_stream 3 width_calc;
195
j = (width_calc-->0)/2;
199
! Menu support routine for HintSub
202
[ AH_HintPrint i count start stop;
203
print "Hints Available:^";
205
if (pretty_flag == 0) {
206
objectloop(i in Hints) {
209
if (count < 10) { print "^ (", count, ") "; }
210
else print "^ (", count, ") ";
212
#ifdef SHOWSOLVEDTAG;
213
if (i has solved) print " (solved)";
219
start = AH_hints_per_page * (AH_current_page - 1);
220
stop = start + AH_hints_per_page;
221
if (AH_current_page > 1) print "^ (previous page)";
222
objectloop(i in Hints) {
225
if (count > start && count <= stop) {
226
print "^ ", (name) i;
227
#ifdef SHOWSOLVEDTAG;
228
if (i has solved) print " (solved)";
230
} ! start < count <= stop
233
if (AH_current_page < AH_num_pages) print "^ (next page)";
237
! return titles, widths, and stuff
238
[ AH_HintInfo i j count target;
241
if (pretty_flag == 0) {
242
objectloop(i in Hints) {
245
if (count == menu_item) j = i;
250
if (AH_current_page == 1) { target = menu_item; }
251
else {target = ((AH_current_page - 1)*AH_hints_per_page) + menu_item;}
252
objectloop (i in Hints) {
255
if (count == target) j = i;
258
! take care of setting count for paging
259
if (AH_current_page == 1 && AH_num_pages ~= 1)
260
{ count = AH_hints_per_page + 1; }
262
if (AH_current_page == AH_num_pages && AH_num_pages ~= 1)
263
{ count = count - ((AH_num_pages-1)*AH_hints_per_page) + 1; }
265
if (AH_current_page == 1 && AH_num_pages == 1)
266
{ count = count; } ! null assignment
267
else { count = AH_hints_per_page + 2; }
269
} ! convoluted elseif
272
if (menu_item == 0) {
274
item_width = AH_CalcWidth(item_name);
278
item_name = j.short_name;
279
item_width = AH_CalcWidth(j.short_name);
283
! call appropriate routine for menu
284
[ AH_HintMenu i j count target;
286
if (pretty_flag == 0) {
287
objectloop (i in Hints) {
290
if (count == menu_item) j = i;
295
! take care of special cases first:
296
if (AH_current_page == 1) {
297
if (menu_item == (AH_hints_per_page + 1)) {
300
return 2; ! redraw menu screen
304
if (menu_item == 1) {
307
return 2; ! redraw menu screen
309
if (menu_item == (AH_hints_per_page + 2)) {
312
return 2; ! redraw menu screen
316
if (AH_current_page == 1) { target = menu_item; }
318
target = ((AH_current_page - 1) * AH_hints_per_page)
319
+ menu_item - 1; ! account for (previous page) option
321
objectloop (i in Hints) {
324
if (count == target) j = i;
332
[ AH_CalcMenu i h count;
334
objectloop(i in Hints) {
335
if (i has in_menu) count++;
338
#ifdef HINTDEBUG_PAGING;
339
print "^height: ", h, "^";
342
h = h - 13; ! adjust for administrative headaches
343
AH_num_pages = (count / h) + 1;
344
AH_hints_per_page = h;
345
#ifdef HINTDEBUG_PAGING;
346
print "^num pages: ", AH_num_pages;
347
print "^hints per page: ", AH_hints_per_page, "^";
353
if (pretty_flag == 0) AH_num_pages = 1;
355
DoMenu(#r$AH_HintPrint, #r$AH_HintInfo, #r$AH_HintMenu);
358
! Okay, the way the HintSub works is like so:
359
! Check to make certain a hint is available and not yet solved.
360
! If not, exit with a comment to that effect.
361
! Find out how many puzzles are currently available and not already given
362
! If none are left, comment that no new hints are available, and past
363
! hints can be viewed using the REVIEW command.
364
! If more than one puzzle is available at this point, pass it off to a
366
! Otherwise, do the normal hint for the only available puzzle.
368
[ HintSub i j numpuz some_given;
373
print "Hints available:^";
374
objectloop (i in Hints) {
384
objectloop (i in Hints) { ! j = the first puzzle coming out
385
if (i has general) { ! of this loop
386
#ifdef GIVEHINTSONCE;
388
if (numpuz == 0) j = i;
393
if (numpuz == 0) j = i;
396
if (i has given || i has solved) some_given++;
401
if (some_given ~= 0) {
402
"No new hints are waiting. Try using REVIEW to look at the hints \
403
you have already seen.";
405
"You haven't found a puzzle yet to have a hint available!";
409
objectloop (i in Hints) {
411
#ifdef GIVEHINTSONCE;
415
print "Giving in_menu to puzzle: ", (name) i, "^";
418
#ifdef GIVEHINTSONCE;
424
objectloop (i in Hints) {
427
print "Removing in_menu from puzzle: ", (name) i, "^";
445
objectloop (i in Hints) {
446
#ifdef REVIEWGIVENONLY;
449
if (i has solved || i has given) {
452
print "Adding puzzle: ", (name) i, "^";
460
"No hints are available to be reviewed.";
464
objectloop (i in Hints) {
467
print "Removing in_menu from ", (name) i, "^";
476
! Disabling the hints system
478
if (AH_hints_available == 0)
479
"Hints are already disabled.";
480
AH_hints_available = 0;
481
"Hints are now disabled.";
485
if (AH_hints_available == 1)
486
"Hints are already on!";
487
"Hints cannot be re-enabled after being disabled.";
490
! And now we declare the grammar for HINT and REVIEW
492
#ifdef HINTDEBUGVERBS;
493
Verb "puzzles" "allpuzzles"
503
* "off" -> HintsOffSub
509
#ifndef NOHINTREVIEW;