Carpet编程入坑跳坑指北


  • TIS成员

    前言

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

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


    基本介绍

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

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

    这里讲到的所有内容都可以在官方的手册找到。

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

    语法技巧

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

    • 对列表的一些奇妙操作,这个后面集中讲;
    • 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)
    );
    

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

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

    那关于Minecraft的功能呢???

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

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

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



  • 这里指的是Scarpet吧:)


 

友情链接

魔茶国际
Powered by TIS