15. 赋予明暗
在许多冒险中,灯是一个重要的物品。没有它,你就无法穿越前方的黑暗洞穴。
在黑暗中的效果因游戏而异。通常情况下,它使命令 "look" 没有效果。在一些游戏中(如 Zork),黑暗是致命的。在其他游戏中,只要你画出了黑暗区域的详细地图,在没有光源的情况下,你仍然可以取得进展。
我们的游戏将保持在这两者之间;在黑暗中不会让你被杀,但你也不能进入任何通道 (具有光亮的通道将是一个例外)。对我们来说,让玩家跑进一个黑暗的区域,而没有不让他机会回到他来的地方,似乎是不公平的。
好吧,所以首先,我们来设计在黑暗中玩家无法看到周围环境。
location.c
#include <stdbool.h>
#include <stdio.h>
#include "object.h"
#include "misc.h"
#include "match.h"
#include "noun.h"
bool executeLookAround(void)
{
if (isLit(player->location))
{
printf("You are in %s.\n", player->location->description);
}
else
{
printf("It is very dark in here.\n");
}
listObjectsAtLocation(player->location);
return true;
}
bool executeLook(void)
{
OBJECT *obj = getVisible("what you want to look at", params[0]);
switch (getDistance(player, obj))
{
case distHereContained:
printf("Hard to see, try to get it first.\n");
break;
case distOverthere:
printf("Too far away, move closer please.\n");
break;
case distNotHere:
printf("You don't see any %s here.\n", params[0]);
break;
case distUnknownObject:
// already handled by getVisible
break;
default:
printf("%s\n", obj->details);
listObjectsAtLocation(obj);
}
return true;
}
static void movePlayer(OBJECT *passage)
{
printf("%s\n", passage->textGo);
if (passage->destination != NULL)
{
player->location = passage->destination;
printf("\n");
executeLookAround();
}
}
bool executeGo(void)
{
OBJECT *obj = getVisible("where you want to go", params[0]);
switch (getDistance(player, obj))
{
case distOverthere:
movePlayer(getPassage(player->location, obj));
break;
case distNotHere:
printf("You don't see any %s here.\n", params[0]);
break;
case distUnknownObject:
// already handled by getVisible
break;
default:
movePlayer(obj);
}
return true;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
其次,在黑暗中玩家无法看到或使用附近的物体。
noun.c
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "object.h"
#include "misc.h"
static bool objectHasTag(OBJECT *obj, const char *noun)
{
if (noun != NULL && *noun != '\0')
{
const char **tag;
for (tag = obj->tags; *tag != NULL; tag++)
{
if (strcmp(*tag, noun) == 0) return true;
}
}
return false;
}
static OBJECT ambiguousNoun;
static OBJECT *getObject(const char *noun, OBJECT *from, DISTANCE maxDistance)
{
OBJECT *obj, *res = NULL;
for (obj = objs; obj < endOfObjs; obj++)
{
if (objectHasTag(obj, noun) && getDistance(from, obj) <= maxDistance)
{
res = res == NULL ? obj : &ambiguousNoun;
}
}
return res;
}
OBJECT *getVisible(const char *intention, const char *noun)
{
OBJECT *obj = getObject(noun, player, distOverthere);
if (obj == NULL)
{
if (getObject(noun, player, distNotHere) == NULL)
{
printf("I don't understand %s.\n", intention);
}
else if (isLit(player->location))
{
printf("You don't see any %s here.\n", noun);
}
else
{
printf("It's too dark.\n");
}
}
else if (obj == &ambiguousNoun)
{
printf("Please be specific about which %s you mean.\n", noun);
obj = NULL;
}
return obj;
}
OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun)
{
OBJECT *obj = NULL;
if (from == NULL)
{
printf("I don't understand who you want to %s.\n", verb);
}
else if ((obj = getObject(noun, from, distHeldContained)) == NULL)
{
if (getObject(noun, player, distNotHere) == NULL)
{
printf("I don't understand what you want to %s.\n", verb);
}
else if (from == player)
{
printf("You are not holding any %s.\n", noun);
}
else
{
printf("There appears to be no %s you can get from %s.\n",
noun, from->description);
}
}
else if (obj == &ambiguousNoun)
{
printf("Please be specific about which %s you want to %s.\n",
noun, verb);
obj = NULL;
}
else if (obj == from)
{
printf("You should not be doing that to %s.\n", obj->description);
obj = NULL;
}
return obj;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
在这两种情况下,我们都使用了一个函数 isLit。它在 misc.c 中被定义(并且使用量增多了)。
misc.h
typedef enum {
distSelf,
distHeld,
distHeldContained,
distLocation,
distHere,
distHereContained,
distOverthere,
distNotHere,
distUnknownObject
} DISTANCE;
extern bool isHolding(OBJECT *container, OBJECT *obj);
extern bool isLit(OBJECT *location);
extern OBJECT *getPassage(OBJECT *from, OBJECT *to);
extern DISTANCE getDistance(OBJECT *from, OBJECT *to);
extern OBJECT *actorHere(void);
extern int listObjectsAtLocation(OBJECT *location);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
misc.c
#include <stdbool.h>
#include <stdio.h>
#include "object.h"
#include "misc.h"
bool isHolding(OBJECT *container, OBJECT *obj)
{
return validObject(obj) && obj->location == container;
}
bool isLit(OBJECT *target)
//检测光亮
{
OBJECT *obj;
if (validObject(target))
{
if (target->light > 0)
{
return true;
}
for (obj = objs; obj < endOfObjs; obj++)
{
if (validObject(obj) && obj->light > 0 &&
(isHolding(target, obj) || isHolding(target, obj->location)))
{
return true;
}
}
}
return false;
}
static bool isNoticeable(OBJECT *obj)
{
return obj->location == player ||
isLit(obj) || isLit(obj->prospect) || isLit(player->location);
}
OBJECT *getPassage(OBJECT *from, OBJECT *to)
{
if (from != NULL && to != NULL)
{
OBJECT *obj;
for (obj = objs; obj < endOfObjs; obj++)
{
if (isHolding(from, obj) && obj->prospect == to)
{
return obj;
}
}
}
return NULL;
}
DISTANCE getDistance(OBJECT *from, OBJECT *to)
{
return to == NULL ? distUnknownObject :
!validObject(to) ? distNotHere :
to == from ? distSelf :
isHolding(from, to) ? distHeld :
!isNoticeable(to) ? distNotHere :
isHolding(to, from) ? distLocation :
isHolding(from->location, to) ? distHere :
isHolding(from, to->location) ? distHeldContained :
isHolding(from->location, to->location) ? distHereContained :
getPassage(from->location, to) != NULL ? distOverthere :
distNotHere;
}
OBJECT *actorHere(void)
{
OBJECT *obj;
for (obj = objs; obj < endOfObjs; obj++)
{
if (isHolding(player->location, obj) && obj != player &&
isNoticeable(obj) && obj->health > 0)
{
return obj;
}
}
return NULL;
}
int listObjectsAtLocation(OBJECT *location)
{
int count = 0;
OBJECT *obj;
for (obj = objs; obj < endOfObjs; obj++)
{
if (obj != player && isHolding(location, obj) && isNoticeable(obj))
{
if (count++ == 0)
{
printf("%s:\n", location->contents);
}
printf("%s\n", obj->description);
}
}
return count;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
注意:
- isLit 将被用来检查一个给定的位置是亮还是暗,但是,仅仅检查位置的属性光线是不够的,因为位置可能被一盏灯照亮。
- isNoticeable 函数相比 isLit 更进一步。它对每个物体都有效,而不仅仅是地点和灯。它还考虑到玩家库存中的物体总是可以被使用,即使是在黑暗中。
- 第 60 行:附近的物体仍然隐藏在黑暗中,被视为 ' 不在这里 '。这自然可以防止游戏泄露玩家不应该知道的物体的信息。
🤔 思考题:你还能想到那哪些可以改进的地方吗?
我们为实现 isLit 函数的功能从而使用了一个新的属性 light。
object.awk
BEGIN {
count = 0;
obj = "";
if (pass == "c2") {
print "\nstatic bool alwaysTrue(void) { return true; }";
print "\nOBJECT objs[] = {";
}
}
/^- / {
outputRecord(",");
obj = $2;
prop["condition"] = "alwaysTrue";
prop["description"] = "NULL";
prop["tags"] = "";
prop["location"] = "NULL";
prop["destination"] = "NULL";
prop["prospect"] = "";
prop["details"] = "\"You see nothing special.\"";
prop["contents"] = "\"You see\"";
prop["textGo"] = "\"You can't get much closer than this.\"";
prop["weight"] = "99";
prop["capacity"] = "0";
prop["health"] = "0";
prop["light"] = "0";
prop["open"] = "cannotBeOpened";
prop["close"] = "cannotBeClosed";
prop["lock"] = "cannotBeLocked";
prop["unlock"] = "cannotBeUnlocked";
}
obj && /^[ \t]+[a-z]/ {
name = $1;
$1 = "";
if (name in prop) {
prop[name] = $0;
if (/^[ \t]*\{/) {
prop[name] = name count;
if (pass == "c1") print "static bool " prop[name] "(void) " $0;
}
}
else if (pass == "c2") {
print "#error \"" FILENAME " line " NR ": unknown attribute '" name "'\"";
}
}
!obj && pass == (/^#include/ ? "c1" : "h") {
print;
}
END {
outputRecord("\n};");
if (pass == "h") {
print "\n#define endOfObjs\t(objs + " count ")";
print "\n#define validObject(obj)\t" \
"((obj) != NULL && (*(obj)->condition)())";
}
}
function outputRecord(separator)
{
if (obj) {
if (pass == "h") {
print "#define " obj "\t(objs + " count ")";
}
else if (pass == "c1") {
print "static const char *tags" count "[] = {" prop["tags"] ", NULL};";
}
else if (pass == "c2") {
print "\t{\t/* " count " = " obj " */";
print "\t\t" prop["condition"] ",";
print "\t\t" prop["description"] ",";
print "\t\ttags" count ",";
print "\t\t" prop["location"] ",";
print "\t\t" prop["destination"] ",";
print "\t\t" prop[prop["prospect"] ? "prospect" : "destination"] ",";
print "\t\t" prop["details"] ",";
print "\t\t" prop["contents"] ",";
print "\t\t" prop["textGo"] ",";
print "\t\t" prop["weight"] ",";
print "\t\t" prop["capacity"] ",";
print "\t\t" prop["health"] ",";
print "\t\t" prop["light"] ",";
print "\t\t" prop["open"] ",";
print "\t\t" prop["close"] ",";
print "\t\t" prop["lock"] ",";
print "\t\t" prop["unlock"];
print "\t}" separator;
delete prop;
}
count++;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
默认情况下,亮度为零意味着一个物体不发光。在大白天的每一个地点(通常是除了地下的所有地点)都会被赋予一个正 (大于 0) 的光线值。其实是什么值并不重要,只要它不是零就可以了。我们还将添加一盏灯,玩家可以携带它来穿越黑暗区域。
object.txt
#include <stdbool.h>
#include <stdio.h>
#include "object.h"
#include "toggle.h"
typedef struct object {
bool (*condition)(void);
const char *description;
const char **tags;
struct object *location;
struct object *destination;
struct object *prospect;
const char *details;
const char *contents;
const char *textGo;
int weight;
int capacity;
int health;
int light;
void (*open)(void);
void (*close)(void);
void (*lock)(void);
void (*unlock)(void);
} OBJECT;
extern OBJECT objs[];
- field
description "an open field"
tags "field"
details "The field is a nice and quiet place under a clear blue sky."
capacity 9999
light 100
//到目前为止,场地是唯一有 "自然 "光线的地方。
- cave
description "a little cave"
tags "cave"
details "The cave is just a cold, damp, rocky chamber."
capacity 9999
- silver
description "a silver coin"
tags "silver", "coin", "silver coin"
location field
details "The coin has an eagle on the obverse."
weight 1
- gold
description "a gold coin"
tags "gold", "coin", "gold coin"
location openBox
details "The shiny coin seems to be a rare and priceless artefact."
weight 1
- guard
description "a burly guard"
tags "guard", "burly guard"
location field
details "The guard is a really big fellow."
contents "He has"
health 100
capacity 20
- player
description "yourself"
tags "yourself"
location field
details "You would need a mirror to look at yourself."
contents "You have"
health 100
capacity 20
- intoCave
condition { return guard->health == 0 || silver->location == guard; }
description "a cave entrance to the east"
tags "east", "entrance"
location field
destination cave
details "The entrance is just a narrow opening in a small outcrop."
textGo "You walk into the cave."
open isAlreadyOpen
- intoCaveBlocked
condition { return guard->health > 0 && silver->location != guard; }
description "a cave entrance to the east"
tags "east", "entrance"
location field
prospect cave
details "The entrance is just a narrow opening in a small outcrop."
textGo "The guard stops you from walking into the cave."
open isAlreadyOpen
- exitCave
description "an exit to the west"
tags "west", "exit"
location cave
destination field
details "Sunlight pours in through an opening in the cave's wall."
textGo "You walk out of the cave."
open isAlreadyOpen
- wallField
description "dense forest all around"
tags "west", "north", "south", "forest"
location field
details "The field is surrounded by trees and undergrowth."
textGo "Dense forest is blocking the way."
- wallCave
description "solid rock all around"
tags "east", "north", "rock"
location cave
details "Carved in stone is a secret password 'abccb'."
textGo "Solid rock is blocking the way."
- backroom
description "a backroom"
tags "backroom"
details "The room is dusty and messy."
capacity 9999
- wallBackroom
description "solid rock all around"
tags "east", "west", "south", "rock"
location backroom
details "Trendy wallpaper covers the rock walls."
textGo "Solid rock is blocking the way."
- openDoorToBackroom
description "an open door to the south"
tags "south", "door", "doorway"
destination backroom
details "The door is open."
textGo "You walk through the door into a backroom."
open isAlreadyOpen
close toggleDoorToBackroom
- closedDoorToBackroom
description "a closed door to the south"
tags "south", "door", "doorway"
location cave
prospect backroom
details "The door is closed."
textGo "The door is closed."
open toggleDoorToBackroom
close isAlreadyClosed
- openDoorToCave
description "an open door to the north"
tags "north", "door", "doorway"
destination cave
details "The door is open."
textGo "You walk through the door into the cave."
open isAlreadyOpen
close toggleDoorToCave
- closedDoorToCave
description "a closed door to the north"
tags "north", "door", "doorway"
location backroom
prospect cave
details "The door is closed."
textGo "The door is closed."
open toggleDoorToCave
close isAlreadyClosed
- openBox
description "a wooden box"
tags "box", "wooden box"
details "The box is open."
weight 5
capacity 10
open isAlreadyOpen
close toggleBox
lock isStillOpen
unlock isAlreadyOpen
- closedBox
description "a wooden box"
tags "box", "wooden box"
details "The box is closed."
weight 5
open toggleBox
close isAlreadyClosed
lock toggleBoxLock
unlock isAlreadyUnlocked
- lockedBox
description "a wooden box"
tags "box", "wooden box"
location backroom
details "The box is closed."
weight 5
open isStillLocked
close isAlreadyClosed
lock isAlreadyLocked
unlock toggleBoxLock
- keyForBox
description "a tiny key"
tags "key", "tiny key"
location cave
details "The key is really small and shiny."
weight 1
- lampOff
description "a lamp"
tags "lamp"
location field
details "The lamp is off."
weight 5
- lampOn
description "a lamp"
tags "lamp"
details "The lamp is on."
weight 5
light 100
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
注意:对于灯,我们实际上有两个对象:打开的灯和关闭的灯,但玩家一次只能看到一个。它们一起作为一个单一的项目。
我们将添加一些命令,我们可以用来打开和关闭灯。
parsexec.c
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include "object.h"
#include "misc.h"
#include "match.h"
#include "location.h"
#include "inventory.h"
#include "inventory2.h"
#include "openclose.h"
#include "onoff.h"
typedef struct
{
const char *pattern;
bool (*function)(void);
} COMMAND;
static bool executeQuit(void)
{
return false;
}
static bool executeNoMatch(void)
{
const char *src = *params;
int len;
for (len = 0; src[len] != '\0' && !isspace(src[len]); len++);
if (len > 0) printf("I don't know how to '%.*s'.\n", len, src);
return true;
}
bool parseAndExecute(const char *input)
{
static const COMMAND commands[] =
{
{ "quit" , executeQuit },
{ "look" , executeLookAround },
{ "look around" , executeLookAround },
{ "look at A" , executeLook },
{ "look A" , executeLook },
{ "examine A" , executeLook },
{ "go to A" , executeGo },
{ "go A" , executeGo },
{ "get A from B" , executeGetFrom },
{ "get A" , executeGet },
{ "put A in B" , executePutIn },
{ "drop A in B" , executePutIn },
{ "drop A" , executeDrop },
{ "ask A from B" , executeAskFrom },
{ "ask A" , executeAsk },
{ "give A to B" , executeGiveTo },
{ "give A" , executeGive },
{ "inventory" , executeInventory },
{ "open A" , executeOpen },
{ "close A" , executeClose },
{ "lock A" , executeLock },
{ "unlock A" , executeUnlock },
{ "turn on A" , executeTurnOn },
{ "turn off A" , executeTurnOff },
{ "turn A on" , executeTurnOn },
{ "turn A off" , executeTurnOff },
{ "A" , executeNoMatch }
};
const COMMAND *cmd;
for (cmd = commands; !matchCommand(input, cmd->pattern); cmd++);
return (*cmd->function)();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
下面是这些命令的实现。
onoff.h
extern bool executeTurnOn(void);
extern bool executeTurnOff(void);
2
onoff.c
#include <stdbool.h>
#include <stdio.h>
#include "object.h"
#include "match.h"
#include "reach.h"
#include "toggle.h"
bool executeTurnOn(void)
{
OBJECT *obj = reachableObject("what you want to turn on", params[0]);
if (obj != NULL)
{
if (obj == lampOff)
{
toggleLamp();
}
else
{
printf(obj == lampOn ? "The lamp is already on.\n"
: "You cannot turn that on.\n");
}
}
return true;
}
bool executeTurnOff(void)
{
OBJECT *obj = reachableObject("what you want to turn off", params[0]);
if (obj != NULL)
{
if (obj == lampOn)
{
toggleLamp();
}
else
{
printf(obj == lampOff ? "The lamp is already off.\n"
: "You cannot turn that off.\n");
}
}
return true;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
为了打开和关闭灯,我们将使用我们用来打开和关闭门和盒子的相同技巧(见第 13 章)。
toggle.h
extern void cannotBeOpened(void);
extern void cannotBeClosed(void);
extern void cannotBeLocked(void);
extern void cannotBeUnlocked(void);
extern void isAlreadyOpen(void);
extern void isAlreadyClosed(void);
extern void isAlreadyLocked(void);
extern void isAlreadyUnlocked(void);
extern void isStillOpen(void);
extern void isStillLocked(void);
extern void toggleDoorToBackroom(void);
extern void toggleDoorToCave(void);
extern void toggleBox(void);
extern void toggleBoxLock(void);
extern void toggleLamp(void);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
toggle.c
#include <stdbool.h>
#include <stdio.h>
#include "object.h"
#include "misc.h"
#include "location.h"
static void swapLocations(const char *verb1, OBJECT *obj1,
const char *verb2, OBJECT *obj2)
{
OBJECT *tmp = obj1->location;
OBJECT *obj = tmp != NULL ? obj1 : obj2;
const char *verb = tmp != NULL ? verb1 : verb2;
obj1->location = obj2->location;
obj2->location = tmp;
if (verb != NULL) printf("You %s %s.\n", verb, obj->description);
}
void cannotBeOpened(void) { printf("That cannot be opened.\n"); }
void cannotBeClosed(void) { printf("That cannot be closed.\n"); }
void cannotBeLocked(void) { printf("That cannot be locked.\n"); }
void cannotBeUnlocked(void) { printf("That cannot be unlocked.\n"); }
void isAlreadyOpen(void) { printf("That is already open.\n"); }
void isAlreadyClosed(void) { printf("That is already closed.\n"); }
void isAlreadyLocked(void) { printf("That is already locked.\n"); }
void isAlreadyUnlocked(void) { printf("That is already unlocked.\n"); }
void isStillOpen(void) { printf("That is still open.\n"); }
void isStillLocked(void) { printf("That is locked.\n"); }
void toggleDoorToBackroom(void)
{
swapLocations(NULL, openDoorToCave, NULL, closedDoorToCave);
swapLocations("close", openDoorToBackroom, "open", closedDoorToBackroom);
}
void toggleDoorToCave(void)
{
swapLocations(NULL, openDoorToBackroom, NULL, closedDoorToBackroom);
swapLocations("close", openDoorToCave, "open", closedDoorToCave);
}
void toggleBox(void)
{
swapLocations("close", openBox, "open", closedBox);
}
void toggleBoxLock(void)
{
if (keyForBox->location == player)
{
swapLocations("lock", closedBox, "unlock", lockedBox);
}
else
{
printf("You don't have a key.\n");
}
}
void toggleLamp(void)
{
bool oldLit = isLit(player->location);
swapLocations("turn off", lampOn, "turn on", lampOff);
if (oldLit != isLit(player->location))
{
printf("\n");
executeLookAround();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
注意:当在黑暗区域打开灯光时,我们立即让玩家看一下周围的环境。这与 'go' 的命令的行为是一致的:当你把目光投向一个地方时,'look' 就会自动执行。
你可能注意到我们在这里做了同样的事情,当把灯关掉的时候,很明显,这只会返回 "这里很黑",但这似乎也是一个相关的观察。
那么,既然我们无论如何都在做 "look around" 的工作,64~68 中 "if" 语句的意义何在?好吧,这可以防止在大白天(即在野外)打开或关闭灯时,或在同一房间内任何其他光源仍在工作时,进行无用的 "环顾"。
最后,我们将在我们生成的地图上标记出黑暗的位置。
map.awk
BEGIN { print "digraph map {\n\tnode [style=filled]"; }
/^- / { outputEdges(); obj = $2; delete a; }
/^[ \t]/ { a[$1] = $2; }
END { outputEdges(); outputNodes(); print "}"; }
function outputEdges()
{
color[obj] = a["light"] ? "white" : "grey";
outputEdge(a["location"], a["destination"], "");
outputEdge(a["location"], a["prospect"], " [style=dashed]");
}
function outputEdge(from, to, style)
{
if (to)
{
nodes[to] = 1;
if (from)
{
nodes[from] = 1;
print "\t" from " -> " to style;
}
}
}
function outputNodes()
{
for (n in nodes) print "\t" n " [fillcolor=" color[n] "]";
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
🤔 思考题:尝试将上面的伪代码用 C 语言实现其功能
玩家们,请注意不要把灯关掉,也不要把它丢掉。如果这样做,那么在黑暗中你将永远无法找回它。换言之,你会被困在黑暗之中!幸运的是,下一章将提供一个撤销笨拙行动的方法。
输出样例:Welcome to Little Cave Adventure. You are in an open field. You see: a silver coin a burly guard a cave entrance to the east dense forestall around a lamp
--> get lamp You pick up a lamp.
--> get coin You pick up a silver coin.
--> give coin You give a silver coin to a burly guard.
--> go cave You walk into the cave.
It is very dark here. You see: an exit to the west
--> get key It's too dark.
--> open door It's too dark.
--> go south It's too dark.
--> turn lamp on You turn on a lamp.
You are in a little cave. You see: an exit to the west solid rock all around a closed door to the south a tiny key
--> look around You are in a little cave. You see: an exit to the west solid rock all around a closed door to the south a tiny key
--> get key You pick up a tiny key.
--> open door You open a closed door to the south.
--> go south You walk through the door into a backroom.
You are in a backroom. You see: solid rock all around an open door to the north a wooden box
--> quit
Bye