path.tin 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. #nop vim: set filetype=tt:;
  2. /*
  3. 本文件属于 PaoTin++ 的一部分。
  4. PaoTin++ © 2020~2023 的所有版权均由担子炮(dzp <danzipao@gmail.com>) 享有并保留一切法律权利
  5. 你可以在遵照 GPLv3 协议的基础之上使用、修改及重新分发本程序。
  6. */
  7. #nop 本文件是 xtintin 的一部分,实现了一些方向和路径运算函数;
  8. ///=== {
  9. ///// 方向和路径运算函数:
  10. //
  11. // #@ dir.Name <方向全拼|方向缩写> [<严格模式>]
  12. // 给出指定方向的中文名称。方向可以通过英文单词或者英文单词的缩写给出。
  13. //
  14. // EXAMPLE: \@dir.Name{eastup}
  15. // RESULT: {东上}
  16. //
  17. // EXAMPLE: \@dir.Name{eu}
  18. // RESULT: {东上}
  19. //
  20. // EXAMPLE: \@dir.Name{enter}
  21. // RESULT: {进去}
  22. //
  23. // EXAMPLE: \@dir.Name{eastup;1}
  24. // RESULT: {东上}
  25. //
  26. // EXAMPLE: \@dir.Name{eu;1}
  27. // RESULT: {东上}
  28. //
  29. // EXAMPLE: \@dir.Name{enter;1}
  30. // RESULT: {进去}
  31. //
  32. // EXAMPLE: \@dir.Name{open door}
  33. // RESULT: {open door}
  34. //
  35. // EXAMPLE: \@dir.Name{open door;1}
  36. // RESULT: {}
  37. // };
  38. #func {dir.Name} { #return @__dir_convert_dir__{name; %1; %2}; };
  39. ///=== {
  40. // #@ dir.Short <方向全拼> [<严格模式>]
  41. // 给出方向对应的英文单词缩写。
  42. //
  43. // EXAMPLE: \@dir.Short{eastup}
  44. // RESULT: {eu}
  45. //
  46. // EXAMPLE: \@dir.Short{eu}
  47. // RESULT: {eu}
  48. //
  49. // EXAMPLE: \@dir.Short{enter}
  50. // RESULT: {enter}
  51. //
  52. // EXAMPLE: \@dir.Short{open door}
  53. // RESULT: {open door}
  54. //
  55. // EXAMPLE: \@dir.Short{eastup;1}
  56. // RESULT: {eu}
  57. //
  58. // EXAMPLE: \@dir.Short{eu;1}
  59. // RESULT: {eu}
  60. //
  61. // EXAMPLE: \@dir.Short{enter;1}
  62. // RESULT: {enter}
  63. //
  64. // EXAMPLE: \@dir.Short{open door;1}
  65. // RESULT: {}
  66. // };
  67. #func {dir.Short} { #return @__dir_convert_dir__{short; %1; %2}; };
  68. ///=== {
  69. // #@ dir.Long <方向缩写> [<严格模式>]
  70. // 给出方向对应的英文单词全拼。
  71. //
  72. // EXAMPLE: \@dir.Long{eu}
  73. // RESULT: {eastup}
  74. //
  75. // EXAMPLE: \@dir.Long{eastup}
  76. // RESULT: {eastup}
  77. //
  78. // EXAMPLE: \@dir.Long{out}
  79. // RESULT: {out}
  80. //
  81. // EXAMPLE: \@dir.Long{open door}
  82. // RESULT: {open door}
  83. //
  84. // EXAMPLE: \@dir.Long{eu;1}
  85. // RESULT: {eastup}
  86. //
  87. // EXAMPLE: \@dir.Long{eastup;1}
  88. // RESULT: {eastup}
  89. //
  90. // EXAMPLE: \@dir.Long{out;1}
  91. // RESULT: {out}
  92. //
  93. // EXAMPLE: \@dir.Long{open door;1}
  94. // RESULT: {}
  95. // };
  96. #func {dir.Long} { #return @__dir_convert_dir__{long; %1; %2}; };
  97. ///=== {
  98. // #@ dir.Reverse <方向> [<严格模式>]
  99. // 给出方向对应的相反方向。
  100. //
  101. // EXAMPLE: \@dir.Reverse{eu}
  102. // RESULT: {wd}
  103. //
  104. // EXAMPLE: \@dir.Reverse{eastup}
  105. // RESULT: {westdown}
  106. //
  107. // EXAMPLE: \@dir.Reverse{enter}
  108. // RESULT: {out}
  109. //
  110. // EXAMPLE: \@dir.Reverse{open door}
  111. // RESULT: {open door}
  112. //
  113. // EXAMPLE: \@dir.Reverse{eu;1}
  114. // RESULT: {wd}
  115. //
  116. // EXAMPLE: \@dir.Reverse{eastup;1}
  117. // RESULT: {westdown}
  118. //
  119. // EXAMPLE: \@dir.Reverse{enter;1}
  120. // RESULT: {out}
  121. //
  122. // EXAMPLE: \@dir.Reverse{open door;1}
  123. // RESULT: {}
  124. //
  125. ///// 以上函数中,凡是支持严格模式参数的,如果严格模式为 true,则给错误方向给出空字符串结果。
  126. // };
  127. #func {dir.Reverse} {
  128. #if { "%1" == "enter{| .*}" } {
  129. #return {out};
  130. };
  131. #else {
  132. #return @__dir_convert_dir__{reverse; %1; %2};
  133. };
  134. };
  135. ///=== {
  136. // #@ dir.IsDir <方向全拼|方向缩写>
  137. // 检查参数是否是一个合格的方向指令。
  138. //
  139. // EXAMPLE: \@dir.IsDir{eu}
  140. // RESULT: {1}
  141. //
  142. // EXAMPLE: \@dir.IsDir{eastup}
  143. // RESULT: {1}
  144. //
  145. // EXAMPLE: \@dir.IsDir{enter}
  146. // RESULT: {1}
  147. //
  148. // EXAMPLE: \@dir.IsDir{open door}
  149. // RESULT: {0}
  150. // };
  151. #func {dir.IsDir} {
  152. #local cmd {%0};
  153. #if { "@dir.Name{{$cmd};1}" == "" } {
  154. #return 0;
  155. };
  156. #else {
  157. #return 1;
  158. };
  159. };
  160. ///=== {
  161. // #@ dir.Type <方向指令>
  162. // 计算方向指令的类型。方向指令有几大类:
  163. // - 标准出口(exit): 标准出口应当是一个小写字母拼写形式的出口
  164. // - 隐藏出口(hidden): 规定全大写字母拼写形式的出口为隐藏出口
  165. // - 动态出口(dynamic): 规定首字母大写拼写形式的出口为动态出口
  166. // - 非标指令(ad-hoc): 如果方向指令转换为小写之后,不是标准出口,则为非标指令
  167. //
  168. // EXAMPLE: \@dir.Type{north}
  169. // RESULT: {exit}
  170. //
  171. // EXAMPLE: \@dir.Type{NORTH}
  172. // RESULT: {hidden}
  173. //
  174. // EXAMPLE: \@dir.Type{North}
  175. // RESULT: {dynamic}
  176. //
  177. // EXAMPLE: \@dir.Type{open door}
  178. // RESULT: {ad-hoc}
  179. // };
  180. #func {dir.Type} {
  181. #local dir {%0};
  182. #local exit {@str.ToLower{$dir}};
  183. #if { ! @dir.IsDir{$exit} } {
  184. #return {ad-hoc};
  185. };
  186. #elseif { "$dir" == "{[A-Z]+}" } {
  187. #return {hidden};
  188. };
  189. #elseif { "$dir" == "{[A-Z][a-z]+}" } {
  190. #return {dynamic};
  191. };
  192. #else {
  193. #return {exit};
  194. };
  195. };
  196. ///=== {
  197. // #@ dir.ToCmd <方向指令> [<模式>]
  198. // 根据方向指令的类别,生成对应的命令。
  199. // 可选的模式用来生成特殊情形下的命令,例如推车程序。
  200. //
  201. // EXAMPLE: \@dir.ToCmd{north}
  202. // RESULT: {go north}
  203. //
  204. // EXAMPLE: \@dir.ToCmd{NORTH}
  205. // RESULT: {north}
  206. //
  207. // EXAMPLE: \@dir.ToCmd{North}
  208. // RESULT: {go north}
  209. //
  210. // EXAMPLE: \@dir.ToCmd{open door}
  211. // RESULT: {open door}
  212. //
  213. // EXAMPLE: \@dir.ToCmd{north;ganche}
  214. // RESULT: {gan che to north}
  215. //
  216. // EXAMPLE: \@dir.ToCmd{NORTH;ganche}
  217. // RESULT: {gan che to north}
  218. //
  219. // EXAMPLE: \@dir.ToCmd{North;ganche}
  220. // RESULT: {gan che to north}
  221. //
  222. // EXAMPLE: \@dir.ToCmd{ride;ganche}
  223. // RESULT: {ride}
  224. // };
  225. #func {dir.ToCmd} {
  226. #local dir {%1};
  227. #local mode {@default{%2;go}};
  228. #local type {@dir.Type{$dir}};
  229. #if { "$mode" == "go" } {
  230. #switch {"$type"} {
  231. #case {"exit"} {#return {go $dir}};
  232. #case {"hidden"} {#return {@str.ToLower{$dir}}};
  233. #case {"dynamic"} {#return {go @str.ToLower{$dir}}};
  234. #case {"ad-hoc"} {#return {$dir}};
  235. #default {#return {$dir}};
  236. };
  237. };
  238. #elseif { "$mode" == "ganche" } {
  239. #switch {"$type"} {
  240. #case {"exit"} {#return {gan che to $dir}};
  241. #case {"hidden"} {#return {gan che to @str.ToLower{$dir}}};
  242. #case {"dynamic"} {#return {gan che to @str.ToLower{$dir}}};
  243. #case {"ad-hoc"} {#return {$dir}};
  244. #default {#return {$dir}};
  245. };
  246. };
  247. };
  248. ///=== {
  249. // #@ path.Reverse <路径>
  250. // 给出路径对应的反向路径。
  251. //
  252. // EXAMPLE: \@path.Reverse{n;e;s;w}
  253. // RESULT: {e;n;w;s}
  254. //
  255. // EXAMPLE: \@path.Reverse{north;east;south;west}
  256. // RESULT: {east;north;west;south}
  257. //
  258. // EXAMPLE: \@path.Reverse{north;east;hp;south;west}
  259. // RESULT: {east;north;hp;west;south}
  260. // };
  261. #func {path.Reverse} {
  262. #local path {%0};
  263. #local newPath {};
  264. #local step {};
  265. #foreach {$path} {step} {
  266. #list newPath insert {1} {@dir.Reverse{$step}};
  267. };
  268. #return {@slist.FromList{$newPath}};
  269. };
  270. ///=== {
  271. // #@ path.Simplify <路径>
  272. // 化简路径。返回化简后的新路径。
  273. //
  274. // EXAMPLE: \@path.Simplify{north;north;north;east;west;south}
  275. // RESULT: {north;north}
  276. //
  277. // EXAMPLE: \@path.Simplify{north;north;north;east;south;west}
  278. // RESULT: {north;north;north;east;south;west}
  279. //
  280. // EXAMPLE: \@path.Simplify{n;n;n;e;w;s}
  281. // RESULT: {n;n}
  282. //
  283. // EXAMPLE: \@path.Simplify{n;n;n;e;s;w}
  284. // RESULT: {n;n;n;e;s;w}
  285. //
  286. // EXAMPLE: \@path.Simplify{n;n;n;e;hp;w;s}
  287. // RESULT: {n;n;n;e;hp;w;s}
  288. //
  289. // };
  290. #func {path.Simplify} {
  291. #local path {@list.FromSlist{%0}};
  292. #local count {&path[]};
  293. #if { $count == 0 } {
  294. #return {};
  295. };
  296. #local idx {1};
  297. #while { $idx < $count } {
  298. #local current {$path[$idx]};
  299. #local next {$path[@math.Eval{$idx + 1}]};
  300. #if { "@dir.Long{$current}" !== "@dir.Reverse{@dir.Long{$next}}" } {
  301. #math idx {$idx + 1};
  302. #continue;
  303. };
  304. #list path delete $idx 2;
  305. #local idx {@math.Max{1;@math.Eval{$idx - 2}}};
  306. #local count {@math.Eval{$count - 2}};
  307. };
  308. #return {@slist.FromList{$path}};
  309. };
  310. ///=== {
  311. // ## path.Compact <路径>
  312. // 压缩路径。返回后的新路径。
  313. //
  314. // EXAMPLE: \@path.Compact{north;north;north;east;south;south;west}
  315. // RESULT: {#3 north;east;south;south;west}
  316. //
  317. // EXAMPLE: \@path.Compact{n;n;n;e;s;s;w}
  318. // RESULT: {#3 n;e;s;s;w}
  319. // };
  320. #func {path.Compact} {
  321. #local path {%0};
  322. #local newPath {};
  323. #local step {};
  324. #local last {};
  325. #local count {};
  326. #foreach {$path;} {step} {
  327. #if { "$last" == "$step" } {
  328. #math count {$count + 1};
  329. };
  330. #else {
  331. #if { "$last" != "" } {
  332. #if { $count > 2 } {
  333. #list newPath add {#$count $last};
  334. };
  335. #else {
  336. #local tmp {};
  337. #loop 1 {$count} {tmp} {
  338. #list newPath add {$last};
  339. };
  340. };
  341. };
  342. #local last {$step};
  343. #local count {1};
  344. };
  345. #if { "$step" == "" } {
  346. #break;
  347. };
  348. };
  349. #return {@slist.FromList{$newPath}};
  350. };
  351. ///=== {
  352. // #@ path.Long <路径>
  353. // 返回长版本的路径。路径中的每个方向命令都会被扩展成完整的单词。
  354. //
  355. // EXAMPLE: \@path.Long{n;n;n;e;w;s}
  356. // RESULT: {north;north;north;east;west;south}
  357. // };
  358. #func {path.Long} {
  359. #return {@fp.Transform{{%0};{\@dir.Long{VALUE}}}};
  360. };
  361. ///=== {
  362. // #@ path.Short <路径>
  363. // 返回长版本的路径。路径中的每个方向命令都会被简化。
  364. //
  365. // EXAMPLE: \@path.Short{north;north;north;east;south;west}
  366. // RESULT: {n;n;n;e;s;w}
  367. // };
  368. #func {path.Short} {
  369. #return {@fp.Transform{{%0};{\@dir.Short{VALUE}}}};
  370. };
  371. #var xtt.dir.table {
  372. {east} {{name}{正东} {short}{e} {long}{east} {reverse}{west} }
  373. {west} {{name}{正西} {short}{w} {long}{west} {reverse}{east} }
  374. {south} {{name}{正南} {short}{s} {long}{south} {reverse}{north} }
  375. {north} {{name}{正北} {short}{n} {long}{north} {reverse}{south} }
  376. {e} {{name}{正东} {short}{e} {long}{east} {reverse}{w} }
  377. {w} {{name}{正西} {short}{w} {long}{west} {reverse}{e} }
  378. {s} {{name}{正南} {short}{s} {long}{south} {reverse}{n} }
  379. {n} {{name}{正北} {short}{n} {long}{north} {reverse}{s} }
  380. {northeast} {{name}{东北} {short}{ne} {long}{northeast} {reverse}{southwest}}
  381. {southeast} {{name}{东南} {short}{se} {long}{southeast} {reverse}{northwest}}
  382. {northwest} {{name}{西北} {short}{nw} {long}{northwest} {reverse}{southeast}}
  383. {southwest} {{name}{西南} {short}{sw} {long}{southwest} {reverse}{northeast}}
  384. {ne} {{name}{东北} {short}{ne} {long}{northeast} {reverse}{sw} }
  385. {se} {{name}{东南} {short}{se} {long}{southeast} {reverse}{nw} }
  386. {nw} {{name}{西北} {short}{nw} {long}{northwest} {reverse}{se} }
  387. {sw} {{name}{西南} {short}{sw} {long}{southwest} {reverse}{ne} }
  388. {up} {{name}{正上} {short}{u} {long}{up} {reverse}{down} }
  389. {down} {{name}{正下} {short}{d} {long}{down} {reverse}{up} }
  390. {u} {{name}{正上} {short}{u} {long}{up} {reverse}{d} }
  391. {d} {{name}{正下} {short}{d} {long}{down} {reverse}{u} }
  392. {eastup} {{name}{东上} {short}{eu} {long}{eastup} {reverse}{westdown} }
  393. {westup} {{name}{西上} {short}{wu} {long}{westup} {reverse}{eastdown} }
  394. {southup} {{name}{南上} {short}{su} {long}{southup} {reverse}{northdown}}
  395. {northup} {{name}{北上} {short}{nu} {long}{northup} {reverse}{southdown}}
  396. {eu} {{name}{东上} {short}{eu} {long}{eastup} {reverse}{wd} }
  397. {wu} {{name}{西上} {short}{wu} {long}{westup} {reverse}{ed} }
  398. {su} {{name}{南上} {short}{su} {long}{southup} {reverse}{nd} }
  399. {nu} {{name}{北上} {short}{nu} {long}{northup} {reverse}{sd} }
  400. {eastdown} {{name}{东下} {short}{ed} {long}{eastdown} {reverse}{westup} }
  401. {westdown} {{name}{西下} {short}{wd} {long}{westdown} {reverse}{eastup} }
  402. {southdown} {{name}{南下} {short}{sd} {long}{southdown} {reverse}{northup} }
  403. {northdown} {{name}{北下} {short}{nd} {long}{northdown} {reverse}{southup} }
  404. {ed} {{name}{东下} {short}{ed} {long}{eastdown} {reverse}{wu} }
  405. {wd} {{name}{西下} {short}{wd} {long}{westdown} {reverse}{eu} }
  406. {sd} {{name}{南下} {short}{sd} {long}{southdown} {reverse}{nu} }
  407. {nd} {{name}{北下} {short}{nd} {long}{northdown} {reverse}{su} }
  408. {out} {{name}{出去} {short}{out} {long}{out} {reverse}{enter} }
  409. {enter} {{name}{进去} {short}{enter} {long}{enter} {reverse}{out} }
  410. };
  411. #func {__dir_convert_dir__} {
  412. #local field {%1};
  413. #local dir {%2};
  414. #local restricted {%3};
  415. #if { "$dir" == "" } {
  416. #return {};
  417. };
  418. #local entry ${xtt.dir.table[$dir]};
  419. #if { "$entry" == "" } {
  420. #if { @isTrue{$restricted} } {
  421. #return {};
  422. };
  423. #else {
  424. #return {$dir};
  425. };
  426. };
  427. #else {
  428. #return {$entry[$field]};
  429. };
  430. };