1. (1) 代表 true
[初级 LPC: 运算式 - 条件运算式]
(2) str[1..6]
[初级 LPC: 字串变数基本操作 - 子字串操作]
(3) 此 mapping 变数尚未指定初值即被使用,会造成执行期错误。
解决方式可用 mapping m = ([]); 指定以指定初值,或是:
void create()
{
if(!m) m = ([ "id" : 10, ]);
else m["id"] = 10;
}
[初级 LPC: 变数操作 - 变数初始化]
[初级 LPC: 基本除错 - 可见错误讯息之执行期错误]
(4) 使用 nosave 修饰字,早期 MudOS 提供的修饰字是 static。
[初级 LPC: 修饰字 - 变数修饰字]
[中级 LPC: 物件属性 - 储存与读取]
注: Mon Oct 28 17:14:29 EST 1996 所诞生之 v22.1a8 (时间在 v22pre11 之前,
然而 v22pre 与 v22.1a 为不同步更新,无以下所提及之选项)于 options.h
中新增了 SENSIBLE_MODIFIERS 的选项,如果 #define 此选项,则不可储存之
变数修饰字由 static 改为 nosave,范围受保护之变数或函式修饰字由 static
变更为 protected。
2. (1) status, int, float, string, buffer, object, mapping, function, class,
mixed, array (包含前面各形式的 array,#define ARRAY_RESERVED_WORD 所编
译出来的 MudOS 提供 array 关键字,与 mixed * 同义)
[初级 LPC: LPC 基本资料型态]
(2) int, float, string, mapping, class 及其所组成之 array,mixed 为此
类型态时亦可。
[中级 LPC: 物件属性 - 可储存类型与不可储存类型]
(3) buffer、object 和 function。另外 mixed 存放的是可储存以外型态的型
态,则无法储存,如不可储存型态之 array,此外,mixed array 中有无
法储存之型态者,或 mapping 中的 key/value 含有其型态时,该位置在
储存时将被留空,下次读入时被设为常数零且未定义之值(称为 undefined
zero)。
[中级 LPC: 物件属性 - 可储存类型与不可储存类型]
(4) buffer 不可储存之原因主要为 MudOS 本身为 C 程式语言所撰写,而它在于
save_object/restore_object 上使用标准 C 字串,即字元阵列方式处理档
案内容,如 buffer 资料中含有 NULL 值,则会造成读取错误,故不得储存。
object 为一物件指标,指标类型的资料型态通常在物件摧毁后会被自动设定
为 undefined zero,当 MudOS shutdown 时物件即被摧毁,并没有储存的必
要,事实上在 MudOS 设计层面而言,它只是临时参考一个物件区块的位址,
记忆体位址在每次使用时并不可能一样,因此不能够储存。即使硬是设计成
可储存,如果该物件为复制物件,LPC 是不容许指定载入一复制物件的。
(此部分重点是 object 为「指标」型态,储存无意义。)
同 object 之叙述部分,function 型态事实上亦是参考一位址,没有储存的
意义。
[中级 LPC: driver 原理之观察与推断]
注: Sat Dec 11 21:43:08 CST 1993 所诞生之 v0.9.18.21 中于 options.h 增加
之 DISALLOW_BUFFER_TYPE 在被定义时,所产生出来的 MudOS 并无 buffer
型态,此外 Fri Mar 24 20:59:08 EST 1995 所诞生之 v21.2a6 及 v21.1b7
将 DISALLOW_BUFFER_TYPE 改名为 NO_BUFFER_TYPE。
Thu Oct 6 19:22:48 EDT 1994 时的 v20.13 中移除了 status 资料型态,可
藉由在 options.h 中 #define HAS_STATUS_TYPE 启用。
3. (1) mapping 和 class
[初级 LPC: 函式呼叫 - 隐含传参呼叫(implicit call by reference)]
(2) 以 copy() 这个 efun 复制一份资料后再传入,如 foo(copy(map_value));
其中 foo 为呼叫的函式, map_value 为一 mapping 变数。
[初级 LPC: 变数操作 - 变数参考关系的消除]
(3) void push_data(mapping info)
{
info = ([ "test" : 0 ]);
}
当 assignment operator 左边为传入值的本身(即 info ),则互相参考关系
消灭。若左边为 info["xxxx"] 这类子值,则参考关系不变,因此内容值亦
会一起改变。
[初级 LPC: 变数操作 - 变数参考关系的消除]
(4) void swap_value(int ref a, int ref b)
{
int c;
c = a;
a = b;
b = c;
}
[初级 LPC: 函式 - call by reference]
注: Thu Aug 3 20:25:27 EDT 1995 所诞生的 v21.6b3 中的 copy() 即支援
class 型态,Mon Dec 5 12:14:46 EST 1994 时出产的 v20.23 即支援
了此 efun。欲使用此 efun 必须在 options 中 #define PACKAGE_CONTRIB
,此选项预设为启用。
Mon Oct 28 17:14:29 EST 1996 的 v22.1a8 中增加了 call by reference
功能,当 options.h 中的 REF_RESERVED_WORD 被 #define 后,即可使用
此关键字,Wed Mar 4 04:57:16 EST 1998 的 v22.2a25 及 v22.2b21 中
如果在 options.h 里 #define COMPAT_32,则 ref 可用 & 符号代替。如
应考者使用 v22.1a8 之前的版本(v22pre11 及其以下亦符合)。
4. (1) load_object() 传回的为原始物件,new() 传回的则为复制物件。在最常见
的情形下,原始物件用 clonep() 测试会传回 0,复制物件为 1,然而当原
始物件为虚拟物件时,clonep() 有可能会传回 1,此处必须注意。
[初级 LPC: LPC OOP 理论 - 原始物件与复制物件]
(2) 不一定有关,虚拟物件可以由载入或复制该物件的函式命名物件名称。
[初级 LPC: LPC OOP 理论 - 物件名称与虚拟物件]
(3) 在 A 物件程式码中使用 B->func() 即可呼叫到原本 B 中的函式 func。
[初级 LPC: LPC OOP 理论 - 物件投影]
(4) 不会停止执行,此时物件中的资料区块已被摧毁,如果再继续使用的话会发
生执行期错误,因此最好在摧毁后直接 return 出去。
[初级 LPC: LPC OOP 理论 - 摧毁物件]
5. (1) 使用 bind 这个 efun 变换。
[初级 LPC: 变数操作 - 函式指标]
(2) evaluate(bind((: fetch_variable("var_name") :), B));
[初级 LPC: 变数操作 - 函式指标]
(3) $1 代表执行此函式指标时,传入的第一个引数会送到此位置。
如: evaluate((: find_object($1) :), "/obj/user");
[初级 LPC: LPC 运算式与述句 - 函式指标]
(4) local variable 要使用 $() 包住,以便在离开有效范围后保留其内容值,
答案为 (: func($(ob), $1) :)
[初级 LPC: LPC 运算式与述句 - 函式指标]
(5) 使用 if(functionp(f) & FP_OWNER_DESTED) 来测试即可。
[初级 LPC: 变数操作 - 函式指标]
6. (1) 使用 scope resolution operator 来呼叫,即在 A 中使用 ::func() 呼叫。
[初级 LPC: 物件继承 - 覆写物件方法]
(2) 在宣告行前端加上 nomask 修饰字,如 nomask void func()
[初级 LPC: 物件继承 - 覆写物件方法]
[初级 LPC: LPC 修饰字]
(3) private 修饰字修饰的函式,仅在物件本身内部才能被呼叫,当此物件被继承
时,于继承树同一层的平行物件,可经由宣告 prototype 呼叫。经由 protected
修饰过的函式
[初级 LPC: LPC 修饰字]
[初级 LPC: 物件继承 - LPC 继承阶层概念]
(4) 只需要在 B 中宣告该函式即可,如
private void func();
[初级 LPC: LPC 修饰字]
[初级 LPC: 物件继承 - LPC 继承阶层概念]
7. (1) process_input
[中级 LPC: driver applies]
(2) connect
[中级 LPC: driver applies]
(3) valid_object
[中级 LPC: driver applies]
(4) receive_message
[中级 LPC: driver applies]
8. (1) 执行该段程式之前用 set_eval_limit() 改变 evaluation cost 的起始值。
(2) 此种程式多为回圈,可于每次回圈开头加上 reset_eval_cost()。
(3) 使用 call_out() 延迟法分段跳开。
[初级 LPC: 基本除错 - 可见错误讯息之执行期错误]
9. (1) regexp(str_array, "^t");
[中级 LPC: regular expression]
(2) sscanf(str, "%*( *)%s", str);
[中级 LPC: regular expression]
10. (1) 当一个物件的原始物件不存在时,遇到 load_object(), find_object(file, 1),
new(), clone_object(), call_other() 的时候。
[初级 LPC: LPC OOP 理论 - 物件的载入与程式码的编译]
(2) MudOS 中每个物件程式码被编译后会产生一中间码,save_binary 主要是储存这些
码在 runtime configuration file 指定的 binary 目录中,如果在载入物件时其
对应的 binary 档案存在,MudOS 将不编译该物件之原始程式码档案,而直接读取
其 binary 档案载入物件。
[初级 LPC: LPC OOP 理论 - 物件的载入与程式码的编译]
[初级 LPC: LPC 前置处理器 - #pragma 编译器选项 - save_binary]
(3) 原先的复制物件依然使用旧的程式区块。
[初级 LPC: LPC OOP 理论 - 原始物件与复制物件]
(4) foreach(object ob in children("/obj/test")) destruct(ob);
[初级 LPC: LPC OOP 理论 - 原始物件与复制物件]
[中级 LPC: 常见 efun 的使用]
11. (1) 呼叫物件身上的 id()。
[中级 LPC: driver applies]
(2) present("obj_id 2", env_ob);
[初级 LPC: LPC OOP 理论 - 空间概念]
[中级 LPC: 常见 efun 的使用]
[中级 LPC: driver applies]
(3) 假设物件 PPL_A 存在于一个环境物件 ROOM_A 之中,他的身上带有 OBJ_A 及
OBJ_B,而 PPL_A 的 inventory list 中的顺位是 OBJ_A 在 OBJ_B 之前,且
PPL_A 中有一段程式码:
int id(string str) { if(str == "guard") return 1; else return 0; }
而 OBJ_A 中有一段程式码:
int id(string str) { if(str == "sword") return 1; else return 0; }
至于 OBJ_B 中有一段与 OBJ_A 完全相同的程式码:
int id(string str) { if(str == "sword") return 1; else return 0; }
则 present("sword", PPL_A); 可以取得 OBJ_A,present("guard", ROOM_A);
可取得 PPL_A,于 PPL_A 物件程式码中撰写 present("sword") 可得到 OBJ_A,
于 ROOM_A 物件程式码中撰写 present("guard") 可得到 PPL_A。
要取得 OBJ_B 则可使用 present("sword 2", PPL_A);
[初级 LPC: LPC OOP 理论 - 空间概念]
[中级 LPC: 常见 efun 的使用]
[中级 LPC: driver applies]
12. (1) log_error
[中级 LPC: driver applies]
[中级 LPC: LPC 错误处理机制]
(2) error_handler
[中级 LPC: driver applies]
[中级 LPC: LPC 错误处理机制]
(3) MudOS 会略过 error_handler() 的呼叫,自行将内定错误讯息写入 runtime
configuration file 中指定的 debug log file 中,同时将错误讯息输出至
stderr。
[中级 LPC: LPC 错误处理机制]
(4) error_handler 仍会被呼叫,但是第二个参数会接收到 1,以作为区别。
[中级 LPC: driver applies]
[中级 LPC: LPC 错误处理机制]
13. MudOS 会遵循一些设定而周期性的呼叫一些物件的 apply functions,请列出这些
apply functions,并说明如何使其开始被 MudOS 周期性呼叫,以及停止方式(没有
的请注明无)。 (4%)
reset,cleanup,swap**?
--------------------------------------------------------------------------------
14. MudOS 所创造出来的世界之基本元素为物件,而这些物件在被产生、消灭及彼此间
的互相关系上也有许多支援,试问:
(1) 一个物件被创造出来时,哪个 function 会被 MudOS 自动呼叫? (1%)
create
(2) 一个物件被摧毁时,被摧毁的物件上有什么 function 会被 MudOS 自动呼叫?
(1%)
destruct?remove? 模糊的问题...
(3) 一个物件的 environment object 被摧毁时,该物件身上哪个 function 会自
动被 MudOS 呼叫? (1%)
move_or_destruct??? 或者 destruct_env_of???
(4) 如果希望 /obj 路径下的所有物件档案均不能被载入,且物件中任一行程式码均
没有机会被执行,应该如何作此限制? (1%)
rm -rf /obj,嘿嘿,要不就限制所有相关 efun.好像前面的问题里面提到过
compile_object update_file 限制?
--------------------------------------------------------------------------------
15. MudOS 的世界里物件与物件之间,有著空间上的相对关系,试问:
(1) 如果玩家物件 A 为某一房间物件的内容物(即 A 位于此房间中),应该透过什么
efun 取得此房间物件? (1%)
environment(A)??? 这些属于增加不少问题难度级别
(2) 如果玩家物件 A 的内容物里有许多道具(即 A 身上有许多道具),我们该透过什
么 efun 一次取得这些道具的集合(即物件阵列)? (1%)
all_inventory(A)???
(3) 试用一些文字叙述假设几个物件环境,以及一些程式码,来说明如何移动一个物
件。 (1%)
是想问move_object还是move呢??
(4) 当一个物件被移动到一个物件中之后,该物件是否还能 shadow 到另一个物件身
上? (1%)
shadow没用过,,,这个不会哦。。。
--------------------------------------------------------------------------------
16. 试以目前所学的技术,设计一个物件程式码,其中有全域变数 basic_data、abilities
以及 magics,其型态均为 mapping,建立一些资料,并以 save_object 储存其内容至
一个档案。并设计一个指定变数回存的功能,也就是撰写一个函式,传入变数名称,该
变数之值即会被回存至上次存档时的内容。 (4%)
回存? restore??晕哦。。。
去copy save.c 就可以咯。。。。
还有restore.c
---------------------------------------------------------------------------------
17. 试撰写一个简易 mudlib 的几个基本物件程式码,使这个 mudlib 能够提供基本连线,
在连线成功后,可用 edit <filename> 的指令格式编辑档案,以 update <filename>
来将 filename 所产生的原始物件摧毁,并重新载入,以 quit 指令离线,并且能使用
shutdown 指令关闭 mud (请记得标明档名,以及这些档案在 runtime configuration
file 中的定义)。 (4%)
记得以前有个mowang版本的mini mudlib,去搞一个...
--------------------------------------------------------------------------------
18. 目前有一个函式,其传入值代表整数型态,代表输入模式,并以 switch case 述句来
判断其值,以执行相关程式码,其值为 1 时代表进行单行输入,为 2 时代表多行输入
,为 3 时代表不处理输入(即拦截),其它情形则发生错误,此函式内容如下:
void start_input(int mode)
{
switch(mode) {
case 1:
// some codes for single line input...
return;
case 2:
// some codes for multi line input...
return;
case 3:
return;
default:
error("No handler for this input mode.\n");
}
}
很明显的此程式码可读性不佳,尤其在使用上,呼叫部分使用 start_input(1)、
start_input(2)等等的方式容易使人无法立即理解,且容易误传其它无效的值进
入,试修改及增加一些程式码,使其更容易阅读,且在使用上较不容易传入无意
义值。 (4%)
不懂,,难道是考多态么??那就分别写三个咯...
--------------------------------------------------------------------------------
19. 有一未经缩排处理的程式码如下:
void do_something()
{
int a, b, c, d, e, f, g, h;
if(!a) a = 10;
b = 5;
if(b)
if(!c)
c = 3;
else
b = 10;
else
b = 20;
h = 16;
for(d=0;d<5;d++)
for(e=0;e<5;e++)
f = 100;
g += f;
}
试将此程式码作正确的缩排处理,使其层次正确以便于区分 if、else、for 述句之
影响范围。 (4%)
有**啊。。。不过这个题真的可以用来考非软件从业人员....
--------------------------------------------------------------------------------
20. [题组] LPC 的 function pointer 提供指向 anonymous function 的功能,则:
(1) 试撰写一段程式码,将一个 function pointer 变数指向一个 anonymous
function,该 anonymous function 接受 2 个整数值输入,回传结果为两传
入变数之和 (2%)
见3
(2) 将此 function pointer 的 owner 设定给 this_player()。 (1%)
是考bind么?
见3
(3) 最后再撰写一行执行此 function pointer 的范例程式码。 (1%)
这三个估计可以考倒不少人,嘿嘿
evaluate( bind((: $1 + $2 :), me), 1, 2)
--------------------------------------------------------------------------------
21. [题组] LPC 中的 0 分为两种,一种是常数零值 (constant zero),一种是未定义之
常数零值(constant zero & undefined),试问:
(1) LPC 中的变数,分别在什么情况下会有这两种不同的 0 值? (1%)
0+2 ------ return 0,false 然后 notify_fail 是这个意思么?还是别的???
别的就不明白了,或者是指 null??????
(2) 我们该如何测试该变数目前是哪种 0 值? (1%)
intp??
(3) 此二种 0 值在 if、while 等条件述句中代表的意义为何? (1%)
flase??
(4) 试撰写一个程式码,使一个已被指定值的 mapping 变数值,回到未定义之常数
零值。 (1%)
mapping m;
m 就是说的这个 0 吧?
用 0 swap value? 别的方法暂时没想到...
--------------------------------------------------------------------------------
22. 假设我们有一个房间物件,其中有一个整数 status 储存著房间的状态旗号,我们假设
status 最右边的位元(第一位元)被设定为 1 时,无法使用战斗指令。第二位元则是灯
光开关的状态,1 为点亮,0 为关闭,当我们每次按下开关时,0 与 1 会相互切换
,请设计以下几个函式:
战斗限制部分: (2%)
set_flag - 用来将 status 的某个位元设定为 1
&oxfff之类的??
clear_flag - 用来将 status 的某个位元设定为 0
灯光部分: (2%)
inverse_flag - 用来将 status 的某个位元由 1 转为 0,或由 0 转为 1
push_button - 按下灯光开关时会被呼叫
--------------------------------------------------------------------------------
23. (1) 请按照以下规格及功能要求设计出 simul_efun:
prototype: mixed *keys(mapping m);
当 m 为 0 值时不发生错误,传回空阵列。 (2%)
if (!mapp(m)) m=([])?????
(2) 设法防止 efun::keys(m); 在 simulated external function object 之外的地
方被执行成功。 (2%)
valid_override 限制?
--------------------------------------------------------------------------------
24. LPC 提供了对于 socket 的支援,试依照下列要求撰写 LPC 程式码:
(1) 建立一个 LPC 物件,并监听 port 60000,有连线产生即接受其连线,当使用者
传送讯息为「quit」时,中断此名使用者的连线,当讯息为「shutdown」时,与
此使用者终止连线,并停止监听 port 60000。 (2%)
去copy ftpd.c就可以了
(2) 承上题,试撰写另一物件,使其能藉由呼叫前一物件之函式,取得正在监听 port
60000 之 socket 所有权,并能持续提供相同的连线与指令处理功能。 (2%)
又是bind??或者传说中的shadow? 那个shadow不会用,没接触过....
--------------------------------------------------------------------------------
25. LPC 提供 virtual object 的支援,带给许多便利性,如大规模的制造房间,构成整
块大陆,可由此功能完成,请作答以下问题:
(1) 试列出并撰写相关函式,以产生任一物件名称为「/domain/test/17,15」之
virtual object,此物件并不需具备任何功能,请记得标明哪个函式属于哪
些物件程式档案里。 (2%)
virtual object 也没用过
(2) 承上题,在此物件中宣告一字串变数,并指定其值后以 save_object 存入资料
档中,试设计一简单的自动读取程式,使此物件下次被 load_object 载入完毕
并被传回后,该字串变数已经回复到上次储存的状态。 (2%)
19题是最有意义的题目,任何人写的代码都不可能一步到位,你总有需要修改以前写的代码的时候(改BUG或者加新功能),良好的排版格式能够使阅读代码更轻松,如果再配上良好的注释的话就更好了
代码除了拿来运行,还需要别人维护,编写代码的时候使用良好的排版和注释能够极大降低维护成本
排版和注释是最基本的要求