欢迎光临散文网 会员登陆 & 注册

Carpet编程入坑跳坑指北

2019-07-19 01:49 作者:禄存天玑  | 我要投稿

作者:禄存

前言

欢迎来TIS论坛,享受极致的 Markdown 渲染体验:https://forum.tis.world/topic/132/carpet编程入坑跳坑指北

首先感谢各位能抽时间看这一篇文章。最近抽了两天时间研究了一下 Carpet 这个脚本语言,这里来和大家分享一下自己的心得体会。

我最早了解到 Carpet 是因为 gnembon 的宣传视频。但是了解了也没去多看。后来因为兔子机研究生物 AI 的时候说到了 Carpet 端,就去研究了一下。花了一个晚上实现了宽度优先搜索,又花了一个下午实现了 A*寻路算法,算是有了点心得体会,来和大家分享一下。

基本介绍

Carpet 是一个用 Java 编写的,拥有较多功能的,基于原版 Minecraft 系统的函数式编程脚本。大体可以用“万物皆函数”概括,与 Java 的“万物皆对象”相映成趣。

Carpet 的运行效率不如Forge,但编写起来更加简单,修改也容易得多。

这里讲到的所有内容都可以在官方的手册 https://gnembon.github.io/scarpet/ 找到。

在读这篇文章之前,最好就对编程有所了解。

语法技巧

首先是各种特殊用法和注意要点: 

  • 对列表的一些奇妙操作,这个后面集中讲;

  • null 的设定是比任何对象都小的:在参与比较大小时,除了与自身相比为 true,否则总是 false

  • global_ 前缀可以声明全局变量,运行完毕后也会被保存;

  • 和 Java 一样,|| && 是“短路”的,也就是只会在必要条件下检测后一项,例如官方的示例;

  • 函数只能传值,例如:delete(list) -> list = l(); a = l(1,2,3); delete(a); print(a); 的输出是 [1, 2, 3]

列表,以及字符串

  • 列表是基于 Java 的 ArrayList 的,字符串是基于 String。运行效率如何自己掂量着看;

  • 列表可以同时存放不同类型的值,这点跟 Python 有点类似;

  • 列表进行 + - * / 的时候,如果后一个是数字,就对列表内的每一个对象进行一次操作;如果也是列表并且长度一样,就会将对象一一对应加起来,形成一个新的对象;如果前后列表长度不一样会报错。

  • 另外,l(l(1,2), l(2,3)) + l(l(1,2), l(2,3)) 以及 l(l(1,2), l(2,3)) + l(1,2)都是可以的;

  • 列表进行 += 时自动往最后面添加后一个操作数;

  • 列表用 element(<list>, <index>) 取出对象的时候,-1 代表最后一个,-2是倒数第二个;下标如果溢出就重新从0开始计数;

  • 字符串在使用 += + 的时候都会自动将后一个对象转换为字符串然后拼接;

  • ~ 在对列表使用时,会在列表中查找后一个对象。查到了返回下标,查不到返回 null;对字符串使用时会将后一个对象转换成字符串,作为正则表达式进行匹配。返回匹配到的字符串或者 null

  • 对字符串使用 - 时,会将后一个对象转换成字符串,并返回一个去除了所有该字符串的新字符串,不进行正则匹配,例如 'ababa' - 'aba' 返回 b

函数式编程和列表

抱歉,这里没有点操作符,大括号和中括号也没有

流操作?可以了解,但没卵用

排序列表是 sort(<list>) 但是外部传入的列表对象没变,你需要 list = sort(list),之前应该说过了,list.sort() 是什么?不存在的!

不过,你可以在一些作者预定义好的函数里写语句,类似 Java 的 Lambda 表达式。(惨,你自己是没法写能传语句的函数的!)例如这样能把一个列表映射成另一个列表,里面的每一个对应的值都是相反的:

map(list, -_)

它可以当作 Java 里的

list.stream().map(x -> -x).toArray()

这里的下划线_就是list里的每一个对象。

同理可得:

  •  filter(list, _ > 0) 能得到一个只有原列表中正数的新列表。 

  • 还有高级版的排序:sort_key(list, -_) 实现了逆序排序。

之前提到了流操作,确实很像,然而并不一样:根本没有那种优化! 例如:first(sort(list), true) 的性能比效果上等价的 min(list) 要差得多!

另外,列表只能在最后添加,不能中间插入,不能中间删除,但是可以根据下标截取出一个新的列表——其他的功能要自己写! 举个例子:

remove_by_val(list, item) -> (    

  new_list = l();

  for (list,

    if (item == _,

       put(new_list, null, _)

    )

  );

  return(new_list)

);

没错,for 和 if 也是函数,只不过能传入语句。具体要看官方手册的定义,同样的还有 loopwhile。另外这里没有方便的 break 和 continue,可能需要立flag或者用超大的条件判断。

看到这里,你可能会觉得不妙:那咋取出列表的特定元素?答案是 element(<list>, <index>),element有点奇妙的特性,上文说过。

那关于Minecraft的功能呢???

抱歉,我没怎么了解(笑)

不过看手册,功能还是挺全的,可以控制时间流逝速度,进行随机刻,搜索实体,获取 NBT 标签,生成结构,执行命令,甚至方便地检测一片区域里的方块……毕竟作者在技术社区混了那么久,基本上你想到的需求是一应俱全的。(实时生物AI追踪呢?)

不过也要小心一点。比起命令方块,Carpet 的安全性要差一点。例如一次在聊天栏输出超大的列表会卡死客户端,服务端在执行脚本的时候默认会冻结住之类的……

Carpet编程入坑跳坑指北的评论 (共 条)

分享到微博请遵守国家法律